On Thu, Jun 11, 2026 at 10:35 PM Daniel Henrique Barboza <[email protected]> wrote: > > All CPUs have the same amount of triggers: 2 triggers per hart, set via > RV_MAX_TRIGGERS. This is not enough anymore: we'll have at least one > future CPU that will demand more triggers per hart when implementing the > RISC-V Server Ref Platform, requiring at least 11 triggers per hart. > > Parametrize the trigger amount using a new 'num_triggers' property. The > default amount is kept at 2 for backwards compatibility. The new > maximum is bumped to a generous 1024 triggers per hart, which hopefully > will be enough for the foreseeable future. > > The property can be set in two ways: > > - a '.num_triggers' CPU definition flag, allowing CPUs to set a custom > amount inside the CPU def in DEFINE_RISCV_CPU(); > - a new 'num-triggers' user property. The user property has a higher > priority than an existing '.num_triggers' CPU def setting. > > Assuming a hypothetical case where a CPU 'X' is defined with > '.num_triggers = 8': > > - -cpu X,num-triggers=30 => num_triggers set to 30 > - -cpu X (...) => num_triggers set to 8 > > For a CPU that doesn't set '.num_triggers': > > - -cpu rv64,num-triggers=30 => num_triggers set to 30 > - -cpu rv64 (...) => num_triggers set to 2 > > Signed-off-by: Daniel Henrique Barboza <[email protected]> > Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Reviewed-by: Alistair Francis <[email protected]> Alistair > --- > target/riscv/cpu.c | 11 +++++++++++ > target/riscv/cpu.h | 19 ++++++++++++++++++- > target/riscv/debug.c | 16 ++++++++-------- > 3 files changed, 37 insertions(+), 9 deletions(-) > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index b20271a220..6d8f9ad3a6 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -1167,6 +1167,11 @@ static void riscv_cpu_init(Object *obj) > IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); > qdev_init_gpio_in_named(DEVICE(cpu), riscv_cpu_set_nmi, > "riscv.cpu.rnmi", RNMI_MAX); > + > + if (mcc->def->num_triggers) { > + env->num_triggers = mcc->def->num_triggers; > + } > + > #endif /* CONFIG_USER_ONLY */ > > general_user_opts = g_hash_table_new(g_str_hash, g_str_equal); > @@ -2619,6 +2624,8 @@ static const Property riscv_cpu_properties[] = { > DEFAULT_RNMI_IRQVEC), > DEFINE_PROP_UINT64("rnmi-exception-vector", RISCVCPU, env.rnmi_excpvec, > DEFAULT_RNMI_EXCPVEC), > + DEFINE_PROP_UINT32("num-triggers", RISCVCPU, env.num_triggers, > + RV_DEFAULT_NUM_TRIGGERS), > #endif > > DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, > false), > @@ -2764,6 +2771,10 @@ static void riscv_cpu_class_base_init(ObjectClass *c, > const void *data) > !valid_vm_1_10_32[mcc->def->cfg.max_satp_mode]) { > mcc->def->cfg.max_satp_mode = VM_1_10_SV32; > } > + > + if (def->num_triggers) { > + mcc->def->num_triggers = def->num_triggers; > + } > #endif > } > if (def->priv_spec != RISCV_PROFILE_ATTR_UNUSED) { > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index ea92e2c68c..38f02a9dc7 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -189,7 +189,22 @@ extern RISCVCPUImpliedExtsRule > *riscv_multi_ext_implied_rules[]; > #define RV_VLEN_MAX 1024 > #define RV_MAX_MHPMEVENTS 32 > #define RV_MAX_MHPMCOUNTERS 32 > -#define RV_MAX_TRIGGERS 2 > + > +/* > + * The Debug 1.0 spec allows a humongous amount of triggers. Section > + * "Enumeration" says: "The above algorithm reads back tselect so that > + * implementations which have 2^n triggers only need to implement n > + * bits of tselect.". tselect can have up to XLEN bits, so the max > + * theoretical RV_MAX_TRIGGERS value is 2^XLEN. > + * > + * Allowing 2^XLEN triggers per hart is silly so we'll set a max to a > + * modest 1024 triggers, which is way more than what we see current > + * hardware use (most chips uses 2-4 triggers per hart, RISC-V Server > + * Ref requires at least 11). With a 1024 max per hart we'll be set > + * for a long time ... hopefully. > + */ > +#define RV_MAX_TRIGGERS 1024 > +#define RV_DEFAULT_NUM_TRIGGERS 2 > > FIELD(VTYPE, VLMUL, 0, 3) > FIELD(VTYPE, VSEW, 3, 3) > @@ -576,6 +591,8 @@ typedef struct RISCVCPUDef { > RISCVCPUConfig cfg; > bool bare; > const RISCVCSR *custom_csrs; > + /* This is just a setter for env->num_triggers. */ > + uint32_t num_triggers; > } RISCVCPUDef; > > /** > diff --git a/target/riscv/debug.c b/target/riscv/debug.c > index 9a4910c431..ba5bc6ae13 100644 > --- a/target/riscv/debug.c > +++ b/target/riscv/debug.c > @@ -26,6 +26,7 @@ > #include "qemu/osdep.h" > #include "qemu/log.h" > #include "qapi/error.h" > +#include "qemu/error-report.h" > #include "cpu.h" > #include "target/riscv/debug.h" > #include "trace.h" > @@ -1049,14 +1050,13 @@ void riscv_trigger_realize(CPURISCVState *env) > { > int i; > > - /* > - * Alloc env->tdata1/2/3, cpu_breakpoint, cpu_watchpoint and > - * itrigger_timer dynamically. This is overkill now > - * given that they could be static arrays with RV_MAX_TRIGGERS > - * but we'll parametrize the trigger number later, i.e. the > - * array length won't be static. > - */ > - env->num_triggers = RV_MAX_TRIGGERS; > + if (env->num_triggers > RV_MAX_TRIGGERS) { > + error_report( > + "Invalid configuration: 'num-triggers' must be less than %u", > + RV_MAX_TRIGGERS); > + exit(1); > + } > + > env->tdata1 = g_new0(uint64_t, env->num_triggers); > env->tdata2 = g_new0(uint64_t, env->num_triggers); > env->tdata3 = g_new0(uint64_t, env->num_triggers); > -- > 2.43.0 > >
