[PATCH 2/3] target/riscv: add unratified RISC-V Zbr0p93 ext

James Wainwright posted 3 patches 1 month, 1 week ago
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <Alistair.Francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
[PATCH 2/3] target/riscv: add unratified RISC-V Zbr0p93 ext
Posted by James Wainwright 1 month, 1 week ago
This extension was not ratified with the Zb[abcs] bitmanip extensions.
This is the latest draft version (0.93) as implemented by the Ibex core.

These instructions are in the reserved encoding space but have not been
ratified and could conflict with future ratified instructions.

Signed-off-by: James Wainwright <james.wainwright@lowrisc.org>
---
 target/riscv/bitmanip_helper.c            | 20 +++++++
 target/riscv/cpu.c                        |  4 +-
 target/riscv/cpu_cfg.h                    |  3 ++
 target/riscv/cpu_cfg_fields.h.inc         |  1 +
 target/riscv/helper.h                     |  2 +
 target/riscv/insn32.decode                | 12 +++++
 target/riscv/insn_trans/trans_rvb.c.inc   | 37 +++++++++++++
 tests/tcg/riscv64/Makefile.softmmu-target |  5 ++
 tests/tcg/riscv64/test-crc32.S            | 64 +++++++++++++++++++++++
 9 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 tests/tcg/riscv64/test-crc32.S

diff --git a/target/riscv/bitmanip_helper.c b/target/riscv/bitmanip_helper.c
index e9c8d7f778..1156a87dd3 100644
--- a/target/riscv/bitmanip_helper.c
+++ b/target/riscv/bitmanip_helper.c
@@ -23,6 +23,8 @@
 #include "exec/target_long.h"
 #include "exec/helper-proto.h"
 #include "tcg/tcg.h"
