In current implementation, the number of debug triggers was hardcoded as
RV_MAX_TRIGGERS macro. This commit replaces the fixed value with a new
"num_triggers" configuration, allowing platforms to configure the number
of debug triggers they want.

If no specific option is provided, the default number of debug triggers
remains 2 as before.

A new CPU property "num-triggers" is added to let users configure the
number of debug triggers from the command line. For example:

  -cpu max,num-triggers=8

Signed-off-by: Alvin Chang <[email protected]>
Reviewed-by: Yu-Ming Chang <[email protected]>
---
 target/riscv/cpu.c                | 34 +++++++++++++++++++++++++++++++
 target/riscv/cpu.h                | 12 +++++------
 target/riscv/cpu_cfg_fields.h.inc |  1 +
 target/riscv/csr.c                |  3 ++-
 target/riscv/debug.c              | 23 +++++++++++++--------
 target/riscv/debug.h              |  2 --
 target/riscv/machine.c            | 16 ++++++++++-----
 7 files changed, 69 insertions(+), 22 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 73d4280..5996d13 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1122,6 +1122,7 @@ static void riscv_cpu_init(Object *obj)
     cpu->cfg.cboz_blocksize = 64;
     cpu->cfg.pmp_regions = 16;
     cpu->cfg.pmp_granularity = MIN_RISCV_PMP_GRANULARITY;
+    cpu->cfg.num_triggers = 2;
     cpu->env.vext_ver = VEXT_VERSION_1_00_0;
     cpu->cfg.max_satp_mode = -1;
 
@@ -1644,6 +1645,38 @@ static const PropertyInfo prop_pmp_granularity = {
     .set = prop_pmp_granularity_set,
 };
 
+static void prop_num_triggers_set(Object *obj, Visitor *v, const char *name,
+                                  void *opaque, Error **errp)
+{
+    RISCVCPU *cpu = RISCV_CPU(obj);
+    uint32_t value;
+
+    visit_type_uint32(v, name, &value, errp);
+
+    if (cpu->cfg.num_triggers != value && riscv_cpu_is_vendor(obj)) {
+        cpu_set_prop_err(cpu, name, errp);
+        return;
+    }
+
+    cpu_option_add_user_setting(name, value);
+    cpu->cfg.num_triggers = value;
+}
+
+static void prop_num_triggers_get(Object *obj, Visitor *v, const char *name,
+                                  void *opaque, Error **errp)
+{
+    uint32_t value = RISCV_CPU(obj)->cfg.pmp_regions;
+
+    visit_type_uint32(v, name, &value, errp);
+}
+
+static const PropertyInfo prop_num_triggers = {
+    .type = "uint32",
+    .description = "num-triggers",
+    .get = prop_num_triggers_get,
+    .set = prop_num_triggers_set,
+};
+
 static int priv_spec_from_str(const char *priv_spec_str)
 {
     int priv_version = -1;
@@ -2645,6 +2678,7 @@ static const Property riscv_cpu_properties[] = {
     {.name = "pmp", .info = &prop_pmp},
     {.name = "num-pmp-regions", .info = &prop_num_pmp_regions},
     {.name = "pmp-granularity", .info = &prop_pmp_granularity},
+    {.name = "num-triggers", .info = &prop_num_triggers},
 
     {.name = "priv_spec", .info = &prop_priv_spec},
     {.name = "vext_spec", .info = &prop_vext_spec},
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 36e7f10..b32ed78 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -450,13 +450,13 @@ struct CPUArchState {
 
     /* trigger module */
     target_ulong trigger_cur;
-    target_ulong tdata1[RV_MAX_TRIGGERS];
-    target_ulong tdata2[RV_MAX_TRIGGERS];
-    target_ulong tdata3[RV_MAX_TRIGGERS];
+    target_ulong *tdata1;
+    target_ulong *tdata2;
+    target_ulong *tdata3;
     target_ulong mcontext;
-    struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS];
-    struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS];
-    QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS];
+    struct CPUBreakpoint **cpu_breakpoint;
+    struct CPUWatchpoint **cpu_watchpoint;
+    QEMUTimer **itrigger_timer;
     int64_t last_icount;
     bool itrigger_enabled;
 
diff --git a/target/riscv/cpu_cfg_fields.h.inc 
b/target/riscv/cpu_cfg_fields.h.inc
index a154ecd..840e8c4 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -167,6 +167,7 @@ TYPED_FIELD(uint16_t, cbop_blocksize, 0)
 TYPED_FIELD(uint16_t, cboz_blocksize, 0)
 TYPED_FIELD(uint8_t,  pmp_regions, 0)
 TYPED_FIELD(uint32_t, pmp_granularity, 0)
