From 340d0939b249c46dfa70f9a1fb378ab3a7a99300 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 22:29:38 +0800 Subject: [PATCH 1/9] Add rv_ctz() for efficient count trailing zero operations Introduce the rv_ctz() function to compute the count of trailing zeros in a 32-bit integer. This function serves as a prerequisite for implementing the ctz instruction in the RISC-V Zbb extension. --- src/common.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/common.h b/src/common.h index 535299da..b784587d 100644 --- a/src/common.h +++ b/src/common.h @@ -72,6 +72,43 @@ 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 + /* * Integer log base 2 * From e069c6339469b117352bad15bfb42bac533a6fd6 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 22:35:55 +0800 Subject: [PATCH 2/9] Add rv_popcount() for efficient population count operations Introduce the rv_popcount() function to compute the population count (number of set bits) in a 32-bit integer. This function is a prerequisite for implementing the cpop instruction in the RISC-V Zbb extension. --- src/common.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/common.h b/src/common.h index b784587d..838b6552 100644 --- a/src/common.h +++ b/src/common.h @@ -109,6 +109,26 @@ static inline int rv_ctz(uint32_t v) } #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 * From 2bbcfbdf85b7494763e8087b0d4412e822e16eb8 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sat, 21 Dec 2024 09:39:40 +0800 Subject: [PATCH 3/9] Add support for Zba address generation extension Add support for the RISC-V Zba address generation extension. These instructions combine shift and addition operations, enabling efficient address calculation in pointer arithmetic and memory access patterns. Supporting the Zba extension improves compatibility with the RISC-V specification and enables optimized handling of address generation tasks. --- Makefile | 4 ++++ src/decode.c | 24 ++++++++++++++++++++++++ src/decode.h | 6 ++++++ src/feature.h | 5 +++++ src/rv32_constopt.c | 20 ++++++++++++++++++++ src/rv32_template.c | 30 ++++++++++++++++++++++++++++++ src/t2c_template.c | 8 ++++++++ 7 files changed, 97 insertions(+) diff --git a/Makefile b/Makefile index f0928fde..57a918ad 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,10 @@ $(call set-feature, Zicsr) ENABLE_Zifencei ?= 1 $(call set-feature, Zifencei) +# Zba Address generation instructions +ENABLE_Zba ?= 1 +$(call set-feature, Zba) + ENABLE_FULL4G ?= 0 # Experimental SDL oriented system calls diff --git a/src/decode.c b/src/decode.c index 248db479..20e5af80 100644 --- a/src/decode.c +++ b/src/decode.c @@ -665,6 +665,30 @@ 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) */ + case 0b0100000: switch (funct3) { case 0b000: /* SUB: Substract */ diff --git a/src/decode.h b/src/decode.h index e2b2984c..5231f3e8 100644 --- a/src/decode.h +++ b/src/decode.h @@ -97,6 +97,12 @@ 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)) \ + ) \ /* 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..848313e4 100644 --- a/src/feature.h +++ b/src/feature.h @@ -37,6 +37,11 @@ #define RV32_FEATURE_Zifencei 1 #endif +/* Zba Address generation instructions */ +#ifndef RV32_FEATURE_Zba +#define RV32_FEATURE_Zba 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..edd650e7 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1039,3 +1039,23 @@ 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 diff --git a/src/rv32_template.c b/src/rv32_template.c index e0e41cf6..c1e5b6cb 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -2600,3 +2600,33 @@ 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 diff --git a/src/t2c_template.c b/src/t2c_template.c index 2ee33720..90cbe632 100644 --- a/src/t2c_template.c +++ b/src/t2c_template.c @@ -793,6 +793,14 @@ 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 + T2C_OP(fuse1, { opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) { From c10b89501701cf979b8960b3ac6a3393a77c6b78 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 19:38:52 +0800 Subject: [PATCH 4/9] Add support for Zbb basic bit-manipulation extension Add support for the RISC-V Zbb basic bit-manipulation extension. This extension introduces fundamental bitwise operations such as bit counting, bit field extraction, and bit rotation, enabling efficient data manipulation and low-level computation. Supporting the Zbb extension improves compatibility with the RISC-V specification and enables optimized handling of bitwise operations in a wide range of applications. --- Makefile | 4 + src/decode.c | 95 ++++++++++++++++++++ src/decode.h | 21 +++++ src/feature.h | 5 ++ src/rv32_constopt.c | 110 +++++++++++++++++++++++ src/rv32_template.c | 207 ++++++++++++++++++++++++++++++++++++++++++++ src/t2c_template.c | 38 ++++++++ 7 files changed, 480 insertions(+) diff --git a/Makefile b/Makefile index 57a918ad..f9421042 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,10 @@ $(call set-feature, Zifencei) ENABLE_Zba ?= 1 $(call set-feature, Zba) +# Zbb Basic bit-manipulation +ENABLE_Zbb ?= 1 +$(call set-feature, Zbb) + ENABLE_FULL4G ?= 0 # Experimental SDL oriented system calls diff --git a/src/decode.c b/src/decode.c index 20e5af80..754d8553 100644 --- a/src/decode.c +++ b/src/decode.c @@ -464,6 +464,28 @@ 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 ir->opcode = rv_insn_slli; if (unlikely(ir->imm & (1 << 5))) return false; @@ -478,6 +500,20 @@ 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 /* SLL, SRL, and SRA perform logical left, logical right, and * arithmetic right shifts on the value in register rs1. */ @@ -689,6 +725,53 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) break; #endif /* RV32_HAS(Zba) */ +#if RV32_HAS(Zbb) + /* 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) { + 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; + default: /* illegal instruction */ + return false; + } + break; + 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) */ + case 0b0100000: switch (funct3) { case 0b000: /* SUB: Substract */ @@ -697,6 +780,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 5231f3e8..ecd1d652 100644 --- a/src/decode.h +++ b/src/decode.h @@ -103,6 +103,27 @@ enum op_field { _(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)) \ + ) \ /* 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 848313e4..627a2c96 100644 --- a/src/feature.h +++ b/src/feature.h @@ -42,6 +42,11 @@ #define RV32_FEATURE_Zba 1 #endif +/* Zbb Basic bit-manipulation */ +#ifndef RV32_FEATURE_Zbb +#define RV32_FEATURE_Zbb 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 edd650e7..fb43330e 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1059,3 +1059,113 @@ CONSTOPT(sh3add, { 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 diff --git a/src/rv32_template.c b/src/rv32_template.c index c1e5b6cb..d5f570d9 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -2630,3 +2630,210 @@ RVOP( })) #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 diff --git a/src/t2c_template.c b/src/t2c_template.c index 90cbe632..c10f87cf 100644 --- a/src/t2c_template.c +++ b/src/t2c_template.c @@ -801,6 +801,44 @@ 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 + T2C_OP(fuse1, { opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) { From 23a234ddcb43a2a153094454b50d45a3170f73ae Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 20:40:32 +0800 Subject: [PATCH 5/9] Add support for Zbc carry-less multiplication extension Add support for the RISC-V Zbc carry-less multiplication extension. This extension introduces instructions for carry-less multiplication, enabling efficient operations in cryptographic algorithms, error-correcting codes, and other specialized applications. Supporting the Zbc extension improves compatibility with the RISC-V specification and enables optimized handling of carry-less multiplication tasks. --- Makefile | 4 ++++ src/decode.c | 17 +++++++++++++++- src/decode.h | 6 ++++++ src/feature.h | 5 +++++ src/rv32_constopt.c | 20 +++++++++++++++++++ src/rv32_template.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ src/t2c_template.c | 8 ++++++++ 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f9421042..7903d607 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,10 @@ $(call set-feature, Zba) ENABLE_Zbb ?= 1 $(call set-feature, Zbb) +# Zbc Carry-less multiplication +ENABLE_Zbc ?= 1 +$(call set-feature, Zbc) + ENABLE_FULL4G ?= 0 # Experimental SDL oriented system calls diff --git a/src/decode.c b/src/decode.c index 754d8553..fae8c386 100644 --- a/src/decode.c +++ b/src/decode.c @@ -725,7 +725,7 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) break; #endif /* RV32_HAS(Zba) */ -#if RV32_HAS(Zbb) +#if RV32_HAS(Zbb) || RV32_HAS(Zbc) /* inst funct7 rs2 rs1 funct3 rd opcode * ------+-------+---+---+------+--+------- * MAX 0000101 rs2 rs1 110 rd 0110011 @@ -737,6 +737,7 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) */ case 0b0000101: switch (funct3) { +#if RV32_HAS(Zbb) case 0b110: /* max */ ir->opcode = rv_insn_max; break; @@ -749,10 +750,24 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) 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 */ diff --git a/src/decode.h b/src/decode.h index ecd1d652..63713fc6 100644 --- a/src/decode.h +++ b/src/decode.h @@ -123,6 +123,12 @@ enum op_field { _(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)) \ ) \ /* RV32M Standard Extension */ \ IIF(RV32_HAS(EXT_M))( \ diff --git a/src/feature.h b/src/feature.h index 627a2c96..dda8a019 100644 --- a/src/feature.h +++ b/src/feature.h @@ -47,6 +47,11 @@ #define RV32_FEATURE_Zbb 1 #endif +/* Zbc Carry-less multiplication */ +#ifndef RV32_FEATURE_Zbc +#define RV32_FEATURE_Zbc 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 fb43330e..d6234922 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1169,3 +1169,23 @@ CONSTOPT(rev8, { 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 diff --git a/src/rv32_template.c b/src/rv32_template.c index d5f570d9..e0aca1e2 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -2837,3 +2837,51 @@ RVOP( })) #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 diff --git a/src/t2c_template.c b/src/t2c_template.c index c10f87cf..50c5ed32 100644 --- a/src/t2c_template.c +++ b/src/t2c_template.c @@ -839,6 +839,14 @@ 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 + T2C_OP(fuse1, { opcode_fuse_t *fuse = ir->fuse; for (int i = 0; i < ir->imm2; i++) { From 29dabe4f1226ca6f1d3df3656ccfff2b2107b9d2 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 22:19:27 +0800 Subject: [PATCH 6/9] Add support for Zbs single-bit instructions extension Add support for the RISC-V Zbs single-bit instructions extension. This extension introduces instructions for efficient manipulation of individual bits, enabling optimized operations in bit-level processing and control. Supporting the Zbs extension improves compatibility with the RISC-V specification and enhances performance in tasks requiring precise single-bit operations. --- Makefile | 4 ++ src/decode.c | 45 ++++++++++++++++++++++ src/decode.h | 11 ++++++ src/feature.h | 5 +++ src/rv32_constopt.c | 51 ++++++++++++++++++++++++ src/rv32_template.c | 94 +++++++++++++++++++++++++++++++++++++++++++++ src/t2c_template.c | 18 +++++++++ 7 files changed, 228 insertions(+) diff --git a/Makefile b/Makefile index 7903d607..96edd9d6 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,10 @@ $(call set-feature, Zbb) 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/src/decode.c b/src/decode.c index fae8c386..f65556da 100644 --- a/src/decode.c +++ b/src/decode.c @@ -485,6 +485,20 @@ static inline bool op_op_imm(rv_insn_t *ir, const uint32_t insn) 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))) @@ -513,6 +527,12 @@ static inline bool op_op_imm(rv_insn_t *ir, const uint32_t insn) 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. @@ -787,6 +807,31 @@ static inline bool op_op(rv_insn_t *ir, const uint32_t insn) 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 */ diff --git a/src/decode.h b/src/decode.h index 63713fc6..a92c7708 100644 --- a/src/decode.h +++ b/src/decode.h @@ -130,6 +130,17 @@ enum op_field { _(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 dda8a019..c4a41939 100644 --- a/src/feature.h +++ b/src/feature.h @@ -52,6 +52,11 @@ #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 d6234922..f317a3ff 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1189,3 +1189,54 @@ CONSTOPT(clmulr, { 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 e0aca1e2..6f2a79f7 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -2885,3 +2885,97 @@ RVOP( })) #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 50c5ed32..01c9d8f3 100644 --- a/src/t2c_template.c +++ b/src/t2c_template.c @@ -847,6 +847,24 @@ 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++) { From 85470694d549f216ea10684a98ef768bbdf37d57 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sat, 21 Dec 2024 09:38:44 +0800 Subject: [PATCH 7/9] Enable testing for Zba, Zbb, Zbc, and Zbs extensions Update the RISC-V architectural test to include support for testing the Zba, Zbb, Zbc, and Zbs extensions. With this change, users can run tests for these extensions using the following command: make arch-test RISCV_DEVICE=IMZbaZbbZbcZbs --- tests/arch-test-target/setup.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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: From 79483f8d6d83ecea6459d622b7ab962f28681018 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sun, 22 Dec 2024 23:46:48 +0800 Subject: [PATCH 8/9] CI: Add Zba, Zbb, Zbc, and Zbs tests to CI pipeline Add tests for the Zba, Zbb, Zbc, and Zbs extensions to the CI pipeline, ensuring that these extensions are validated automatically during continuous integration. --- .ci/riscv-tests.sh | 1 + 1 file changed, 1 insertion(+) 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 From 73dea0c5e3a9473b523b0e5536c061d6b3521d19 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Mon, 23 Dec 2024 12:52:40 +0800 Subject: [PATCH 9/9] Mention Zba, Zbb, Zbc, and Zbs extensions in README Update the README to include details about the RISC-V Zba, Zbb, Zbc, and Zbs bit manipulation extensions. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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