+#include "qemu/crc32.h"
+#include "qemu/crc32c.h"
 
 target_ulong HELPER(clmul)(target_ulong rs1, target_ulong rs2)
 {
@@ -129,3 +131,21 @@ target_ulong HELPER(xperm8)(target_ulong rs1, target_ulong rs2)
 {
     return do_xperm(rs1, rs2, 3);
 }
+
+target_ulong HELPER(crc32)(target_ulong rs1, target_ulong sz)
+{
+    for (target_ulong i = 0; i < sz; i++) {
+        rs1 = crc32_table[rs1 & 0xFF] ^ (rs1 >> 8);
+    }
+
+    return rs1;
+}
+
+target_ulong HELPER(crc32c)(target_ulong rs1, target_ulong sz)
+{
+    for (target_ulong i = 0; i < sz; i++) {
+        rs1 = crc32c_table[rs1 & 0xFF] ^ (rs1 >> 8);
+    }
+
+    return rs1;
+}
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e56470a374..b83efb210e 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1377,6 +1377,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = {
 /* These are experimental so mark with 'x-' */
 const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = {
     MULTI_EXT_CFG_BOOL("x-svukte", ext_svukte, false),
+    MULTI_EXT_CFG_BOOL("x-zbr", ext_zbr, false),
 
     { },
 };
@@ -3056,7 +3057,8 @@ static const TypeInfo riscv_cpu_type_infos[] = {
         .cfg.ext_zba = true,
         .cfg.ext_zbb = true,
         .cfg.ext_zbc = true,
-        .cfg.ext_zbs = true
+        .cfg.ext_zbs = true,
+        .cfg.ext_zbr = true
     ),
 
     DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E31, TYPE_RISCV_CPU_SIFIVE_E,
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index cd1cba797c..2f18d16de2 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -70,4 +70,7 @@ MATERIALISE_EXT_PREDICATE(xtheadmempair)
 MATERIALISE_EXT_PREDICATE(xtheadsync)
 MATERIALISE_EXT_PREDICATE(XVentanaCondOps)
 
+/* Extensions that are not yet upstream */
+MATERIALISE_EXT_PREDICATE(zbr);
+
 #endif
diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
index 70ec650abf..38cb512010 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -11,6 +11,7 @@ BOOL_FIELD(ext_zbc)
 BOOL_FIELD(ext_zbkb)
 BOOL_FIELD(ext_zbkc)
 BOOL_FIELD(ext_zbkx)
+BOOL_FIELD(ext_zbr)
 BOOL_FIELD(ext_zbs)
 BOOL_FIELD(ext_zca)
 BOOL_FIELD(ext_zcb)
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index b785456ee0..7722c590bd 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -84,6 +84,8 @@ DEF_HELPER_FLAGS_1(unzip, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_1(zip, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_2(xperm4, TCG_CALL_NO_RWG_SE, tl, tl, tl)
 DEF_HELPER_FLAGS_2(xperm8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl)
 
 /* Floating Point - Half Precision */
 DEF_HELPER_FLAGS_3(fadd_h, TCG_CALL_NO_RWG, i64, env, i64, i64)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 6e35c4b1e6..97bf9687b7 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -847,6 +847,18 @@ binvi      01101. ........... 001 ..... 0010011 @sh
 bset       0010100 .......... 001 ..... 0110011 @r
 bseti      00101. ........... 001 ..... 0010011 @sh
 
+# *** RV32 Zbr Experimental Extension ***
+crc32_b    0110000  10000 ..... 001 ..... 0010011 @r2
+crc32_h    0110000  10001 ..... 001 ..... 0010011 @r2
+crc32_w    0110000  10010 ..... 001 ..... 0010011 @r2
+crc32c_b   0110000  11000 ..... 001 ..... 0010011 @r2
+crc32c_h   0110000  11001 ..... 001 ..... 0010011 @r2
+crc32c_w   0110000  11010 ..... 001 ..... 0010011 @r2
+
+# *** RV64 Zbr Experimental Extension (in addition to RV32 Zbr) ***
+crc32_d    0110000  10011 ..... 001 ..... 0010011 @r2
+crc32c_d   0110000  11011 ..... 001 ..... 0010011 @r2
+
 # *** Zfa Standard Extension ***
 fli_s       1111000 00001 ..... 000 ..... 1010011 @r2
 fli_d       1111001 00001 ..... 000 ..... 1010011 @r2
diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc
index e4dcc7c991..59db8b047f 100644
--- a/target/riscv/insn_trans/trans_rvb.c.inc
+++ b/target/riscv/insn_trans/trans_rvb.c.inc
@@ -36,6 +36,12 @@
     }                                            \
 } while (0)
 
+#define REQUIRE_ZBR(ctx) do {                    \
+    if (!ctx->cfg_ptr->ext_zbr) {                \
+        return false;                            \
+    }                                            \
+} while (0)
+
 #define REQUIRE_ZBS(ctx) do {                    \
     if (!ctx->cfg_ptr->ext_zbs) {                \
         return false;                            \
@@ -569,3 +575,34 @@ static bool trans_xperm8(DisasContext *ctx, arg_xperm8 *a)
     REQUIRE_ZBKX(ctx);
     return gen_arith(ctx, a, EXT_NONE, gen_helper_xperm8, NULL);
 }
+
+static bool gen_crc(DisasContext *ctx, arg_r2 *a,
+                    void (*func)(TCGv, TCGv, TCGv), TCGv tsz)
+{
+    REQUIRE_ZBR(ctx);
+    TCGv dest = dest_gpr(ctx, a->rd);
+    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
+
+    func(dest, src1, tsz);
+    gen_set_gpr(ctx, a->rd, dest);
+
+    return true;
+}
+
+#define TRANS_CRC32(NAME, SIZE) \
+    static bool trans_crc32_##NAME(DisasContext *ctx, arg_r2 *a) \
+    { if (SIZE == 8) { REQUIRE_64BIT(ctx); }; \
+      return gen_crc(ctx, a, gen_helper_crc32, tcg_constant_tl(SIZE)); }
+#define TRANS_CRC32C(NAME, SIZE) \
+    static bool trans_crc32c_##NAME(DisasContext *ctx, arg_r2 *a) \
+    { if (SIZE == 8) { REQUIRE_64BIT(ctx); }; \
+      return gen_crc(ctx, a, gen_helper_crc32c, tcg_constant_tl(SIZE)); }
+
+TRANS_CRC32(b, 1);
+TRANS_CRC32(h, 2);
+TRANS_CRC32(w, 4);
+TRANS_CRC32(d, 8);
+TRANS_CRC32C(b, 1);
+TRANS_CRC32C(h, 2);
+TRANS_CRC32C(w, 4);
+TRANS_CRC32C(d, 8);
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index eb1ce6504a..f0bf4fa124 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -36,5 +36,10 @@ run-plugin-interruptedmemory: interruptedmemory
 	  $(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
 	  $(QEMU_OPTS)$<)
 
+EXTRA_RUNS += run-test-crc32
+comma:= ,
+run-test-crc32: test-crc32
+	$(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-zbr=true $(QEMU_OPTS)$<)
+
 # We don't currently support the multiarch system tests
 undefine MULTIARCH_TESTS
diff --git a/tests/tcg/riscv64/test-crc32.S b/tests/tcg/riscv64/test-crc32.S
new file mode 100644
index 0000000000..70d70b16a9
--- /dev/null
+++ b/tests/tcg/riscv64/test-crc32.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2026 lowRISC CIC
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define crc32(op, rd, rs1) .insn r 19, 1, 48, rd, rs1, x##op
+
+#define crc32_b(rd, rs1) crc32(16, rd, rs1)
+#define crc32_h(rd, rs1) crc32(17, rd, rs1)
+#define crc32_w(rd, rs1) crc32(18, rd, rs1)
+#define crc32_d(rd, rs1) crc32(19, rd, rs1)
+#define crc32c_b(rd, rs1) crc32(24, rd, rs1)
+#define crc32c_h(rd, rs1) crc32(25, rd, rs1)
+#define crc32c_w(rd, rs1) crc32(26, rd, rs1)
+#define crc32c_d(rd, rs1) crc32(27, rd, rs1)
+
+	.option norvc
+
+	.text
+	.globl _start
+_start:
+	lla t0, trap
+	csrw mtvec, t0
+
+	li	t0, 0x34e24a2cd65650d4
+
+	crc32_b 	(t0, t0)
+	crc32_h 	(t0, t0)
+	crc32_w 	(t0, t0)
+	crc32_d 	(t0, t0)
+	crc32c_b	(t0, t0)
+	crc32c_h	(t0, t0)
+	crc32c_w	(t0, t0)
+	crc32c_d	(t0, t0)
+
+	li	t1, 0x68167e78
+
+	li	a0, 0
+	beq	t0, t1, _exit
+fail:
+	li	a0, 1
+_exit:
+	lla	a1, semiargs
+	li	t0, 0x20026	# ADP_Stopped_ApplicationExit
+	sd	t0, 0(a1)
+	sd	a0, 8(a1)
+	li	a0, 0x20	# TARGET_SYS_EXIT_EXTENDED
+
+	# Semihosting call sequence
+	.balign	16
+	slli	zero, zero, 0x1f
+	ebreak
+	srai	zero, zero, 0x7
+	j	.
+
+	.data
+	.balign	16
+semiargs:
+	.space	16
+
+trap:
+	csrr t0, mepc
+	addi t0, t0, 4
+	mret
-- 
2.48.1
Re: [PATCH 2/3] target/riscv: add unratified RISC-V Zbr0p93 ext
Posted by Alistair Francis 1 month, 1 week ago
On Thu, Mar 5, 2026 at 12:11 AM James Wainwright
<james.wainwright@lowrisc.org> wrote:
>
> This extension was not ratified with the Zb[abcs] bitmanip extensions.
> This is the latest draft version (0.93) as implemented by the Ibex core.
>
> These instructions are in the reserved encoding space but have not been
> ratified and could conflict with future ratified instructions.

Looking at https://github.com/riscv/riscv-bitmanip/issues/188 I assume
that these instructions will never be ratified.

We don't have a policy on what to do with deprecated draft extensions,
but I'm reluctant to add these. At some point in the future they will
conflict with a ratified extension, which will cause all sorts of
issues.

These should probably just be a vendor specific thing

Alistair

>
> Signed-off-by: James Wainwright <james.wainwright@lowrisc.org>
> ---
>  target/riscv/bitmanip_helper.c            | 20 +++++++
>  target/riscv/cpu.c                        |  4 +-
>  target/riscv/cpu_cfg.h                    |  3 ++
>  target/riscv/cpu_cfg_fields.h.inc         |  1 +
>  target/riscv/helper.h                     |  2 +
>  target/riscv/insn32.decode                | 12 +++++
>  target/riscv/insn_trans/trans_rvb.c.inc   | 37 +++++++++++++
>  tests/tcg/riscv64/Makefile.softmmu-target |  5 ++
>  tests/tcg/riscv64/test-crc32.S            | 64 +++++++++++++++++++++++
>  9 files changed, 147 insertions(+), 1 deletion(-)
>  create mode 100644 tests/tcg/riscv64/test-crc32.S
>
> diff --git a/target/riscv/bitmanip_helper.c b/target/riscv/bitmanip_helper.c
> index e9c8d7f778..1156a87dd3 100644
> --- a/target/riscv/bitmanip_helper.c
> +++ b/target/riscv/bitmanip_helper.c
> @@ -23,6 +23,8 @@
>  #include "exec/target_long.h"
>  #include "exec/helper-proto.h"
>  #include "tcg/tcg.h"
> +#include "qemu/crc32.h"
> +#include "qemu/crc32c.h"
>
>  target_ulong HELPER(clmul)(target_ulong rs1, target_ulong rs2)
>  {
> @@ -129,3 +131,21 @@ target_ulong HELPER(xperm8)(target_ulong rs1, target_ulong rs2)
>  {
>      return do_xperm(rs1, rs2, 3);
>  }
> +
> +target_ulong HELPER(crc32)(target_ulong rs1, target_ulong sz)
> +{
> +    for (target_ulong i = 0; i < sz; i++) {
> +        rs1 = crc32_table[rs1 & 0xFF] ^ (rs1 >> 8);
> +    }
> +
> +    return rs1;
> +}
> +
> +target_ulong HELPER(crc32c)(target_ulong rs1, target_ulong sz)
> +{
> +    for (target_ulong i = 0; i < sz; i++) {
> +        rs1 = crc32c_table[rs1 & 0xFF] ^ (rs1 >> 8);
> +    }
> +
> +    return rs1;
> +}
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index e56470a374..b83efb210e 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1377,6 +1377,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = {
>  /* These are experimental so mark with 'x-' */
>  const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = {
>      MULTI_EXT_CFG_BOOL("x-svukte", ext_svukte, false),
> +    MULTI_EXT_CFG_BOOL("x-zbr", ext_zbr, false),
>
>      { },
>  };
> @@ -3056,7 +3057,8 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>          .cfg.ext_zba = true,
>          .cfg.ext_zbb = true,
>          .cfg.ext_zbc = true,
> -        .cfg.ext_zbs = true
> +        .cfg.ext_zbs = true,
> +        .cfg.ext_zbr = true
>      ),
>
>      DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E31, TYPE_RISCV_CPU_SIFIVE_E,
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index cd1cba797c..2f18d16de2 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -70,4 +70,7 @@ MATERIALISE_EXT_PREDICATE(xtheadmempair)
>  MATERIALISE_EXT_PREDICATE(xtheadsync)
>  MATERIALISE_EXT_PREDICATE(XVentanaCondOps)
>
> +/* Extensions that are not yet upstream */
> +MATERIALISE_EXT_PREDICATE(zbr);
> +
>  #endif
> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
> index 70ec650abf..38cb512010 100644
> --- a/target/riscv/cpu_cfg_fields.h.inc
> +++ b/target/riscv/cpu_cfg_fields.h.inc
> @@ -11,6 +11,7 @@ BOOL_FIELD(ext_zbc)
>  BOOL_FIELD(ext_zbkb)
>  BOOL_FIELD(ext_zbkc)
>  BOOL_FIELD(ext_zbkx)
> +BOOL_FIELD(ext_zbr)
>  BOOL_FIELD(ext_zbs)
>  BOOL_FIELD(ext_zca)
>  BOOL_FIELD(ext_zcb)
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index b785456ee0..7722c590bd 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -84,6 +84,8 @@ DEF_HELPER_FLAGS_1(unzip, TCG_CALL_NO_RWG_SE, tl, tl)
>  DEF_HELPER_FLAGS_1(zip, TCG_CALL_NO_RWG_SE, tl, tl)
>  DEF_HELPER_FLAGS_2(xperm4, TCG_CALL_NO_RWG_SE, tl, tl, tl)
>  DEF_HELPER_FLAGS_2(xperm8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl)
> +DEF_HELPER_FLAGS_2(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl)
>
>  /* Floating Point - Half Precision */
>  DEF_HELPER_FLAGS_3(fadd_h, TCG_CALL_NO_RWG, i64, env, i64, i64)
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 6e35c4b1e6..97bf9687b7 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -847,6 +847,18 @@ binvi      01101. ........... 001 ..... 0010011 @sh
>  bset       0010100 .......... 001 ..... 0110011 @r
>  bseti      00101. ........... 001 ..... 0010011 @sh
>
> +# *** RV32 Zbr Experimental Extension ***
> +crc32_b    0110000  10000 ..... 001 ..... 0010011 @r2
> +crc32_h    0110000  10001 ..... 001 ..... 0010011 @r2
> +crc32_w    0110000  10010 ..... 001 ..... 0010011 @r2
> +crc32c_b   0110000  11000 ..... 001 ..... 0010011 @r2
> +crc32c_h   0110000  11001 ..... 001 ..... 0010011 @r2
> +crc32c_w   0110000  11010 ..... 001 ..... 0010011 @r2
> +
> +# *** RV64 Zbr Experimental Extension (in addition to RV32 Zbr) ***
> +crc32_d    0110000  10011 ..... 001 ..... 0010011 @r2
> +crc32c_d   0110000  11011 ..... 001 ..... 0010011 @r2
> +
>  # *** Zfa Standard Extension ***
>  fli_s       1111000 00001 ..... 000 ..... 1010011 @r2
>  fli_d       1111001 00001 ..... 000 ..... 1010011 @r2
> diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc
> index e4dcc7c991..59db8b047f 100644
> --- a/target/riscv/insn_trans/trans_rvb.c.inc
> +++ b/target/riscv/insn_trans/trans_rvb.c.inc
> @@ -36,6 +36,12 @@
>      }                                            \
>  } while (0)
>
> +#define REQUIRE_ZBR(ctx) do {                    \
> +    if (!ctx->cfg_ptr->ext_zbr) {                \
> +        return false;                            \
> +    }                                            \
> +} while (0)
> +
>  #define REQUIRE_ZBS(ctx) do {                    \
>      if (!ctx->cfg_ptr->ext_zbs) {                \
>          return false;                            \
> @@ -569,3 +575,34 @@ static bool trans_xperm8(DisasContext *ctx, arg_xperm8 *a)
>      REQUIRE_ZBKX(ctx);
>      return gen_arith(ctx, a, EXT_NONE, gen_helper_xperm8, NULL);
>  }
> +
> +static bool gen_crc(DisasContext *ctx, arg_r2 *a,
> +                    void (*func)(TCGv, TCGv, TCGv), TCGv tsz)
> +{
> +    REQUIRE_ZBR(ctx);
> +    TCGv dest = dest_gpr(ctx, a->rd);
> +    TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
> +
> +    func(dest, src1, tsz);
> +    gen_set_gpr(ctx, a->rd, dest);
> +
> +    return true;
> +}
> +
> +#define TRANS_CRC32(NAME, SIZE) \
> +    static bool trans_crc32_##NAME(DisasContext *ctx, arg_r2 *a) \
> +    { if (SIZE == 8) { REQUIRE_64BIT(ctx); }; \
> +      return gen_crc(ctx, a, gen_helper_crc32, tcg_constant_tl(SIZE)); }
> +#define TRANS_CRC32C(NAME, SIZE) \
> +    static bool trans_crc32c_##NAME(DisasContext *ctx, arg_r2 *a) \
> +    { if (SIZE == 8) { REQUIRE_64BIT(ctx); }; \
> +      return gen_crc(ctx, a, gen_helper_crc32c, tcg_constant_tl(SIZE)); }
> +
> +TRANS_CRC32(b, 1);
> +TRANS_CRC32(h, 2);
> +TRANS_CRC32(w, 4);
> +TRANS_CRC32(d, 8);
> +TRANS_CRC32C(b, 1);
> +TRANS_CRC32C(h, 2);
> +TRANS_CRC32C(w, 4);
> +TRANS_CRC32C(d, 8);
> diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
> index eb1ce6504a..f0bf4fa124 100644
> --- a/tests/tcg/riscv64/Makefile.softmmu-target
> +++ b/tests/tcg/riscv64/Makefile.softmmu-target
> @@ -36,5 +36,10 @@ run-plugin-interruptedmemory: interruptedmemory
>           $(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
>           $(QEMU_OPTS)$<)
>
> +EXTRA_RUNS += run-test-crc32
> +comma:= ,
> +run-test-crc32: test-crc32
> +       $(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-zbr=true $(QEMU_OPTS)$<)
> +
>  # We don't currently support the multiarch system tests
>  undefine MULTIARCH_TESTS
> diff --git a/tests/tcg/riscv64/test-crc32.S b/tests/tcg/riscv64/test-crc32.S
> new file mode 100644
> index 0000000000..70d70b16a9
> --- /dev/null
> +++ b/tests/tcg/riscv64/test-crc32.S
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (c) 2026 lowRISC CIC
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#define crc32(op, rd, rs1) .insn r 19, 1, 48, rd, rs1, x##op
> +
> +#define crc32_b(rd, rs1) crc32(16, rd, rs1)
> +#define crc32_h(rd, rs1) crc32(17, rd, rs1)
> +#define crc32_w(rd, rs1) crc32(18, rd, rs1)
> +#define crc32_d(rd, rs1) crc32(19, rd, rs1)
> +#define crc32c_b(rd, rs1) crc32(24, rd, rs1)
> +#define crc32c_h(rd, rs1) crc32(25, rd, rs1)
> +#define crc32c_w(rd, rs1) crc32(26, rd, rs1)
> +#define crc32c_d(rd, rs1) crc32(27, rd, rs1)
> +
> +       .option norvc
> +
> +       .text
> +       .globl _start
> +_start:
> +       lla t0, trap
> +       csrw mtvec, t0
> +
> +       li      t0, 0x34e24a2cd65650d4
> +
> +       crc32_b         (t0, t0)
> +       crc32_h         (t0, t0)
> +       crc32_w         (t0, t0)
> +       crc32_d         (t0, t0)
> +       crc32c_b        (t0, t0)
> +       crc32c_h        (t0, t0)
> +       crc32c_w        (t0, t0)
> +       crc32c_d        (t0, t0)
> +
> +       li      t1, 0x68167e78
> +
> +       li      a0, 0
> +       beq     t0, t1, _exit
> +fail:
> +       li      a0, 1
> +_exit:
> +       lla     a1, semiargs
> +       li      t0, 0x20026     # ADP_Stopped_ApplicationExit
> +       sd      t0, 0(a1)
> +       sd      a0, 8(a1)
> +       li      a0, 0x20        # TARGET_SYS_EXIT_EXTENDED
> +
> +       # Semihosting call sequence
> +       .balign 16
> +       slli    zero, zero, 0x1f
> +       ebreak
> +       srai    zero, zero, 0x7
> +       j       .
> +
> +       .data
> +       .balign 16
> +semiargs:
> +       .space  16
> +
> +trap:
> +       csrr t0, mepc
> +       addi t0, t0, 4
> +       mret
> --
> 2.48.1
>
>
Re: [PATCH 2/3] target/riscv: add unratified RISC-V Zbr0p93 ext
Posted by James Wainwright 1 month, 1 week ago
> We don't have a policy on what to do with deprecated draft extensions,
but I'm reluctant to add these. At some point in the future they will
conflict with a ratified extension, which will cause all sorts of
issues.

