On Mon, 2026-08-31 at 11:10 -0300, Daniel Henrique Barboza wrote:
> From: Chao Liu <[email protected]>
>
> 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).
>
> The Sdext is not fully implemented, so it is disabled by default.
>
> Signed-off-by: Chao Liu <[email protected]>
> Reviewed-by: Daniel Henrique Barboza
> <[email protected]>
> Tested-by: Tao Tang <[email protected]>
You are missing your Signed-off-by line here (and on the other
patches).
> ---
> target/riscv/cpu.c | 7 ++
> target/riscv/cpu.h | 4 +
> target/riscv/cpu_bits.h | 33 ++++++++
> target/riscv/cpu_cfg_fields.h.inc | 1 +
> target/riscv/machine.c | 20 +++++
> target/riscv/tcg/csr.c | 126
> ++++++++++++++++++++++++++++++
> 6 files changed, 191 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 61109672d6..c2078473aa 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -248,6 +248,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_INTERNAL_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0,
> has_priv_1_12),
> @@ -1091,6 +1092,12 @@ static void riscv_cpu_reset_hold(Object *obj,
> ResetType type)
>
> #ifndef CONFIG_USER_ONLY
> #ifdef CONFIG_TCG
> + env->debug_mode = false;
> + env->dcsr = DCSR_DEBUGVER(4);
> + env->dpc = 0;
> + env->dscratch[0] = 0;
> + env->dscratch[1] = 0;
> +
> if (cpu->cfg.debug || cpu->cfg.ext_sdtrig) {
> riscv_trigger_reset_hold(env);
> }
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 718b66487a..74bddc8415 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -507,6 +507,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 c01050ce2b..769c945517 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 f91c780299..24f3606f94 100644
> --- a/target/riscv/cpu_cfg_fields.h.inc
> +++ b/target/riscv/cpu_cfg_fields.h.inc
> @@ -105,6 +105,7 @@ BOOL_FIELD(ext_zvfbfmin)
> BOOL_FIELD(ext_zvfbfwma)
> BOOL_FIELD(ext_zvfh)
> BOOL_FIELD(ext_zvfhmin)
> +BOOL_FIELD(ext_sdext)
> BOOL_FIELD(ext_sdtrig)
> BOOL_FIELD(ext_smaia)
> BOOL_FIELD(ext_ssaia)
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 74edb8c2b5..aba162d0f1 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -302,6 +302,25 @@ static const VMStateDescription vmstate_debug =
> {
> VMSTATE_VARRAY_UINT32(env.tdata3, RISCVCPU,
> env.num_triggers, 0,
> vmstate_info_uint64, uint64_t),
> + 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 = debug_needed,
> + .post_load = debug_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()
> }
> };
> @@ -577,6 +596,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_ctr,
> &vmstate_sstc,
> &vmstate_mseccfg,
> + &vmstate_sdext,
> NULL
> }
> };
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index bd4b6dc114..988261cccf 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -3207,6 +3207,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;
This should be a 32-bit value, as the register is always 32-bit
Alistair
> + 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)
> @@ -6435,6 +6555,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 },