diff --git a/.ci/riscv-tests.sh b/.ci/riscv-tests.sh index d7c1d23d..14936fea 100755 --- a/.ci/riscv-tests.sh +++ b/.ci/riscv-tests.sh @@ -19,3 +19,4 @@ make ENABLE_EXT_M=1 ENABLE_EXT_A=1 ENABLE_EXT_F=1 ENABLE_EXT_C=1 \ ENABLE_Zicsr=1 ENABLE_Zifencei=1 ENABLE_FULL4G=1 make arch-test RISCV_DEVICE=IMAFCZicsrZifencei || exit 1 make arch-test RISCV_DEVICE=FCZicsr || exit 1 +make arch-test RISCV_DEVICE=IMZbaZbbZbcZbs || exit 1 diff --git a/Makefile b/Makefile index f0928fde..96edd9d6 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,22 @@ $(call set-feature, Zicsr) ENABLE_Zifencei ?= 1 $(call set-feature, Zifencei) +# Zba Address generation instructions +ENABLE_Zba ?= 1 +$(call set-feature, Zba) + +# Zbb Basic bit-manipulation +ENABLE_Zbb ?= 1 +$(call set-feature, Zbb) + +# Zbc Carry-less multiplication +ENABLE_Zbc ?= 1 +$(call set-feature, Zbc) + +# Zbs Single-bit instructions +ENABLE_Zbs ?= 1 +$(call set-feature, Zbs) + ENABLE_FULL4G ?= 0 # Experimental SDL oriented system calls diff --git a/README.md b/README.md index bc855899..9d66a5c8 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ a focus on efficiency and readability. Features: * Fast interpreter for executing the RV32 ISA -* Comprehensive support for RV32I and M, A, F, C extensions +* Comprehensive support for RV32I and M, A, F, C, Zba, Zbb, Zbc, Zbs extensions * Memory-efficient design * Built-in ELF loader * Implementation of commonly used newlib system calls @@ -120,6 +120,10 @@ The image containing all the necessary tools for development and testing can be * `ENABLE_EXT_A`: Standard Extension for Atomic Instructions * `ENABLE_EXT_F`: Standard Extension for Single-Precision Floating Point Instructions * `ENABLE_EXT_C`: Standard Extension for Compressed Instructions (RV32C.D excluded) +* `ENABLE_Zba`: Standard Extension for Address Generation Instructions +* `ENABLE_Zbb`: Standard Extension for Basic Bit-Manipulation Instructions +* `ENABLE_Zbc`: Standard Extension for Carry-Less Multiplication Instructions +* `ENABLE_Zbs`: Standard Extension for Single-Bit Instructions * `ENABLE_Zicsr`: Control and Status Register (CSR) * `ENABLE_Zifencei`: Instruction-Fetch Fence * `ENABLE_GDBSTUB` : GDB remote debugging support @@ -187,6 +191,10 @@ Current progress of this emulator in riscv-arch-test (RV32): - `A`: Standard Extension for Atomic Instructions - `F`: Standard Extension for Single-Precision Floating-Point - `C`: Standard Extension for Compressed Instruction + - `Zba`: Standard Extension for Address Generation Instructions + - `Zbb`: Standard Extension for Basic Bit-Manipulation + - `Zbc`: Standard Extension for Carry-Less Multiplication + - `Zbs`: Standard Extension for Single-Bit Instructions - `Zifencei`: Instruction-Fetch Fence - `privilege`: RISCV Privileged Specification diff --git a/src/common.h b/src/common.h index 535299da..838b6552 100644 --- a/src/common.h +++ b/src/common.h @@ -72,6 +72,63 @@ static inline int rv_clz(uint32_t v) } #endif +#if defined(_MSC_VER) +#include +static inline int rv_ctz(uint32_t v) +{ + /* 0 is considered as undefined behavior */ + assert(v); + + uint32_t trailing_zero = 0; + _BitScanForward(&trailing_zero, v); + return trailing_zero; +} +#elif defined(__GNUC__) || defined(__clang__) +static inline int rv_ctz(uint32_t v) +{ + /* https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */ + /* 0 is considered as undefined behavior */ + assert(v); + + return __builtin_ctz(v); +} +#else /* generic implementation */ +static inline int rv_ctz(uint32_t v) +{ + /* 0 is considered as undefined behavior */ + assert(v); + + /* https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup + */ + + static const int mul_debruijn[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + + return mul_debruijn[((uint32_t) ((v & -v) * 0x077CB531U)) >> 27]; +} +#endif + +#if defined(__GNUC__) || defined(__clang__) +static inline int rv_popcount(uint32_t v) +{ + /* https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */ + + return __builtin_popcount(v); +} +#else /* generic implementation */ +static inline int rv_popcount(uint32_t v) +{ + /* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + */ + + v -= (v >> 1) & 0x55555555; + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + v = (v + (v >> 4)) & 0x0f0f0f0f; + return (v * 0x01010101) >> 24; +} +#endif + /* * Integer log base 2 * diff --git a/src/decode.c b/src/decode.c index 248db479..f65556da 100644 --- a/src/decode.c +++ b/src/decode.c @@ -464,6 +464,42 @@ static inline bool op_op_imm(rv_insn_t *ir, const uint32_t insn) ir->opcode = rv_insn_addi; break; case 1: /* SLLI: Shift Left Logical */ +#if RV32_HAS(Zbb) + if (ir->imm == 0b011000000000) { /* clz */ + ir->opcode = rv_insn_clz; + return true; + } + if (ir->imm == 0b011000000001) { /* ctz */ + ir->opcode = rv_insn_ctz; + return true; + } + if (ir->imm == 0b011000000010) { /* cpop */ + ir->opcode = rv_insn_cpop; + return true; + } + if (ir->imm == 0b011000000100) { /* sext.b */ + ir->opcode = rv_insn_sextb; + return true; + } + if (ir->imm == 0b011000000101) { /* sext.h */ + ir->opcode = rv_insn_sexth; + return true; + } +#endif +#if RV32_HAS(Zbs) + if (ir->imm >> 5 == 0b0100100) { /* bclri */ + ir->opcode = rv_insn_bclri; + return true; + } + if (ir->imm >> 5 == 0b0110100) { /* binvi */ + ir->opcode = rv_insn_binvi; + return true; + } + if (ir->imm >> 5 == 0b0010100) { /* bseti */ + ir->opcode = rv_insn_bseti; + return true; + } +#endif ir->opcode = rv_insn_slli; if (unlikely(ir->imm & (1 << 5))) return false; @@ -478,6 +514,26 @@ static inline bool op_op_imm(rv_insn_t *ir, const uint32_t insn) ir->opcode = rv_insn_xori; break; case 5: +#if RV32_HAS(Zbb) + if (ir->imm >> 5 == 0b0110000) { /* rori */ + ir->opcode = rv_insn_rori; + return true; + } + if (ir->imm == 0b001010000111) { /* orc.b */ + ir->opcode = rv_insn_orcb; + return true; + } + if (ir->imm == 0b011010011000) { /* rev8 */ + ir->opcode = rv_insn_rev8; + return true; + } +#endif +#if RV32_HAS(Zbs) + if (ir->imm >> 5 == 0b0100100) { /* bexti */ + ir->opcode = rv_insn_bexti; + return true; + } +#endif /* SLL, SRL, and SRA perform logical left, logical right, and * arithmetic right shifts on the value in register rs1. */ @@ -665,6 +721,117 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) break; #endif /* RV32_HAS(EXT_M) */ +#if RV32_HAS(Zba) + /* inst funct7 rs2 rs1 funct3 rd opcode + * ------+-------+---+---+------+--+------- + * SH1ADD 0010000 rs2 rs1 010 rd 0110011 + * SH2ADD 0010000 rs2 rs1 100 rd 0110011 + * SH3ADD 0010000 rs2 rs1 110 rd 0110011 + */ + case 0b0010000: + switch (funct3) { + case 0b010: /* sh1add */ + ir->opcode = rv_insn_sh1add; + break; + case 0b100: /* sh2add */ + ir->opcode = rv_insn_sh2add; + break; + case 0b110: /* sh3add */ + ir->opcode = rv_insn_sh3add; + break; + default: /* illegal instruction */ + return false; + } + break; +#endif /* RV32_HAS(Zba) */ + +#if RV32_HAS(Zbb) || RV32_HAS(Zbc) + /* inst funct7 rs2 rs1 funct3 rd opcode + * ------+-------+---+---+------+--+------- + * MAX 0000101 rs2 rs1 110 rd 0110011 + * MIN 0000101 rs2 rs1 100 rd 0110011 + * MAXU 0000101 rs2 rs1 111 rd 0110011 + * MINU 0000101 rs2 rs1 101 rd 0110011 + * ROL 0110000 rs2 rs1 001 rd 0110011 + * ROR 0110000 rs2 rs1 101 rd 0110011 + */ + case 0b0000101: + switch (funct3) { +#if RV32_HAS(Zbb) + case 0b110: /* max */ + ir->opcode = rv_insn_max; + break; + case 0b100: /* min */ + ir->opcode = rv_insn_min; + break; + case 0b111: /* maxu */ + ir->opcode = rv_insn_maxu; + break; + case 0b101: /* minu */ + ir->opcode = rv_insn_minu; + break; +#endif +#if RV32_HAS(Zbc) + case 0b001: /*clmul */ + ir->opcode = rv_insn_clmul; + break; + case 0b011: /*clmulh */ + ir->opcode = rv_insn_clmulh; + break; + case 0b010: /*clmulr */ + ir->opcode = rv_insn_clmulr; + break; +#endif + default: /* illegal instruction */ + return false; + } + break; +#endif +#if RV32_HAS(Zbb) + case 0b0110000: + switch (funct3) { + case 0b001: /* rol */ + ir->opcode = rv_insn_rol; + break; + case 0b101: /* ror */ + ir->opcode = rv_insn_ror; + break; + default: /* illegal instruction */ + return false; + } + break; + case 0b0000100: + if (unlikely(ir->rs2)) + return false; + ir->opcode = rv_insn_zexth; + break; +#endif /* RV32_HAS(Zbb) */ + +#if RV32_HAS(Zbs) + case 0b0100100: + switch (funct3) { + case 0b001: /* bclr */ + ir->opcode = rv_insn_bclr; + break; + case 0b101: /* bext */ + ir->opcode = rv_insn_bext; + break; + default: /* illegal instruction */ + return false; + } + break; + case 0b0110100: + if (unlikely(funct3 != 0b001)) + return false; + ir->opcode = rv_insn_binv; + break; + case 0b0010100: + if (unlikely(funct3 != 0b001)) + return false; + ir->opcode = rv_insn_bset; + break; +#endif /* RV32_HAS(Zbs) */ + case 0b0100000: switch (funct3) { case 0b000: /* SUB: Substract */ @@ -673,6 +840,18 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) case 0b101: /* SRA: Shift Right Arithmetic */ ir->opcode = rv_insn_sra; break; +#if RV32_HAS(Zbb) + case 0b111: /* ANDN */ + ir->opcode = rv_insn_andn; + break; + case 0b110: /* ORN */ + ir->opcode = rv_insn_orn; + break; + case 0b100: /* XNOR */ + ir->opcode = rv_insn_xnor; + break; +#endif /* RV32_HAS(Zbb) */ + default: /* illegal instruction */ return false; } diff --git a/src/decode.h b/src/decode.h index e2b2984c..a92c7708 100644 --- a/src/decode.h +++ b/src/decode.h @@ -97,6 +97,50 @@ enum op_field { _(csrrsi, 0, 4, 0, ENC(rs1, rd)) \ _(csrrci, 0, 4, 0, ENC(rs1, rd)) \ ) \ + /* RV32 Zba Standard Extension */ \ + IIF(RV32_HAS(Zba))( \ + _(sh1add, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(sh2add, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(sh3add, 0, 4, 0, ENC(rs1, rs2, rd)) \ + ) \ + /* RV32 Zbb Standard Extension */ \ + IIF(RV32_HAS(Zbb))( \ + _(andn, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(orn, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(xnor, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(clz, 0, 4, 0, ENC(rs1, rd)) \ + _(ctz, 0, 4, 0, ENC(rs1, rd)) \ + _(cpop, 0, 4, 0, ENC(rs1, rd)) \ + _(max, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(maxu, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(min, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(minu, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(sextb, 0, 4, 0, ENC(rs1, rd)) \ + _(sexth, 0, 4, 0, ENC(rs1, rd)) \ + _(zexth, 0, 4, 0, ENC(rs1, rd)) \ + _(rol, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(ror, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(rori, 0, 4, 0, ENC(rs1, rd)) \ + _(orcb, 0, 4, 0, ENC(rs1, rd)) \ + _(rev8, 0, 4, 0, ENC(rs1, rd)) \ + ) \ + /* RV32 Zbc Standard Extension */ \ + IIF(RV32_HAS(Zbc))( \ + _(clmul, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(clmulh, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(clmulr, 0, 4, 0, ENC(rs1, rs2, rd)) \ + ) \ + /* RV32 Zbs Standard Extension */ \ + IIF(RV32_HAS(Zbs))( \ + _(bclr, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(bclri, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(bext, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(bexti, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(binv, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(binvi, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(bset, 0, 4, 0, ENC(rs1, rs2, rd)) \ + _(bseti, 0, 4, 0, ENC(rs1, rs2, rd)) \ + ) \ /* RV32M Standard Extension */ \ IIF(RV32_HAS(EXT_M))( \ _(mul, 0, 4, 1, ENC(rs1, rs2, rd)) \ diff --git a/src/feature.h b/src/feature.h index a8956b47..c4a41939 100644 --- a/src/feature.h +++ b/src/feature.h @@ -37,6 +37,26 @@ #define RV32_FEATURE_Zifencei 1 #endif +/* Zba Address generation instructions */ +#ifndef RV32_FEATURE_Zba +#define RV32_FEATURE_Zba 1 +#endif + +/* Zbb Basic bit-manipulation */ +#ifndef RV32_FEATURE_Zbb +#define RV32_FEATURE_Zbb 1 +#endif + +/* Zbc Carry-less multiplication */ +#ifndef RV32_FEATURE_Zbc +#define RV32_FEATURE_Zbc 1 +#endif + +/* Zbs Single-bit instructions */ +#ifndef RV32_FEATURE_Zbs +#define RV32_FEATURE_Zbs 1 +#endif + /* Experimental SDL oriented system calls */ #ifndef RV32_FEATURE_SDL #define RV32_FEATURE_SDL 1 diff --git a/src/rv32_constopt.c b/src/rv32_constopt.c index 0f78271a..f317a3ff 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1039,3 +1039,204 @@ CONSTOPT(cflw, {}) /* C.FSW */ CONSTOPT(cfsw, {}) #endif + +#if RV32_HAS(Zba) +/* SH1ADD */ +CONSTOPT(sh1add, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* SH2ADD */ +CONSTOPT(sh2add, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* SH3ADD */ +CONSTOPT(sh3add, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) +#endif + +#if RV32_HAS(Zbb) +/* ANDN */ +CONSTOPT(andn, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* ORN */ +CONSTOPT(orn, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* XNOR */ +CONSTOPT(xnor, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* CLZ */ +CONSTOPT(clz, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* CTZ */ +CONSTOPT(ctz, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* CPOP */ +CONSTOPT(cpop, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* MAX */ +CONSTOPT(max, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* MAXU */ +CONSTOPT(maxu, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* MIN */ +CONSTOPT(min, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* MINU */ +CONSTOPT(minu, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* SEXT.B */ +CONSTOPT(sextb, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* SEXT.H */ +CONSTOPT(sexth, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* ZEXT.H */ +CONSTOPT(zexth, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* ROL */ +CONSTOPT(rol, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* ROR */ +CONSTOPT(ror, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* RORI */ +CONSTOPT(rori, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* ORCB */ +CONSTOPT(orcb, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* REV8 */ +CONSTOPT(rev8, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) +#endif + +#if RV32_HAS(Zbc) +/* CLMUL */ +CONSTOPT(clmul, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* CLMULH */ +CONSTOPT(clmulh, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* CLMULR */ +CONSTOPT(clmulr, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) +#endif + +#if RV32_HAS(Zbs) +/* BCLR */ +CONSTOPT(bclr, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BCLRI */ +CONSTOPT(bclri, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BEXT */ +CONSTOPT(bext, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BEXTI */ +CONSTOPT(bexti, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BINV */ +CONSTOPT(binv, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BINVI */ +CONSTOPT(binvi, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BSET */ +CONSTOPT(bset, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +/* BSETI */ +CONSTOPT(bseti, { + if (ir->rd) + info->is_constant[ir->rd] = false; +}) + +#endif diff --git a/src/rv32_template.c b/src/rv32_template.c index e0e41cf6..6f2a79f7 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -2600,3 +2600,382 @@ RVOP( assert; /* FIXME: Implement */ })) #endif + +/* RV32Zba Standard Extension */ + +#if RV32_HAS(Zba) + +/* SH1ADD */ +RVOP( + sh1add, + { rv->X[ir->rd] = (rv->X[ir->rs1] << 1) + rv->X[ir->rs2]; }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* SH2ADD */ +RVOP( + sh2add, + { rv->X[ir->rd] = (rv->X[ir->rs1] << 2) + rv->X[ir->rs2]; }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* SH3ADD */ +RVOP( + sh3add, + { rv->X[ir->rd] = (rv->X[ir->rs1] << 3) + rv->X[ir->rs2]; }, + GEN({ + assert; /* FIXME: Implement */ + })) + +#endif + +/* RV32Zbb Standard Extension */ + +#if RV32_HAS(Zbb) + +/* ANDN */ +RVOP( + andn, + { rv->X[ir->rd] = rv->X[ir->rs1] & (~rv->X[ir->rs2]); }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* ORN */ +RVOP( + orn, + { rv->X[ir->rd] = rv->X[ir->rs1] | (~rv->X[ir->rs2]); }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* XNOR */ +RVOP( + xnor, + { rv->X[ir->rd] = ~(rv->X[ir->rs1] ^ rv->X[ir->rs2]); }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* CLZ */ +RVOP( + clz, + { + if (rv->X[ir->rs1]) + rv->X[ir->rd] = rv_clz(rv->X[ir->rs1]); + else + rv->X[ir->rd] = 32; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* CTZ */ +RVOP( + ctz, + { + if (rv->X[ir->rs1]) + rv->X[ir->rd] = rv_ctz(rv->X[ir->rs1]); + else + rv->X[ir->rd] = 32; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* CPOP */ +RVOP( + cpop, + { rv->X[ir->rd] = rv_popcount(rv->X[ir->rs1]); }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* MAX */ +RVOP( + max, + { + const int32_t x = rv->X[ir->rs1]; + const int32_t y = rv->X[ir->rs2]; + rv->X[ir->rd] = x > y ? rv->X[ir->rs1] : rv->X[ir->rs2]; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* MIN */ +RVOP( + min, + { + const int32_t x = rv->X[ir->rs1]; + const int32_t y = rv->X[ir->rs2]; + rv->X[ir->rd] = x < y ? rv->X[ir->rs1] : rv->X[ir->rs2]; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* MAXU */ +RVOP( + maxu, + { + const uint32_t x = rv->X[ir->rs1]; + const uint32_t y = rv->X[ir->rs2]; + rv->X[ir->rd] = x > y ? rv->X[ir->rs1] : rv->X[ir->rs2]; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* MINU */ +RVOP( + minu, + { + const uint32_t x = rv->X[ir->rs1]; + const uint32_t y = rv->X[ir->rs2]; + rv->X[ir->rd] = x < y ? rv->X[ir->rs1] : rv->X[ir->rs2]; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* SEXT.B */ +RVOP( + sextb, + { + rv->X[ir->rd] = rv->X[ir->rs1] & 0xff; + if (rv->X[ir->rs1] & (1U << 7)) + rv->X[ir->rd] |= 0xffffff00; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* SEXT.H */ +RVOP( + sexth, + { + rv->X[ir->rd] = rv->X[ir->rs1] & 0xffff; + if (rv->X[ir->rs1] & (1U << 15)) + rv->X[ir->rd] |= 0xffff0000; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* ZEXT.H */ +RVOP( + zexth, + { rv->X[ir->rd] = rv->X[ir->rs1] & 0x0000ffff; }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* ROL */ +RVOP( + rol, + { + const unsigned int shamt = rv->X[ir->rs2] & 0b11111; + rv->X[ir->rd] = + (rv->X[ir->rs1] << shamt) | (rv->X[ir->rs1] >> (32 - shamt)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* ROR */ +RVOP( + ror, + { + const unsigned int shamt = rv->X[ir->rs2] & 0b11111; + rv->X[ir->rd] = + (rv->X[ir->rs1] >> shamt) | (rv->X[ir->rs1] << (32 - shamt)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* RORI */ +RVOP( + rori, + { + const unsigned int shamt = ir->imm & 0b11111; + rv->X[ir->rd] = + (rv->X[ir->rs1] >> shamt) | (rv->X[ir->rs1] << (32 - shamt)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* ORCB */ +RVOP( + orcb, + { + const uint32_t x = rv->X[ir->rs1]; + rv->X[ir->rd] = 0; + for (int i = 0; i < 4; i++) + if (x & (0xffu << (i * 8))) + rv->X[ir->rd] |= 0xffu << (i * 8); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* REV8 */ +RVOP( + rev8, + { + rv->X[ir->rd] = (((rv->X[ir->rs1] & 0xffU) << 24) | + ((rv->X[ir->rs1] & 0xff00U) << 8) | + ((rv->X[ir->rs1] & 0xff0000U) >> 8) | + ((rv->X[ir->rs1] & 0xff000000U) >> 24)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +#endif + +/* RV32Zbc Standard Extension */ + +#if RV32_HAS(Zbc) + +/* CLMUL */ +RVOP( + clmul, + { + uint32_t output = 0; + for (int i = 0; i < 32; i++) + if ((rv->X[ir->rs2] >> i) & 1) + output ^= rv->X[ir->rs1] << i; + rv->X[ir->rd] = output; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* CLMULH */ +RVOP( + clmulh, + { + uint32_t output = 0; + for (int i = 1; i < 32; i++) + if ((rv->X[ir->rs2] >> i) & 1) + output ^= rv->X[ir->rs1] >> (32 - i); + rv->X[ir->rd] = output; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* CLMULR */ +RVOP( + clmulr, + { + uint32_t output = 0; + for (int i = 0; i < 32; i++) + if ((rv->X[ir->rs2] >> i) & 1) + output ^= rv->X[ir->rs1] >> (32 - i - 1); + rv->X[ir->rd] = output; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +#endif + +/* RV32Zbs Standard Extension */ + +#if RV32_HAS(Zbs) + +/* BCLR */ +RVOP( + bclr, + { + const unsigned int index = rv->X[ir->rs2] & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] & (~(1U << index)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BCLRI */ +RVOP( + bclri, + { + const unsigned int index = ir->imm & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] & (~(1U << index)); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BEXT */ +RVOP( + bext, + { + const unsigned int index = rv->X[ir->rs2] & (32 - 1); + rv->X[ir->rd] = (rv->X[ir->rs1] >> index) & 1; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BEXTI */ +RVOP( + bexti, + { + const unsigned int index = ir->imm & (32 - 1); + rv->X[ir->rd] = (rv->X[ir->rs1] >> index) & 1; + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BINV */ +RVOP( + binv, + { + const unsigned int index = rv->X[ir->rs2] & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] ^ (1U << index); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BINVI */ +RVOP( + binvi, + { + const unsigned int index = ir->imm & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] ^ (1U << index); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BSET */ +RVOP( + bset, + { + const unsigned int index = rv->X[ir->rs2] & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] | (1U << index); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +/* BSETI */ +RVOP( + bseti, + { + const unsigned int index = ir->imm & (32 - 1); + rv->X[ir->rd] = rv->X[ir->rs1] | (1U << index); + }, + GEN({ + assert; /* FIXME: Implement */ + })) + +#endif diff --git a/src/t2c_template.c b/src/t2c_template.c index 2ee33720..01c9d8f3 100644 --- a/src/t2c_template.c +++ b/src/t2c_template.c @@ -793,6 +793,78 @@ T2C_OP(cflw, { __UNREACHABLE; }) T2C_OP(cfsw, { __UNREACHABLE; }) #endif +#if RV32_HAS(Zba) +T2C_OP(sh1add, { __UNREACHABLE; }) + +T2C_OP(sh2add, { __UNREACHABLE; }) + +T2C_OP(sh3add, { __UNREACHABLE; }) +#endif + +#if RV32_HAS(Zbb) +T2C_OP(andn, { __UNREACHABLE; }) + +T2C_OP(orn, { __UNREACHABLE; }) + +T2C_OP(xnor, { __UNREACHABLE; }) + +T2C_OP(clz, { __UNREACHABLE; }) + +T2C_OP(ctz, { __UNREACHABLE; }) + +T2C_OP(cpop, { __UNREACHABLE; }) + +T2C_OP(max, { __UNREACHABLE; }) + +T2C_OP(maxu, { __UNREACHABLE; }) + +T2C_OP(min, { __UNREACHABLE; }) + +T2C_OP(minu, { __UNREACHABLE; }) + +T2C_OP(sextb, { __UNREACHABLE; }) + +T2C_OP(sexth, { __UNREACHABLE; }) + +T2C_OP(zexth, { __UNREACHABLE; }) + +T2C_OP(rol, { __UNREACHABLE; }) + +T2C_OP(ror, { __UNREACHABLE; }) + +T2C_OP(rori, { __UNREACHABLE; }) + +T2C_OP(orcb, { __UNREACHABLE; }) + +T2C_OP(rev8, { __UNREACHABLE; }) +#endif + +#if RV32_HAS(Zbc) +T2C_OP(clmul, { __UNREACHABLE; }) + +T2C_OP(clmulh, { __UNREACHABLE; }) + +T2C_OP(clmulr, { __UNREACHABLE; }) +#endif + +#if RV32_HAS(Zbs) +T2C_OP(bclr, { __UNREACHABLE; }) + +T2C_OP(bclri, { __UNREACHABLE; }) + +T2C_OP(bext, { __UNREACHABLE; }) + +T2C_OP(bexti, { __UNREACHABLE; }) + +T2C_OP(binv, { __UNREACHABLE; }) + +T2C_OP(binvi, { __UNREACHABLE; }) + +T2C_OP(bset, { __UNREACHABLE; }) + +T2C_OP(bseti, { __UNREACHABLE; }) +#endif + T2C_OP(fuse1, { opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) { diff --git a/tests/arch-test-target/setup.py b/tests/arch-test-target/setup.py index 47e843f0..e7bd9e6e 100644 --- a/tests/arch-test-target/setup.py +++ b/tests/arch-test-target/setup.py @@ -24,10 +24,18 @@ def setup_testlist(riscv_device): if 'C' in riscv_device: misa |= constants.misa_C ISA += 'C' + if 'Zba' in riscv_device: + ISA += '_Zba' if 'Z' in ISA else 'Zba' + if 'Zbb' in riscv_device: + ISA += '_Zbb' if 'Z' in ISA else 'Zbb' + if 'Zbc' in riscv_device: + ISA += '_Zbc' if 'Z' in ISA else 'Zbc' + if 'Zbs' in riscv_device: + ISA += '_Zbs' if 'Z' in ISA else 'Zbs' if 'Zicsr' in riscv_device: - ISA += 'Zicsr' + ISA += '_Zicsr' if 'Z' in ISA else 'Zicsr' if 'Zifencei' in riscv_device: - ISA += '_Zifencei' if 'Zicsr' in ISA else 'Zifencei' + ISA += '_Zifencei' if 'Z' in ISA else 'Zifencei' with open(ispec, 'r') as file: try: