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
1919 #define USING_GLOBALS
2020 #include "tcc.h"
2121
22+enum {
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+
37+typedef struct Operand {
38+ uint32_t type;
39+ union {
40+ uint8_t reg;
41+ uint16_t regset;
42+ ExprValue e;
43+ };
44+} Operand;
45+
46+static void asm_binary_opcode(TCCState* s1, int token);
47+static void asm_clobber(uint8_t *clobber_regs, const char *str);
48+static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
49+static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
50+static void asm_emit_i(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
51+static void asm_emit_j(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
52+static void asm_emit_opcode(uint32_t opcode);
53+static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
54+static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
55+static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
56+static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
57+static void asm_nullary_opcode(TCCState *s1, int token);
58+static void asm_opcode(TCCState *s1, int token);
59+static int asm_parse_regvar(int t);
60+static void asm_ternary_opcode(TCCState *s1, int token);
61+static void asm_unary_opcode(TCCState *s1, int token);
62+static void gen_expr32(ExprValue *pe);
63+static void parse_operand(TCCState *s1, Operand *op);
64+static void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
65+/* C extension */
66+static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
67+static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm);
68+static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
69+static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
70+static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm);
71+static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm);
72+static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
73+static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm);
74+static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm);
75+
2276 /* XXX: make it faster ? */
2377 ST_FUNC void g(int c)
2478 {
@@ -63,6 +117,9 @@ static void asm_emit_opcode(uint32_t opcode) { · 38 unmodified lines
63117
64118 static void asm_nullary_opcode(TCCState *s1, int token)
65119 {
120+ static const Operand nil = {.type = OP_REG};
121+ static const Operand zimm = {.type = OP_IM12S};
122+
66123 switch (token) {
67124 // Sync instructions
68125
@@ -84,36 +141,27 @@ static void asm_nullary_opcode(TCCState *s1, int token) · 15 unmodified lines
84141
85142 // Other
86143
144+ case TOK_ASM_nop:
145+ asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
146+ return;
147+
87148 case TOK_ASM_wfi:
88149 asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
89150 return;
90151
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+
91160 default:
92161 expect("nullary instruction");
93162 }
94163 }
95164
96−enum {
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−
105−typedef struct Operand {
106− uint32_t type;
107− union {
108− uint8_t reg;
109− uint16_t regset;
110− ExprValue e;
111− };
112−} Operand;
113−
114−static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2);
115−static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2);
116−
117165 /* Parse a text containing operand and store the result in OP */
118166 static void parse_operand(TCCState *s1, Operand *op)
119167 {
@@ -134,27 +182,22 @@ static void parse_operand(TCCState *s1, Operand *op) · 14 unmodified lines
134182 asm_expr(s1, &e);
135183 op->type = OP_IM32;
136184 op->e = e;
185+ /* compare against unsigned 12-bit maximum */
137186 if (!op->e.sym) {
138− if ((int) op->e.v >= -2048 && (int) op->e.v < 2048)
187+ if (op->e.v < 0x2000)
139188 op->type = OP_IM12S;
140189 } else
141190 expect("operand");
142191 }
143192
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.
149193 static void asm_unary_opcode(TCCState *s1, int token)
150194 {
151195 uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
152196 Operand op;
197+ static const Operand nil = {.type = OP_REG};
198+
153199 parse_operand(s1, &op);
154− if (op.type != OP_REG) {
155− expect("register");
156− return;
157− }
200+ /* Note: Those all map to CSR--so they are pseudo-instructions. */
158201 opcode |= ENCODE_RD(op.reg);
159202
160203 switch (token) {
@@ -176,6 +219,18 @@ static void asm_unary_opcode(TCCState *s1, int token) · 15 unmodified lines
176219 case TOK_ASM_rdinstreth:
177220 asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
178221 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;
179234 default:
180235 expect("unary instruction");
181236 }
@@ -221,6 +276,100 @@ static void asm_binary_opcode(TCCState* s1, int token) · 39 unmodified lines
221276 case TOK_ASM_jal:
222277 asm_emit_j(token, 0x6f, ops, ops + 1);
223278 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+
224373 default:
225374 expect("binary instruction");
226375 }
@@ -263,7 +412,7 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper · 36 unmodified lines
263412 return;
264413 }
265414 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));
267416 return;
268417 }
269418 /* 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
278427
279428 static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
280429 {
281− uint64_t imm;
430+ uint32_t imm;
282431
283432 if (rd->type != OP_REG) {
284433 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
311460 gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));
312461 }
313462
314−static void asm_shift_opcode(TCCState *s1, int token)
463+static void asm_ternary_opcode(TCCState *s1, int token)
315464 {
316465 Operand ops[3];
317466 parse_operand(s1, &ops[0]);
@@ -363,27 +512,7 @@ static void asm_shift_opcode(TCCState *s1, int token) · 45 unmodified lines
363512 case TOK_ASM_sraiw:
364513 asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
365514 return;
366− default:
367− expect("shift instruction");
368− }
369−}
370−
371−static 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]);
385515
386− switch (token) {
387516 // Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
388517
389518 case TOK_ASM_add:
@@ -446,64 +575,26 @@ static void asm_data_processing_opcode(TCCState* s1, int token) · 56 unmodified lines
446575 asm_emit_i(token, 0x67 | (0 << 12), ops, ops + 1, ops + 2);
447576 return;
448577
449− default:
450− expect("known data processing instruction");
451− }
452−}
453−
454−/* caller: Add funct3 to opcode */
455−static 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));
578+ /* branch (RS1, RS2, IMM); B-format */
579+ case TOK_ASM_beq:
580+ asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
459581 return;
460− }
461− if (rs2->type != OP_REG) {
462− tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
582+ case TOK_ASM_bne:
583+ asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
463584 return;
464− }
465− if (imm->type != OP_IM12S) {
466− tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
585+ case TOK_ASM_blt:
586+ asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
467587 return;
468− }
469− {
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−
483−static 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");
588+ case TOK_ASM_bge:
589+ asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
489590 return;
490− }
491− if (tok == ',')
492− next();
493− else
494− expect("','");
495− parse_operand(s1, &ops[1]);
496− if (ops[1].type != OP_REG) {
497− expect("register");
591+ case TOK_ASM_bltu:
592+ asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
593+ return;
594+ case TOK_ASM_bgeu:
595+ asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
498596 return;
499− }
500− if (tok == ',')
501− next();
502− else
503− expect("','");
504− parse_operand(s1, &ops[2]);
505597
506− switch (token) {
507598 // Loads (RD,RS1,I); I-format
508599
509600 case TOK_ASM_lb:
@@ -544,69 +635,86 @@ static void asm_data_transfer_opcode(TCCState* s1, int token) · 34 unmodified lines
544635 asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
545636 return;
546637
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+
547665 default:
548− expect("known data transfer instruction");
666+ expect("ternary instruction");
549667 }
550668 }
551669
552−static void asm_branch_opcode(TCCState* s1, int token)
670+/* caller: Add funct3 to opcode */
671+static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
553672 {
554− // Branch (RS1,RS2,IMM); SB-format
555− uint32_t opcode = (0x18 << 2) | 3;
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");
673+ if (rs1->type != OP_REG) {
674+ tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
561675 return;
562676 }
563− if (tok == ',')
564− next();
565− else
566− expect("','");
567− parse_operand(s1, &ops[1]);
568− if (ops[1].type != OP_REG) {
569− expect("register");
677+ if (rs2->type != OP_REG) {
678+ tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
570679 return;
571680 }
572− if (tok == ',')
573− next();
574− else
575− expect("','");
576− parse_operand(s1, &ops[2]);
681+ if (imm->type != OP_IM12S) {
682+ tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
683+ return;
684+ }
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+}
577698
578− if (ops[2].type != OP_IM12S) {
579− tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
699+static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm)
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));
580705 return;
581706 }
582− offset = ops[2].e.v;
583− if (offset & 1) {
584− tcc_error("'%s': Expected third operand that is an even immediate value", get_tok_str(token, NULL));
707+ if (rs2->type != OP_REG) {
708+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
585709 return;
586710 }
587−
588− switch (token) {
589− case TOK_ASM_beq:
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");
711+ if (imm->type != OP_IM12S) {
712+ tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
713+ return;
609714 }
715+
716+ offset = imm->e.v;
717+
610718 /* B-type instruction:
611719 31 imm[12]
612720 30...25 imm[10:5]
@@ -616,19 +724,20 @@ static void asm_branch_opcode(TCCState* s1, int token) · 3 unmodified lines
616724 8...11 imm[4:1]
617725 7 imm[11]
618726 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));
620728 }
621729
622730 ST_FUNC void asm_opcode(TCCState *s1, int token)
623731 {
624732 switch (token) {
733+ case TOK_ASM_ebreak:
734+ case TOK_ASM_ecall:
625735 case TOK_ASM_fence:
626736 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:
631737 case TOK_ASM_hrts:
738+ case TOK_ASM_mrth:
739+ case TOK_ASM_mrts:
740+ case TOK_ASM_nop:
632741 case TOK_ASM_wfi:
633742 asm_nullary_opcode(s1, token);
634743 return;
@@ -648,68 +757,108 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 13 unmodified lines
648757 asm_binary_opcode(s1, token);
649758 return;
650759
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−
672760 case TOK_ASM_add:
673761 case TOK_ASM_addi:
674− case TOK_ASM_sub:
675− case TOK_ASM_addw:
676762 case TOK_ASM_addiw:
677− case TOK_ASM_subw:
678− case TOK_ASM_xor:
679− case TOK_ASM_xori:
680− case TOK_ASM_or:
681− case TOK_ASM_ori:
763+ case TOK_ASM_addw:
682764 case TOK_ASM_and:
683765 case TOK_ASM_andi:
684− case TOK_ASM_slt:
685− case TOK_ASM_slti:
686− case TOK_ASM_sltu:
687− case TOK_ASM_sltiu:
688− case TOK_ASM_jalr:
689− asm_data_processing_opcode(s1, token);
690− return;
691−
766+ case TOK_ASM_beq:
767+ case TOK_ASM_bge:
768+ case TOK_ASM_bgeu:
769+ case TOK_ASM_blt:
770+ case TOK_ASM_bltu:
771+ case TOK_ASM_bne:
772+ case TOK_ASM_jalr:
692773 case TOK_ASM_lb:
693− case TOK_ASM_lh:
694− case TOK_ASM_lw:
695774 case TOK_ASM_lbu:
696− case TOK_ASM_lhu:
697775 case TOK_ASM_ld:
776+ case TOK_ASM_lh:
777+ case TOK_ASM_lhu:
778+ case TOK_ASM_lw:
698779 case TOK_ASM_lwu:
780+ case TOK_ASM_or:
781+ case TOK_ASM_ori:
699782 case TOK_ASM_sb:
783+ case TOK_ASM_sd:
700784 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:
701803 case TOK_ASM_sw:
702− case TOK_ASM_sd:
703− asm_data_transfer_opcode(s1, token);
804+ case TOK_ASM_xor:
805+ case TOK_ASM_xori:
806+ asm_ternary_opcode(s1, token);
704807 return;
705808
706− case TOK_ASM_beq:
707− case TOK_ASM_bne:
708− case TOK_ASM_blt:
709− case TOK_ASM_bge:
710− case TOK_ASM_bltu:
711− case TOK_ASM_bgeu:
712− asm_branch_opcode(s1, token);
809+ /* C extension */
810+ case TOK_ASM_c_ebreak:
811+ case TOK_ASM_c_nop:
812+ asm_nullary_opcode(s1, token);
813+ return;
814+
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);
713862 return;
714863
715864 default:
@@ -756,19 +905,456 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) · 40 unmodified lines
756905
757906 ST_FUNC int asm_parse_regvar (int t)
758907 {
759− if (t >= TOK_ASM_x0 && t <= TOK_ASM_pc) { /* register name */
760− if (t >= TOK_ASM_zero && t <= TOK_ASM_t6)
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
908+ /* PC register not implemented */
909+ if (t >= TOK_ASM_pc || t < TOK_ASM_x0)
771910 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 */
929+static 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+
968+static 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+
1023+static 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 */
1076+static 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 */
1120+static 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 */
1151+static 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 */
1221+static 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 */
1243+static 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 */
1312+static 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+ }
7721358 }
7731359
7741360 /*************************************************************/
riscv64-tok.h+76−20
@@ -5,8 +5,11 @@ · 4 unmodified lines
55 * The specifications are available under https://riscv.org/technical/specifications/
66 */
77
8−/* register */
8+#define DEF_ASM_WITH_SUFFIX(x, y) \
9+ DEF(TOK_ASM_ ## x ## _ ## y, #x "." #y)
910
11+/* register */
12+ /* integer */
1013 DEF_ASM(x0)
1114 DEF_ASM(x1)
1215 DEF_ASM(x2)
@@ -39,9 +42,42 @@ · 26 unmodified lines
3942 DEF_ASM(x29)
4043 DEF_ASM(x30)
4144 DEF_ASM(x31)
42−
43−/* register macros */
44−
45+ /* float */
46+ DEF_ASM(f0)
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 */
4581 DEF_ASM(zero)
4682 DEF_ASM(ra)
4783 DEF_ASM(sp)
@@ -50,7 +86,7 @@ · 2 unmodified lines
5086 DEF_ASM(t0)
5187 DEF_ASM(t1)
5288 DEF_ASM(t2)
53− DEF_ASM(fp)
89+ DEF_ASM(s0)
5490 DEF_ASM(s1)
5591 DEF_ASM(a0)
5692 DEF_ASM(a1)
@@ -74,14 +110,42 @@ · 17 unmodified lines
74110 DEF_ASM(t4)
75111 DEF_ASM(t5)
76112 DEF_ASM(t6)
77−
78− DEF_ASM(s0) // = x8
79−
113+ /* float */
114+ DEF_ASM(ft0)
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 */
80147 DEF_ASM(pc)
81148
82−#define DEF_ASM_WITH_SUFFIX(x, y) \
83− DEF(TOK_ASM_ ## x ## _ ## y, #x #y)
84−
85149 /* Loads */
86150
87151 DEF_ASM(lb)
@@ -110,18 +174,12 @@ · 22 unmodified lines
110174 DEF_ASM(slli)
111175 DEF_ASM(srli)
112176 DEF_ASM(sllw)
113− DEF_ASM(slld)
114177 DEF_ASM(slliw)
115− DEF_ASM(sllid)
116178 DEF_ASM(srlw)
117− DEF_ASM(srld)
118179 DEF_ASM(srliw)
119− DEF_ASM(srlid)
120180 DEF_ASM(srai)
121181 DEF_ASM(sraw)
122− DEF_ASM(srad)
123182 DEF_ASM(sraiw)
124− DEF_ASM(sraid)
125183
126184 /* Arithmetic */
127185
@@ -236,11 +294,8 @@ · 108 unmodified lines
236294
237295 /* Shifts */
238296 DEF_ASM_WITH_SUFFIX(c, slli)
239− DEF_ASM_WITH_SUFFIX(c, slli64)
240297 DEF_ASM_WITH_SUFFIX(c, srli)
241− DEF_ASM_WITH_SUFFIX(c, srli64)
242298 DEF_ASM_WITH_SUFFIX(c, srai)
243− DEF_ASM_WITH_SUFFIX(c, srai64)
244299
245300 /* Arithmetic */
246301 DEF_ASM_WITH_SUFFIX(c, add)
@@ -293,3 +348,4 @@ · 46 unmodified lines
293348 DEF_ASM(hrts)
294349 DEF_ASM(wfi)
295350
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