[RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state

Chao Liu posted 7 patches 2 weeks, 6 days ago
There is a newer version of this series
[RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Chao Liu 2 weeks, 6 days ago
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
Re: [RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Daniel Henrique Barboza 1 week, 6 days ago
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
>       }
>   };
Re: [RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Chao Liu 1 week, 6 days ago
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
      }
  };
Re: [RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Daniel Henrique Barboza 1 week, 6 days ago

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
>>>       }
>>>   };
>>


Re: [RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Chao Liu 1 week, 6 days ago
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
>>>>       }
>>>>   };
>>>
>

Re: [RFC PATCH v2 2/7] target/riscv: add sdext debug CSRs state
Posted by Chao Liu 1 week, 6 days ago
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
>>>>       }
>>>>   };
>>>
>