diff --git a/test/sim/rvcpp/rv.cpp b/test/sim/rvcpp/rv.cpp index 636ec9d..2fe7aab 100644 --- a/test/sim/rvcpp/rv.cpp +++ b/test/sim/rvcpp/rv.cpp @@ -7,10 +7,14 @@ #include #include +#include "rv_opcodes.h" #include "rv_types.h" #include "mem.h" -// Minimal RISC-V interpreter, supporting RV32IM only +// Minimal RISC-V interpreter, supporting: +// - RV32I +// - M +// - C (also called Zca) // Use unsigned arithmetic everywhere, with explicit sign extension as required. static inline ux_t sext(ux_t bits, int sign_bit) { @@ -20,6 +24,12 @@ static inline ux_t sext(ux_t bits, int sign_bit) { return (bits & (1u << sign_bit + 1) - 1) - ((bits & 1u << sign_bit) << 1); } +// Inclusive msb:lsb style, like Verilog (and like the ISA manual) +#define BITS_UPTO(msb) (~((-1u << (msb)) << 1)) +#define BITRANGE(msb, lsb) (BITS_UPTO((msb) - (lsb)) << (lsb)) +#define GETBITS(x, msb, lsb) (((x) & BITRANGE(msb, lsb)) >> (lsb)) +#define GETBIT(x, bit) (((x) >> (bit)) & 1u) + static inline ux_t imm_i(uint32_t instr) { return (instr >> 20) - (instr >> 19 & 0x1000); } @@ -48,6 +58,45 @@ static inline ux_t imm_j(uint32_t instr) { - (instr >> 11 & 0x100000); } +static inline ux_t imm_ci(uint32_t instr) { + return GETBITS(instr, 6, 2) - (GETBIT(instr, 12) << 5); +} + +static inline ux_t imm_cj(uint32_t instr) { + return -(GETBIT(instr, 12) << 11) + + (GETBIT(instr, 11) << 4) + + (GETBITS(instr, 10, 9) << 8) + + (GETBIT(instr, 8) << 10) + + (GETBIT(instr, 7) << 6) + + (GETBIT(instr, 6) << 7) + + (GETBITS(instr, 5, 3) << 1) + + (GETBIT(instr, 2) << 5); +} + +static inline ux_t imm_cb(uint32_t instr) { + return -(GETBIT(instr, 12) << 8) + + (GETBITS(instr, 11, 10) << 3) + + (GETBITS(instr, 6, 5) << 6) + + (GETBITS(instr, 4, 3) << 1) + + (GETBIT(instr, 2) << 5); +} + +static inline uint c_rs1_s(uint32_t instr) { + return GETBITS(instr, 9, 7) + 8; +} + +static inline uint c_rs2_s(uint32_t instr) { + return GETBITS(instr, 4, 2) + 8; +} + +static inline uint c_rs1_l(uint32_t instr) { + return GETBITS(instr, 11, 7); +} + +static inline uint c_rs2_l(uint32_t instr) { + return GETBITS(instr, 6, 2); +} + struct RVCSR { enum { WRITE = 0, @@ -96,7 +145,7 @@ struct RVCore { ux_t pc; RVCSR csr; - RVCore(ux_t reset_vector=0xc0) { + RVCore(ux_t reset_vector=0x40) { std::fill(std::begin(regs), std::end(regs), 0); pc = reset_vector; } @@ -115,8 +164,8 @@ struct RVCore { OPC_SYSTEM = 0b11'100 }; - void step(MemBase32 &mem) { - uint32_t instr = mem.r32(pc); + void step(MemBase32 &mem, bool trace=false) { + uint32_t instr = mem.r16(pc) | (mem.r16(pc + 2) << 16); std::optional rd_wdata; std::optional pc_wdata; uint regnum_rs1 = instr >> 15 & 0x1f; @@ -130,234 +179,374 @@ struct RVCore { uint funct3 = instr >> 12 & 0x7; uint funct7 = instr >> 25 & 0x7f; - switch (opc) { + if ((instr & 0x3) == 0x3) { + // 32-bit instruction + switch (opc) { - case OPC_OP: { - if (funct7 == 0b00'00000) { - if (funct3 == 0b000) - rd_wdata = rs1 + rs2; - else if (funct3 == 0b001) - rd_wdata = rs1 << (rs2 & 0x1f); - else if (funct3 == 0b010) - rd_wdata = (sx_t)rs1 < (sx_t)rs2; - else if (funct3 == 0b011) - rd_wdata = rs1 < rs2; - else if (funct3 == 0b100) - rd_wdata = rs1 ^ rs2; - else if (funct3 == 0b101) - rd_wdata = rs1 >> (rs2 & 0x1f); - else if (funct3 == 0b110) - rd_wdata = rs1 | rs2; - else if (funct3 == 0b111) - rd_wdata = rs1 & rs2; - else - instr_invalid = true; - } - else if (funct7 == 0b01'00000) { - if (funct3 == 0b000) - rd_wdata = rs1 - rs2; - else if (funct3 == 0b101) - rd_wdata = (sx_t)rs1 >> (rs2 & 0x1f); - else - instr_invalid = true; - } - else if (funct7 == 0b00'00001) { - if (funct3 < 0b100) { - sdx_t mul_op_a = rs1; - sdx_t mul_op_b = rs2; - if (funct3 != 0b011) - mul_op_a -= (mul_op_a & (1 << XLEN - 1)) << 1; - if (funct3 < 0b010) - mul_op_b -= (mul_op_b & (1 << XLEN - 1)) << 1; - sdx_t mul_result = mul_op_a * mul_op_b; + case OPC_OP: { + if (funct7 == 0b00'00000) { if (funct3 == 0b000) - rd_wdata = mul_result; + rd_wdata = rs1 + rs2; + else if (funct3 == 0b001) + rd_wdata = rs1 << (rs2 & 0x1f); + else if (funct3 == 0b010) + rd_wdata = (sx_t)rs1 < (sx_t)rs2; + else if (funct3 == 0b011) + rd_wdata = rs1 < rs2; + else if (funct3 == 0b100) + rd_wdata = rs1 ^ rs2; + else if (funct3 == 0b101) + rd_wdata = rs1 >> (rs2 & 0x1f); + else if (funct3 == 0b110) + rd_wdata = rs1 | rs2; + else if (funct3 == 0b111) + rd_wdata = rs1 & rs2; else - rd_wdata = mul_result >> XLEN; + instr_invalid = true; } - else { - asm volatile("" : : : "memory"); - if (funct3 == 0b100) { - if (rs2 == 0) - rd_wdata = -1; - else if (rs2 == ~0u) - rd_wdata = -rs1; + else if (funct7 == 0b01'00000) { + if (funct3 == 0b000) + rd_wdata = rs1 - rs2; + else if (funct3 == 0b101) + rd_wdata = (sx_t)rs1 >> (rs2 & 0x1f); + else + instr_invalid = true; + } + else if (funct7 == 0b00'00001) { + if (funct3 < 0b100) { + sdx_t mul_op_a = rs1; + sdx_t mul_op_b = rs2; + if (funct3 != 0b011) + mul_op_a -= (mul_op_a & (1 << XLEN - 1)) << 1; + if (funct3 < 0b010) + mul_op_b -= (mul_op_b & (1 << XLEN - 1)) << 1; + sdx_t mul_result = mul_op_a * mul_op_b; + if (funct3 == 0b000) + rd_wdata = mul_result; else - rd_wdata = (sx_t)rs1 / (sx_t)rs2; + rd_wdata = mul_result >> XLEN; } - else if (funct3 == 0b101) { - rd_wdata = rs2 ? rs1 / rs2 : ~0ul; + else { + if (funct3 == 0b100) { + if (rs2 == 0) + rd_wdata = -1; + else if (rs2 == ~0u) + rd_wdata = -rs1; + else + rd_wdata = (sx_t)rs1 / (sx_t)rs2; + } + else if (funct3 == 0b101) { + rd_wdata = rs2 ? rs1 / rs2 : ~0ul; + } + else if (funct3 == 0b110) { + if (rs2 == 0) + rd_wdata = rs1; + else if (rs2 == ~0u) // potential overflow of division + rd_wdata = 0; + else + rd_wdata = (sx_t)rs1 % (sx_t)rs2; + } + else if (funct3 == 0b111) { + rd_wdata = rs2 ? rs1 % rs2 : rs1; + } } - else if (funct3 == 0b110) { - if (rs2 == 0) - rd_wdata = rs1; - else if (rs2 == ~0u) // potential overflow of division - rd_wdata = 0; - else - rd_wdata = (sx_t)rs1 % (sx_t)rs2; - } - else if (funct3 == 0b111) { - rd_wdata = rs2 ? rs1 % rs2 : rs1; - } - } - } - else { - instr_invalid = true; - } - break; - } - - case OPC_OP_IMM: { - ux_t imm = imm_i(instr); - if (funct3 == 0b000) - rd_wdata = rs1 + imm; - else if (funct3 == 0b010) - rd_wdata = !!((sx_t)rs1 < (sx_t)imm); - else if (funct3 == 0b011) - rd_wdata = !!(rs1 < imm); - else if (funct3 == 0b100) - rd_wdata = rs1 ^ imm; - else if (funct3 == 0b110) - rd_wdata = rs1 | imm; - else if (funct3 == 0b111) - rd_wdata = rs1 & imm; - else if (funct3 == 0b001 || funct3 == 0b101) { - // shamt is regnum_rs2 - if (funct7 == 0b00'00000 && funct3 == 0b001) { - rd_wdata = rs1 << regnum_rs2; - } - else if (funct7 == 0b00'00000 && funct3 == 0b101) { - rd_wdata = rs1 >> regnum_rs2; - } - else if (funct7 == 0b01'00000 && funct3 == 0b101) { - rd_wdata = (sx_t)rs1 >> regnum_rs2; } else { instr_invalid = true; } + break; } - else { + + case OPC_OP_IMM: { + ux_t imm = imm_i(instr); + if (funct3 == 0b000) + rd_wdata = rs1 + imm; + else if (funct3 == 0b010) + rd_wdata = !!((sx_t)rs1 < (sx_t)imm); + else if (funct3 == 0b011) + rd_wdata = !!(rs1 < imm); + else if (funct3 == 0b100) + rd_wdata = rs1 ^ imm; + else if (funct3 == 0b110) + rd_wdata = rs1 | imm; + else if (funct3 == 0b111) + rd_wdata = rs1 & imm; + else if (funct3 == 0b001 || funct3 == 0b101) { + // shamt is regnum_rs2 + if (funct7 == 0b00'00000 && funct3 == 0b001) { + rd_wdata = rs1 << regnum_rs2; + } + else if (funct7 == 0b00'00000 && funct3 == 0b101) { + rd_wdata = rs1 >> regnum_rs2; + } + else if (funct7 == 0b01'00000 && funct3 == 0b101) { + rd_wdata = (sx_t)rs1 >> regnum_rs2; + } + else { + instr_invalid = true; + } + } + else { + instr_invalid = true; + } + break; + } + + case OPC_BRANCH: { + ux_t target = pc + imm_b(instr); + bool taken = false; + if ((funct3 & 0b110) == 0b000) + taken = rs1 == rs2; + else if ((funct3 & 0b110) == 0b100) + taken = (sx_t)rs1 < (sx_t) rs2; + else if ((funct3 & 0b110) == 0b110) + taken = rs1 < rs2; + else + instr_invalid = true; + if (!instr_invalid && funct3 & 0b001) + taken = !taken; + if (taken) + pc_wdata = target; + break; + } + + case OPC_LOAD: { + ux_t load_addr = rs1 + imm_i(instr); + if (funct3 == 0b000) + rd_wdata = sext(mem.r8(load_addr), 7); + else if (funct3 == 0b001) + rd_wdata = sext(mem.r16(load_addr), 15); + else if (funct3 == 0b010) + rd_wdata = mem.r32(load_addr); + else if (funct3 == 0b100) + rd_wdata = mem.r8(load_addr); + else if (funct3 == 0b101) + rd_wdata = mem.r16(load_addr); + else + instr_invalid = true; + break; + } + + case OPC_STORE: { + ux_t store_addr = rs1 + imm_s(instr); + if (funct3 == 0b000) + mem.w8(store_addr, rs2 & 0xffu); + else if (funct3 == 0b001) + mem.w16(store_addr, rs2 & 0xffffu); + else if (funct3 == 0b010) + mem.w32(store_addr, rs2); + else + instr_invalid = true; + break; + } + + case OPC_JAL: + rd_wdata = pc + 4; + pc_wdata = pc + imm_j(instr); + break; + + case OPC_JALR: + rd_wdata = pc + 4; + pc_wdata = (rs1 + imm_i(instr)) & -2u; + break; + + case OPC_LUI: + rd_wdata = imm_u(instr); + break; + + case OPC_AUIPC: + rd_wdata = pc + imm_u(instr); + break; + + case OPC_SYSTEM: { + uint16_t csr_addr = instr >> 20; + if (funct3 >= 0b001 && funct3 <= 0b011) { + // csrrw, csrrs, csrrc + uint write_op = funct3 - 0b001; + if (write_op != RVCSR::WRITE || regnum_rd != 0) + rd_wdata = csr.read(csr_addr); + if (write_op == RVCSR::WRITE || regnum_rs1 != 0) + csr.write(csr_addr, rs1, write_op); + } + else if (funct3 >= 0b101 && funct3 <= 0b111) { + // csrrwi, csrrsi, csrrci + uint write_op = funct3 - 0b101; + if (write_op != RVCSR::WRITE || regnum_rd != 0) + rd_wdata = csr.read(csr_addr); + if (write_op == RVCSR::WRITE || regnum_rs1 != 0) + csr.write(csr_addr, regnum_rs1, write_op); + } + else { + instr_invalid = true; + } + break; + } + + default: + instr_invalid = true; + break; + } + } else { + regnum_rd = 0; + // 16-bit instructions + // RVC Quadrant 00: + if (RVOPC_MATCH(instr, C_ADDI4SPN)) { + regnum_rd = c_rs2_s(instr); + rd_wdata = regs[2] + + (GETBITS(instr, 12, 11) << 4) + + (GETBITS(instr, 10, 7) << 6) + + (GETBIT(instr, 6) << 2) + + (GETBIT(instr, 5) << 3); + } else if (RVOPC_MATCH(instr, C_LW)) { + regnum_rd = c_rs2_s(instr); + uint32_t addr = regs[c_rs1_s(instr)] + + (GETBIT(instr, 6) << 2) + + (GETBITS(instr, 12, 10) << 3) + + (GETBIT(instr, 5) << 6); + rd_wdata = mem.r32(addr); + } else if (RVOPC_MATCH(instr, C_SW)) { + uint32_t addr = regs[c_rs1_s(instr)] + + (GETBIT(instr, 6) << 2) + + (GETBITS(instr, 12, 10) << 3) + + (GETBIT(instr, 5) << 6); + mem.w32(addr, regs[c_rs2_s(instr)]); + // RVC Quadrant 01: + } else if (RVOPC_MATCH(instr, C_ADDI)) { + regnum_rd = c_rs1_l(instr); + rd_wdata = regs[c_rs1_l(instr)] + imm_ci(instr); + } else if (RVOPC_MATCH(instr, C_JAL)) { + pc_wdata = pc + imm_cj(instr); + regnum_rd = 1; + rd_wdata = pc + 2; + } else if (RVOPC_MATCH(instr, C_LI)) { + regnum_rd = c_rs1_l(instr); + rd_wdata = imm_ci(instr); + } else if (RVOPC_MATCH(instr, C_LUI)) { + regnum_rd = c_rs1_l(instr); + // ADDI16SPN if rd is sp + if (regnum_rd == 2) { + rd_wdata = regs[2] + - (GETBIT(instr, 12) << 9) + + (GETBIT(instr, 6) << 4) + + (GETBIT(instr, 5) << 6) + + (GETBITS(instr, 4, 3) << 7) + + (GETBIT(instr, 2) << 5); + } else { + rd_wdata = -(GETBIT(instr, 12) << 17) + + (GETBITS(instr, 6, 2) << 12); + } + } else if (RVOPC_MATCH(instr, C_SRLI)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[regnum_rd] >> GETBITS(instr, 6, 2); + } else if (RVOPC_MATCH(instr, C_SRAI)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = (sx_t)regs[regnum_rd] >> GETBITS(instr, 6, 2); + } else if (RVOPC_MATCH(instr, C_ANDI)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[regnum_rd] & imm_ci(instr); + } else if (RVOPC_MATCH(instr, C_SUB)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[c_rs1_s(instr)] - regs[c_rs2_s(instr)]; + } else if (RVOPC_MATCH(instr, C_XOR)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[c_rs1_s(instr)] ^ regs[c_rs2_s(instr)]; + } else if (RVOPC_MATCH(instr, C_OR)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[c_rs1_s(instr)] | regs[c_rs2_s(instr)]; + } else if (RVOPC_MATCH(instr, C_AND)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[c_rs1_s(instr)] & regs[c_rs2_s(instr)]; + } else if (RVOPC_MATCH(instr, C_J)) { + pc_wdata = pc + imm_cj(instr); + } else if (RVOPC_MATCH(instr, C_BEQZ)) { + if (regs[c_rs1_s(instr)] == 0) { + pc_wdata = pc + imm_cb(instr); + } + } else if (RVOPC_MATCH(instr, C_BNEZ)) { + if (regs[c_rs1_s(instr)] != 0) { + pc_wdata = pc + imm_cb(instr); + } + // RVC Quadrant 10: + } else if (RVOPC_MATCH(instr, C_SLLI)) { + regnum_rd = c_rs1_s(instr); + rd_wdata = regs[regnum_rd] << GETBITS(instr, 6, 2); + } else if (RVOPC_MATCH(instr, C_MV)) { + if (c_rs2_l(instr) == 0) { + // c.jr + pc_wdata = regs[c_rs1_l(instr)] & -2u;; + } else { + regnum_rd = c_rs1_l(instr); + rd_wdata = regs[c_rs2_l(instr)]; + } + } else if (RVOPC_MATCH(instr, C_ADD)) { + if (c_rs2_l(instr) == 0) { + // c.jalr + pc_wdata = regs[c_rs1_l(instr)] & -2u; + regnum_rd = 1; + rd_wdata = pc + 2; + } else { + regnum_rd = c_rs1_l(instr); + rd_wdata = regs[c_rs1_l(instr)] + regs[c_rs2_l(instr)]; + } + } else if (RVOPC_MATCH(instr, C_LWSP)) { + regnum_rd = c_rs1_l(instr); + ux_t addr = regs[2] + + (GETBIT(instr, 12) << 5) + + (GETBITS(instr, 6, 4) << 2) + + (GETBITS(instr, 3, 2) << 6); + rd_wdata = mem.r32(addr); + } else if (RVOPC_MATCH(instr, C_SWSP)) { + ux_t addr = regs[2] + + (GETBITS(instr, 12, 9) << 2) + + (GETBITS(instr, 8, 7) << 6); + mem.w32(addr, regs[c_rs2_l(instr)]); + } else { instr_invalid = true; } - break; } - - case OPC_BRANCH: { - ux_t target = pc + imm_b(instr); - bool taken = false; - if ((funct3 & 0b110) == 0b000) - taken = rs1 == rs2; - else if ((funct3 & 0b110) == 0b100) - taken = (sx_t)rs1 < (sx_t) rs2; - else if ((funct3 & 0b110) == 0b110) - taken = rs1 < rs2; - else - instr_invalid = true; - if (!instr_invalid && funct3 & 0b001) - taken = !taken; - if (taken) - pc_wdata = target; - break; - } - - case OPC_LOAD: { - ux_t load_addr = rs1 + imm_i(instr); - if (funct3 == 0b000) - rd_wdata = sext(mem.r8(load_addr), 7); - else if (funct3 == 0b001) - rd_wdata = sext(mem.r16(load_addr), 15); - else if (funct3 == 0b010) - rd_wdata = mem.r32(load_addr); - else if (funct3 == 0b100) - rd_wdata = mem.r8(load_addr); - else if (funct3 == 0b101) - rd_wdata = mem.r16(load_addr); - else - instr_invalid = true; - break; - } - - case OPC_STORE: { - ux_t store_addr = rs1 + imm_s(instr); - if (funct3 == 0b000) - mem.w8(store_addr, rs2 & 0xffu); - else if (funct3 == 0b001) - mem.w16(store_addr, rs2 & 0xffffu); - else if (funct3 == 0b010) - mem.w32(store_addr, rs2); - else - instr_invalid = true; - break; - } - - case OPC_JAL: - rd_wdata = pc + 4; - pc_wdata = pc + imm_j(instr); - break; - - case OPC_JALR: - rd_wdata = pc + 4; - pc_wdata = (rs1 + imm_i(instr)) & -2u; - break; - - case OPC_LUI: - rd_wdata = imm_u(instr); - break; - - case OPC_AUIPC: - rd_wdata = pc + imm_u(instr); - break; - - case OPC_SYSTEM: { - uint16_t csr_addr = instr >> 20; - if (funct3 >= 0b001 && funct3 <= 0b011) { - // csrrw, csrrs, csrrc - uint write_op = funct3 - 0b001; - if (write_op != RVCSR::WRITE || regnum_rd != 0) - rd_wdata = csr.read(csr_addr); - if (write_op == RVCSR::WRITE || regnum_rs1 != 0) - csr.write(csr_addr, rs1, write_op); - } - else if (funct3 >= 0b101 && funct3 <= 0b111) { - // csrrwi, csrrsi, csrrci - uint write_op = funct3 - 0b101; - if (write_op != RVCSR::WRITE || regnum_rd != 0) - rd_wdata = csr.read(csr_addr); - if (write_op == RVCSR::WRITE || regnum_rs1 != 0) - csr.write(csr_addr, regnum_rs1, write_op); - } - else { - instr_invalid = true; - } - break; - } - - default: - instr_invalid = true; - break; - } - if (instr_invalid) printf("Invalid instr %08x at %08x\n", instr, pc); + if (trace) { + printf("%08x: ", pc); + if ((instr & 0x3) == 0x3) { + printf("%08x : ", instr); + } else { + printf(" %04x : ", instr & 0xffffu); + } + if (regnum_rd != 0) { + printf("%-3s <- %08x ", friendly_reg_names[regnum_rd], *rd_wdata); + } else { + printf(" "); + } + if (pc_wdata) { + printf(": pc <- %08x\n", *pc_wdata); + } else { + printf(":\n"); + } + } + if (pc_wdata) pc = *pc_wdata; else - pc = pc + 4; + pc = pc + ((instr & 0x3) == 0x3 ? 4 : 2); if (rd_wdata && regnum_rd != 0) regs[regnum_rd] = *rd_wdata; csr.step(); + } }; const char *help_str = -"Usage: tb binfile [--dump start end] [--cycles n]\n" -" binfile : Binary to load into start of memory\n" +"Usage: tb [--bin x.bin] [--dump start end] [--vcd x.vcd] [--cycles n]\n" +" --bin x.bin : Flat binary file loaded to address 0x0 in RAM\n" +" --vcd x.vcd : Dummy option for compatibility with CXXRTL tb\n" " --dump start end : Print out memory contents between start and end (exclusive)\n" " after execution finishes. Can be passed multiple times.\n" " --cycles n : Maximum number of cycles to run before exiting.\n" " --memsize n : Memory size in units of 1024 bytes, default is 16 MB\n" +" --trace : Print out execution tracing info\n" ; void exit_help(std::string errtext = "") { @@ -372,10 +561,26 @@ int main(int argc, char **argv) { std::vector> dump_ranges; int64_t max_cycles = 100000; uint32_t ramsize = 16 * (1 << 20); + bool load_bin = false; + std::string bin_path; + bool trace_execution = false; - for (int i = 2; i < argc; ++i) { + for (int i = 1; i < argc; ++i) { std::string s(argv[i]); - if (s == "--dump") { + if (s == "--bin") { + if (argc - i < 2) + exit_help("Option --bin requires an argument\n"); + load_bin = true; + bin_path = argv[i + 1]; + i += 1; + } + else if (s == "--vcd") { + if (argc - i < 2) + exit_help("Option --vcd requires an argument\n"); + // (We ignore this argument, it's supported for + i += 1; + } + else if (s == "--dump") { if (argc - i < 3) exit_help("Option --dump requires 2 arguments\n"); dump_ranges.push_back(std::make_tuple( @@ -396,6 +601,9 @@ int main(int argc, char **argv) { ramsize = 1024 * std::stol(argv[i + 1], 0, 0); i += 1; } + else if (s == "--trace") { + trace_execution = true; + } else { std::cerr << "Unrecognised argument " << s << "\n"; exit_help(""); @@ -408,21 +616,23 @@ int main(int argc, char **argv) { mem.add(0, ramsize, &ram); mem.add(0x80000000u, 12, &io); - std::ifstream fd(argv[1], std::ios::binary | std::ios::ate); - std::streamsize bin_size = fd.tellg(); - if (bin_size > ramsize) { - std::cerr << "Binary file (" << bin_size << " bytes) is larger than memory (" << ramsize << " bytes)\n"; - return -1; + if (load_bin) { + std::ifstream fd(bin_path, std::ios::binary | std::ios::ate); + std::streamsize bin_size = fd.tellg(); + if (bin_size > ramsize) { + std::cerr << "Binary file (" << bin_size << " bytes) is larger than memory (" << ramsize << " bytes)\n"; + return -1; + } + fd.seekg(0, std::ios::beg); + fd.read((char*)ram.mem, bin_size); } - fd.seekg(0, std::ios::beg); - fd.read((char*)ram.mem, bin_size); RVCore core; int64_t cyc; try { for (cyc = 0; cyc < max_cycles; ++cyc) - core.step(mem); + core.step(mem, trace_execution); } catch (TBExitException e) { printf("CPU requested halt. Exit code %d\n", e.exitcode); diff --git a/test/sim/rvcpp/rv_opcodes.h b/test/sim/rvcpp/rv_opcodes.h new file mode 100644 index 0000000..83a345e --- /dev/null +++ b/test/sim/rvcpp/rv_opcodes.h @@ -0,0 +1,346 @@ +#ifndef _RV_OPCODES_H +#define _RV_OPCODES_H + +// Base ISA (some of these are Z now) +#define RVOPC_BEQ_BITS 0b00000000000000000000000001100011 +#define RVOPC_BEQ_MASK 0b00000000000000000111000001111111 +#define RVOPC_BNE_BITS 0b00000000000000000001000001100011 +#define RVOPC_BNE_MASK 0b00000000000000000111000001111111 +#define RVOPC_BLT_BITS 0b00000000000000000100000001100011 +#define RVOPC_BLT_MASK 0b00000000000000000111000001111111 +#define RVOPC_BGE_BITS 0b00000000000000000101000001100011 +#define RVOPC_BGE_MASK 0b00000000000000000111000001111111 +#define RVOPC_BLTU_BITS 0b00000000000000000110000001100011 +#define RVOPC_BLTU_MASK 0b00000000000000000111000001111111 +#define RVOPC_BGEU_BITS 0b00000000000000000111000001100011 +#define RVOPC_BGEU_MASK 0b00000000000000000111000001111111 +#define RVOPC_JALR_BITS 0b00000000000000000000000001100111 +#define RVOPC_JALR_MASK 0b00000000000000000111000001111111 +#define RVOPC_JAL_BITS 0b00000000000000000000000001101111 +#define RVOPC_JAL_MASK 0b00000000000000000000000001111111 +#define RVOPC_LUI_BITS 0b00000000000000000000000000110111 +#define RVOPC_LUI_MASK 0b00000000000000000000000001111111 +#define RVOPC_AUIPC_BITS 0b00000000000000000000000000010111 +#define RVOPC_AUIPC_MASK 0b00000000000000000000000001111111 +#define RVOPC_ADDI_BITS 0b00000000000000000000000000010011 +#define RVOPC_ADDI_MASK 0b00000000000000000111000001111111 +#define RVOPC_SLLI_BITS 0b00000000000000000001000000010011 +#define RVOPC_SLLI_MASK 0b11111110000000000111000001111111 +#define RVOPC_SLTI_BITS 0b00000000000000000010000000010011 +#define RVOPC_SLTI_MASK 0b00000000000000000111000001111111 +#define RVOPC_SLTIU_BITS 0b00000000000000000011000000010011 +#define RVOPC_SLTIU_MASK 0b00000000000000000111000001111111 +#define RVOPC_XORI_BITS 0b00000000000000000100000000010011 +#define RVOPC_XORI_MASK 0b00000000000000000111000001111111 +#define RVOPC_SRLI_BITS 0b00000000000000000101000000010011 +#define RVOPC_SRLI_MASK 0b11111110000000000111000001111111 +#define RVOPC_SRAI_BITS 0b01000000000000000101000000010011 +#define RVOPC_SRAI_MASK 0b11111110000000000111000001111111 +#define RVOPC_ORI_BITS 0b00000000000000000110000000010011 +#define RVOPC_ORI_MASK 0b00000000000000000111000001111111 +#define RVOPC_ANDI_BITS 0b00000000000000000111000000010011 +#define RVOPC_ANDI_MASK 0b00000000000000000111000001111111 +#define RVOPC_ADD_BITS 0b00000000000000000000000000110011 +#define RVOPC_ADD_MASK 0b11111110000000000111000001111111 +#define RVOPC_SUB_BITS 0b01000000000000000000000000110011 +#define RVOPC_SUB_MASK 0b11111110000000000111000001111111 +#define RVOPC_SLL_BITS 0b00000000000000000001000000110011 +#define RVOPC_SLL_MASK 0b11111110000000000111000001111111 +#define RVOPC_SLT_BITS 0b00000000000000000010000000110011 +#define RVOPC_SLT_MASK 0b11111110000000000111000001111111 +#define RVOPC_SLTU_BITS 0b00000000000000000011000000110011 +#define RVOPC_SLTU_MASK 0b11111110000000000111000001111111 +#define RVOPC_XOR_BITS 0b00000000000000000100000000110011 +#define RVOPC_XOR_MASK 0b11111110000000000111000001111111 +#define RVOPC_SRL_BITS 0b00000000000000000101000000110011 +#define RVOPC_SRL_MASK 0b11111110000000000111000001111111 +#define RVOPC_SRA_BITS 0b01000000000000000101000000110011 +#define RVOPC_SRA_MASK 0b11111110000000000111000001111111 +#define RVOPC_OR_BITS 0b00000000000000000110000000110011 +#define RVOPC_OR_MASK 0b11111110000000000111000001111111 +#define RVOPC_AND_BITS 0b00000000000000000111000000110011 +#define RVOPC_AND_MASK 0b11111110000000000111000001111111 +#define RVOPC_LB_BITS 0b00000000000000000000000000000011 +#define RVOPC_LB_MASK 0b00000000000000000111000001111111 +#define RVOPC_LH_BITS 0b00000000000000000001000000000011 +#define RVOPC_LH_MASK 0b00000000000000000111000001111111 +#define RVOPC_LW_BITS 0b00000000000000000010000000000011 +#define RVOPC_LW_MASK 0b00000000000000000111000001111111 +#define RVOPC_LBU_BITS 0b00000000000000000100000000000011 +#define RVOPC_LBU_MASK 0b00000000000000000111000001111111 +#define RVOPC_LHU_BITS 0b00000000000000000101000000000011 +#define RVOPC_LHU_MASK 0b00000000000000000111000001111111 +#define RVOPC_SB_BITS 0b00000000000000000000000000100011 +#define RVOPC_SB_MASK 0b00000000000000000111000001111111 +#define RVOPC_SH_BITS 0b00000000000000000001000000100011 +#define RVOPC_SH_MASK 0b00000000000000000111000001111111 +#define RVOPC_SW_BITS 0b00000000000000000010000000100011 +#define RVOPC_SW_MASK 0b00000000000000000111000001111111 +#define RVOPC_FENCE_BITS 0b00000000000000000000000000001111 +#define RVOPC_FENCE_MASK 0b00000000000011111111111111111111 +#define RVOPC_FENCE_I_BITS 0b00000000000000000001000000001111 +#define RVOPC_FENCE_I_MASK 0b11111111111111111111111111111111 +#define RVOPC_ECALL_BITS 0b00000000000000000000000001110011 +#define RVOPC_ECALL_MASK 0b11111111111111111111111111111111 +#define RVOPC_EBREAK_BITS 0b00000000000100000000000001110011 +#define RVOPC_EBREAK_MASK 0b11111111111111111111111111111111 +#define RVOPC_CSRRW_BITS 0b00000000000000000001000001110011 +#define RVOPC_CSRRW_MASK 0b00000000000000000111000001111111 +#define RVOPC_CSRRS_BITS 0b00000000000000000010000001110011 +#define RVOPC_CSRRS_MASK 0b00000000000000000111000001111111 +#define RVOPC_CSRRC_BITS 0b00000000000000000011000001110011 +#define RVOPC_CSRRC_MASK 0b00000000000000000111000001111111 +#define RVOPC_CSRRWI_BITS 0b00000000000000000101000001110011 +#define RVOPC_CSRRWI_MASK 0b00000000000000000111000001111111 +#define RVOPC_CSRRSI_BITS 0b00000000000000000110000001110011 +#define RVOPC_CSRRSI_MASK 0b00000000000000000111000001111111 +#define RVOPC_CSRRCI_BITS 0b00000000000000000111000001110011 +#define RVOPC_CSRRCI_MASK 0b00000000000000000111000001111111 +#define RVOPC_MRET_BITS 0b00110000001000000000000001110011 +#define RVOPC_MRET_MASK 0b11111111111111111111111111111111 +#define RVOPC_SYSTEM_BITS 0b00000000000000000000000001110011 +#define RVOPC_SYSTEM_MASK 0b00000000000000000000000001111111 +#define RVOPC_WFI_BITS 0b00010000010100000000000001110011 +#define RVOPC_WFI_MASK 0b11111111111111111111111111111111 + +// M extension +#define RVOPC_MUL_BITS 0b00000010000000000000000000110011 +#define RVOPC_MUL_MASK 0b11111110000000000111000001111111 +#define RVOPC_MULH_BITS 0b00000010000000000001000000110011 +#define RVOPC_MULH_MASK 0b11111110000000000111000001111111 +#define RVOPC_MULHSU_BITS 0b00000010000000000010000000110011 +#define RVOPC_MULHSU_MASK 0b11111110000000000111000001111111 +#define RVOPC_MULHU_BITS 0b00000010000000000011000000110011 +#define RVOPC_MULHU_MASK 0b11111110000000000111000001111111 +#define RVOPC_DIV_BITS 0b00000010000000000100000000110011 +#define RVOPC_DIV_MASK 0b11111110000000000111000001111111 +#define RVOPC_DIVU_BITS 0b00000010000000000101000000110011 +#define RVOPC_DIVU_MASK 0b11111110000000000111000001111111 +#define RVOPC_REM_BITS 0b00000010000000000110000000110011 +#define RVOPC_REM_MASK 0b11111110000000000111000001111111 +#define RVOPC_REMU_BITS 0b00000010000000000111000000110011 +#define RVOPC_REMU_MASK 0b11111110000000000111000001111111 + +// A extension +#define RVOPC_LR_W_BITS 0b00010000000000000010000000101111 +#define RVOPC_LR_W_MASK 0b11111001111100000111000001111111 +#define RVOPC_SC_W_BITS 0b00011000000000000010000000101111 +#define RVOPC_SC_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOSWAP_W_BITS 0b00001000000000000010000000101111 +#define RVOPC_AMOSWAP_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOADD_W_BITS 0b00000000000000000010000000101111 +#define RVOPC_AMOADD_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOXOR_W_BITS 0b00100000000000000010000000101111 +#define RVOPC_AMOXOR_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOAND_W_BITS 0b01100000000000000010000000101111 +#define RVOPC_AMOAND_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOOR_W_BITS 0b01000000000000000010000000101111 +#define RVOPC_AMOOR_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOMIN_W_BITS 0b10000000000000000010000000101111 +#define RVOPC_AMOMIN_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOMAX_W_BITS 0b10100000000000000010000000101111 +#define RVOPC_AMOMAX_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOMINU_W_BITS 0b11000000000000000010000000101111 +#define RVOPC_AMOMINU_W_MASK 0b11111000000000000111000001111111 +#define RVOPC_AMOMAXU_W_BITS 0b11100000000000000010000000101111 +#define RVOPC_AMOMAXU_W_MASK 0b11111000000000000111000001111111 + +// Zba (address generation) +#define RVOPC_SH1ADD_BITS 0b00100000000000000010000000110011 +#define RVOPC_SH1ADD_MASK 0b11111110000000000111000001111111 +#define RVOPC_SH2ADD_BITS 0b00100000000000000100000000110011 +#define RVOPC_SH2ADD_MASK 0b11111110000000000111000001111111 +#define RVOPC_SH3ADD_BITS 0b00100000000000000110000000110011 +#define RVOPC_SH3ADD_MASK 0b11111110000000000111000001111111 + +// Zbb (basic bit manipulation) +#define RVOPC_ANDN_BITS 0b01000000000000000111000000110011 +#define RVOPC_ANDN_MASK 0b11111110000000000111000001111111 +#define RVOPC_CLZ_BITS 0b01100000000000000001000000010011 +#define RVOPC_CLZ_MASK 0b11111111111100000111000001111111 +#define RVOPC_CPOP_BITS 0b01100000001000000001000000010011 +#define RVOPC_CPOP_MASK 0b11111111111100000111000001111111 +#define RVOPC_CTZ_BITS 0b01100000000100000001000000010011 +#define RVOPC_CTZ_MASK 0b11111111111100000111000001111111 +#define RVOPC_MAX_BITS 0b00001010000000000110000000110011 +#define RVOPC_MAX_MASK 0b11111110000000000111000001111111 +#define RVOPC_MAXU_BITS 0b00001010000000000111000000110011 +#define RVOPC_MAXU_MASK 0b11111110000000000111000001111111 +#define RVOPC_MIN_BITS 0b00001010000000000100000000110011 +#define RVOPC_MIN_MASK 0b11111110000000000111000001111111 +#define RVOPC_MINU_BITS 0b00001010000000000101000000110011 +#define RVOPC_MINU_MASK 0b11111110000000000111000001111111 +#define RVOPC_ORC_B_BITS 0b00101000011100000101000000010011 +#define RVOPC_ORC_B_MASK 0b11111111111100000111000001111111 +#define RVOPC_ORN_BITS 0b01000000000000000110000000110011 +#define RVOPC_ORN_MASK 0b11111110000000000111000001111111 +#define RVOPC_REV8_BITS 0b01101001100000000101000000010011 +#define RVOPC_REV8_MASK 0b11111111111100000111000001111111 +#define RVOPC_ROL_BITS 0b01100000000000000001000000110011 +#define RVOPC_ROL_MASK 0b11111110000000000111000001111111 +#define RVOPC_ROR_BITS 0b01100000000000000101000000110011 +#define RVOPC_ROR_MASK 0b11111110000000000111000001111111 +#define RVOPC_RORI_BITS 0b01100000000000000101000000010011 +#define RVOPC_RORI_MASK 0b11111110000000000111000001111111 +#define RVOPC_SEXT_B_BITS 0b01100000010000000001000000010011 +#define RVOPC_SEXT_B_MASK 0b11111111111100000111000001111111 +#define RVOPC_SEXT_H_BITS 0b01100000010100000001000000010011 +#define RVOPC_SEXT_H_MASK 0b11111111111100000111000001111111 +#define RVOPC_XNOR_BITS 0b01000000000000000100000000110011 +#define RVOPC_XNOR_MASK 0b11111110000000000111000001111111 +#define RVOPC_ZEXT_H_BITS 0b00001000000000000100000000110011 +#define RVOPC_ZEXT_H_MASK 0b11111111111100000111000001111111 + +// Zbc (carry-less multiply) +#define RVOPC_CLMUL_BITS 0b00001010000000000001000000110011 +#define RVOPC_CLMUL_MASK 0b11111110000000000111000001111111 +#define RVOPC_CLMULH_BITS 0b00001010000000000011000000110011 +#define RVOPC_CLMULH_MASK 0b11111110000000000111000001111111 +#define RVOPC_CLMULR_BITS 0b00001010000000000010000000110011 +#define RVOPC_CLMULR_MASK 0b11111110000000000111000001111111 + +// Zbs (single-bit manipulation) +#define RVOPC_BCLR_BITS 0b01001000000000000001000000110011 +#define RVOPC_BCLR_MASK 0b11111110000000000111000001111111 +#define RVOPC_BCLRI_BITS 0b01001000000000000001000000010011 +#define RVOPC_BCLRI_MASK 0b11111110000000000111000001111111 +#define RVOPC_BEXT_BITS 0b01001000000000000101000000110011 +#define RVOPC_BEXT_MASK 0b11111110000000000111000001111111 +#define RVOPC_BEXTI_BITS 0b01001000000000000101000000010011 +#define RVOPC_BEXTI_MASK 0b11111110000000000111000001111111 +#define RVOPC_BINV_BITS 0b01101000000000000001000000110011 +#define RVOPC_BINV_MASK 0b11111110000000000111000001111111 +#define RVOPC_BINVI_BITS 0b01101000000000000001000000010011 +#define RVOPC_BINVI_MASK 0b11111110000000000111000001111111 +#define RVOPC_BSET_BITS 0b00101000000000000001000000110011 +#define RVOPC_BSET_MASK 0b11111110000000000111000001111111 +#define RVOPC_BSETI_BITS 0b00101000000000000001000000010011 +#define RVOPC_BSETI_MASK 0b11111110000000000111000001111111 + +// Zbkb (basic bit manipulation for crypto) (minus those in Zbb) +#define RVOPC_PACK_BITS 0b00001000000000000100000000110011 +#define RVOPC_PACK_MASK 0b11111110000000000111000001111111 +#define RVOPC_PACKH_BITS 0b00001000000000000111000000110011 +#define RVOPC_PACKH_MASK 0b11111110000000000111000001111111 +#define RVOPC_BREV8_BITS 0b01101000011100000101000000010011 +#define RVOPC_BREV8_MASK 0b11111111111100000111000001111111 +#define RVOPC_UNZIP_BITS 0b00001000111100000101000000010011 +#define RVOPC_UNZIP_MASK 0b11111111111100000111000001111111 +#define RVOPC_ZIP_BITS 0b00001000111100000001000000010011 +#define RVOPC_ZIP_MASK 0b11111111111100000111000001111111 + +// Zbkc is a subset of Zbc. + +// Zbkx (crossbar permutation) +#define RVOPC_XPERM_B_BITS 0b00101000000000000100000000110011 +#define RVOPC_XPERM_B_MASK 0b11111110000000000111000001111111 +#define RVOPC_XPERM_N_BITS 0b00101000000000000010000000110011 +#define RVOPC_XPERM_N_MASK 0b11111110000000000111000001111111 + +// Hazard3 custom instructions + +// Xh3b (Hazard3 custom bitmanip): currently just a multi-bit version of bext/bexti from Zbs +#define RVOPC_H3_BEXTM_BITS 0b00000000000000000000000000001011 // custom-0 funct3=0 +#define RVOPC_H3_BEXTM_MASK 0b11100010000000000111000001111111 +#define RVOPC_H3_BEXTMI_BITS 0b00000000000000000100000000001011 // custom-0 funct3=4 +#define RVOPC_H3_BEXTMI_MASK 0b11100010000000000111000001111111 + +// C Extension +#define RVOPC_C_ADDI4SPN_BITS 0b0000000000000000 // *** illegal if imm 0 +#define RVOPC_C_ADDI4SPN_MASK 0b1110000000000011 +#define RVOPC_C_LW_BITS 0b0100000000000000 +#define RVOPC_C_LW_MASK 0b1110000000000011 +#define RVOPC_C_SW_BITS 0b1100000000000000 +#define RVOPC_C_SW_MASK 0b1110000000000011 + +#define RVOPC_C_ADDI_BITS 0b0000000000000001 +#define RVOPC_C_ADDI_MASK 0b1110000000000011 +#define RVOPC_C_JAL_BITS 0b0010000000000001 +#define RVOPC_C_JAL_MASK 0b1110000000000011 +#define RVOPC_C_J_BITS 0b1010000000000001 +#define RVOPC_C_J_MASK 0b1110000000000011 +#define RVOPC_C_LI_BITS 0b0100000000000001 +#define RVOPC_C_LI_MASK 0b1110000000000011 +// addi16sp when rd=2: +#define RVOPC_C_LUI_BITS 0b0110000000000001 // *** reserved if imm 0 (for both LUI and ADDI16SP) +#define RVOPC_C_LUI_MASK 0b1110000000000011 +#define RVOPC_C_SRLI_BITS 0b1000000000000001 // On RV32 imm[5] (instr[12]) must be 0, else reserved NSE. +#define RVOPC_C_SRLI_MASK 0b1111110000000011 +#define RVOPC_C_SRAI_BITS 0b1000010000000001 // On RV32 imm[5] (instr[12]) must be 0, else reserved NSE. +#define RVOPC_C_SRAI_MASK 0b1111110000000011 +#define RVOPC_C_ANDI_BITS 0b1000100000000001 +#define RVOPC_C_ANDI_MASK 0b1110110000000011 +#define RVOPC_C_SUB_BITS 0b1000110000000001 +#define RVOPC_C_SUB_MASK 0b1111110001100011 +#define RVOPC_C_XOR_BITS 0b1000110000100001 +#define RVOPC_C_XOR_MASK 0b1111110001100011 +#define RVOPC_C_OR_BITS 0b1000110001000001 +#define RVOPC_C_OR_MASK 0b1111110001100011 +#define RVOPC_C_AND_BITS 0b1000110001100001 +#define RVOPC_C_AND_MASK 0b1111110001100011 +#define RVOPC_C_BEQZ_BITS 0b1100000000000001 +#define RVOPC_C_BEQZ_MASK 0b1110000000000011 +#define RVOPC_C_BNEZ_BITS 0b1110000000000001 +#define RVOPC_C_BNEZ_MASK 0b1110000000000011 + +#define RVOPC_C_SLLI_BITS 0b0000000000000010 // On RV32 imm[5] (instr[12]) must be 0, else reserved NSE. +#define RVOPC_C_SLLI_MASK 0b1111000000000011 +// jr if !rs2: +#define RVOPC_C_MV_BITS 0b1000000000000010 // *** reserved if JR and !rs1 (instr[11:7]) +#define RVOPC_C_MV_MASK 0b1111000000000011 +// jalr if !rs2: +#define RVOPC_C_ADD_BITS 0b1001000000000010 // *** EBREAK if !instr[11:2] +#define RVOPC_C_ADD_MASK 0b1111000000000011 +#define RVOPC_C_LWSP_BITS 0b0100000000000010 +#define RVOPC_C_LWSP_MASK 0b1110000000000011 +#define RVOPC_C_SWSP_BITS 0b1100000000000010 +#define RVOPC_C_SWSP_MASK 0b1110000000000011 + +// Zcb simple additional compressed instructions +#define RVOPC_C_LBU_BITS 0b1000000000000000 +#define RVOPC_C_LBU_MASK 0b1111110000000011 +#define RVOPC_C_LHU_BITS 0b1000010000000000 +#define RVOPC_C_LHU_MASK 0b1111110001000011 +#define RVOPC_C_LH_BITS 0b1000010001000000 +#define RVOPC_C_LH_MASK 0b1111110001000011 +#define RVOPC_C_SB_BITS 0b1000100000000000 +#define RVOPC_C_SB_MASK 0b1111110000000011 +#define RVOPC_C_SH_BITS 0b1000110000000000 +#define RVOPC_C_SH_MASK 0b1111110001000011 +#define RVOPC_C_ZEXT_B_BITS 0b1001110001100001 +#define RVOPC_C_ZEXT_B_MASK 0b1111110001111111 +#define RVOPC_C_SEXT_B_BITS 0b1001110001100101 +#define RVOPC_C_SEXT_B_MASK 0b1111110001111111 +#define RVOPC_C_ZEXT_H_BITS 0b1001110001101001 +#define RVOPC_C_ZEXT_H_MASK 0b1111110001111111 +#define RVOPC_C_SEXT_H_BITS 0b1001110001101101 +#define RVOPC_C_SEXT_H_MASK 0b1111110001111111 +#define RVOPC_C_NOT_BITS 0b1001110001110101 +#define RVOPC_C_NOT_MASK 0b1111110001111111 +#define RVOPC_C_MUL_BITS 0b1001110001000001 +#define RVOPC_C_MUL_MASK 0b1111110001100011 + +// Zcmp push/pop instructions +#define RVOPC_CM_PUSH_BITS 0b1011100000000010 +#define RVOPC_CM_PUSH_MASK 0b1111111100000011 +#define RVOPC_CM_POP_BITS 0b1011101000000010 +#define RVOPC_CM_POP_MASK 0b1111111100000011 +#define RVOPC_CM_POPRETZ_BITS 0b1011110000000010 +#define RVOPC_CM_POPRETZ_MASK 0b1111111100000011 +#define RVOPC_CM_POPRET_BITS 0b1011111000000010 +#define RVOPC_CM_POPRET_MASK 0b1111111100000011 +#define RVOPC_CM_MVSA01_BITS 0b1010110000100010 +#define RVOPC_CM_MVSA01_MASK 0b1111110001100011 +#define RVOPC_CM_MVA01S_BITS 0b1010110001100010 +#define RVOPC_CM_MVA01S_MASK 0b1111110001100011 + +#define _RVOPC_MATCH(x, instr_mask, instr_bits) ((x & instr_mask) == instr_bits) +#define RVOPC_MATCH(x, instr) _RVOPC_MATCH(x, RVOPC_ ## instr ## _MASK, RVOPC_ ## instr ## _BITS) + +static const char *friendly_reg_names[32] = { + "x0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", + "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", + "s10", "s11", "t3", "t4", "t5", "t6" +}; + +#endif