RISC-V Debug Specification:
https://github.com/riscv/riscv-debug-spec/releases/tag/1.0
Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
them to Debug Mode (or host debugger access).
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
---
target/riscv/cpu.c | 9 +++
target/riscv/cpu.h | 4 +
target/riscv/cpu_bits.h | 33 ++++++++
target/riscv/cpu_cfg_fields.h.inc | 1 +
target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
target/riscv/machine.c | 20 +++++
6 files changed, 193 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index f1b977f0ee..bd6cff33cf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
+ ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
@@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
env->vill = true;
+ env->debug_mode = false;
+ env->dcsr = DCSR_DEBUGVER(4);
+ env->dpc = 0;
+ env->dscratch[0] = 0;
+ env->dscratch[1] = 0;
#ifndef CONFIG_USER_ONLY
if (cpu->cfg.ext_sdtrig) {
@@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
*/
cpu->cfg.ext_sdtrig = true;
+ /* sdext is not fully implemented, so it is disabled by default. */
+ cpu->cfg.ext_sdext = false;
+
if (mcc->def->profile) {
mcc->def->profile->enabled = true;
}
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4c0676ed53..2a265faae5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -476,6 +476,10 @@ struct CPUArchState {
/* True if in debugger mode. */
bool debugger;
+ bool debug_mode;
+ target_ulong dcsr;
+ target_ulong dpc;
+ target_ulong dscratch[2];
uint64_t mstateen[SMSTATEEN_MAX_COUNT];
uint64_t hstateen[SMSTATEEN_MAX_COUNT];
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index b62dd82fe7..bb59f7ff56 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -467,6 +467,39 @@
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
+#define CSR_DSCRATCH1 0x7b3
+
+/* DCSR fields */
+#define DCSR_XDEBUGVER_SHIFT 28
+#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
+#define DCSR_DEBUGVER(val) ((target_ulong)(val) << DCSR_XDEBUGVER_SHIFT)
+#define DCSR_EXTCAUSE_SHIFT 24
+#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
+#define DCSR_CETRIG BIT(19)
+#define DCSR_PELP BIT(18)
+#define DCSR_EBREAKVS BIT(17)
+#define DCSR_EBREAKVU BIT(16)
+#define DCSR_EBREAKM BIT(15)
+#define DCSR_EBREAKS BIT(13)
+#define DCSR_EBREAKU BIT(12)
+#define DCSR_STEPIE BIT(11)
+#define DCSR_STOPCOUNT BIT(10)
+#define DCSR_STOPTIME BIT(9)
+#define DCSR_CAUSE_SHIFT 6
+#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
+#define DCSR_V BIT(5)
+#define DCSR_MPRVEN BIT(4)
+#define DCSR_NMIP BIT(3)
+#define DCSR_STEP BIT(2)
+#define DCSR_PRV_MASK 0x3u
+
+#define DCSR_CAUSE_EBREAK 1
+#define DCSR_CAUSE_TRIGGER 2
+#define DCSR_CAUSE_HALTREQ 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_RESET 5
+#define DCSR_CAUSE_GROUP 6
+#define DCSR_CAUSE_OTHER 7
/* Performance Counters */
#define CSR_MHPMCOUNTER3 0xb03
diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
index a8c133d663..99b5529161 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
BOOL_FIELD(ext_zimop)
BOOL_FIELD(ext_zcmop)
BOOL_FIELD(ext_ztso)
+BOOL_FIELD(ext_sdext)
BOOL_FIELD(ext_sdtrig)
BOOL_FIELD(ext_smstateen)
BOOL_FIELD(ext_sstc)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 870fad87ac..3e38c943e0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+#if !defined(CONFIG_USER_ONLY)
+static RISCVException sdext(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_sdext) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (!env->debug_mode && !env->debugger) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static target_ulong dcsr_visible_mask(CPURISCVState *env)
+{
+ target_ulong mask = (target_ulong)-1;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!riscv_has_ext(env, RVH)) {
+ mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
+ }
+ if (!riscv_has_ext(env, RVS)) {
+ mask &= ~DCSR_EBREAKS;
+ }
+ if (!riscv_has_ext(env, RVU)) {
+ mask &= ~DCSR_EBREAKU;
+ }
+ if (!cpu->cfg.ext_zicfilp) {
+ mask &= ~DCSR_PELP;
+ }
+ if (!cpu->cfg.ext_smdbltrp) {
+ mask &= ~DCSR_CETRIG;
+ }
+
+ return mask;
+}
+
+static RISCVException read_dcsr(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->dcsr & dcsr_visible_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static target_ulong dcsr_writable_mask(CPURISCVState *env)
+{
+ target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
+ DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
+ DCSR_STEP | DCSR_PRV_MASK;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ mask |= DCSR_MPRVEN;
+
+ if (riscv_has_ext(env, RVH)) {
+ mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
+ }
+ if (riscv_has_ext(env, RVS)) {
+ mask |= DCSR_EBREAKS;
+ }
+ if (riscv_has_ext(env, RVU)) {
+ mask |= DCSR_EBREAKU;
+ }
+ if (cpu->cfg.ext_zicfilp) {
+ mask |= DCSR_PELP;
+ }
+ if (cpu->cfg.ext_smdbltrp) {
+ mask |= DCSR_CETRIG;
+ }
+
+ return mask;
+}
+
+static RISCVException write_dcsr(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ target_ulong mask = dcsr_writable_mask(env);
+ target_ulong new_val = env->dcsr;
+
+ new_val &= ~mask;
+ new_val |= val & mask;
+ new_val &= ~DCSR_XDEBUGVER_MASK;
+ new_val |= DCSR_DEBUGVER(4);
+ env->dcsr = new_val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_dpc(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->dpc & get_xepc_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_dpc(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ env->dpc = val & get_xepc_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_dscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
+
+ *val = env->dscratch[index];
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_dscratch(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
+
+ env->dscratch[index] = val;
+ return RISCV_EXCP_NONE;
+}
+#endif /* !CONFIG_USER_ONLY */
+
/* Execution environment configuration setup */
static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
target_ulong *val)
@@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
[CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
[CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
+#if !defined(CONFIG_USER_ONLY)
+ [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
+ [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
+ [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch },
+ [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch },
+#endif
[CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL, rmw_xctrctl },
[CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 62c51c8033..52264cf047 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
+ VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
+ VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_sdext = {
+ .name = "cpu/sdext",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = sdtrig_needed,
+ .post_load = sdtrig_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
+ VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_ctr,
&vmstate_sstc,
&vmstate_sdtrig,
+ &vmstate_sdext,
NULL
}
};
--
2.52.0
Hi Chao,
I wasn't able to apply this patch. Applied all Max's series first, then
tried to apply yours.
The conflict in target/riscv/cpu.c seems to indicate you're basing the
patches on top of something that we don't have upstream:
diff a/target/riscv/cpu.c b/target/riscv/cpu.c (rejected hunks)
@@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj,
ResetType type)
set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
env->vill = true;
+ env->debug_mode = false;
+ env->dcsr = DCSR_DEBUGVER(4);
+ env->dpc = 0;
+ env->dscratch[0] = 0;
+ env->dscratch[1] = 0;
#ifndef CONFIG_USER_ONLY
if (cpu->cfg.ext_sdtrig) {
The 'set_ocp_fp8*' lines over here can't be find anywhere else in QEMU,
so I suppose you're basing the patches on top of something else.
If you could base the patches on top of alistair/riscv-to-apply.next
tree, plus Max's patches, that would be great.
Thanks,
Daniel
On 1/20/2026 5:23 AM, Chao Liu wrote:
> RISC-V Debug Specification:
> https://github.com/riscv/riscv-debug-spec/releases/tag/1.0
>
> Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
> and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
> them to Debug Mode (or host debugger access).
>
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> ---
> target/riscv/cpu.c | 9 +++
> target/riscv/cpu.h | 4 +
> target/riscv/cpu_bits.h | 33 ++++++++
> target/riscv/cpu_cfg_fields.h.inc | 1 +
> target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
> target/riscv/machine.c | 20 +++++
> 6 files changed, 193 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index f1b977f0ee..bd6cff33cf 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
> ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
> ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
> ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
> + ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
> ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
> ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
> ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
> env->vill = true;
> + env->debug_mode = false;
> + env->dcsr = DCSR_DEBUGVER(4);
> + env->dpc = 0;
> + env->dscratch[0] = 0;
> + env->dscratch[1] = 0;
>
> #ifndef CONFIG_USER_ONLY
> if (cpu->cfg.ext_sdtrig) {
> @@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
> */
> cpu->cfg.ext_sdtrig = true;
>
> + /* sdext is not fully implemented, so it is disabled by default. */
> + cpu->cfg.ext_sdext = false;
> +
> if (mcc->def->profile) {
> mcc->def->profile->enabled = true;
> }
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4c0676ed53..2a265faae5 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -476,6 +476,10 @@ struct CPUArchState {
>
> /* True if in debugger mode. */
> bool debugger;
> + bool debug_mode;
> + target_ulong dcsr;
> + target_ulong dpc;
> + target_ulong dscratch[2];
>
> uint64_t mstateen[SMSTATEEN_MAX_COUNT];
> uint64_t hstateen[SMSTATEEN_MAX_COUNT];
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index b62dd82fe7..bb59f7ff56 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -467,6 +467,39 @@
> #define CSR_DCSR 0x7b0
> #define CSR_DPC 0x7b1
> #define CSR_DSCRATCH 0x7b2
> +#define CSR_DSCRATCH1 0x7b3
> +
> +/* DCSR fields */
> +#define DCSR_XDEBUGVER_SHIFT 28
> +#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
> +#define DCSR_DEBUGVER(val) ((target_ulong)(val) << DCSR_XDEBUGVER_SHIFT)
> +#define DCSR_EXTCAUSE_SHIFT 24
> +#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
> +#define DCSR_CETRIG BIT(19)
> +#define DCSR_PELP BIT(18)
> +#define DCSR_EBREAKVS BIT(17)
> +#define DCSR_EBREAKVU BIT(16)
> +#define DCSR_EBREAKM BIT(15)
> +#define DCSR_EBREAKS BIT(13)
> +#define DCSR_EBREAKU BIT(12)
> +#define DCSR_STEPIE BIT(11)
> +#define DCSR_STOPCOUNT BIT(10)
> +#define DCSR_STOPTIME BIT(9)
> +#define DCSR_CAUSE_SHIFT 6
> +#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
> +#define DCSR_V BIT(5)
> +#define DCSR_MPRVEN BIT(4)
> +#define DCSR_NMIP BIT(3)
> +#define DCSR_STEP BIT(2)
> +#define DCSR_PRV_MASK 0x3u
> +
> +#define DCSR_CAUSE_EBREAK 1
> +#define DCSR_CAUSE_TRIGGER 2
> +#define DCSR_CAUSE_HALTREQ 3
> +#define DCSR_CAUSE_STEP 4
> +#define DCSR_CAUSE_RESET 5
> +#define DCSR_CAUSE_GROUP 6
> +#define DCSR_CAUSE_OTHER 7
>
> /* Performance Counters */
> #define CSR_MHPMCOUNTER3 0xb03
> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
> index a8c133d663..99b5529161 100644
> --- a/target/riscv/cpu_cfg_fields.h.inc
> +++ b/target/riscv/cpu_cfg_fields.h.inc
> @@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
> BOOL_FIELD(ext_zimop)
> BOOL_FIELD(ext_zcmop)
> BOOL_FIELD(ext_ztso)
> +BOOL_FIELD(ext_sdext)
> BOOL_FIELD(ext_sdtrig)
> BOOL_FIELD(ext_smstateen)
> BOOL_FIELD(ext_sstc)
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 870fad87ac..3e38c943e0 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState *env, int csrno,
> return RISCV_EXCP_NONE;
> }
>
> +#if !defined(CONFIG_USER_ONLY)
> +static RISCVException sdext(CPURISCVState *env, int csrno)
> +{
> + if (!riscv_cpu_cfg(env)->ext_sdext) {
> + return RISCV_EXCP_ILLEGAL_INST;
> + }
> +
> + if (!env->debug_mode && !env->debugger) {
> + return RISCV_EXCP_ILLEGAL_INST;
> + }
> +
> + return RISCV_EXCP_NONE;
> +}
> +
> +static target_ulong dcsr_visible_mask(CPURISCVState *env)
> +{
> + target_ulong mask = (target_ulong)-1;
> + RISCVCPU *cpu = env_archcpu(env);
> +
> + if (!riscv_has_ext(env, RVH)) {
> + mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
> + }
> + if (!riscv_has_ext(env, RVS)) {
> + mask &= ~DCSR_EBREAKS;
> + }
> + if (!riscv_has_ext(env, RVU)) {
> + mask &= ~DCSR_EBREAKU;
> + }
> + if (!cpu->cfg.ext_zicfilp) {
> + mask &= ~DCSR_PELP;
> + }
> + if (!cpu->cfg.ext_smdbltrp) {
> + mask &= ~DCSR_CETRIG;
> + }
> +
> + return mask;
> +}
> +
> +static RISCVException read_dcsr(CPURISCVState *env, int csrno,
> + target_ulong *val)
> +{
> + *val = env->dcsr & dcsr_visible_mask(env);
> + return RISCV_EXCP_NONE;
> +}
> +
> +static target_ulong dcsr_writable_mask(CPURISCVState *env)
> +{
> + target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
> + DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
> + DCSR_STEP | DCSR_PRV_MASK;
> + RISCVCPU *cpu = env_archcpu(env);
> +
> + mask |= DCSR_MPRVEN;
> +
> + if (riscv_has_ext(env, RVH)) {
> + mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
> + }
> + if (riscv_has_ext(env, RVS)) {
> + mask |= DCSR_EBREAKS;
> + }
> + if (riscv_has_ext(env, RVU)) {
> + mask |= DCSR_EBREAKU;
> + }
> + if (cpu->cfg.ext_zicfilp) {
> + mask |= DCSR_PELP;
> + }
> + if (cpu->cfg.ext_smdbltrp) {
> + mask |= DCSR_CETRIG;
> + }
> +
> + return mask;
> +}
> +
> +static RISCVException write_dcsr(CPURISCVState *env, int csrno,
> + target_ulong val, uintptr_t ra)
> +{
> + target_ulong mask = dcsr_writable_mask(env);
> + target_ulong new_val = env->dcsr;
> +
> + new_val &= ~mask;
> + new_val |= val & mask;
> + new_val &= ~DCSR_XDEBUGVER_MASK;
> + new_val |= DCSR_DEBUGVER(4);
> + env->dcsr = new_val;
> + return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_dpc(CPURISCVState *env, int csrno,
> + target_ulong *val)
> +{
> + *val = env->dpc & get_xepc_mask(env);
> + return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_dpc(CPURISCVState *env, int csrno,
> + target_ulong val, uintptr_t ra)
> +{
> + env->dpc = val & get_xepc_mask(env);
> + return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_dscratch(CPURISCVState *env, int csrno,
> + target_ulong *val)
> +{
> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
> +
> + *val = env->dscratch[index];
> + return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_dscratch(CPURISCVState *env, int csrno,
> + target_ulong val, uintptr_t ra)
> +{
> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
> +
> + env->dscratch[index] = val;
> + return RISCV_EXCP_NONE;
> +}
> +#endif /* !CONFIG_USER_ONLY */
> +
> /* Execution environment configuration setup */
> static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
> target_ulong *val)
> @@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
> [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
> [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
> +#if !defined(CONFIG_USER_ONLY)
> + [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
> + [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
> + [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch },
> + [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch },
> +#endif
>
> [CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL, rmw_xctrctl },
> [CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 62c51c8033..52264cf047 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
> VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
> VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
> VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const VMStateDescription vmstate_sdext = {
> + .name = "cpu/sdext",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = sdtrig_needed,
> + .post_load = sdtrig_post_load,
> + .fields = (const VMStateField[]) {
> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
> VMSTATE_END_OF_LIST()
> }
> };
> @@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_ctr,
> &vmstate_sstc,
> &vmstate_sdtrig,
> + &vmstate_sdext,
> NULL
> }
> };
Hi Daniel,
On 1/26/2026 8:47 PM, Daniel Henrique Barboza wrote:
Hi Chao,
I wasn't able to apply this patch. Applied all Max's series first, then
tried to apply yours.
The conflict in target/riscv/cpu.c seems to indicate you're basing the
patches on top of something that we don't have upstream:
diff a/target/riscv/cpu.c b/target/riscv/cpu.c (rejected hunks)
@@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj,
ResetType type)
set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
env->vill = true;
+ env->debug_mode = false;
+ env->dcsr = DCSR_DEBUGVER(4);
+ env->dpc = 0;
+ env->dscratch[0] = 0;
+ env->dscratch[1] = 0;
#ifndef CONFIG_USER_ONLY
if (cpu->cfg.ext_sdtrig) {
The 'set_ocp_fp8*' lines over here can't be find anywhere else in QEMU, so
I suppose you're basing the patches on top of something else.
If you could base the patches on top of alistair/riscv-to-apply.next tree,
plus Max's patches, that would be great.
This series is based on the master commit: 06a24591: "disas/riscv: Add
support of Zvfofp4min extension".
Max's patches have been merged into the master branch.
Thanks,
Chao
On 1/20/2026 5:23 AM, Chao Liu wrote:
RISC-V Debug Specification:
https://github.com/riscv/riscv-debug-spec/releases/tag/1.0
Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
them to Debug Mode (or host debugger access).
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
<chao.liu.zevorn@gmail.com>
---
target/riscv/cpu.c | 9 +++
target/riscv/cpu.h | 4 +
target/riscv/cpu_bits.h | 33 ++++++++
target/riscv/cpu_cfg_fields.h.inc | 1 +
target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
target/riscv/machine.c | 20 +++++
6 files changed, 193 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index f1b977f0ee..bd6cff33cf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
+ ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
@@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj,
ResetType type)
set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
env->vill = true;
+ env->debug_mode = false;
+ env->dcsr = DCSR_DEBUGVER(4);
+ env->dpc = 0;
+ env->dscratch[0] = 0;
+ env->dscratch[1] = 0;
#ifndef CONFIG_USER_ONLY
if (cpu->cfg.ext_sdtrig) {
@@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
*/
cpu->cfg.ext_sdtrig = true;
+ /* sdext is not fully implemented, so it is disabled by default. */
+ cpu->cfg.ext_sdext = false;
+
if (mcc->def->profile) {
mcc->def->profile->enabled = true;
}
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4c0676ed53..2a265faae5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -476,6 +476,10 @@ struct CPUArchState {
/* True if in debugger mode. */
bool debugger;
+ bool debug_mode;
+ target_ulong dcsr;
+ target_ulong dpc;
+ target_ulong dscratch[2];
uint64_t mstateen[SMSTATEEN_MAX_COUNT];
uint64_t hstateen[SMSTATEEN_MAX_COUNT];
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index b62dd82fe7..bb59f7ff56 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -467,6 +467,39 @@
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
+#define CSR_DSCRATCH1 0x7b3
+
+/* DCSR fields */
+#define DCSR_XDEBUGVER_SHIFT 28
+#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
+#define DCSR_DEBUGVER(val) ((target_ulong)(val) <<
DCSR_XDEBUGVER_SHIFT)
+#define DCSR_EXTCAUSE_SHIFT 24
+#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
+#define DCSR_CETRIG BIT(19)
+#define DCSR_PELP BIT(18)
+#define DCSR_EBREAKVS BIT(17)
+#define DCSR_EBREAKVU BIT(16)
+#define DCSR_EBREAKM BIT(15)
+#define DCSR_EBREAKS BIT(13)
+#define DCSR_EBREAKU BIT(12)
+#define DCSR_STEPIE BIT(11)
+#define DCSR_STOPCOUNT BIT(10)
+#define DCSR_STOPTIME BIT(9)
+#define DCSR_CAUSE_SHIFT 6
+#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
+#define DCSR_V BIT(5)
+#define DCSR_MPRVEN BIT(4)
+#define DCSR_NMIP BIT(3)
+#define DCSR_STEP BIT(2)
+#define DCSR_PRV_MASK 0x3u
+
+#define DCSR_CAUSE_EBREAK 1
+#define DCSR_CAUSE_TRIGGER 2
+#define DCSR_CAUSE_HALTREQ 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_RESET 5
+#define DCSR_CAUSE_GROUP 6
+#define DCSR_CAUSE_OTHER 7
/* Performance Counters */
#define CSR_MHPMCOUNTER3 0xb03
diff --git a/target/riscv/cpu_cfg_fields.h.inc
b/target/riscv/cpu_cfg_fields.h.inc
index a8c133d663..99b5529161 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
BOOL_FIELD(ext_zimop)
BOOL_FIELD(ext_zcmop)
BOOL_FIELD(ext_ztso)
+BOOL_FIELD(ext_sdext)
BOOL_FIELD(ext_sdtrig)
BOOL_FIELD(ext_smstateen)
BOOL_FIELD(ext_sstc)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 870fad87ac..3e38c943e0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState
*env, int csrno,
return RISCV_EXCP_NONE;
}
+#if !defined(CONFIG_USER_ONLY)
+static RISCVException sdext(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_sdext) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (!env->debug_mode && !env->debugger) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static target_ulong dcsr_visible_mask(CPURISCVState *env)
+{
+ target_ulong mask = (target_ulong)-1;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!riscv_has_ext(env, RVH)) {
+ mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
+ }
+ if (!riscv_has_ext(env, RVS)) {
+ mask &= ~DCSR_EBREAKS;
+ }
+ if (!riscv_has_ext(env, RVU)) {
+ mask &= ~DCSR_EBREAKU;
+ }
+ if (!cpu->cfg.ext_zicfilp) {
+ mask &= ~DCSR_PELP;
+ }
+ if (!cpu->cfg.ext_smdbltrp) {
+ mask &= ~DCSR_CETRIG;
+ }
+
+ return mask;
+}
+
+static RISCVException read_dcsr(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->dcsr & dcsr_visible_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static target_ulong dcsr_writable_mask(CPURISCVState *env)
+{
+ target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
+ DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
+ DCSR_STEP | DCSR_PRV_MASK;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ mask |= DCSR_MPRVEN;
+
+ if (riscv_has_ext(env, RVH)) {
+ mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
+ }
+ if (riscv_has_ext(env, RVS)) {
+ mask |= DCSR_EBREAKS;
+ }
+ if (riscv_has_ext(env, RVU)) {
+ mask |= DCSR_EBREAKU;
+ }
+ if (cpu->cfg.ext_zicfilp) {
+ mask |= DCSR_PELP;
+ }
+ if (cpu->cfg.ext_smdbltrp) {
+ mask |= DCSR_CETRIG;
+ }
+
+ return mask;
+}
+
+static RISCVException write_dcsr(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ target_ulong mask = dcsr_writable_mask(env);
+ target_ulong new_val = env->dcsr;
+
+ new_val &= ~mask;
+ new_val |= val & mask;
+ new_val &= ~DCSR_XDEBUGVER_MASK;
+ new_val |= DCSR_DEBUGVER(4);
+ env->dcsr = new_val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_dpc(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->dpc & get_xepc_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_dpc(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ env->dpc = val & get_xepc_mask(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_dscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
+
+ *val = env->dscratch[index];
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_dscratch(CPURISCVState *env, int csrno,
+ target_ulong val, uintptr_t ra)
+{
+ int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
+
+ env->dscratch[index] = val;
+ return RISCV_EXCP_NONE;
+}
+#endif /* !CONFIG_USER_ONLY */
+
/* Execution environment configuration setup */
static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
target_ulong *val)
@@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata
},
[CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore
},
[CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext
},
+#if !defined(CONFIG_USER_ONLY)
+ [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
+ [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
+ [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch
},
+ [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch
},
+#endif
[CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL,
rmw_xctrctl },
[CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL,
rmw_xctrctl },
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 62c51c8033..52264cf047 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
+ VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
+ VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_sdext = {
+ .name = "cpu/sdext",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = sdtrig_needed,
+ .post_load = sdtrig_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
+ VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
+ VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_ctr,
&vmstate_sstc,
&vmstate_sdtrig,
+ &vmstate_sdext,
NULL
}
};
On 1/26/2026 10:16 AM, Chao Liu wrote:
> __
>
>
> Hi Daniel,
>
> On 1/26/2026 8:47 PM, Daniel Henrique Barboza wrote:
>> Hi Chao,
>>
>> I wasn't able to apply this patch. Applied all Max's series first,
>> then tried to apply yours.
>>
>> The conflict in target/riscv/cpu.c seems to indicate you're basing the
>> patches on top of something that we don't have upstream:
>>
>> diff a/target/riscv/cpu.c b/target/riscv/cpu.c (rejected hunks)
>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj,
>> ResetType type)
>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>> env->vill = true;
>> + env->debug_mode = false;
>> + env->dcsr = DCSR_DEBUGVER(4);
>> + env->dpc = 0;
>> + env->dscratch[0] = 0;
>> + env->dscratch[1] = 0;
>>
>> #ifndef CONFIG_USER_ONLY
>> if (cpu->cfg.ext_sdtrig) {
>>
>>
>> The 'set_ocp_fp8*' lines over here can't be find anywhere else in
>> QEMU, so I suppose you're basing the patches on top of something else.
>>
>> If you could base the patches on top of alistair/riscv-to-apply.next
>> tree, plus Max's patches, that would be great.
>>
> This series is based on the master commit: 06a24591: "disas/riscv: Add
> support of Zvfofp4min extension".
> Max's patches have been merged into the master branch.
I'm afraid there's some confusion ...
$ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
$ git pull
Already up to date.
$ git log --grep="Zvfofp4min"
$
You can also check out here:
https://gitlab.com/qemu-project/qemu/-/commits/master?search=Zvfofp4min
There's no "Zvfofp4min" in QEMU master. In fact, if you're referring to
these patches:
[PATCH 00/18] Add OCP FP8/FP4 and RISC-V Zvfofp8min/Zvfofp4min extension
support
They're still under review. Thanks,
Daniel
> Thanks,
> Chao
>>
>>
>> On 1/20/2026 5:23 AM, Chao Liu wrote:
>>> RISC-V Debug Specification:
>>> https://github.com/riscv/riscv-debug-spec/releases/tag/1.0 <https://
>>> github.com/riscv/riscv-debug-spec/releases/tag/1.0>
>>>
>>> Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
>>> and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
>>> them to Debug Mode (or host debugger access).
>>>
>>> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
>>> <mailto:chao.liu.zevorn@gmail.com>
>>> ---
>>> target/riscv/cpu.c | 9 +++
>>> target/riscv/cpu.h | 4 +
>>> target/riscv/cpu_bits.h | 33 ++++++++
>>> target/riscv/cpu_cfg_fields.h.inc | 1 +
>>> target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
>>> target/riscv/machine.c | 20 +++++
>>> 6 files changed, 193 insertions(+)
>>>
>>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>>> index f1b977f0ee..bd6cff33cf 100644
>>> --- a/target/riscv/cpu.c
>>> +++ b/target/riscv/cpu.c
>>> @@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>>> ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
>>> ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>>> ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
>>> + ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
>>> ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
>>> ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0,
>>> has_priv_1_12),
>>> ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
>>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj,
>>> ResetType type)
>>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>>> env->vill = true;
>>> + env->debug_mode = false;
>>> + env->dcsr = DCSR_DEBUGVER(4);
>>> + env->dpc = 0;
>>> + env->dscratch[0] = 0;
>>> + env->dscratch[1] = 0;
>>> #ifndef CONFIG_USER_ONLY
>>> if (cpu->cfg.ext_sdtrig) {
>>> @@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
>>> */
>>> cpu->cfg.ext_sdtrig = true;
>>> + /* sdext is not fully implemented, so it is disabled by
>>> default. */
>>> + cpu->cfg.ext_sdext = false;
>>> +
>>> if (mcc->def->profile) {
>>> mcc->def->profile->enabled = true;
>>> }
>>> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>> index 4c0676ed53..2a265faae5 100644
>>> --- a/target/riscv/cpu.h
>>> +++ b/target/riscv/cpu.h
>>> @@ -476,6 +476,10 @@ struct CPUArchState {
>>> /* True if in debugger mode. */
>>> bool debugger;
>>> + bool debug_mode;
>>> + target_ulong dcsr;
>>> + target_ulong dpc;
>>> + target_ulong dscratch[2];
>>> uint64_t mstateen[SMSTATEEN_MAX_COUNT];
>>> uint64_t hstateen[SMSTATEEN_MAX_COUNT];
>>> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>>> index b62dd82fe7..bb59f7ff56 100644
>>> --- a/target/riscv/cpu_bits.h
>>> +++ b/target/riscv/cpu_bits.h
>>> @@ -467,6 +467,39 @@
>>> #define CSR_DCSR 0x7b0
>>> #define CSR_DPC 0x7b1
>>> #define CSR_DSCRATCH 0x7b2
>>> +#define CSR_DSCRATCH1 0x7b3
>>> +
>>> +/* DCSR fields */
>>> +#define DCSR_XDEBUGVER_SHIFT 28
>>> +#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
>>> +#define DCSR_DEBUGVER(val) ((target_ulong)(val) <<
>>> DCSR_XDEBUGVER_SHIFT)
>>> +#define DCSR_EXTCAUSE_SHIFT 24
>>> +#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
>>> +#define DCSR_CETRIG BIT(19)
>>> +#define DCSR_PELP BIT(18)
>>> +#define DCSR_EBREAKVS BIT(17)
>>> +#define DCSR_EBREAKVU BIT(16)
>>> +#define DCSR_EBREAKM BIT(15)
>>> +#define DCSR_EBREAKS BIT(13)
>>> +#define DCSR_EBREAKU BIT(12)
>>> +#define DCSR_STEPIE BIT(11)
>>> +#define DCSR_STOPCOUNT BIT(10)
>>> +#define DCSR_STOPTIME BIT(9)
>>> +#define DCSR_CAUSE_SHIFT 6
>>> +#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
>>> +#define DCSR_V BIT(5)
>>> +#define DCSR_MPRVEN BIT(4)
>>> +#define DCSR_NMIP BIT(3)
>>> +#define DCSR_STEP BIT(2)
>>> +#define DCSR_PRV_MASK 0x3u
>>> +
>>> +#define DCSR_CAUSE_EBREAK 1
>>> +#define DCSR_CAUSE_TRIGGER 2
>>> +#define DCSR_CAUSE_HALTREQ 3
>>> +#define DCSR_CAUSE_STEP 4
>>> +#define DCSR_CAUSE_RESET 5
>>> +#define DCSR_CAUSE_GROUP 6
>>> +#define DCSR_CAUSE_OTHER 7
>>> /* Performance Counters */
>>> #define CSR_MHPMCOUNTER3 0xb03
>>> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/
>>> cpu_cfg_fields.h.inc
>>> index a8c133d663..99b5529161 100644
>>> --- a/target/riscv/cpu_cfg_fields.h.inc
>>> +++ b/target/riscv/cpu_cfg_fields.h.inc
>>> @@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
>>> BOOL_FIELD(ext_zimop)
>>> BOOL_FIELD(ext_zcmop)
>>> BOOL_FIELD(ext_ztso)
>>> +BOOL_FIELD(ext_sdext)
>>> BOOL_FIELD(ext_sdtrig)
>>> BOOL_FIELD(ext_smstateen)
>>> BOOL_FIELD(ext_sstc)
>>> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>> index 870fad87ac..3e38c943e0 100644
>>> --- a/target/riscv/csr.c
>>> +++ b/target/riscv/csr.c
>>> @@ -3136,6 +3136,126 @@ static RISCVException
>>> write_mtval(CPURISCVState *env, int csrno,
>>> return RISCV_EXCP_NONE;
>>> }
>>> +#if !defined(CONFIG_USER_ONLY)
>>> +static RISCVException sdext(CPURISCVState *env, int csrno)
>>> +{
>>> + if (!riscv_cpu_cfg(env)->ext_sdext) {
>>> + return RISCV_EXCP_ILLEGAL_INST;
>>> + }
>>> +
>>> + if (!env->debug_mode && !env->debugger) {
>>> + return RISCV_EXCP_ILLEGAL_INST;
>>> + }
>>> +
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static target_ulong dcsr_visible_mask(CPURISCVState *env)
>>> +{
>>> + target_ulong mask = (target_ulong)-1;
>>> + RISCVCPU *cpu = env_archcpu(env);
>>> +
>>> + if (!riscv_has_ext(env, RVH)) {
>>> + mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
>>> + }
>>> + if (!riscv_has_ext(env, RVS)) {
>>> + mask &= ~DCSR_EBREAKS;
>>> + }
>>> + if (!riscv_has_ext(env, RVU)) {
>>> + mask &= ~DCSR_EBREAKU;
>>> + }
>>> + if (!cpu->cfg.ext_zicfilp) {
>>> + mask &= ~DCSR_PELP;
>>> + }
>>> + if (!cpu->cfg.ext_smdbltrp) {
>>> + mask &= ~DCSR_CETRIG;
>>> + }
>>> +
>>> + return mask;
>>> +}
>>> +
>>> +static RISCVException read_dcsr(CPURISCVState *env, int csrno,
>>> + target_ulong *val)
>>> +{
>>> + *val = env->dcsr & dcsr_visible_mask(env);
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static target_ulong dcsr_writable_mask(CPURISCVState *env)
>>> +{
>>> + target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
>>> + DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
>>> + DCSR_STEP | DCSR_PRV_MASK;
>>> + RISCVCPU *cpu = env_archcpu(env);
>>> +
>>> + mask |= DCSR_MPRVEN;
>>> +
>>> + if (riscv_has_ext(env, RVH)) {
>>> + mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
>>> + }
>>> + if (riscv_has_ext(env, RVS)) {
>>> + mask |= DCSR_EBREAKS;
>>> + }
>>> + if (riscv_has_ext(env, RVU)) {
>>> + mask |= DCSR_EBREAKU;
>>> + }
>>> + if (cpu->cfg.ext_zicfilp) {
>>> + mask |= DCSR_PELP;
>>> + }
>>> + if (cpu->cfg.ext_smdbltrp) {
>>> + mask |= DCSR_CETRIG;
>>> + }
>>> +
>>> + return mask;
>>> +}
>>> +
>>> +static RISCVException write_dcsr(CPURISCVState *env, int csrno,
>>> + target_ulong val, uintptr_t ra)
>>> +{
>>> + target_ulong mask = dcsr_writable_mask(env);
>>> + target_ulong new_val = env->dcsr;
>>> +
>>> + new_val &= ~mask;
>>> + new_val |= val & mask;
>>> + new_val &= ~DCSR_XDEBUGVER_MASK;
>>> + new_val |= DCSR_DEBUGVER(4);
>>> + env->dcsr = new_val;
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static RISCVException read_dpc(CPURISCVState *env, int csrno,
>>> + target_ulong *val)
>>> +{
>>> + *val = env->dpc & get_xepc_mask(env);
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static RISCVException write_dpc(CPURISCVState *env, int csrno,
>>> + target_ulong val, uintptr_t ra)
>>> +{
>>> + env->dpc = val & get_xepc_mask(env);
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static RISCVException read_dscratch(CPURISCVState *env, int csrno,
>>> + target_ulong *val)
>>> +{
>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>> +
>>> + *val = env->dscratch[index];
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +
>>> +static RISCVException write_dscratch(CPURISCVState *env, int csrno,
>>> + target_ulong val, uintptr_t ra)
>>> +{
>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>> +
>>> + env->dscratch[index] = val;
>>> + return RISCV_EXCP_NONE;
>>> +}
>>> +#endif /* !CONFIG_USER_ONLY */
>>> +
>>> /* Execution environment configuration setup */
>>> static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
>>> target_ulong *val)
>>> @@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>>> [CSR_TDATA3] = { "tdata3", debug, read_tdata,
>>> write_tdata },
>>> [CSR_TINFO] = { "tinfo", debug, read_tinfo,
>>> write_ignore },
>>> [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext,
>>> write_mcontext },
>>> +#if !defined(CONFIG_USER_ONLY)
>>> + [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
>>> + [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
>>> + [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch,
>>> write_dscratch },
>>> + [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch,
>>> write_dscratch },
>>> +#endif
>>> [CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL,
>>> rmw_xctrctl },
>>> [CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL,
>>> rmw_xctrctl },
>>> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>>> index 62c51c8033..52264cf047 100644
>>> --- a/target/riscv/machine.c
>>> +++ b/target/riscv/machine.c
>>> @@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
>>> VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
>>> VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
>>> VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>> + VMSTATE_END_OF_LIST()
>>> + }
>>> +};
>>> +
>>> +static const VMStateDescription vmstate_sdext = {
>>> + .name = "cpu/sdext",
>>> + .version_id = 1,
>>> + .minimum_version_id = 1,
>>> + .needed = sdtrig_needed,
>>> + .post_load = sdtrig_post_load,
>>> + .fields = (const VMStateField[]) {
>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>> VMSTATE_END_OF_LIST()
>>> }
>>> };
>>> @@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>>> &vmstate_ctr,
>>> &vmstate_sstc,
>>> &vmstate_sdtrig,
>>> + &vmstate_sdext,
>>> NULL
>>> }
>>> };
>>
On 1/26/2026 10:01 PM, Daniel Henrique Barboza wrote:
>
>
> On 1/26/2026 10:16 AM, Chao Liu wrote:
>> __
>>
>>
>> Hi Daniel,
>>
>> On 1/26/2026 8:47 PM, Daniel Henrique Barboza wrote:
>>> Hi Chao,
>>>
>>> I wasn't able to apply this patch. Applied all Max's series first, then tried to apply yours.
>>>
>>> The conflict in target/riscv/cpu.c seems to indicate you're basing the patches on top of something that we don't have upstream:
>>>
>>> diff a/target/riscv/cpu.c b/target/riscv/cpu.c (rejected hunks)
>>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
>>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>>> env->vill = true;
>>> + env->debug_mode = false;
>>> + env->dcsr = DCSR_DEBUGVER(4);
>>> + env->dpc = 0;
>>> + env->dscratch[0] = 0;
>>> + env->dscratch[1] = 0;
>>>
>>> #ifndef CONFIG_USER_ONLY
>>> if (cpu->cfg.ext_sdtrig) {
>>>
>>>
>>> The 'set_ocp_fp8*' lines over here can't be find anywhere else in QEMU, so I suppose you're basing the patches on top of something else.
>>>
>>> If you could base the patches on top of alistair/riscv-to-apply.next tree, plus Max's patches, that would be great.
>>>
>> This series is based on the master commit: 06a24591: "disas/riscv: Add support of Zvfofp4min extension".
>> Max's patches have been merged into the master branch.
>
> I'm afraid there's some confusion ...
>
>
> $ git checkout master
> Already on 'master'
> Your branch is up to date with 'origin/master'.
> $ git pull
> Already up to date.
> $ git log --grep="Zvfofp4min"
> $
>
>
> You can also check out here:
>
> https://gitlab.com/qemu-project/qemu/-/commits/master?search=Zvfofp4min
>
>
> There's no "Zvfofp4min" in QEMU master. In fact, if you're referring to
> these patches:
>
> [PATCH 00/18] Add OCP FP8/FP4 and RISC-V Zvfofp8min/Zvfofp4min extension support
>
> They're still under review. Thanks,
>
> Daniel
>
>
Thanks to Daniel for pointing this out. I will rebase this series of sdext patches on the alistair/riscv-to-apply.next tree and Max's patches for resubmission.
Thanks,
Chao
>> Thanks,
>> Chao
>>>
>>>
>>> On 1/20/2026 5:23 AM, Chao Liu wrote:
>>>> RISC-V Debug Specification:
>>>> https://github.com/riscv/riscv-debug-spec/releases/tag/1.0 <https:// github.com/riscv/riscv-debug-spec/releases/tag/1.0>
>>>>
>>>> Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
>>>> and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
>>>> them to Debug Mode (or host debugger access).
>>>>
>>>> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com> <mailto:chao.liu.zevorn@gmail.com>
>>>> ---
>>>> target/riscv/cpu.c | 9 +++
>>>> target/riscv/cpu.h | 4 +
>>>> target/riscv/cpu_bits.h | 33 ++++++++
>>>> target/riscv/cpu_cfg_fields.h.inc | 1 +
>>>> target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
>>>> target/riscv/machine.c | 20 +++++
>>>> 6 files changed, 193 insertions(+)
>>>>
>>>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>>>> index f1b977f0ee..bd6cff33cf 100644
>>>> --- a/target/riscv/cpu.c
>>>> +++ b/target/riscv/cpu.c
>>>> @@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>>>> ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
>>>> ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>>>> ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
>>>> + ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
>>>> ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
>>>> ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
>>>> ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
>>>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
>>>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>>>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>>>> env->vill = true;
>>>> + env->debug_mode = false;
>>>> + env->dcsr = DCSR_DEBUGVER(4);
>>>> + env->dpc = 0;
>>>> + env->dscratch[0] = 0;
>>>> + env->dscratch[1] = 0;
>>>> #ifndef CONFIG_USER_ONLY
>>>> if (cpu->cfg.ext_sdtrig) {
>>>> @@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
>>>> */
>>>> cpu->cfg.ext_sdtrig = true;
>>>> + /* sdext is not fully implemented, so it is disabled by default. */
>>>> + cpu->cfg.ext_sdext = false;
>>>> +
>>>> if (mcc->def->profile) {
>>>> mcc->def->profile->enabled = true;
>>>> }
>>>> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>>> index 4c0676ed53..2a265faae5 100644
>>>> --- a/target/riscv/cpu.h
>>>> +++ b/target/riscv/cpu.h
>>>> @@ -476,6 +476,10 @@ struct CPUArchState {
>>>> /* True if in debugger mode. */
>>>> bool debugger;
>>>> + bool debug_mode;
>>>> + target_ulong dcsr;
>>>> + target_ulong dpc;
>>>> + target_ulong dscratch[2];
>>>> uint64_t mstateen[SMSTATEEN_MAX_COUNT];
>>>> uint64_t hstateen[SMSTATEEN_MAX_COUNT];
>>>> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>>>> index b62dd82fe7..bb59f7ff56 100644
>>>> --- a/target/riscv/cpu_bits.h
>>>> +++ b/target/riscv/cpu_bits.h
>>>> @@ -467,6 +467,39 @@
>>>> #define CSR_DCSR 0x7b0
>>>> #define CSR_DPC 0x7b1
>>>> #define CSR_DSCRATCH 0x7b2
>>>> +#define CSR_DSCRATCH1 0x7b3
>>>> +
>>>> +/* DCSR fields */
>>>> +#define DCSR_XDEBUGVER_SHIFT 28
>>>> +#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
>>>> +#define DCSR_DEBUGVER(val) ((target_ulong)(val) << DCSR_XDEBUGVER_SHIFT)
>>>> +#define DCSR_EXTCAUSE_SHIFT 24
>>>> +#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
>>>> +#define DCSR_CETRIG BIT(19)
>>>> +#define DCSR_PELP BIT(18)
>>>> +#define DCSR_EBREAKVS BIT(17)
>>>> +#define DCSR_EBREAKVU BIT(16)
>>>> +#define DCSR_EBREAKM BIT(15)
>>>> +#define DCSR_EBREAKS BIT(13)
>>>> +#define DCSR_EBREAKU BIT(12)
>>>> +#define DCSR_STEPIE BIT(11)
>>>> +#define DCSR_STOPCOUNT BIT(10)
>>>> +#define DCSR_STOPTIME BIT(9)
>>>> +#define DCSR_CAUSE_SHIFT 6
>>>> +#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
>>>> +#define DCSR_V BIT(5)
>>>> +#define DCSR_MPRVEN BIT(4)
>>>> +#define DCSR_NMIP BIT(3)
>>>> +#define DCSR_STEP BIT(2)
>>>> +#define DCSR_PRV_MASK 0x3u
>>>> +
>>>> +#define DCSR_CAUSE_EBREAK 1
>>>> +#define DCSR_CAUSE_TRIGGER 2
>>>> +#define DCSR_CAUSE_HALTREQ 3
>>>> +#define DCSR_CAUSE_STEP 4
>>>> +#define DCSR_CAUSE_RESET 5
>>>> +#define DCSR_CAUSE_GROUP 6
>>>> +#define DCSR_CAUSE_OTHER 7
>>>> /* Performance Counters */
>>>> #define CSR_MHPMCOUNTER3 0xb03
>>>> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/ cpu_cfg_fields.h.inc
>>>> index a8c133d663..99b5529161 100644
>>>> --- a/target/riscv/cpu_cfg_fields.h.inc
>>>> +++ b/target/riscv/cpu_cfg_fields.h.inc
>>>> @@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
>>>> BOOL_FIELD(ext_zimop)
>>>> BOOL_FIELD(ext_zcmop)
>>>> BOOL_FIELD(ext_ztso)
>>>> +BOOL_FIELD(ext_sdext)
>>>> BOOL_FIELD(ext_sdtrig)
>>>> BOOL_FIELD(ext_smstateen)
>>>> BOOL_FIELD(ext_sstc)
>>>> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>>> index 870fad87ac..3e38c943e0 100644
>>>> --- a/target/riscv/csr.c
>>>> +++ b/target/riscv/csr.c
>>>> @@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState *env, int csrno,
>>>> return RISCV_EXCP_NONE;
>>>> }
>>>> +#if !defined(CONFIG_USER_ONLY)
>>>> +static RISCVException sdext(CPURISCVState *env, int csrno)
>>>> +{
>>>> + if (!riscv_cpu_cfg(env)->ext_sdext) {
>>>> + return RISCV_EXCP_ILLEGAL_INST;
>>>> + }
>>>> +
>>>> + if (!env->debug_mode && !env->debugger) {
>>>> + return RISCV_EXCP_ILLEGAL_INST;
>>>> + }
>>>> +
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static target_ulong dcsr_visible_mask(CPURISCVState *env)
>>>> +{
>>>> + target_ulong mask = (target_ulong)-1;
>>>> + RISCVCPU *cpu = env_archcpu(env);
>>>> +
>>>> + if (!riscv_has_ext(env, RVH)) {
>>>> + mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
>>>> + }
>>>> + if (!riscv_has_ext(env, RVS)) {
>>>> + mask &= ~DCSR_EBREAKS;
>>>> + }
>>>> + if (!riscv_has_ext(env, RVU)) {
>>>> + mask &= ~DCSR_EBREAKU;
>>>> + }
>>>> + if (!cpu->cfg.ext_zicfilp) {
>>>> + mask &= ~DCSR_PELP;
>>>> + }
>>>> + if (!cpu->cfg.ext_smdbltrp) {
>>>> + mask &= ~DCSR_CETRIG;
>>>> + }
>>>> +
>>>> + return mask;
>>>> +}
>>>> +
>>>> +static RISCVException read_dcsr(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + *val = env->dcsr & dcsr_visible_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static target_ulong dcsr_writable_mask(CPURISCVState *env)
>>>> +{
>>>> + target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
>>>> + DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
>>>> + DCSR_STEP | DCSR_PRV_MASK;
>>>> + RISCVCPU *cpu = env_archcpu(env);
>>>> +
>>>> + mask |= DCSR_MPRVEN;
>>>> +
>>>> + if (riscv_has_ext(env, RVH)) {
>>>> + mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
>>>> + }
>>>> + if (riscv_has_ext(env, RVS)) {
>>>> + mask |= DCSR_EBREAKS;
>>>> + }
>>>> + if (riscv_has_ext(env, RVU)) {
>>>> + mask |= DCSR_EBREAKU;
>>>> + }
>>>> + if (cpu->cfg.ext_zicfilp) {
>>>> + mask |= DCSR_PELP;
>>>> + }
>>>> + if (cpu->cfg.ext_smdbltrp) {
>>>> + mask |= DCSR_CETRIG;
>>>> + }
>>>> +
>>>> + return mask;
>>>> +}
>>>> +
>>>> +static RISCVException write_dcsr(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + target_ulong mask = dcsr_writable_mask(env);
>>>> + target_ulong new_val = env->dcsr;
>>>> +
>>>> + new_val &= ~mask;
>>>> + new_val |= val & mask;
>>>> + new_val &= ~DCSR_XDEBUGVER_MASK;
>>>> + new_val |= DCSR_DEBUGVER(4);
>>>> + env->dcsr = new_val;
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException read_dpc(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + *val = env->dpc & get_xepc_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException write_dpc(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + env->dpc = val & get_xepc_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException read_dscratch(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>>> +
>>>> + *val = env->dscratch[index];
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException write_dscratch(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>>> +
>>>> + env->dscratch[index] = val;
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +#endif /* !CONFIG_USER_ONLY */
>>>> +
>>>> /* Execution environment configuration setup */
>>>> static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
>>>> target_ulong *val)
>>>> @@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>>>> [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
>>>> [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
>>>> [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
>>>> +#if !defined(CONFIG_USER_ONLY)
>>>> + [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
>>>> + [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
>>>> + [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch },
>>>> + [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch },
>>>> +#endif
>>>> [CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL, rmw_xctrctl },
>>>> [CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
>>>> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>>>> index 62c51c8033..52264cf047 100644
>>>> --- a/target/riscv/machine.c
>>>> +++ b/target/riscv/machine.c
>>>> @@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
>>>> VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
>>>> VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
>>>> VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
>>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>>> + VMSTATE_END_OF_LIST()
>>>> + }
>>>> +};
>>>> +
>>>> +static const VMStateDescription vmstate_sdext = {
>>>> + .name = "cpu/sdext",
>>>> + .version_id = 1,
>>>> + .minimum_version_id = 1,
>>>> + .needed = sdtrig_needed,
>>>> + .post_load = sdtrig_post_load,
>>>> + .fields = (const VMStateField[]) {
>>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>>> VMSTATE_END_OF_LIST()
>>>> }
>>>> };
>>>> @@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>>>> &vmstate_ctr,
>>>> &vmstate_sstc,
>>>> &vmstate_sdtrig,
>>>> + &vmstate_sdext,
>>>> NULL
>>>> }
>>>> };
>>>
>
On 1/26/2026 10:01 PM, Daniel Henrique Barboza wrote:
>
>
> On 1/26/2026 10:16 AM, Chao Liu wrote:
>> __
>>
>>
>> Hi Daniel,
>>
>> On 1/26/2026 8:47 PM, Daniel Henrique Barboza wrote:
>>> Hi Chao,
>>>
>>> I wasn't able to apply this patch. Applied all Max's series first, then tried to apply yours.
>>>
>>> The conflict in target/riscv/cpu.c seems to indicate you're basing the patches on top of something that we don't have upstream:
>>>
>>> diff a/target/riscv/cpu.c b/target/riscv/cpu.c (rejected hunks)
>>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
>>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>>> env->vill = true;
>>> + env->debug_mode = false;
>>> + env->dcsr = DCSR_DEBUGVER(4);
>>> + env->dpc = 0;
>>> + env->dscratch[0] = 0;
>>> + env->dscratch[1] = 0;
>>>
>>> #ifndef CONFIG_USER_ONLY
>>> if (cpu->cfg.ext_sdtrig) {
>>>
>>>
>>> The 'set_ocp_fp8*' lines over here can't be find anywhere else in QEMU, so I suppose you're basing the patches on top of something else.
>>>
>>> If you could base the patches on top of alistair/riscv-to-apply.next tree, plus Max's patches, that would be great.
>>>
>> This series is based on the master commit: 06a24591: "disas/riscv: Add support of Zvfofp4min extension".
>> Max's patches have been merged into the master branch.
>
> I'm afraid there's some confusion ...
>
>
> $ git checkout master
> Already on 'master'
> Your branch is up to date with 'origin/master'.
> $ git pull
> Already up to date.
> $ git log --grep="Zvfofp4min"
> $
>
>
> You can also check out here:
>
> https://gitlab.com/qemu-project/qemu/-/commits/master?search=Zvfofp4min
>
>
> There's no "Zvfofp4min" in QEMU master. In fact, if you're referring to
> these patches:
>
> [PATCH 00/18] Add OCP FP8/FP4 and RISC-V Zvfofp8min/Zvfofp4min extension support
>
> They're still under review. Thanks,
>
> Daniel
>
>
Thanks to Daniel for pointing this out. I will rebase this series of sdext patches on the
alistair/riscv-to-apply.next tree and Max’s patches for resubmission.
Thanks,
Chao
>> Thanks,
>> Chao
>>>
>>>
>>> On 1/20/2026 5:23 AM, Chao Liu wrote:
>>>> RISC-V Debug Specification:
>>>> https://github.com/riscv/riscv-debug-spec/releases/tag/1.0 <https:// github.com/riscv/riscv-debug-spec/releases/tag/1.0>
>>>>
>>>> Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
>>>> and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
>>>> them to Debug Mode (or host debugger access).
>>>>
>>>> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com> <mailto:chao.liu.zevorn@gmail.com>
>>>> ---
>>>> target/riscv/cpu.c | 9 +++
>>>> target/riscv/cpu.h | 4 +
>>>> target/riscv/cpu_bits.h | 33 ++++++++
>>>> target/riscv/cpu_cfg_fields.h.inc | 1 +
>>>> target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
>>>> target/riscv/machine.c | 20 +++++
>>>> 6 files changed, 193 insertions(+)
>>>>
>>>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>>>> index f1b977f0ee..bd6cff33cf 100644
>>>> --- a/target/riscv/cpu.c
>>>> +++ b/target/riscv/cpu.c
>>>> @@ -211,6 +211,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>>>> ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
>>>> ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>>>> ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
>>>> + ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
>>>> ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
>>>> ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
>>>> ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
>>>> @@ -788,6 +789,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
>>>> set_ocp_fp8_same_canonical_nan(true, &env->fp_status);
>>>> set_ocp_fp8e5m2_no_signal_nan(true, &env->fp_status);
>>>> env->vill = true;
>>>> + env->debug_mode = false;
>>>> + env->dcsr = DCSR_DEBUGVER(4);
>>>> + env->dpc = 0;
>>>> + env->dscratch[0] = 0;
>>>> + env->dscratch[1] = 0;
>>>> #ifndef CONFIG_USER_ONLY
>>>> if (cpu->cfg.ext_sdtrig) {
>>>> @@ -1140,6 +1146,9 @@ static void riscv_cpu_init(Object *obj)
>>>> */
>>>> cpu->cfg.ext_sdtrig = true;
>>>> + /* sdext is not fully implemented, so it is disabled by default. */
>>>> + cpu->cfg.ext_sdext = false;
>>>> +
>>>> if (mcc->def->profile) {
>>>> mcc->def->profile->enabled = true;
>>>> }
>>>> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>>> index 4c0676ed53..2a265faae5 100644
>>>> --- a/target/riscv/cpu.h
>>>> +++ b/target/riscv/cpu.h
>>>> @@ -476,6 +476,10 @@ struct CPUArchState {
>>>> /* True if in debugger mode. */
>>>> bool debugger;
>>>> + bool debug_mode;
>>>> + target_ulong dcsr;
>>>> + target_ulong dpc;
>>>> + target_ulong dscratch[2];
>>>> uint64_t mstateen[SMSTATEEN_MAX_COUNT];
>>>> uint64_t hstateen[SMSTATEEN_MAX_COUNT];
>>>> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>>>> index b62dd82fe7..bb59f7ff56 100644
>>>> --- a/target/riscv/cpu_bits.h
>>>> +++ b/target/riscv/cpu_bits.h
>>>> @@ -467,6 +467,39 @@
>>>> #define CSR_DCSR 0x7b0
>>>> #define CSR_DPC 0x7b1
>>>> #define CSR_DSCRATCH 0x7b2
>>>> +#define CSR_DSCRATCH1 0x7b3
>>>> +
>>>> +/* DCSR fields */
>>>> +#define DCSR_XDEBUGVER_SHIFT 28
>>>> +#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
>>>> +#define DCSR_DEBUGVER(val) ((target_ulong)(val) << DCSR_XDEBUGVER_SHIFT)
>>>> +#define DCSR_EXTCAUSE_SHIFT 24
>>>> +#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
>>>> +#define DCSR_CETRIG BIT(19)
>>>> +#define DCSR_PELP BIT(18)
>>>> +#define DCSR_EBREAKVS BIT(17)
>>>> +#define DCSR_EBREAKVU BIT(16)
>>>> +#define DCSR_EBREAKM BIT(15)
>>>> +#define DCSR_EBREAKS BIT(13)
>>>> +#define DCSR_EBREAKU BIT(12)
>>>> +#define DCSR_STEPIE BIT(11)
>>>> +#define DCSR_STOPCOUNT BIT(10)
>>>> +#define DCSR_STOPTIME BIT(9)
>>>> +#define DCSR_CAUSE_SHIFT 6
>>>> +#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
>>>> +#define DCSR_V BIT(5)
>>>> +#define DCSR_MPRVEN BIT(4)
>>>> +#define DCSR_NMIP BIT(3)
>>>> +#define DCSR_STEP BIT(2)
>>>> +#define DCSR_PRV_MASK 0x3u
>>>> +
>>>> +#define DCSR_CAUSE_EBREAK 1
>>>> +#define DCSR_CAUSE_TRIGGER 2
>>>> +#define DCSR_CAUSE_HALTREQ 3
>>>> +#define DCSR_CAUSE_STEP 4
>>>> +#define DCSR_CAUSE_RESET 5
>>>> +#define DCSR_CAUSE_GROUP 6
>>>> +#define DCSR_CAUSE_OTHER 7
>>>> /* Performance Counters */
>>>> #define CSR_MHPMCOUNTER3 0xb03
>>>> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/ cpu_cfg_fields.h.inc
>>>> index a8c133d663..99b5529161 100644
>>>> --- a/target/riscv/cpu_cfg_fields.h.inc
>>>> +++ b/target/riscv/cpu_cfg_fields.h.inc
>>>> @@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
>>>> BOOL_FIELD(ext_zimop)
>>>> BOOL_FIELD(ext_zcmop)
>>>> BOOL_FIELD(ext_ztso)
>>>> +BOOL_FIELD(ext_sdext)
>>>> BOOL_FIELD(ext_sdtrig)
>>>> BOOL_FIELD(ext_smstateen)
>>>> BOOL_FIELD(ext_sstc)
>>>> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>>> index 870fad87ac..3e38c943e0 100644
>>>> --- a/target/riscv/csr.c
>>>> +++ b/target/riscv/csr.c
>>>> @@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState *env, int csrno,
>>>> return RISCV_EXCP_NONE;
>>>> }
>>>> +#if !defined(CONFIG_USER_ONLY)
>>>> +static RISCVException sdext(CPURISCVState *env, int csrno)
>>>> +{
>>>> + if (!riscv_cpu_cfg(env)->ext_sdext) {
>>>> + return RISCV_EXCP_ILLEGAL_INST;
>>>> + }
>>>> +
>>>> + if (!env->debug_mode && !env->debugger) {
>>>> + return RISCV_EXCP_ILLEGAL_INST;
>>>> + }
>>>> +
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static target_ulong dcsr_visible_mask(CPURISCVState *env)
>>>> +{
>>>> + target_ulong mask = (target_ulong)-1;
>>>> + RISCVCPU *cpu = env_archcpu(env);
>>>> +
>>>> + if (!riscv_has_ext(env, RVH)) {
>>>> + mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
>>>> + }
>>>> + if (!riscv_has_ext(env, RVS)) {
>>>> + mask &= ~DCSR_EBREAKS;
>>>> + }
>>>> + if (!riscv_has_ext(env, RVU)) {
>>>> + mask &= ~DCSR_EBREAKU;
>>>> + }
>>>> + if (!cpu->cfg.ext_zicfilp) {
>>>> + mask &= ~DCSR_PELP;
>>>> + }
>>>> + if (!cpu->cfg.ext_smdbltrp) {
>>>> + mask &= ~DCSR_CETRIG;
>>>> + }
>>>> +
>>>> + return mask;
>>>> +}
>>>> +
>>>> +static RISCVException read_dcsr(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + *val = env->dcsr & dcsr_visible_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static target_ulong dcsr_writable_mask(CPURISCVState *env)
>>>> +{
>>>> + target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
>>>> + DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
>>>> + DCSR_STEP | DCSR_PRV_MASK;
>>>> + RISCVCPU *cpu = env_archcpu(env);
>>>> +
>>>> + mask |= DCSR_MPRVEN;
>>>> +
>>>> + if (riscv_has_ext(env, RVH)) {
>>>> + mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
>>>> + }
>>>> + if (riscv_has_ext(env, RVS)) {
>>>> + mask |= DCSR_EBREAKS;
>>>> + }
>>>> + if (riscv_has_ext(env, RVU)) {
>>>> + mask |= DCSR_EBREAKU;
>>>> + }
>>>> + if (cpu->cfg.ext_zicfilp) {
>>>> + mask |= DCSR_PELP;
>>>> + }
>>>> + if (cpu->cfg.ext_smdbltrp) {
>>>> + mask |= DCSR_CETRIG;
>>>> + }
>>>> +
>>>> + return mask;
>>>> +}
>>>> +
>>>> +static RISCVException write_dcsr(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + target_ulong mask = dcsr_writable_mask(env);
>>>> + target_ulong new_val = env->dcsr;
>>>> +
>>>> + new_val &= ~mask;
>>>> + new_val |= val & mask;
>>>> + new_val &= ~DCSR_XDEBUGVER_MASK;
>>>> + new_val |= DCSR_DEBUGVER(4);
>>>> + env->dcsr = new_val;
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException read_dpc(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + *val = env->dpc & get_xepc_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException write_dpc(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + env->dpc = val & get_xepc_mask(env);
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException read_dscratch(CPURISCVState *env, int csrno,
>>>> + target_ulong *val)
>>>> +{
>>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>>> +
>>>> + *val = env->dscratch[index];
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +
>>>> +static RISCVException write_dscratch(CPURISCVState *env, int csrno,
>>>> + target_ulong val, uintptr_t ra)
>>>> +{
>>>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>>>> +
>>>> + env->dscratch[index] = val;
>>>> + return RISCV_EXCP_NONE;
>>>> +}
>>>> +#endif /* !CONFIG_USER_ONLY */
>>>> +
>>>> /* Execution environment configuration setup */
>>>> static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
>>>> target_ulong *val)
>>>> @@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>>>> [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
>>>> [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
>>>> [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
>>>> +#if !defined(CONFIG_USER_ONLY)
>>>> + [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
>>>> + [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
>>>> + [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch },
>>>> + [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch },
>>>> +#endif
>>>> [CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL, rmw_xctrctl },
>>>> [CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
>>>> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>>>> index 62c51c8033..52264cf047 100644
>>>> --- a/target/riscv/machine.c
>>>> +++ b/target/riscv/machine.c
>>>> @@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
>>>> VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
>>>> VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
>>>> VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
>>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>>> + VMSTATE_END_OF_LIST()
>>>> + }
>>>> +};
>>>> +
>>>> +static const VMStateDescription vmstate_sdext = {
>>>> + .name = "cpu/sdext",
>>>> + .version_id = 1,
>>>> + .minimum_version_id = 1,
>>>> + .needed = sdtrig_needed,
>>>> + .post_load = sdtrig_post_load,
>>>> + .fields = (const VMStateField[]) {
>>>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>>>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>>>> VMSTATE_END_OF_LIST()
>>>> }
>>>> };
>>>> @@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>>>> &vmstate_ctr,
>>>> &vmstate_sstc,
>>>> &vmstate_sdtrig,
>>>> + &vmstate_sdext,
>>>> NULL
>>>> }
>>>> };
>>>
>
© 2016 - 2026 Red Hat, Inc.