+TYPED_FIELD(uint32_t, num_triggers, 0)
 
 TYPED_FIELD(int8_t, max_satp_mode, -1)
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 5c91658..fce5f94 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -5346,7 +5346,8 @@ static RISCVException read_tdata(CPURISCVState *env, int 
csrno,
                                  target_ulong *val)
 {
     /* return 0 in tdata1 to end the trigger enumeration */
-    if (env->trigger_cur >= RV_MAX_TRIGGERS && csrno == CSR_TDATA1) {
+    if (env->trigger_cur >= riscv_cpu_cfg(env)->num_triggers &&
+        csrno == CSR_TDATA1) {
         *val = 0;
         return RISCV_EXCP_NONE;
     }
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 5664466..460363f 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -171,7 +171,7 @@ target_ulong tselect_csr_read(CPURISCVState *env)
 
 void tselect_csr_write(CPURISCVState *env, target_ulong val)
 {
-    if (val < RV_MAX_TRIGGERS) {
+    if (val < riscv_cpu_cfg(env)->num_triggers) {
         env->trigger_cur = val;
     }
 }
@@ -700,7 +700,7 @@ static bool check_itrigger_priv(CPURISCVState *env, int 
index)
 bool riscv_itrigger_enabled(CPURISCVState *env)
 {
     int count;
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -720,7 +720,7 @@ bool riscv_itrigger_enabled(CPURISCVState *env)
 void helper_itrigger_match(CPURISCVState *env)
 {
     int count;
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -749,7 +749,7 @@ static void riscv_itrigger_update_count(CPURISCVState *env)
     int64_t last_icount = env->last_icount, current_icount;
     current_icount = env->last_icount = icount_get_raw();
 
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -949,7 +949,7 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
     int i;
 
     QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-        for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+        for (i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
             trigger_type = get_trigger_type(env, i);
 
             if (!trigger_common_match(env, trigger_type, i)) {
@@ -995,7 +995,7 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
CPUWatchpoint *wp)
     int flags;
     int i;
 
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
         trigger_type = get_trigger_type(env, i);
 
         if (!trigger_common_match(env, trigger_type, i)) {
@@ -1046,9 +1046,16 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
CPUWatchpoint *wp)
 
 void riscv_trigger_realize(CPURISCVState *env)
 {
+    uint32_t num_triggers = riscv_cpu_cfg(env)->num_triggers;
     int i;
 
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    env->tdata1 = g_new0(target_ulong, num_triggers);
+    env->tdata2 = g_new0(target_ulong, num_triggers);
+    env->tdata3 = g_new0(target_ulong, num_triggers);
+    env->cpu_breakpoint = g_new0(struct CPUBreakpoint *, num_triggers);
+    env->cpu_watchpoint = g_new0(struct CPUWatchpoint *, num_triggers);
+    env->itrigger_timer = g_new0(QEMUTimer *, num_triggers);
+    for (i = 0; i < num_triggers; i++) {
         env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                               riscv_itrigger_timer_cb, env);
     }
@@ -1060,7 +1067,7 @@ void riscv_trigger_reset_hold(CPURISCVState *env)
     int i;
 
     /* init to type 2 triggers */
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (i = 0; i < riscv_cpu_cfg(env)->num_triggers; i++) {
         /*
          * type = TRIGGER_TYPE_AD_MATCH
          * dmode = 0 (both debug and M-mode can write tdata)
diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index f76b8f9..d3aae61 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -24,8 +24,6 @@
 
 #include "exec/breakpoint.h"
 
-#define RV_MAX_TRIGGERS         2
-
 /* register index of tdata CSRs */
 enum {
     TDATA1 = 0,
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 18d790a..c7244b7 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -239,15 +239,21 @@ static int debug_post_load(void *opaque, int version_id)
 
 static const VMStateDescription vmstate_debug = {
     .name = "cpu/debug",
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .needed = debug_needed,
     .post_load = debug_post_load,
     .fields = (const VMStateField[]) {
         VMSTATE_UINTTL(env.trigger_cur, RISCVCPU),
-        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_VARRAY_UINT32(env.tdata1, RISCVCPU,
+                              cfg.num_triggers, 0,
+                              vmstate_info_uinttl, target_ulong),
+        VMSTATE_VARRAY_UINT32(env.tdata2, RISCVCPU,
+                              cfg.num_triggers, 0,
+                              vmstate_info_uinttl, target_ulong),
+        VMSTATE_VARRAY_UINT32(env.tdata3, RISCVCPU,
+                              cfg.num_triggers, 0,
+                              vmstate_info_uinttl, target_ulong),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.43.0


Reply via email to