History

riscv64-asm.c: implement C extension

add nop fix asm_emit_i immediate check (negative offsets were missing) fix check for IM12S remove non-existent instructions (example: slli64 is just slli with imm=0)

noneofyourbusiness committed 2 years ago

Commit d87801b1 parent 81a32ec2 files · +881 −239Browse files

Unified · Split

2 files
  1. riscv64-asm.c +805 −219
  2. riscv64-tok.h +76 −20
riscv64-asm.c+805−219
@@ -19,6 +19,60 @@ ST_FUNC void gen_le32(int c); · 18 unmodified lines
19#define USING_GLOBALS19#define USING_GLOBALS
20#include "tcc.h"20#include "tcc.h"
21 21
22enum {
23 OPT_REG,
24 OPT_IM12S,
25 OPT_IM32,
26};
27#define C_ENCODE_RS1(register_index) ((register_index) << 7)
28#define C_ENCODE_RS2(register_index) ((register_index) << 2)
29#define ENCODE_RD(register_index) ((register_index) << 7)
30#define ENCODE_RS1(register_index) ((register_index) << 15)
31#define ENCODE_RS2(register_index) ((register_index) << 20)
32#define NTH_BIT(b, n) ((b >> n) & 1)
33#define OP_IM12S (1 << OPT_IM12S)
34#define OP_IM32 (1 << OPT_IM32)
35#define OP_REG (1 << OPT_REG)
36
37typedef struct Operand {
38 uint32_t type;
39 union {
40 uint8_t reg;
41 uint16_t regset;
42 ExprValue e;
43 };
44} Operand;
45
46static void asm_binary_opcode(TCCState* s1, int token);
47static void asm_clobber(uint8_t *clobber_regs, const char *str);
48static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
49static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
50static void asm_emit_i(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
51static void asm_emit_j(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
52static void asm_emit_opcode(uint32_t opcode);
53static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
54static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
55static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
56static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
57static void asm_nullary_opcode(TCCState *s1, int token);
58static void asm_opcode(TCCState *s1, int token);
59static int asm_parse_regvar(int t);
60static void asm_ternary_opcode(TCCState *s1, int token);
61static void asm_unary_opcode(TCCState *s1, int token);
62static void gen_expr32(ExprValue *pe);
63static void parse_operand(TCCState *s1, Operand *op);
64static void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
65/* C extension */
66static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
67static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm);
68static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
69static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
70static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm);
71static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm);
72static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
73static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm);
74static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm);
75
22/* XXX: make it faster ? */76/* XXX: make it faster ? */
23ST_FUNC void g(int c)77ST_FUNC void g(int c)
24{78{
@@ -63,6 +117,9 @@ static void asm_emit_opcode(uint32_t opcode) { · 38 unmodified lines
63 117
64static void asm_nullary_opcode(TCCState *s1, int token)118static void asm_nullary_opcode(TCCState *s1, int token)
65{119{
120 static const Operand nil = {.type = OP_REG};
121 static const Operand zimm = {.type = OP_IM12S};
122
66 switch (token) {123 switch (token) {
67 // Sync instructions124 // Sync instructions
68 125
@@ -84,36 +141,27 @@ static void asm_nullary_opcode(TCCState *s1, int token) · 15 unmodified lines
84 141
85 // Other142 // Other
86 143
144 case TOK_ASM_nop:
145 asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
146 return;
147
87 case TOK_ASM_wfi:148 case TOK_ASM_wfi:
88 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));149 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
89 return;150 return;
90 151
152 /* C extension */
153 case TOK_ASM_c_ebreak:
154 asm_emit_cr(token, 2 | (9 << 12), &nil, &nil);
155 return;
156 case TOK_ASM_c_nop:
157 asm_emit_ci(token, 1, &nil, &zimm);
158 return;
159
91 default:160 default:
92 expect("nullary instruction");161 expect("nullary instruction");
93 }162 }
94}163}
95 164
96enum {
97 OPT_REG,
98 OPT_IM12S,
99 OPT_IM32,
100};
101#define OP_REG (1 << OPT_REG)
102#define OP_IM32 (1 << OPT_IM32)
103#define OP_IM12S (1 << OPT_IM12S)
104
105typedef struct Operand {
106 uint32_t type;
107 union {
108 uint8_t reg;
109 uint16_t regset;
110 ExprValue e;
111 };
112} Operand;
113
114static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2);
115static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2);
116
117/* Parse a text containing operand and store the result in OP */165/* Parse a text containing operand and store the result in OP */
118static void parse_operand(TCCState *s1, Operand *op)166static void parse_operand(TCCState *s1, Operand *op)
119{167{
@@ -134,27 +182,22 @@ static void parse_operand(TCCState *s1, Operand *op) · 14 unmodified lines
134 asm_expr(s1, &e);182 asm_expr(s1, &e);
135 op->type = OP_IM32;183 op->type = OP_IM32;
136 op->e = e;184 op->e = e;
185 /* compare against unsigned 12-bit maximum */
137 if (!op->e.sym) {186 if (!op->e.sym) {
138 if ((int) op->e.v >= -2048 && (int) op->e.v < 2048)187 if (op->e.v < 0x2000)
139 op->type = OP_IM12S;188 op->type = OP_IM12S;
140 } else189 } else
141 expect("operand");190 expect("operand");
142}191}
143 192
144#define ENCODE_RS1(register_index) ((register_index) << 15)
145#define ENCODE_RS2(register_index) ((register_index) << 20)
146#define ENCODE_RD(register_index) ((register_index) << 7)
147
148// Note: Those all map to CSR--so they are pseudo-instructions.
149static void asm_unary_opcode(TCCState *s1, int token)193static void asm_unary_opcode(TCCState *s1, int token)
150{194{
151 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);195 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
152 Operand op;196 Operand op;
197 static const Operand nil = {.type = OP_REG};
198
153 parse_operand(s1, &op);199 parse_operand(s1, &op);
154 if (op.type != OP_REG) {200 /* Note: Those all map to CSR--so they are pseudo-instructions. */
155 expect("register");
156 return;
157 }
158 opcode |= ENCODE_RD(op.reg);201 opcode |= ENCODE_RD(op.reg);
159 202
160 switch (token) {203 switch (token) {
@@ -176,6 +219,18 @@ static void asm_unary_opcode(TCCState *s1, int token) · 15 unmodified lines
176 case TOK_ASM_rdinstreth:219 case TOK_ASM_rdinstreth:
177 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));220 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
178 return;221 return;
222 case TOK_ASM_c_j:
223 asm_emit_cj(token, 1 | (5 << 13), &op);
224 return;
225 case TOK_ASM_c_jal: /* RV32C-only */
226 asm_emit_cj(token, 1 | (1 << 13), &op);
227 return;
228 case TOK_ASM_c_jalr:
229 asm_emit_cr(token, 2 | (9 << 12), &op, &nil);
230 return;
231 case TOK_ASM_c_jr:
232 asm_emit_cr(token, 2 | (8 << 12), &op, &nil);
233 return;
179 default:234 default:
180 expect("unary instruction");235 expect("unary instruction");
181 }236 }
@@ -221,6 +276,100 @@ static void asm_binary_opcode(TCCState* s1, int token) · 39 unmodified lines
221 case TOK_ASM_jal:276 case TOK_ASM_jal:
222 asm_emit_j(token, 0x6f, ops, ops + 1);277 asm_emit_j(token, 0x6f, ops, ops + 1);
223 return;278 return;
279
280 /* C extension */
281 case TOK_ASM_c_add:
282 asm_emit_cr(token, 2 | (9 << 12), ops, ops + 1);
283 return;
284 case TOK_ASM_c_mv:
285 asm_emit_cr(token, 2 | (8 << 12), ops, ops + 1);
286 return;
287
288 case TOK_ASM_c_addi16sp:
289 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
290 return;
291 case TOK_ASM_c_addi:
292 asm_emit_ci(token, 1, ops, ops + 1);
293 return;
294 case TOK_ASM_c_addiw:
295 asm_emit_ci(token, 1 | (1 << 13), ops, ops + 1);
296 return;
297 case TOK_ASM_c_fldsp:
298 asm_emit_ci(token, 2 | (1 << 13), ops, ops + 1);
299 return;
300 case TOK_ASM_c_flwsp: /* RV32FC-only */
301 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
302 return;
303 case TOK_ASM_c_ldsp:
304 asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
305 return;
306 case TOK_ASM_c_li:
307 asm_emit_ci(token, 1 | (2 << 13), ops, ops + 1);
308 return;
309 case TOK_ASM_c_lui:
310 asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
311 return;
312 case TOK_ASM_c_lwsp:
313 asm_emit_ci(token, 2 | (2 << 13), ops, ops + 1);
314 return;
315 case TOK_ASM_c_slli:
316 asm_emit_ci(token, 2, ops, ops + 1);
317 return;
318
319 case TOK_ASM_c_addi4spn:
320 asm_emit_ciw(token, 0, ops, ops + 1);
321 return;
322
323#define CA (1 | (3 << 10) | (4 << 13))
324 case TOK_ASM_c_addw:
325 asm_emit_ca(token, CA | (1 << 5) | (1 << 12), ops, ops + 1);
326 return;
327 case TOK_ASM_c_and:
328 asm_emit_ca(token, CA | (3 << 5), ops, ops + 1);
329 return;
330 case TOK_ASM_c_or:
331 asm_emit_ca(token, CA | (2 << 5), ops, ops + 1);
332 return;
333 case TOK_ASM_c_sub:
334 asm_emit_ca(token, CA, ops, ops + 1);
335 return;
336 case TOK_ASM_c_subw:
337 asm_emit_ca(token, CA | (1 << 12), ops, ops + 1);
338 return;
339 case TOK_ASM_c_xor:
340 asm_emit_ca(token, CA | (1 << 5), ops, ops + 1);
341 return;
342#undef CA
343
344 case TOK_ASM_c_andi:
345 asm_emit_cb(token, 1 | (2 << 10) | (4 << 13), ops, ops + 1);
346 return;
347 case TOK_ASM_c_beqz:
348 asm_emit_cb(token, 1 | (6 << 13), ops, ops + 1);
349 return;
350 case TOK_ASM_c_bnez:
351 asm_emit_cb(token, 1 | (7 << 13), ops, ops + 1);
352 return;
353 case TOK_ASM_c_srai:
354 asm_emit_cb(token, 1 | (1 << 10) | (4 << 13), ops, ops + 1);
355 return;
356 case TOK_ASM_c_srli:
357 asm_emit_cb(token, 1 | (4 << 13), ops, ops + 1);
358 return;
359
360 case TOK_ASM_c_sdsp:
361 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
362 return;
363 case TOK_ASM_c_swsp:
364 asm_emit_css(token, 2 | (6 << 13), ops, ops + 1);
365 return;
366 case TOK_ASM_c_fswsp: /* RV32FC-only */
367 asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
368 return;
369 case TOK_ASM_c_fsdsp:
370 asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
371 return;
372
224 default:373 default:
225 expect("binary instruction");374 expect("binary instruction");
226 }375 }
@@ -263,7 +412,7 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper · 36 unmodified lines
263 return;412 return;
264 }413 }
265 if (rs2->type != OP_IM12S) {414 if (rs2->type != OP_IM12S) {
266 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 4095", get_tok_str(token, NULL));415 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
267 return;416 return;
268 }417 }
269 /* I-type instruction:418 /* I-type instruction:
@@ -278,7 +427,7 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper · 8 unmodified lines
278 427
279static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)428static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
280{429{
281 uint64_t imm;430 uint32_t imm;
282 431
283 if (rd->type != OP_REG) {432 if (rd->type != OP_REG) {
284 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));433 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
@@ -311,7 +460,7 @@ static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Oper · 26 unmodified lines
311 gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));460 gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));
312}461}
313 462
314static void asm_shift_opcode(TCCState *s1, int token)463static void asm_ternary_opcode(TCCState *s1, int token)
315{464{
316 Operand ops[3];465 Operand ops[3];
317 parse_operand(s1, &ops[0]);466 parse_operand(s1, &ops[0]);
@@ -363,27 +512,7 @@ static void asm_shift_opcode(TCCState *s1, int token) · 45 unmodified lines
363 case TOK_ASM_sraiw:512 case TOK_ASM_sraiw:
364 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);513 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
365 return;514 return;
366 default:
367 expect("shift instruction");
368 }
369}
370
371static void asm_data_processing_opcode(TCCState* s1, int token)
372{
373 Operand ops[3];
374 parse_operand(s1, &ops[0]);
375 if (tok == ',')
376 next();
377 else
378 expect("','");
379 parse_operand(s1, &ops[1]);
380 if (tok == ',')
381 next();
382 else
383 expect("','");
384 parse_operand(s1, &ops[2]);
385 515
386 switch (token) {
387 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format516 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
388 517
389 case TOK_ASM_add:518 case TOK_ASM_add:
@@ -446,64 +575,26 @@ static void asm_data_processing_opcode(TCCState* s1, int token) · 56 unmodified lines
446 asm_emit_i(token, 0x67 | (0 << 12), ops, ops + 1, ops + 2);575 asm_emit_i(token, 0x67 | (0 << 12), ops, ops + 1, ops + 2);
447 return;576 return;
448 577
449 default:578 /* branch (RS1, RS2, IMM); B-format */
450 expect("known data processing instruction");579 case TOK_ASM_beq:
451 }580 asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
452}
453
454/* caller: Add funct3 to opcode */
455static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
456{
457 if (rs1->type != OP_REG) {
458 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
459 return;581 return;
460 }582 case TOK_ASM_bne:
461 if (rs2->type != OP_REG) {583 asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
462 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
463 return;584 return;
464 }585 case TOK_ASM_blt:
465 if (imm->type != OP_IM12S) {586 asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
466 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
467 return;587 return;
468 }588 case TOK_ASM_bge:
469 {589 asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
470 uint16_t v = imm->e.v;
471 /* S-type instruction:
472 31...25 imm[11:5]
473 24...20 rs2
474 19...15 rs1
475 14...12 funct3
476 11...7 imm[4:0]
477 6...0 opcode
478 opcode always fixed pos. */
479 gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
480 }
481}
482
483static void asm_data_transfer_opcode(TCCState* s1, int token)
484{
485 Operand ops[3];
486 parse_operand(s1, &ops[0]);
487 if (ops[0].type != OP_REG) {
488 expect("register");
489 return;590 return;
490 }591 case TOK_ASM_bltu:
491 if (tok == ',')592 asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
492 next();593 return;
493 else594 case TOK_ASM_bgeu:
494 expect("','");595 asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
495 parse_operand(s1, &ops[1]);
496 if (ops[1].type != OP_REG) {
497 expect("register");
498 return;596 return;
499 }
500 if (tok == ',')
501 next();
502 else
503 expect("','");
504 parse_operand(s1, &ops[2]);
505 597
506 switch (token) {
507 // Loads (RD,RS1,I); I-format598 // Loads (RD,RS1,I); I-format
508 599
509 case TOK_ASM_lb:600 case TOK_ASM_lb:
@@ -544,69 +635,86 @@ static void asm_data_transfer_opcode(TCCState* s1, int token) · 34 unmodified lines
544 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);635 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
545 return;636 return;
546 637
638 /* C extension */
639 /* register-based loads and stores (RD, RS1, IMM); CL-format */
640 case TOK_ASM_c_fld:
641 asm_emit_cl(token, 1 << 13, ops, ops + 1, ops + 2);
642 return;
643 case TOK_ASM_c_flw: /* RV32FC-only */
644 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
645 return;
646 case TOK_ASM_c_fsd:
647 asm_emit_cs(token, 5 << 13, ops, ops + 1, ops + 2);
648 return;
649 case TOK_ASM_c_fsw: /* RV32FC-only */
650 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
651 return;
652 case TOK_ASM_c_ld:
653 asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
654 return;
655 case TOK_ASM_c_lw:
656 asm_emit_cl(token, 2 << 13, ops, ops + 1, ops + 2);
657 return;
658 case TOK_ASM_c_sd:
659 asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
660 return;
661 case TOK_ASM_c_sw:
662 asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
663 return;
664
547 default:665 default:
548 expect("known data transfer instruction");666 expect("ternary instruction");
549 }667 }
550}668}
551 669
552static void asm_branch_opcode(TCCState* s1, int token)670/* caller: Add funct3 to opcode */
671static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
553{672{
554 // Branch (RS1,RS2,IMM); SB-format673 if (rs1->type != OP_REG) {
555 uint32_t opcode = (0x18 << 2) | 3;674 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
556 uint32_t offset = 0;
557 Operand ops[3];
558 parse_operand(s1, &ops[0]);
559 if (ops[0].type != OP_REG) {
560 expect("register");
561 return;675 return;
562 }676 }
563 if (tok == ',')677 if (rs2->type != OP_REG) {
564 next();678 tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
565 else
566 expect("','");
567 parse_operand(s1, &ops[1]);
568 if (ops[1].type != OP_REG) {
569 expect("register");
570 return;679 return;
571 }680 }
572 if (tok == ',')681 if (imm->type != OP_IM12S) {
573 next();682 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
574 else683 return;
575 expect("','");684 }
576 parse_operand(s1, &ops[2]);685 {
686 uint16_t v = imm->e.v;
687 /* S-type instruction:
688 31...25 imm[11:5]
689 24...20 rs2
690 19...15 rs1
691 14...12 funct3
692 11...7 imm[4:0]
693 6...0 opcode
694 opcode always fixed pos. */
695 gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
696 }
697}
577 698
578 if (ops[2].type != OP_IM12S) {699static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm)
579 tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));700{
701 uint32_t offset;
702
703 if (rs1->type != OP_REG) {
704 tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
580 return;705 return;
581 }706 }
582 offset = ops[2].e.v;707 if (rs2->type != OP_REG) {
583 if (offset & 1) {708 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
584 tcc_error("'%s': Expected third operand that is an even immediate value", get_tok_str(token, NULL));
585 return;709 return;
586 }710 }
587 711 if (imm->type != OP_IM12S) {
588 switch (token) {712 tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
589 case TOK_ASM_beq:713 return;
590 opcode |= 0 << 12;
591 break;
592 case TOK_ASM_bne:
593 opcode |= 1 << 12;
594 break;
595 case TOK_ASM_blt:
596 opcode |= 4 << 12;
597 break;
598 case TOK_ASM_bge:
599 opcode |= 5 << 12;
600 break;
601 case TOK_ASM_bltu:
602 opcode |= 6 << 12;
603 break;
604 case TOK_ASM_bgeu:
605 opcode |= 7 << 12;
606 break;
607 default:
608 expect("known branch instruction");
609 }714 }
715
716 offset = imm->e.v;
717
610 /* B-type instruction:718 /* B-type instruction:
611 31 imm[12]719 31 imm[12]
612 30...25 imm[10:5]720 30...25 imm[10:5]
@@ -616,19 +724,20 @@ static void asm_branch_opcode(TCCState* s1, int token) · 3 unmodified lines
616 8...11 imm[4:1]724 8...11 imm[4:1]
617 7 imm[11]725 7 imm[11]
618 6...0 opcode */726 6...0 opcode */
619 asm_emit_opcode(opcode | ENCODE_RS1(ops[0].reg) | ENCODE_RS2(ops[1].reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31));727 asm_emit_opcode(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31));
620}728}
621 729
622ST_FUNC void asm_opcode(TCCState *s1, int token)730ST_FUNC void asm_opcode(TCCState *s1, int token)
623{731{
624 switch (token) {732 switch (token) {
733 case TOK_ASM_ebreak:
734 case TOK_ASM_ecall:
625 case TOK_ASM_fence:735 case TOK_ASM_fence:
626 case TOK_ASM_fence_i:736 case TOK_ASM_fence_i:
627 case TOK_ASM_ecall:
628 case TOK_ASM_ebreak:
629 case TOK_ASM_mrts:
630 case TOK_ASM_mrth:
631 case TOK_ASM_hrts:737 case TOK_ASM_hrts:
738 case TOK_ASM_mrth:
739 case TOK_ASM_mrts:
740 case TOK_ASM_nop:
632 case TOK_ASM_wfi:741 case TOK_ASM_wfi:
633 asm_nullary_opcode(s1, token);742 asm_nullary_opcode(s1, token);
634 return;743 return;
@@ -648,68 +757,108 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 13 unmodified lines
648 asm_binary_opcode(s1, token);757 asm_binary_opcode(s1, token);
649 return;758 return;
650 759
651 case TOK_ASM_sll:
652 case TOK_ASM_slli:
653 case TOK_ASM_srl:
654 case TOK_ASM_srli:
655 case TOK_ASM_sra:
656 case TOK_ASM_srai:
657 case TOK_ASM_sllw:
658 case TOK_ASM_slld:
659 case TOK_ASM_slliw:
660 case TOK_ASM_sllid:
661 case TOK_ASM_srlw:
662 case TOK_ASM_srld:
663 case TOK_ASM_srliw:
664 case TOK_ASM_srlid:
665 case TOK_ASM_sraw:
666 case TOK_ASM_srad:
667 case TOK_ASM_sraiw:
668 case TOK_ASM_sraid:
669 asm_shift_opcode(s1, token);
670 return;
671
672 case TOK_ASM_add:760 case TOK_ASM_add:
673 case TOK_ASM_addi:761 case TOK_ASM_addi:
674 case TOK_ASM_sub:
675 case TOK_ASM_addw:
676 case TOK_ASM_addiw:762 case TOK_ASM_addiw:
677 case TOK_ASM_subw:763 case TOK_ASM_addw:
678 case TOK_ASM_xor:
679 case TOK_ASM_xori:
680 case TOK_ASM_or:
681 case TOK_ASM_ori:
682 case TOK_ASM_and:764 case TOK_ASM_and:
683 case TOK_ASM_andi:765 case TOK_ASM_andi:
684 case TOK_ASM_slt:766 case TOK_ASM_beq:
685 case TOK_ASM_slti:767 case TOK_ASM_bge:
686 case TOK_ASM_sltu:768 case TOK_ASM_bgeu:
687 case TOK_ASM_sltiu:769 case TOK_ASM_blt:
688 case TOK_ASM_jalr:770 case TOK_ASM_bltu:
689 asm_data_processing_opcode(s1, token);771 case TOK_ASM_bne:
690 return;772 case TOK_ASM_jalr:
691
692 case TOK_ASM_lb:773 case TOK_ASM_lb:
693 case TOK_ASM_lh:
694 case TOK_ASM_lw:
695 case TOK_ASM_lbu:774 case TOK_ASM_lbu:
696 case TOK_ASM_lhu:
697 case TOK_ASM_ld:775 case TOK_ASM_ld:
776 case TOK_ASM_lh:
777 case TOK_ASM_lhu:
778 case TOK_ASM_lw:
698 case TOK_ASM_lwu:779 case TOK_ASM_lwu:
780 case TOK_ASM_or:
781 case TOK_ASM_ori:
699 case TOK_ASM_sb:782 case TOK_ASM_sb:
783 case TOK_ASM_sd:
700 case TOK_ASM_sh:784 case TOK_ASM_sh:
785 case TOK_ASM_sll:
786 case TOK_ASM_slli:
787 case TOK_ASM_slliw:
788 case TOK_ASM_sllw:
789 case TOK_ASM_slt:
790 case TOK_ASM_slti:
791 case TOK_ASM_sltiu:
792 case TOK_ASM_sltu:
793 case TOK_ASM_sra:
794 case TOK_ASM_srai:
795 case TOK_ASM_sraiw:
796 case TOK_ASM_sraw:
797 case TOK_ASM_srl:
798 case TOK_ASM_srli:
799 case TOK_ASM_srliw:
800 case TOK_ASM_srlw:
801 case TOK_ASM_sub:
802 case TOK_ASM_subw:
701 case TOK_ASM_sw:803 case TOK_ASM_sw:
702 case TOK_ASM_sd:804 case TOK_ASM_xor:
703 asm_data_transfer_opcode(s1, token);805 case TOK_ASM_xori:
806 asm_ternary_opcode(s1, token);
704 return;807 return;
705 808
706 case TOK_ASM_beq:809 /* C extension */
707 case TOK_ASM_bne:810 case TOK_ASM_c_ebreak:
708 case TOK_ASM_blt:811 case TOK_ASM_c_nop:
709 case TOK_ASM_bge:812 asm_nullary_opcode(s1, token);
710 case TOK_ASM_bltu:813 return;
711 case TOK_ASM_bgeu:814
712 asm_branch_opcode(s1, token);815 case TOK_ASM_c_j:
816 case TOK_ASM_c_jal:
817 case TOK_ASM_c_jalr:
818 case TOK_ASM_c_jr:
819 asm_unary_opcode(s1, token);
820 return;
821
822 case TOK_ASM_c_add:
823 case TOK_ASM_c_addi16sp:
824 case TOK_ASM_c_addi4spn:
825 case TOK_ASM_c_addi:
826 case TOK_ASM_c_addiw:
827 case TOK_ASM_c_addw:
828 case TOK_ASM_c_and:
829 case TOK_ASM_c_andi:
830 case TOK_ASM_c_beqz:
831 case TOK_ASM_c_bnez:
832 case TOK_ASM_c_fldsp:
833 case TOK_ASM_c_flwsp:
834 case TOK_ASM_c_fsdsp:
835 case TOK_ASM_c_fswsp:
836 case TOK_ASM_c_ldsp:
837 case TOK_ASM_c_li:
838 case TOK_ASM_c_lui:
839 case TOK_ASM_c_lwsp:
840 case TOK_ASM_c_mv:
841 case TOK_ASM_c_or:
842 case TOK_ASM_c_sdsp:
843 case TOK_ASM_c_slli:
844 case TOK_ASM_c_srai:
845 case TOK_ASM_c_srli:
846 case TOK_ASM_c_sub:
847 case TOK_ASM_c_subw:
848 case TOK_ASM_c_swsp:
849 case TOK_ASM_c_xor:
850 asm_binary_opcode(s1, token);
851 return;
852
853 case TOK_ASM_c_fld:
854 case TOK_ASM_c_flw:
855 case TOK_ASM_c_fsd:
856 case TOK_ASM_c_fsw:
857 case TOK_ASM_c_ld:
858 case TOK_ASM_c_lw:
859 case TOK_ASM_c_sd:
860 case TOK_ASM_c_sw:
861 asm_ternary_opcode(s1, token);
713 return;862 return;
714 863
715 default:864 default:
@@ -756,19 +905,456 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) · 40 unmodified lines
756 905
757ST_FUNC int asm_parse_regvar (int t)906ST_FUNC int asm_parse_regvar (int t)
758{907{
759 if (t >= TOK_ASM_x0 && t <= TOK_ASM_pc) { /* register name */908 /* PC register not implemented */
760 if (t >= TOK_ASM_zero && t <= TOK_ASM_t6)909 if (t >= TOK_ASM_pc || t < TOK_ASM_x0)
761 return t - TOK_ASM_zero;
762 switch (t) {
763 case TOK_ASM_s0:
764 return 8;
765 case TOK_ASM_pc:
766 tcc_error("PC register not implemented.");
767 default:
768 return t - TOK_ASM_x0;
769 }
770 } else
771 return -1;910 return -1;
911
912 if (t < TOK_ASM_f0)
913 return t - TOK_ASM_x0;
914
915 if (t < TOK_ASM_zero)
916 return t - TOK_ASM_f0;
917
918 /* ABI mnemonic */
919 if (t < TOK_ASM_ft0)
920 return t - TOK_ASM_zero;
921
922 return t - TOK_ASM_ft0;
923}
924
925/*************************************************************/
926/* C extension */
927
928/* caller: Add funct6, funct2 into opcode */
929static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
930{
931 uint8_t dst, src;
932
933 if (rd->type != OP_REG) {
934 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
935 return;
936 }
937
938 if (rs2->type != OP_REG) {
939 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
940 return;
941 }
942
943 /* subtract index of x8 */
944 dst = rd->reg - 8;
945 src = rs2->reg - 8;
946
947 /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
948 if (dst > 7) {
949 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
950 return;
951 }
952
953 if (src > 7) {
954 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
955 return;
956 }
957
958 /* CA-type instruction:
959 15...10 funct6
960 9...7 rd'/rs1'
961 6..5 funct2
962 4...2 rs2'
963 1...0 opcode */
964
965 gen_le16(opcode | C_ENCODE_RS2(src) | C_ENCODE_RS1(dst));
966}
967
968static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm)
969{
970 uint32_t offset;
971 uint8_t dst, src;
972
973 if (rs1->type != OP_REG) {
974 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
975 return;
976 }
977
978 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
979 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
980 return;
981 }
982
983 offset = imm->e.v;
984
985 if (offset & 1) {
986 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
987 return;
988 }
989
990 src = rs1->reg - 8;
991
992 if (src > 7) {
993 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
994 return;
995 }
996
997 /* CB-type instruction:
998 15...13 funct3
999 12...10 offset
1000 9..7 rs1'
1001 6...2 offset
1002 1...0 opcode */
1003
1004 /* non-branch also using CB:
1005 15...13 funct3
1006 12 imm
1007 11..10 funct2
1008 9...7 rd'/rs1'
1009 6..2 imm
1010 1...0 opcode */
1011
1012 switch (token) {
1013 case TOK_ASM_c_beqz:
1014 case TOK_ASM_c_bnez:
1015 gen_le16(opcode | C_ENCODE_RS1(src) | ((NTH_BIT(offset, 5) | (((offset >> 1) & 3) << 1) | (((offset >> 6) & 3) << 3)) << 2) | ((((offset >> 3) & 3) | NTH_BIT(offset, 8)) << 10));
1016 return;
1017 default:
1018 gen_le16(opcode | C_ENCODE_RS1(src) | ((offset & 0x1f) << 2) | (NTH_BIT(offset, 5) << 12));
1019 return;
1020 }
1021}
1022
1023static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1024{
1025 uint32_t immediate;
1026
1027 if (rd->type != OP_REG) {
1028 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1029 return;
1030 }
1031
1032 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1033 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1034 return;
1035 }
1036
1037 immediate = imm->e.v;
1038
1039 /* CI-type instruction:
1040 15...13 funct3
1041 12 imm
1042 11...7 rd/rs1
1043 6...2 imm
1044 1...0 opcode */
1045
1046 switch (token) {
1047 case TOK_ASM_c_addi:
1048 case TOK_ASM_c_addiw:
1049 case TOK_ASM_c_li:
1050 case TOK_ASM_c_slli:
1051 gen_le16(opcode | ((immediate & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1052 return;
1053 case TOK_ASM_c_addi16sp:
1054 gen_le16(opcode | NTH_BIT(immediate, 5) << 2 | (((immediate >> 7) & 3) << 3) | NTH_BIT(immediate, 6) << 5 | NTH_BIT(immediate, 4) << 6 | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 9) << 12));
1055 return;
1056 case TOK_ASM_c_lui:
1057 gen_le16(opcode | (((immediate >> 12) & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 17) << 12));
1058 return;
1059 case TOK_ASM_c_fldsp:
1060 case TOK_ASM_c_ldsp:
1061 gen_le16(opcode | (((immediate >> 6) & 7) << 2) | (((immediate >> 3) & 2) << 5) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1062 return;
1063 case TOK_ASM_c_flwsp:
1064 case TOK_ASM_c_lwsp:
1065 gen_le16(opcode | (((immediate >> 6) & 3) << 2) | (((immediate >> 2) & 7) << 4) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
1066 return;
1067 case TOK_ASM_c_nop:
1068 gen_le16(opcode);
1069 return;
1070 default:
1071 expect("known instruction");
1072 }
1073}
1074
1075/* caller: Add funct3 into opcode */
1076static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
1077{
1078 uint32_t nzuimm;
1079 uint8_t dst;
1080
1081 if (rd->type != OP_REG) {
1082 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1083 return;
1084 }
1085
1086 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1087 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1088 return;
1089 }
1090
1091 dst = rd->reg - 8;
1092
1093 if (dst > 7) {
1094 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1095 return;
1096 }
1097
1098 nzuimm = imm->e.v;
1099
1100 if (nzuimm > 0x3fc) {
1101 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token, NULL));
1102 return;
1103 }
1104
1105 if (nzuimm & 3) {
1106 tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL));
1107 return;
1108 }
1109
1110 /* CIW-type instruction:
1111 15...13 funct3
1112 12...5 imm
1113 4...2 rd'
1114 1...0 opcode */
1115
1116 gen_le16(opcode | ENCODE_RS2(rd->reg) | ((NTH_BIT(nzuimm, 3) | (NTH_BIT(nzuimm, 2) << 1) | (((nzuimm >> 6) & 0xf) << 2) | (((nzuimm >> 4) & 3) << 6)) << 5));
1117}
1118
1119/* caller: Add funct3 into opcode */
1120static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm)
1121{
1122 uint32_t offset;
1123
1124 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1125 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1126 return;
1127 }
1128
1129 offset = imm->e.v;
1130
1131 /* +-2 KiB range; max. 0x7fe min. 0xffe (-0x7fe) */
1132 if (offset > 0x1fff) {
1133 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x1fff", get_tok_str(token, NULL));
1134 return;
1135 }
1136
1137 if (offset & 1) {
1138 tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
1139 return;
1140 }
1141
1142 /* CJ-type instruction:
1143 15...13 funct3
1144 12...2 offset[11|4|9:8|10|6|7|3:1|5]
1145 1...0 opcode */
1146
1147 gen_le16(opcode | (NTH_BIT(offset, 5) << 2) | (((offset >> 1) & 7) << 3) | (NTH_BIT(offset, 7) << 6) | (NTH_BIT(offset, 6) << 7) | (NTH_BIT(offset, 10) << 8) | (((offset >> 8) & 3) << 9) | (NTH_BIT(offset, 4) << 11) | (NTH_BIT(offset, 11) << 12));
1148}
1149
1150/* caller: Add funct3 into opcode */
1151static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm)
1152{
1153 uint32_t offset;
1154 uint8_t dst, src;
1155
1156 if (rd->type != OP_REG) {
1157 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1158 return;
1159 }
1160
1161 if (rs1->type != OP_REG) {
1162 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1163 return;
1164 }
1165
1166 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1167 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1168 return;
1169 }
1170
1171 dst = rd->reg - 8;
1172 src = rs1->reg - 8;
1173
1174 if (dst > 7) {
1175 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1176 return;
1177 }
1178
1179 if (src > 7) {
1180 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1181 return;
1182 }
1183
1184 offset = imm->e.v;
1185
1186 if (offset > 0xff) {
1187 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1188 return;
1189 }
1190
1191 if (offset & 3) {
1192 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1193 return;
1194 }
1195
1196 /* CL-type instruction:
1197 15...13 funct3
1198 12...10 imm
1199 9...7 rs1'
1200 6...5 imm
1201 4...2 rd'
1202 1...0 opcode */
1203
1204 switch (token) {
1205 /* imm variant 1 */
1206 case TOK_ASM_c_flw:
1207 case TOK_ASM_c_lw:
1208 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (NTH_BIT(offset, 6) << 5) | (NTH_BIT(offset, 2) << 6) | (((offset >> 3) & 7) << 10));
1209 return;
1210 /* imm variant 2 */
1211 case TOK_ASM_c_fld:
1212 case TOK_ASM_c_ld:
1213 gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1214 return;
1215 default:
1216 expect("known instruction");
1217 }
1218}
1219
1220/* caller: Add funct4 into opcode */
1221static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
1222{
1223 if (rd->type != OP_REG) {
1224 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1225 return;
1226 }
1227
1228 if (rs2->type != OP_REG) {
1229 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1230 return;
1231 }
1232
1233 /* CR-type instruction:
1234 15...12 funct4
1235 11..7 rd/rs1
1236 6...2 rs2
1237 1...0 opcode */
1238
1239 gen_le16(opcode | C_ENCODE_RS1(rd->reg) | C_ENCODE_RS2(rs2->reg));
1240}
1241
1242/* caller: Add funct3 into opcode */
1243static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm)
1244{
1245 uint32_t offset;
1246 uint8_t base, src;
1247
1248 if (rs2->type != OP_REG) {
1249 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1250 return;
1251 }
1252
1253 if (rs1->type != OP_REG) {
1254 tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
1255 return;
1256 }
1257
1258 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1259 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1260 return;
1261 }
1262
1263 base = rs1->reg - 8;
1264 src = rs2->reg - 8;
1265
1266 if (base > 7) {
1267 tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
1268 return;
1269 }
1270
1271 if (src > 7) {
1272 tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
1273 return;
1274 }
1275
1276 offset = imm->e.v;
1277
1278 if (offset > 0xff) {
1279 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1280 return;
1281 }
1282
1283 if (offset & 3) {
1284 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1285 return;
1286 }
1287
1288 /* CS-type instruction:
1289 15...13 funct3
1290 12...10 imm
1291 9...7 rs1'
1292 6...5 imm
1293 4...2 rs2'
1294 1...0 opcode */
1295 switch (token) {
1296 /* imm variant 1 */
1297 case TOK_ASM_c_fsw:
1298 case TOK_ASM_c_sw:
1299 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (NTH_BIT(offset, 6) << 5) | (NTH_BIT(offset, 2) << 6) | (((offset >> 3) & 7) << 10));
1300 return;
1301 /* imm variant 2 */
1302 case TOK_ASM_c_fsd:
1303 case TOK_ASM_c_sd:
1304 gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
1305 return;
1306 default:
1307 expect("known instruction");
1308 }
1309}
1310
1311/* caller: Add funct3 into opcode */
1312static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm)
1313{
1314 uint32_t offset;
1315
1316 if (rs2->type != OP_REG) {
1317 tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
1318 return;
1319 }
1320
1321 if (imm->type != OP_IM12S && imm->type != OP_IM32) {
1322 tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
1323 return;
1324 }
1325
1326 offset = imm->e.v;
1327
1328 if (offset > 0xff) {
1329 tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
1330 return;
1331 }
1332
1333 if (offset & 3) {
1334 tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
1335 return;
1336 }
1337
1338 /* CSS-type instruction:
1339 15...13 funct3
1340 12...7 imm
1341 6...2 rs2
1342 1...0 opcode */
1343
1344 switch (token) {
1345 /* imm variant 1 */
1346 case TOK_ASM_c_fswsp:
1347 case TOK_ASM_c_swsp:
1348 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 3) << 7) | (((offset >> 2) & 0xf) << 9));
1349 return;
1350 /* imm variant 2 */
1351 case TOK_ASM_c_fsdsp:
1352 case TOK_ASM_c_sdsp:
1353 gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 7) << 7) | (((offset >> 3) & 7) << 10));
1354 return;
1355 default:
1356 expect("known instruction");
1357 }
772}1358}
773 1359
774/*************************************************************/1360/*************************************************************/
riscv64-tok.h+76−20
@@ -5,8 +5,11 @@ · 4 unmodified lines
5 * The specifications are available under https://riscv.org/technical/specifications/5 * The specifications are available under https://riscv.org/technical/specifications/
6 */6 */
7 7
8/* register */8#define DEF_ASM_WITH_SUFFIX(x, y) \
9 DEF(TOK_ASM_ ## x ## _ ## y, #x "." #y)
9 10
11/* register */
12 /* integer */
10 DEF_ASM(x0)13 DEF_ASM(x0)
11 DEF_ASM(x1)14 DEF_ASM(x1)
12 DEF_ASM(x2)15 DEF_ASM(x2)
@@ -39,9 +42,42 @@ · 26 unmodified lines
39 DEF_ASM(x29)42 DEF_ASM(x29)
40 DEF_ASM(x30)43 DEF_ASM(x30)
41 DEF_ASM(x31)44 DEF_ASM(x31)
42 45 /* float */
43/* register macros */46 DEF_ASM(f0)
44 47 DEF_ASM(f1)
48 DEF_ASM(f2)
49 DEF_ASM(f3)
50 DEF_ASM(f4)
51 DEF_ASM(f5)
52 DEF_ASM(f6)
53 DEF_ASM(f7)
54 DEF_ASM(f8)
55 DEF_ASM(f9)
56 DEF_ASM(f10)
57 DEF_ASM(f11)
58 DEF_ASM(f12)
59 DEF_ASM(f13)
60 DEF_ASM(f14)
61 DEF_ASM(f15)
62 DEF_ASM(f16)
63 DEF_ASM(f17)
64 DEF_ASM(f18)
65 DEF_ASM(f19)
66 DEF_ASM(f20)
67 DEF_ASM(f21)
68 DEF_ASM(f22)
69 DEF_ASM(f23)
70 DEF_ASM(f24)
71 DEF_ASM(f25)
72 DEF_ASM(f26)
73 DEF_ASM(f27)
74 DEF_ASM(f28)
75 DEF_ASM(f29)
76 DEF_ASM(f30)
77 DEF_ASM(f31)
78
79/* register ABI mnemonics, refer to RISC-V ABI 1.0 */
80 /* integer */
45 DEF_ASM(zero)81 DEF_ASM(zero)
46 DEF_ASM(ra)82 DEF_ASM(ra)
47 DEF_ASM(sp)83 DEF_ASM(sp)
@@ -50,7 +86,7 @@ · 2 unmodified lines
50 DEF_ASM(t0)86 DEF_ASM(t0)
51 DEF_ASM(t1)87 DEF_ASM(t1)
52 DEF_ASM(t2)88 DEF_ASM(t2)
53 DEF_ASM(fp)89 DEF_ASM(s0)
54 DEF_ASM(s1)90 DEF_ASM(s1)
55 DEF_ASM(a0)91 DEF_ASM(a0)
56 DEF_ASM(a1)92 DEF_ASM(a1)
@@ -74,14 +110,42 @@ · 17 unmodified lines
74 DEF_ASM(t4)110 DEF_ASM(t4)
75 DEF_ASM(t5)111 DEF_ASM(t5)
76 DEF_ASM(t6)112 DEF_ASM(t6)
77 113 /* float */
78 DEF_ASM(s0) // = x8114 DEF_ASM(ft0)
79 115 DEF_ASM(ft1)
116 DEF_ASM(ft2)
117 DEF_ASM(ft3)
118 DEF_ASM(ft4)
119 DEF_ASM(ft5)
120 DEF_ASM(ft6)
121 DEF_ASM(ft7)
122 DEF_ASM(fs0)
123 DEF_ASM(fs1)
124 DEF_ASM(fa0)
125 DEF_ASM(fa1)
126 DEF_ASM(fa2)
127 DEF_ASM(fa3)
128 DEF_ASM(fa4)
129 DEF_ASM(fa5)
130 DEF_ASM(fa6)
131 DEF_ASM(fa7)
132 DEF_ASM(fs2)
133 DEF_ASM(fs3)
134 DEF_ASM(fs4)
135 DEF_ASM(fs5)
136 DEF_ASM(fs6)
137 DEF_ASM(fs7)
138 DEF_ASM(fs8)
139 DEF_ASM(fs9)
140 DEF_ASM(fs10)
141 DEF_ASM(fs11)
142 DEF_ASM(ft8)
143 DEF_ASM(ft9)
144 DEF_ASM(ft10)
145 DEF_ASM(ft11)
146 /* not in the ABI */
80 DEF_ASM(pc)147 DEF_ASM(pc)
81 148
82#define DEF_ASM_WITH_SUFFIX(x, y) \
83 DEF(TOK_ASM_ ## x ## _ ## y, #x #y)
84
85/* Loads */149/* Loads */
86 150
87 DEF_ASM(lb)151 DEF_ASM(lb)
@@ -110,18 +174,12 @@ · 22 unmodified lines
110 DEF_ASM(slli)174 DEF_ASM(slli)
111 DEF_ASM(srli)175 DEF_ASM(srli)
112 DEF_ASM(sllw)176 DEF_ASM(sllw)
113 DEF_ASM(slld)
114 DEF_ASM(slliw)177 DEF_ASM(slliw)
115 DEF_ASM(sllid)
116 DEF_ASM(srlw)178 DEF_ASM(srlw)
117 DEF_ASM(srld)
118 DEF_ASM(srliw)179 DEF_ASM(srliw)
119 DEF_ASM(srlid)
120 DEF_ASM(srai)180 DEF_ASM(srai)
121 DEF_ASM(sraw)181 DEF_ASM(sraw)
122 DEF_ASM(srad)
123 DEF_ASM(sraiw)182 DEF_ASM(sraiw)
124 DEF_ASM(sraid)
125 183
126/* Arithmetic */184/* Arithmetic */
127 185
@@ -236,11 +294,8 @@ · 108 unmodified lines
236 294
237/* Shifts */295/* Shifts */
238 DEF_ASM_WITH_SUFFIX(c, slli)296 DEF_ASM_WITH_SUFFIX(c, slli)
239 DEF_ASM_WITH_SUFFIX(c, slli64)
240 DEF_ASM_WITH_SUFFIX(c, srli)297 DEF_ASM_WITH_SUFFIX(c, srli)
241 DEF_ASM_WITH_SUFFIX(c, srli64)
242 DEF_ASM_WITH_SUFFIX(c, srai)298 DEF_ASM_WITH_SUFFIX(c, srai)
243 DEF_ASM_WITH_SUFFIX(c, srai64)
244 299
245/* Arithmetic */300/* Arithmetic */
246 DEF_ASM_WITH_SUFFIX(c, add)301 DEF_ASM_WITH_SUFFIX(c, add)
@@ -293,3 +348,4 @@ · 46 unmodified lines
293 DEF_ASM(hrts)348 DEF_ASM(hrts)
294 DEF_ASM(wfi)349 DEF_ASM(wfi)
295 350
351#undef DEF_ASM_WITH_SUFFIX

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t