On Wed, 2026-09-09 at 11:48 -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 > > Allow mcontrol/mcontrol6 action=1 when Sdext is enabled. When such a > trigger hits, enter Debug Mode with cause=trigger and stop with > EXCP_DEBUG. > > Also report inst-count triggers in tinfo and read their action field. > > Signed-off-by: Chao Liu <[email protected]> > Reviewed-by: Daniel Henrique Barboza > <[email protected]> > Tested-by: Tao Tang <[email protected]> > Signed-off-by: Daniel Henrique Barboza > <[email protected]>
Acked-by: Alistair Francis <[email protected]> Alistair > --- > target/riscv/tcg/debug.c | 54 > ++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 52 insertions(+), 2 deletions(-) > > diff --git a/target/riscv/tcg/debug.c b/target/riscv/tcg/debug.c > index 2537515f54..aaf2dca17e 100644 > --- a/target/riscv/tcg/debug.c > +++ b/target/riscv/tcg/debug.c > @@ -34,6 +34,7 @@ > #include "exec/watchpoint.h" > #include "system/cpu-timers.h" > #include "exec/icount.h" > +#include "accel/tcg/cpu-loop.h" > > /* > * The following M-mode trigger CSRs are implemented: > @@ -117,6 +118,8 @@ static trigger_action_t > get_trigger_action(CPURISCVState *env, > action = (tdata1 & TYPE6_ACTION) >> 12; > break; > case TRIGGER_TYPE_INST_CNT: > + action = tdata1 & ITRIGGER_ACTION; > + break; > case TRIGGER_TYPE_INT: > case TRIGGER_TYPE_EXCP: > case TRIGGER_TYPE_EXT_SRC: > @@ -287,6 +290,7 @@ static target_ulong textra_validate(CPURISCVState > *env, target_ulong tdata3) > > static void do_trigger_action(CPURISCVState *env, target_ulong > trigger_index) > { > + CPUState *cs = env_cpu(env); > trigger_action_t action = get_trigger_action(env, > trigger_index); > > switch (action) { > @@ -296,6 +300,21 @@ static void do_trigger_action(CPURISCVState > *env, target_ulong trigger_index) > riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); > break; > case DBG_ACTION_DBG_MODE: > + if (!env_archcpu(env)->cfg.ext_sdext) { > + qemu_log_mask(LOG_GUEST_ERROR, > + "trigger action=debug mode requires > Sdext\n"); > + riscv_raise_exception(env, RISCV_EXCP_BREAKPOINT, 0); > + } > + riscv_cpu_enter_debug_mode(env, env->pc, > DCSR_CAUSE_TRIGGER); > + /* > + * If this came from the Trigger Module's CPU > breakpoint/watchpoint, > + * we're already returning via EXCP_DEBUG. Otherwise, stop > now. > + */ > + if (cs->exception_index != EXCP_DEBUG) { > + cs->exception_index = EXCP_DEBUG; > + cpu_loop_exit_restore(cs, GETPC()); > + } > + break; > case DBG_ACTION_TRACE0: > case DBG_ACTION_TRACE1: > case DBG_ACTION_TRACE2: > @@ -448,6 +467,7 @@ static target_ulong > type2_mcontrol_validate(CPURISCVState *env, > { > target_ulong val; > uint32_t size; > + uint32_t action; > > /* validate the generic part first */ > val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH); > @@ -455,11 +475,25 @@ static target_ulong > type2_mcontrol_validate(CPURISCVState *env, > /* validate unimplemented (always zero) bits */ > warn_always_zero_bit(ctrl, TYPE2_MATCH, "match"); > warn_always_zero_bit(ctrl, TYPE2_CHAIN, "chain"); > - warn_always_zero_bit(ctrl, TYPE2_ACTION, "action"); > warn_always_zero_bit(ctrl, TYPE2_TIMING, "timing"); > warn_always_zero_bit(ctrl, TYPE2_SELECT, "select"); > warn_always_zero_bit(ctrl, TYPE2_HIT, "hit"); > > + action = (ctrl & TYPE2_ACTION) >> 12; > + if (action == DBG_ACTION_BP) { > + val |= ctrl & TYPE2_ACTION; > + } else if (action == DBG_ACTION_DBG_MODE) { > + if (env_archcpu(env)->cfg.ext_sdext) { > + val |= ctrl & TYPE2_ACTION; > + } else { > + qemu_log_mask(LOG_GUEST_ERROR, > + "trigger action=debug mode requires > Sdext\n"); > + } > + } else { > + qemu_log_mask(LOG_UNIMP, "trigger action: %u is not > supported\n", > + action); > + } > + > /* validate size encoding */ > size = type2_breakpoint_size(env, ctrl); > if (access_size[size] == -1) { > @@ -576,6 +610,7 @@ static target_ulong > type6_mcontrol6_validate(CPURISCVState *env, > { > target_ulong val; > uint32_t size; > + uint32_t action; > > /* validate the generic part first */ > val = tdata1_validate(env, ctrl, TRIGGER_TYPE_AD_MATCH6); > @@ -583,7 +618,6 @@ static target_ulong > type6_mcontrol6_validate(CPURISCVState *env, > /* validate unimplemented (always zero) bits */ > warn_always_zero_bit(ctrl, TYPE6_MATCH, "match"); > warn_always_zero_bit(ctrl, TYPE6_CHAIN, "chain"); > - warn_always_zero_bit(ctrl, TYPE6_ACTION, "action"); > warn_always_zero_bit(ctrl, TYPE6_SELECT, "select"); > warn_always_zero_bit(ctrl, TYPE6_HIT, "hit"); > > @@ -593,6 +627,21 @@ static target_ulong > type6_mcontrol6_validate(CPURISCVState *env, > warn_always_zero_bit(ctrl, TYPE6_TIMING_0_13, "timing"); > } > > + action = (ctrl & TYPE6_ACTION) >> 12; > + if (action == DBG_ACTION_BP) { > + val |= ctrl & TYPE6_ACTION; > + } else if (action == DBG_ACTION_DBG_MODE) { > + if (env_archcpu(env)->cfg.ext_sdext) { > + val |= ctrl & TYPE6_ACTION; > + } else { > + qemu_log_mask(LOG_GUEST_ERROR, > + "trigger action=debug mode requires > Sdext\n"); > + } > + } else { > + qemu_log_mask(LOG_UNIMP, "trigger action: %u is not > supported\n", > + action); > + } > + > /* validate size encoding */ > size = extract32(ctrl, 16, 4); > if (access_size[size] == -1) { > @@ -959,6 +1008,7 @@ void tdata_csr_write(CPURISCVState *env, int > tdata_index, target_ulong val) > target_ulong tinfo_csr_read(CPURISCVState *env) > { > target_ulong val = BIT(TRIGGER_TYPE_AD_MATCH) | > + BIT(TRIGGER_TYPE_INST_CNT) | > BIT(TRIGGER_TYPE_AD_MATCH6); > > if (debug_trigger_version_1_0(env)) {
