summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornoneofyourbusiness <noneofyourbusiness@danwin1210.de>2023-12-02 23:46:39 +0100
committernoneofyourbusiness <noneofyourbusiness@danwin1210.de>2023-12-08 17:07:06 +0100
commitd87801bd50abb04be894628338164537d88654dc (patch)
tree2e6a5bfc832b4c0c02123264c0e2f8a703de7f87
parent81a32ec305ee871d8129978bf3d57bc108bec46b (diff)
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)
-rw-r--r--riscv64-asm.c1022
-rw-r--r--riscv64-tok.h96
2 files changed, 880 insertions, 238 deletions
diff --git a/riscv64-asm.c b/riscv64-asm.c
index 1e6bada..e3a3e71 100644
--- a/riscv64-asm.c
+++ b/riscv64-asm.c
@@ -19,6 +19,60 @@ ST_FUNC void gen_le32(int c);
#define USING_GLOBALS
#include "tcc.h"
+enum {
+ OPT_REG,
+ OPT_IM12S,
+ OPT_IM32,
+};
+#define C_ENCODE_RS1(register_index) ((register_index) << 7)
+#define C_ENCODE_RS2(register_index) ((register_index) << 2)
+#define ENCODE_RD(register_index) ((register_index) << 7)
+#define ENCODE_RS1(register_index) ((register_index) << 15)
+#define ENCODE_RS2(register_index) ((register_index) << 20)
+#define NTH_BIT(b, n) ((b >> n) & 1)
+#define OP_IM12S (1 << OPT_IM12S)
+#define OP_IM32 (1 << OPT_IM32)
+#define OP_REG (1 << OPT_REG)
+
+typedef struct Operand {
+ uint32_t type;
+ union {
+ uint8_t reg;
+ uint16_t regset;
+ ExprValue e;
+ };
+} Operand;
+
+static void asm_binary_opcode(TCCState* s1, int token);
+static void asm_clobber(uint8_t *clobber_regs, const char *str);
+static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
+static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
+static void asm_emit_i(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
+static void asm_emit_j(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
+static void asm_emit_opcode(uint32_t opcode);
+static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
+static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
+static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
+static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
+static void asm_nullary_opcode(TCCState *s1, int token);
+static void asm_opcode(TCCState *s1, int token);
+static int asm_parse_regvar(int t);
+static void asm_ternary_opcode(TCCState *s1, int token);
+static void asm_unary_opcode(TCCState *s1, int token);
+static void gen_expr32(ExprValue *pe);
+static void parse_operand(TCCState *s1, Operand *op);
+static void subst_asm_operand(CString *add_str, SValue *sv, int modifier);
+/* C extension */
+static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
+static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm);
+static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
+static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm);
+static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm);
+static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm);
+static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2);
+static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm);
+static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm);
+
/* XXX: make it faster ? */
ST_FUNC void g(int c)
{
@@ -63,6 +117,9 @@ static void asm_emit_opcode(uint32_t opcode) {
static void asm_nullary_opcode(TCCState *s1, int token)
{
+ static const Operand nil = {.type = OP_REG};
+ static const Operand zimm = {.type = OP_IM12S};
+
switch (token) {
// Sync instructions
@@ -84,36 +141,27 @@ static void asm_nullary_opcode(TCCState *s1, int token)
// Other
+ case TOK_ASM_nop:
+ asm_emit_i(token, (4 << 2) | 3, &nil, &nil, &zimm);
+ return;
+
case TOK_ASM_wfi:
asm_emit_opcode((0x1C << 2) | 3 | (0x105 << 20));
return;
+ /* C extension */
+ case TOK_ASM_c_ebreak:
+ asm_emit_cr(token, 2 | (9 << 12), &nil, &nil);
+ return;
+ case TOK_ASM_c_nop:
+ asm_emit_ci(token, 1, &nil, &zimm);
+ return;
+
default:
expect("nullary instruction");
}
}
-enum {
- OPT_REG,
- OPT_IM12S,
- OPT_IM32,
-};
-#define OP_REG (1 << OPT_REG)
-#define OP_IM32 (1 << OPT_IM32)
-#define OP_IM12S (1 << OPT_IM12S)
-
-typedef struct Operand {
- uint32_t type;
- union {
- uint8_t reg;
- uint16_t regset;
- ExprValue e;
- };
-} Operand;
-
-static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2);
-static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2);
-
/* Parse a text containing operand and store the result in OP */
static void parse_operand(TCCState *s1, Operand *op)
{
@@ -134,27 +182,22 @@ static void parse_operand(TCCState *s1, Operand *op)
asm_expr(s1, &e);
op->type = OP_IM32;
op->e = e;
+ /* compare against unsigned 12-bit maximum */
if (!op->e.sym) {
- if ((int) op->e.v >= -2048 && (int) op->e.v < 2048)
+ if (op->e.v < 0x2000)
op->type = OP_IM12S;
} else
expect("operand");
}
-#define ENCODE_RS1(register_index) ((register_index) << 15)
-#define ENCODE_RS2(register_index) ((register_index) << 20)
-#define ENCODE_RD(register_index) ((register_index) << 7)
-
-// Note: Those all map to CSR--so they are pseudo-instructions.
static void asm_unary_opcode(TCCState *s1, int token)
{
uint32_t opcode = (0x1C << 2) | 3 | (2 << 12);
Operand op;
+ static const Operand nil = {.type = OP_REG};
+
parse_operand(s1, &op);
- if (op.type != OP_REG) {
- expect("register");
- return;
- }
+ /* Note: Those all map to CSR--so they are pseudo-instructions. */
opcode |= ENCODE_RD(op.reg);
switch (token) {
@@ -176,6 +219,18 @@ static void asm_unary_opcode(TCCState *s1, int token)
case TOK_ASM_rdinstreth:
asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
return;
+ case TOK_ASM_c_j:
+ asm_emit_cj(token, 1 | (5 << 13), &op);
+ return;
+ case TOK_ASM_c_jal: /* RV32C-only */
+ asm_emit_cj(token, 1 | (1 << 13), &op);
+ return;
+ case TOK_ASM_c_jalr:
+ asm_emit_cr(token, 2 | (9 << 12), &op, &nil);
+ return;
+ case TOK_ASM_c_jr:
+ asm_emit_cr(token, 2 | (8 << 12), &op, &nil);
+ return;
default:
expect("unary instruction");
}
@@ -221,6 +276,100 @@ static void asm_binary_opcode(TCCState* s1, int token)
case TOK_ASM_jal:
asm_emit_j(token, 0x6f, ops, ops + 1);
return;
+
+ /* C extension */
+ case TOK_ASM_c_add:
+ asm_emit_cr(token, 2 | (9 << 12), ops, ops + 1);
+ return;
+ case TOK_ASM_c_mv:
+ asm_emit_cr(token, 2 | (8 << 12), ops, ops + 1);
+ return;
+
+ case TOK_ASM_c_addi16sp:
+ asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_addi:
+ asm_emit_ci(token, 1, ops, ops + 1);
+ return;
+ case TOK_ASM_c_addiw:
+ asm_emit_ci(token, 1 | (1 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_fldsp:
+ asm_emit_ci(token, 2 | (1 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_flwsp: /* RV32FC-only */
+ asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_ldsp:
+ asm_emit_ci(token, 2 | (3 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_li:
+ asm_emit_ci(token, 1 | (2 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_lui:
+ asm_emit_ci(token, 1 | (3 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_lwsp:
+ asm_emit_ci(token, 2 | (2 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_slli:
+ asm_emit_ci(token, 2, ops, ops + 1);
+ return;
+
+ case TOK_ASM_c_addi4spn:
+ asm_emit_ciw(token, 0, ops, ops + 1);
+ return;
+
+#define CA (1 | (3 << 10) | (4 << 13))
+ case TOK_ASM_c_addw:
+ asm_emit_ca(token, CA | (1 << 5) | (1 << 12), ops, ops + 1);
+ return;
+ case TOK_ASM_c_and:
+ asm_emit_ca(token, CA | (3 << 5), ops, ops + 1);
+ return;
+ case TOK_ASM_c_or:
+ asm_emit_ca(token, CA | (2 << 5), ops, ops + 1);
+ return;
+ case TOK_ASM_c_sub:
+ asm_emit_ca(token, CA, ops, ops + 1);
+ return;
+ case TOK_ASM_c_subw:
+ asm_emit_ca(token, CA | (1 << 12), ops, ops + 1);
+ return;
+ case TOK_ASM_c_xor:
+ asm_emit_ca(token, CA | (1 << 5), ops, ops + 1);
+ return;
+#undef CA
+
+ case TOK_ASM_c_andi:
+ asm_emit_cb(token, 1 | (2 << 10) | (4 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_beqz:
+ asm_emit_cb(token, 1 | (6 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_bnez:
+ asm_emit_cb(token, 1 | (7 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_srai:
+ asm_emit_cb(token, 1 | (1 << 10) | (4 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_srli:
+ asm_emit_cb(token, 1 | (4 << 13), ops, ops + 1);
+ return;
+
+ case TOK_ASM_c_sdsp:
+ asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_swsp:
+ asm_emit_css(token, 2 | (6 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_fswsp: /* RV32FC-only */
+ asm_emit_css(token, 2 | (7 << 13), ops, ops + 1);
+ return;
+ case TOK_ASM_c_fsdsp:
+ asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
+ return;
+
default:
expect("binary instruction");
}
@@ -263,7 +412,7 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper
return;
}
if (rs2->type != OP_IM12S) {
- tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 4095", get_tok_str(token, NULL));
+ tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
return;
}
/* I-type instruction:
@@ -278,7 +427,7 @@ static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Oper
static void asm_emit_j(int token, uint32_t opcode, const Operand* rd, const Operand* rs2)
{
- uint64_t imm;
+ uint32_t imm;
if (rd->type != OP_REG) {
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
gen_le32(opcode | ENCODE_RD(rd->reg) | (((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3ff) << 21) | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xff) << 12));
}
-static void asm_shift_opcode(TCCState *s1, int token)
+static void asm_ternary_opcode(TCCState *s1, int token)
{
Operand ops[3];
parse_operand(s1, &ops[0]);
@@ -363,27 +512,7 @@ static void asm_shift_opcode(TCCState *s1, int token)
case TOK_ASM_sraiw:
asm_emit_i(token, (0x6 << 2) | 3 | (5 << 12), &ops[0], &ops[1], &ops[2]);
return;
- default:
- expect("shift instruction");
- }
-}
-
-static void asm_data_processing_opcode(TCCState* s1, int token)
-{
- Operand ops[3];
- parse_operand(s1, &ops[0]);
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[1]);
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[2]);
- switch (token) {
// Arithmetic (RD,RS1,(RS2|IMM)); R-format, I-format or U-format
case TOK_ASM_add:
@@ -446,64 +575,26 @@ static void asm_data_processing_opcode(TCCState* s1, int token)
asm_emit_i(token, 0x67 | (0 << 12), ops, ops + 1, ops + 2);
return;
- default:
- expect("known data processing instruction");
- }
-}
-
-/* caller: Add funct3 to opcode */
-static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
-{
- if (rs1->type != OP_REG) {
- tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
+ /* branch (RS1, RS2, IMM); B-format */
+ case TOK_ASM_beq:
+ asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2);
return;
- }
- if (rs2->type != OP_REG) {
- tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
+ case TOK_ASM_bne:
+ asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2);
return;
- }
- if (imm->type != OP_IM12S) {
- tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
+ case TOK_ASM_blt:
+ asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2);
return;
- }
- {
- uint16_t v = imm->e.v;
- /* S-type instruction:
- 31...25 imm[11:5]
- 24...20 rs2
- 19...15 rs1
- 14...12 funct3
- 11...7 imm[4:0]
- 6...0 opcode
- opcode always fixed pos. */
- gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
- }
-}
-
-static void asm_data_transfer_opcode(TCCState* s1, int token)
-{
- Operand ops[3];
- parse_operand(s1, &ops[0]);
- if (ops[0].type != OP_REG) {
- expect("register");
+ case TOK_ASM_bge:
+ asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2);
return;
- }
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[1]);
- if (ops[1].type != OP_REG) {
- expect("register");
+ case TOK_ASM_bltu:
+ asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_bgeu:
+ asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2);
return;
- }
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[2]);
- switch (token) {
// Loads (RD,RS1,I); I-format
case TOK_ASM_lb:
@@ -544,69 +635,86 @@ static void asm_data_transfer_opcode(TCCState* s1, int token)
asm_emit_s(token, (0x8 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]);
return;
+ /* C extension */
+ /* register-based loads and stores (RD, RS1, IMM); CL-format */
+ case TOK_ASM_c_fld:
+ asm_emit_cl(token, 1 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_flw: /* RV32FC-only */
+ asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_fsd:
+ asm_emit_cs(token, 5 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_fsw: /* RV32FC-only */
+ asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_ld:
+ asm_emit_cl(token, 3 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_lw:
+ asm_emit_cl(token, 2 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_sd:
+ asm_emit_cs(token, 7 << 13, ops, ops + 1, ops + 2);
+ return;
+ case TOK_ASM_c_sw:
+ asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
+ return;
+
default:
- expect("known data transfer instruction");
+ expect("ternary instruction");
}
}
-static void asm_branch_opcode(TCCState* s1, int token)
+/* caller: Add funct3 to opcode */
+static void asm_emit_s(int token, uint32_t opcode, const Operand* rs1, const Operand* rs2, const Operand* imm)
{
- // Branch (RS1,RS2,IMM); SB-format
- uint32_t opcode = (0x18 << 2) | 3;
- uint32_t offset = 0;
- Operand ops[3];
- parse_operand(s1, &ops[0]);
- if (ops[0].type != OP_REG) {
- expect("register");
+ if (rs1->type != OP_REG) {
+ tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
return;
}
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[1]);
- if (ops[1].type != OP_REG) {
- expect("register");
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected second source operand that is a register", get_tok_str(token, NULL));
return;
}
- if (tok == ',')
- next();
- else
- expect("','");
- parse_operand(s1, &ops[2]);
+ if (imm->type != OP_IM12S) {
+ tcc_error("'%s': Expected third operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
+ return;
+ }
+ {
+ uint16_t v = imm->e.v;
+ /* S-type instruction:
+ 31...25 imm[11:5]
+ 24...20 rs2
+ 19...15 rs1
+ 14...12 funct3
+ 11...7 imm[4:0]
+ 6...0 opcode
+ opcode always fixed pos. */
+ gen_le32(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | ((v & 0x1F) << 7) | ((v >> 5) << 25));
+ }
+}
- if (ops[2].type != OP_IM12S) {
- tcc_error("'%s': Expected third operand that is an immediate value between 0 and 0xfff", get_tok_str(token, NULL));
+static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm)
+{
+ uint32_t offset;
+
+ if (rs1->type != OP_REG) {
+ tcc_error("'%s': Expected first source operand that is a register", get_tok_str(token, NULL));
return;
}
- offset = ops[2].e.v;
- if (offset & 1) {
- tcc_error("'%s': Expected third operand that is an even immediate value", get_tok_str(token, NULL));
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
return;
}
-
- switch (token) {
- case TOK_ASM_beq:
- opcode |= 0 << 12;
- break;
- case TOK_ASM_bne:
- opcode |= 1 << 12;
- break;
- case TOK_ASM_blt:
- opcode |= 4 << 12;
- break;
- case TOK_ASM_bge:
- opcode |= 5 << 12;
- break;
- case TOK_ASM_bltu:
- opcode |= 6 << 12;
- break;
- case TOK_ASM_bgeu:
- opcode |= 7 << 12;
- break;
- default:
- expect("known branch instruction");
+ if (imm->type != OP_IM12S) {
+ tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
+ return;
}
+
+ offset = imm->e.v;
+
/* B-type instruction:
31 imm[12]
30...25 imm[10:5]
@@ -616,19 +724,20 @@ static void asm_branch_opcode(TCCState* s1, int token)
8...11 imm[4:1]
7 imm[11]
6...0 opcode */
- 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));
+ 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));
}
ST_FUNC void asm_opcode(TCCState *s1, int token)
{
switch (token) {
+ case TOK_ASM_ebreak:
+ case TOK_ASM_ecall:
case TOK_ASM_fence:
case TOK_ASM_fence_i:
- case TOK_ASM_ecall:
- case TOK_ASM_ebreak:
- case TOK_ASM_mrts:
- case TOK_ASM_mrth:
case TOK_ASM_hrts:
+ case TOK_ASM_mrth:
+ case TOK_ASM_mrts:
+ case TOK_ASM_nop:
case TOK_ASM_wfi:
asm_nullary_opcode(s1, token);
return;
@@ -648,68 +757,108 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
asm_binary_opcode(s1, token);
return;
- case TOK_ASM_sll:
- case TOK_ASM_slli:
- case TOK_ASM_srl:
- case TOK_ASM_srli:
- case TOK_ASM_sra:
- case TOK_ASM_srai:
- case TOK_ASM_sllw:
- case TOK_ASM_slld:
- case TOK_ASM_slliw:
- case TOK_ASM_sllid:
- case TOK_ASM_srlw:
- case TOK_ASM_srld:
- case TOK_ASM_srliw:
- case TOK_ASM_srlid:
- case TOK_ASM_sraw:
- case TOK_ASM_srad:
- case TOK_ASM_sraiw:
- case TOK_ASM_sraid:
- asm_shift_opcode(s1, token);
- return;
-
case TOK_ASM_add:
case TOK_ASM_addi:
- case TOK_ASM_sub:
- case TOK_ASM_addw:
case TOK_ASM_addiw:
- case TOK_ASM_subw:
- case TOK_ASM_xor:
- case TOK_ASM_xori:
- case TOK_ASM_or:
- case TOK_ASM_ori:
+ case TOK_ASM_addw:
case TOK_ASM_and:
case TOK_ASM_andi:
- case TOK_ASM_slt:
- case TOK_ASM_slti:
- case TOK_ASM_sltu:
- case TOK_ASM_sltiu:
+ case TOK_ASM_beq:
+ case TOK_ASM_bge:
+ case TOK_ASM_bgeu:
+ case TOK_ASM_blt:
+ case TOK_ASM_bltu:
+ case TOK_ASM_bne:
case TOK_ASM_jalr:
- asm_data_processing_opcode(s1, token);
- return;
-
case TOK_ASM_lb:
- case TOK_ASM_lh:
- case TOK_ASM_lw:
case TOK_ASM_lbu:
- case TOK_ASM_lhu:
case TOK_ASM_ld:
+ case TOK_ASM_lh:
+ case TOK_ASM_lhu:
+ case TOK_ASM_lw:
case TOK_ASM_lwu:
+ case TOK_ASM_or:
+ case TOK_ASM_ori:
case TOK_ASM_sb:
+ case TOK_ASM_sd:
case TOK_ASM_sh:
+ case TOK_ASM_sll:
+ case TOK_ASM_slli:
+ case TOK_ASM_slliw:
+ case TOK_ASM_sllw:
+ case TOK_ASM_slt:
+ case TOK_ASM_slti:
+ case TOK_ASM_sltiu:
+ case TOK_ASM_sltu:
+ case TOK_ASM_sra:
+ case TOK_ASM_srai:
+ case TOK_ASM_sraiw:
+ case TOK_ASM_sraw:
+ case TOK_ASM_srl:
+ case TOK_ASM_srli:
+ case TOK_ASM_srliw:
+ case TOK_ASM_srlw:
+ case TOK_ASM_sub:
+ case TOK_ASM_subw:
case TOK_ASM_sw:
- case TOK_ASM_sd:
- asm_data_transfer_opcode(s1, token);
+ case TOK_ASM_xor:
+ case TOK_ASM_xori:
+ asm_ternary_opcode(s1, token);
return;
- case TOK_ASM_beq:
- case TOK_ASM_bne:
- case TOK_ASM_blt:
- case TOK_ASM_bge:
- case TOK_ASM_bltu:
- case TOK_ASM_bgeu:
- asm_branch_opcode(s1, token);
+ /* C extension */
+ case TOK_ASM_c_ebreak:
+ case TOK_ASM_c_nop:
+ asm_nullary_opcode(s1, token);
+ return;
+
+ case TOK_ASM_c_j:
+ case TOK_ASM_c_jal:
+ case TOK_ASM_c_jalr:
+ case TOK_ASM_c_jr:
+ asm_unary_opcode(s1, token);
+ return;
+
+ case TOK_ASM_c_add:
+ case TOK_ASM_c_addi16sp:
+ case TOK_ASM_c_addi4spn:
+ case TOK_ASM_c_addi:
+ case TOK_ASM_c_addiw:
+ case TOK_ASM_c_addw:
+ case TOK_ASM_c_and:
+ case TOK_ASM_c_andi:
+ case TOK_ASM_c_beqz:
+ case TOK_ASM_c_bnez:
+ case TOK_ASM_c_fldsp:
+ case TOK_ASM_c_flwsp:
+ case TOK_ASM_c_fsdsp:
+ case TOK_ASM_c_fswsp:
+ case TOK_ASM_c_ldsp:
+ case TOK_ASM_c_li:
+ case TOK_ASM_c_lui:
+ case TOK_ASM_c_lwsp:
+ case TOK_ASM_c_mv:
+ case TOK_ASM_c_or:
+ case TOK_ASM_c_sdsp:
+ case TOK_ASM_c_slli:
+ case TOK_ASM_c_srai:
+ case TOK_ASM_c_srli:
+ case TOK_ASM_c_sub:
+ case TOK_ASM_c_subw:
+ case TOK_ASM_c_swsp:
+ case TOK_ASM_c_xor:
+ asm_binary_opcode(s1, token);
+ return;
+
+ case TOK_ASM_c_fld:
+ case TOK_ASM_c_flw:
+ case TOK_ASM_c_fsd:
+ case TOK_ASM_c_fsw:
+ case TOK_ASM_c_ld:
+ case TOK_ASM_c_lw:
+ case TOK_ASM_c_sd:
+ case TOK_ASM_c_sw:
+ asm_ternary_opcode(s1, token);
return;
default:
@@ -756,19 +905,456 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
ST_FUNC int asm_parse_regvar (int t)
{
- if (t >= TOK_ASM_x0 && t <= TOK_ASM_pc) { /* register name */
- if (t >= TOK_ASM_zero && t <= TOK_ASM_t6)
- return t - TOK_ASM_zero;
- switch (t) {
- case TOK_ASM_s0:
- return 8;
- case TOK_ASM_pc:
- tcc_error("PC register not implemented.");
- default:
- return t - TOK_ASM_x0;
- }
- } else
+ /* PC register not implemented */
+ if (t >= TOK_ASM_pc || t < TOK_ASM_x0)
return -1;
+
+ if (t < TOK_ASM_f0)
+ return t - TOK_ASM_x0;
+
+ if (t < TOK_ASM_zero)
+ return t - TOK_ASM_f0;
+
+ /* ABI mnemonic */
+ if (t < TOK_ASM_ft0)
+ return t - TOK_ASM_zero;
+
+ return t - TOK_ASM_ft0;
+}
+
+/*************************************************************/
+/* C extension */
+
+/* caller: Add funct6, funct2 into opcode */
+static void asm_emit_ca(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
+{
+ uint8_t dst, src;
+
+ if (rd->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* subtract index of x8 */
+ dst = rd->reg - 8;
+ src = rs2->reg - 8;
+
+ /* only registers {x,f}8 to {x,f}15 are valid (3-bit) */
+ if (dst > 7) {
+ tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (src > 7) {
+ tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CA-type instruction:
+ 15...10 funct6
+ 9...7 rd'/rs1'
+ 6..5 funct2
+ 4...2 rs2'
+ 1...0 opcode */
+
+ gen_le16(opcode | C_ENCODE_RS2(src) | C_ENCODE_RS1(dst));
+}
+
+static void asm_emit_cb(int token, uint16_t opcode, const Operand *rs1, const Operand *imm)
+{
+ uint32_t offset;
+ uint8_t dst, src;
+
+ if (rs1->type != OP_REG) {
+ tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ offset = imm->e.v;
+
+ if (offset & 1) {
+ tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ src = rs1->reg - 8;
+
+ if (src > 7) {
+ tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CB-type instruction:
+ 15...13 funct3
+ 12...10 offset
+ 9..7 rs1'
+ 6...2 offset
+ 1...0 opcode */
+
+ /* non-branch also using CB:
+ 15...13 funct3
+ 12 imm
+ 11..10 funct2
+ 9...7 rd'/rs1'
+ 6..2 imm
+ 1...0 opcode */
+
+ switch (token) {
+ case TOK_ASM_c_beqz:
+ case TOK_ASM_c_bnez:
+ 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));
+ return;
+ default:
+ gen_le16(opcode | C_ENCODE_RS1(src) | ((offset & 0x1f) << 2) | (NTH_BIT(offset, 5) << 12));
+ return;
+ }
+}
+
+static void asm_emit_ci(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
+{
+ uint32_t immediate;
+
+ if (rd->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ immediate = imm->e.v;
+
+ /* CI-type instruction:
+ 15...13 funct3
+ 12 imm
+ 11...7 rd/rs1
+ 6...2 imm
+ 1...0 opcode */
+
+ switch (token) {
+ case TOK_ASM_c_addi:
+ case TOK_ASM_c_addiw:
+ case TOK_ASM_c_li:
+ case TOK_ASM_c_slli:
+ gen_le16(opcode | ((immediate & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
+ return;
+ case TOK_ASM_c_addi16sp:
+ 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));
+ return;
+ case TOK_ASM_c_lui:
+ gen_le16(opcode | (((immediate >> 12) & 0x1f) << 2) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 17) << 12));
+ return;
+ case TOK_ASM_c_fldsp:
+ case TOK_ASM_c_ldsp:
+ gen_le16(opcode | (((immediate >> 6) & 7) << 2) | (((immediate >> 3) & 2) << 5) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
+ return;
+ case TOK_ASM_c_flwsp:
+ case TOK_ASM_c_lwsp:
+ gen_le16(opcode | (((immediate >> 6) & 3) << 2) | (((immediate >> 2) & 7) << 4) | ENCODE_RD(rd->reg) | (NTH_BIT(immediate, 5) << 12));
+ return;
+ case TOK_ASM_c_nop:
+ gen_le16(opcode);
+ return;
+ default:
+ expect("known instruction");
+ }
+}
+
+/* caller: Add funct3 into opcode */
+static void asm_emit_ciw(int token, uint16_t opcode, const Operand *rd, const Operand *imm)
+{
+ uint32_t nzuimm;
+ uint8_t dst;
+
+ if (rd->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ dst = rd->reg - 8;
+
+ if (dst > 7) {
+ tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ nzuimm = imm->e.v;
+
+ if (nzuimm > 0x3fc) {
+ tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x3ff", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (nzuimm & 3) {
+ tcc_error("'%s': Expected source operand that is a non-zero immediate value divisible by 4", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CIW-type instruction:
+ 15...13 funct3
+ 12...5 imm
+ 4...2 rd'
+ 1...0 opcode */
+
+ 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));
+}
+
+/* caller: Add funct3 into opcode */
+static void asm_emit_cj(int token, uint16_t opcode, const Operand *imm)
+{
+ uint32_t offset;
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ offset = imm->e.v;
+
+ /* +-2 KiB range; max. 0x7fe min. 0xffe (-0x7fe) */
+ if (offset > 0x1fff) {
+ tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0x1fff", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (offset & 1) {
+ tcc_error("'%s': Expected source operand that is an even immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CJ-type instruction:
+ 15...13 funct3
+ 12...2 offset[11|4|9:8|10|6|7|3:1|5]
+ 1...0 opcode */
+
+ 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));
+}
+
+/* caller: Add funct3 into opcode */
+static void asm_emit_cl(int token, uint16_t opcode, const Operand *rd, const Operand *rs1, const Operand *imm)
+{
+ uint32_t offset;
+ uint8_t dst, src;
+
+ if (rd->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (rs1->type != OP_REG) {
+ tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ dst = rd->reg - 8;
+ src = rs1->reg - 8;
+
+ if (dst > 7) {
+ tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (src > 7) {
+ tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ offset = imm->e.v;
+
+ if (offset > 0xff) {
+ tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (offset & 3) {
+ tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CL-type instruction:
+ 15...13 funct3
+ 12...10 imm
+ 9...7 rs1'
+ 6...5 imm
+ 4...2 rd'
+ 1...0 opcode */
+
+ switch (token) {
+ /* imm variant 1 */
+ case TOK_ASM_c_flw:
+ case TOK_ASM_c_lw:
+ 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));
+ return;
+ /* imm variant 2 */
+ case TOK_ASM_c_fld:
+ case TOK_ASM_c_ld:
+ gen_le16(opcode | C_ENCODE_RS2(dst) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
+ return;
+ default:
+ expect("known instruction");
+ }
+}
+
+/* caller: Add funct4 into opcode */
+static void asm_emit_cr(int token, uint16_t opcode, const Operand *rd, const Operand *rs2)
+{
+ if (rd->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CR-type instruction:
+ 15...12 funct4
+ 11..7 rd/rs1
+ 6...2 rs2
+ 1...0 opcode */
+
+ gen_le16(opcode | C_ENCODE_RS1(rd->reg) | C_ENCODE_RS2(rs2->reg));
+}
+
+/* caller: Add funct3 into opcode */
+static void asm_emit_cs(int token, uint16_t opcode, const Operand *rs2, const Operand *rs1, const Operand *imm)
+{
+ uint32_t offset;
+ uint8_t base, src;
+
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (rs1->type != OP_REG) {
+ tcc_error("'%s': Expected source operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ base = rs1->reg - 8;
+ src = rs2->reg - 8;
+
+ if (base > 7) {
+ tcc_error("'%s': Expected destination operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (src > 7) {
+ tcc_error("'%s': Expected source operand that is a valid C-extension register", get_tok_str(token, NULL));
+ return;
+ }
+
+ offset = imm->e.v;
+
+ if (offset > 0xff) {
+ tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (offset & 3) {
+ tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CS-type instruction:
+ 15...13 funct3
+ 12...10 imm
+ 9...7 rs1'
+ 6...5 imm
+ 4...2 rs2'
+ 1...0 opcode */
+ switch (token) {
+ /* imm variant 1 */
+ case TOK_ASM_c_fsw:
+ case TOK_ASM_c_sw:
+ 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));
+ return;
+ /* imm variant 2 */
+ case TOK_ASM_c_fsd:
+ case TOK_ASM_c_sd:
+ gen_le16(opcode | C_ENCODE_RS2(base) | C_ENCODE_RS1(src) | (((offset >> 6) & 3) << 5) | (((offset >> 3) & 7) << 10));
+ return;
+ default:
+ expect("known instruction");
+ }
+}
+
+/* caller: Add funct3 into opcode */
+static void asm_emit_css(int token, uint16_t opcode, const Operand *rs2, const Operand *imm)
+{
+ uint32_t offset;
+
+ if (rs2->type != OP_REG) {
+ tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (imm->type != OP_IM12S && imm->type != OP_IM32) {
+ tcc_error("'%s': Expected source operand that is an immediate value", get_tok_str(token, NULL));
+ return;
+ }
+
+ offset = imm->e.v;
+
+ if (offset > 0xff) {
+ tcc_error("'%s': Expected source operand that is an immediate value between 0 and 0xff", get_tok_str(token, NULL));
+ return;
+ }
+
+ if (offset & 3) {
+ tcc_error("'%s': Expected source operand that is an immediate value divisible by 4", get_tok_str(token, NULL));
+ return;
+ }
+
+ /* CSS-type instruction:
+ 15...13 funct3
+ 12...7 imm
+ 6...2 rs2
+ 1...0 opcode */
+
+ switch (token) {
+ /* imm variant 1 */
+ case TOK_ASM_c_fswsp:
+ case TOK_ASM_c_swsp:
+ gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 3) << 7) | (((offset >> 2) & 0xf) << 9));
+ return;
+ /* imm variant 2 */
+ case TOK_ASM_c_fsdsp:
+ case TOK_ASM_c_sdsp:
+ gen_le16(opcode | ENCODE_RS2(rs2->reg) | (((offset >> 6) & 7) << 7) | (((offset >> 3) & 7) << 10));
+ return;
+ default:
+ expect("known instruction");
+ }
}
/*************************************************************/
diff --git a/riscv64-tok.h b/riscv64-tok.h
index 986cffa..c8a6e8e 100644
--- a/riscv64-tok.h
+++ b/riscv64-tok.h
@@ -5,8 +5,11 @@
* The specifications are available under https://riscv.org/technical/specifications/
*/
-/* register */
+#define DEF_ASM_WITH_SUFFIX(x, y) \
+ DEF(TOK_ASM_ ## x ## _ ## y, #x "." #y)
+/* register */
+ /* integer */
DEF_ASM(x0)
DEF_ASM(x1)
DEF_ASM(x2)
@@ -39,9 +42,42 @@
DEF_ASM(x29)
DEF_ASM(x30)
DEF_ASM(x31)
-
-/* register macros */
-
+ /* float */
+ DEF_ASM(f0)
+ DEF_ASM(f1)
+ DEF_ASM(f2)
+ DEF_ASM(f3)
+ DEF_ASM(f4)
+ DEF_ASM(f5)
+ DEF_ASM(f6)
+ DEF_ASM(f7)
+ DEF_ASM(f8)
+ DEF_ASM(f9)
+ DEF_ASM(f10)
+ DEF_ASM(f11)
+ DEF_ASM(f12)
+ DEF_ASM(f13)
+ DEF_ASM(f14)
+ DEF_ASM(f15)
+ DEF_ASM(f16)
+ DEF_ASM(f17)
+ DEF_ASM(f18)
+ DEF_ASM(f19)
+ DEF_ASM(f20)
+ DEF_ASM(f21)
+ DEF_ASM(f22)
+ DEF_ASM(f23)
+ DEF_ASM(f24)
+ DEF_ASM(f25)
+ DEF_ASM(f26)
+ DEF_ASM(f27)
+ DEF_ASM(f28)
+ DEF_ASM(f29)
+ DEF_ASM(f30)
+ DEF_ASM(f31)
+
+/* register ABI mnemonics, refer to RISC-V ABI 1.0 */
+ /* integer */
DEF_ASM(zero)
DEF_ASM(ra)
DEF_ASM(sp)
@@ -50,7 +86,7 @@
DEF_ASM(t0)
DEF_ASM(t1)
DEF_ASM(t2)
- DEF_ASM(fp)
+ DEF_ASM(s0)
DEF_ASM(s1)
DEF_ASM(a0)
DEF_ASM(a1)
@@ -74,14 +110,42 @@
DEF_ASM(t4)
DEF_ASM(t5)
DEF_ASM(t6)
-
- DEF_ASM(s0) // = x8
-
+ /* float */
+ DEF_ASM(ft0)
+ DEF_ASM(ft1)
+ DEF_ASM(ft2)
+ DEF_ASM(ft3)
+ DEF_ASM(ft4)
+ DEF_ASM(ft5)
+ DEF_ASM(ft6)
+ DEF_ASM(ft7)
+ DEF_ASM(fs0)
+ DEF_ASM(fs1)
+ DEF_ASM(fa0)
+ DEF_ASM(fa1)
+ DEF_ASM(fa2)
+ DEF_ASM(fa3)
+ DEF_ASM(fa4)
+ DEF_ASM(fa5)
+ DEF_ASM(fa6)
+ DEF_ASM(fa7)
+ DEF_ASM(fs2)
+ DEF_ASM(fs3)
+ DEF_ASM(fs4)
+ DEF_ASM(fs5)
+ DEF_ASM(fs6)
+ DEF_ASM(fs7)
+ DEF_ASM(fs8)
+ DEF_ASM(fs9)
+ DEF_ASM(fs10)
+ DEF_ASM(fs11)
+ DEF_ASM(ft8)
+ DEF_ASM(ft9)
+ DEF_ASM(ft10)
+ DEF_ASM(ft11)
+ /* not in the ABI */
DEF_ASM(pc)
-#define DEF_ASM_WITH_SUFFIX(x, y) \
- DEF(TOK_ASM_ ## x ## _ ## y, #x #y)
-
/* Loads */
DEF_ASM(lb)
@@ -110,18 +174,12 @@
DEF_ASM(slli)
DEF_ASM(srli)
DEF_ASM(sllw)
- DEF_ASM(slld)
DEF_ASM(slliw)
- DEF_ASM(sllid)
DEF_ASM(srlw)
- DEF_ASM(srld)
DEF_ASM(srliw)
- DEF_ASM(srlid)
DEF_ASM(srai)
DEF_ASM(sraw)
- DEF_ASM(srad)
DEF_ASM(sraiw)
- DEF_ASM(sraid)
/* Arithmetic */
@@ -236,11 +294,8 @@
/* Shifts */
DEF_ASM_WITH_SUFFIX(c, slli)
- DEF_ASM_WITH_SUFFIX(c, slli64)
DEF_ASM_WITH_SUFFIX(c, srli)
- DEF_ASM_WITH_SUFFIX(c, srli64)
DEF_ASM_WITH_SUFFIX(c, srai)
- DEF_ASM_WITH_SUFFIX(c, srai64)
/* Arithmetic */
DEF_ASM_WITH_SUFFIX(c, add)
@@ -293,3 +348,4 @@
DEF_ASM(hrts)
DEF_ASM(wfi)
+#undef DEF_ASM_WITH_SUFFIX