Agreed, it's not ideal. FWIW it looks like OpenTitan is moving to use the
ratified `clmul` instructions to implement CRC32 going forward (
https://github.com/lowRISC/opentitan/pull/28511 and
https://github.com/lowRISC/opentitan/pull/29200) but the Earl Grey chip has
already been taped out with Zbr instructions in the ROM, so it would be
nice if we could emulate that upstream.

Does the extension being implemented as experimental and opt-in help,
similar to how `X` extensions share an encoding space? It seems unlikely
for machines other than Earl Grey to use Zbr0p93.

> These should probably just be a vendor specific thing

It's a shame that it's in the ratified encoding space or it would already
be like a vendor extension.
Re: [PATCH 2/3] target/riscv: add unratified RISC-V Zbr0p93 ext
Posted by Alistair Francis 1 month ago
On Fri, Mar 6, 2026 at 4:00 AM James Wainwright
<james.wainwright@lowrisc.org> wrote:
>
> > We don't have a policy on what to do with deprecated draft extensions,
> but I'm reluctant to add these. At some point in the future they will
> conflict with a ratified extension, which will cause all sorts of
> issues.
>
> Agreed, it's not ideal. FWIW it looks like OpenTitan is moving to use the ratified `clmul` instructions to implement CRC32 going forward (https://github.com/lowRISC/opentitan/pull/28511 and https://github.com/lowRISC/opentitan/pull/29200) but the Earl Grey chip has already been taped out with Zbr instructions in the ROM, so it would be nice if we could emulate that upstream.
>
> Does the extension being implemented as experimental and opt-in help, similar to how `X` extensions share an encoding space? It seems unlikely for machines other than Earl Grey to use Zbr0p93.
>
> > These should probably just be a vendor specific thing
>
> It's a shame that it's in the ratified encoding space or it would already be like a vendor extension.

You should still be able to support it, just structure it and name it
as a vendor extension in QEMU instead of a standard RISC-V extension.

Alistair