This is an automated email from Gerrit.

"liangzhen <[email protected]>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/9224

-- gerrit

commit 59a4e60b86d912821b390c424a6b4ee349b9629b
Author: liangzhen <[email protected]>
Date:   Mon Mar 31 15:18:52 2025 +0800

    target/riscv: Introduce `riscv set_group` command
    
    Add support for associating a halt/resume group with
    current target or an external trigger via a newly exposed
    configuration option "riscv set_group".
    
    Change-Id: I343dbbfa5c6c1043cf6a939b4d6352adaee3703c
    Signed-off-by: liangzhen <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 63d07533e6..531c00d752 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11874,6 +11874,22 @@ The second argument configures how OpenOCD should use 
the selected trigger featu
 With no parameters, prints current trigger features configuration.
 @end deffn
 
+@deffn {Command} {riscv set_group} <@option{halt_group}|@option{resume_group}> 
group ['trigger' triggernum]
+OpenOCD assigns a hart or a given external trigger into a RISC-V halt/resume 
group.
+This command associates current target or supplied external trigger(s) with 
this halt/resume group.
+
+@option{trigger} and @var{triggernum} Specify the index of the external 
trigger.
+When an external input trigger fires, the harts in the halt/resume group will 
get halted/resume.
+Similarly, all external output triggers will be notified when a hart in the 
halt/resume group halts/resumes.
+
+The only supported value of @var{grouptype} is @option{halt_group}. RISC-V 
resume groups
+are not allowed because the concept of a target resuming due to a different 
reason than
+user's resume request is not supported by OpenOCD and GDB. Allowing 
@var{grouptype} to
+be set to @option{resume_group} might be useful for hardware testing, but 
OpenOCD will
+report a warning.
+@end deffn
+
+
 @subsection RISC-V Authentication Commands
 
 The following commands can be used to authenticate to a RISC-V system. Eg.  a
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 6fa5e025be..3d6a404de8 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -68,12 +68,8 @@ static int riscv013_access_memory(struct target *target, 
const struct riscv_mem_
 static bool riscv013_get_impebreak(const struct target *target);
 static unsigned int riscv013_get_progbufsize(const struct target *target);
 
-enum grouptype {
-       HALT_GROUP,
-       RESUME_GROUP
-};
 static int set_group(struct target *target, bool *supported, unsigned int 
group,
-               enum grouptype grouptype);
+               enum grouptype grouptype, bool is_trigger, unsigned int 
trigger_num);
 
 /**
  * Since almost everything can be accomplish by scanning the dbus register, all
@@ -138,6 +134,8 @@ typedef struct {
         * abstractcs.busy may have remained set. In that case we may need to
         * re-check the busy state before executing these operations. */
        bool abstract_cmd_maybe_busy;
+
+       struct riscv_ext_trigger external_triggers[RISCV_MAX_EXTTRIGGERS];
 } dm013_info_t;
 
 typedef struct {
@@ -1739,7 +1737,7 @@ static int halt_set_dcsr_ebreak(struct target *target)
 
        if (info->haltgroup_supported) {
                bool supported;
-               if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
+               if (set_group(target, &supported, 0, HALT_GROUP, false, 0) != 
ERROR_OK)
                        return ERROR_FAIL;
                if (!supported)
                        LOG_TARGET_ERROR(target, "Couldn't place hart in halt 
group 0. "
@@ -1761,7 +1759,7 @@ static int halt_set_dcsr_ebreak(struct target *target)
        /* Add it back to the halt group. */
        if (info->haltgroup_supported) {
                bool supported;
-               if (set_group(target, &supported, target->smp, HALT_GROUP) != 
ERROR_OK)
+               if (set_group(target, &supported, target->smp, HALT_GROUP, 
false, 0) != ERROR_OK)
                        return ERROR_FAIL;
                if (!supported)
                        LOG_TARGET_ERROR(target, "Couldn't place hart back in 
halt group %d. "
@@ -1792,19 +1790,54 @@ static void deinit_target(struct target *target)
 }
 
 static int set_group(struct target *target, bool *supported, unsigned int 
group,
-               enum grouptype grouptype)
+               enum grouptype grouptype, bool is_trigger, unsigned int 
trigger_num)
 {
-       uint32_t write_val = DM_DMCS2_HGWRITE;
        assert(group <= 31);
+       assert(trigger_num < 16);
+
+       if (!is_trigger && dm013_select_target(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       dm013_info_t *dm = get_dm(target);
+       if (!dm)
+               return ERROR_FAIL;
+       if (is_trigger && 
((dm->external_triggers[trigger_num].haltgroup_was_set &&
+                       dm->external_triggers[trigger_num].haltgroup_num == 
group) ||
+                       (dm->external_triggers[trigger_num].resumegroup_was_set 
&&
+                       dm->external_triggers[trigger_num].resumegroup_num == 
group))) {
+               LOG_TARGET_WARNING(target, "External trigger %d (at address 
dbgbase=0x%" PRIx32 ") "
+                               "for %s group %d has been set.", trigger_num, 
dm->base,
+                               (grouptype == HALT_GROUP) ? "halt" : "resume", 
group);
+               return ERROR_OK;
+       }
+
+       uint32_t write_val = DM_DMCS2_HGWRITE;
        write_val = set_field(write_val, DM_DMCS2_GROUP, group);
        write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == 
HALT_GROUP) ? 0 : 1);
+       write_val = set_field(write_val, DM_DMCS2_DMEXTTRIGGER, trigger_num);
+       write_val = set_field(write_val, DM_DMCS2_HGSELECT,
+                           is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : 
DM_DMCS2_HGSELECT_HARTS);
        if (dm_write(target, DM_DMCS2, write_val) != ERROR_OK)
                return ERROR_FAIL;
        uint32_t read_val;
        if (dm_read(target, &read_val, DM_DMCS2) != ERROR_OK)
                return ERROR_FAIL;
        if (supported)
-               *supported = (get_field(read_val, DM_DMCS2_GROUP) == group);
+               *supported = (get_field(read_val, DM_DMCS2_GROUP) == group &&
+                       get_field(read_val, DM_DMCS2_GROUPTYPE) == ((grouptype 
== HALT_GROUP) ? 0 : 1) &&
+                       get_field(read_val, DM_DMCS2_HGSELECT) ==
+                               (is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : 
DM_DMCS2_HGSELECT_HARTS) &&
+                       get_field(read_val, DM_DMCS2_DMEXTTRIGGER) == 
trigger_num);
+       if (is_trigger && *supported) {
+               if (grouptype == HALT_GROUP) {
+                       dm->external_triggers[trigger_num].haltgroup_was_set = 
true;
+                       dm->external_triggers[trigger_num].haltgroup_num = 
group;
+               } else {
+                       dm->external_triggers[trigger_num].resumegroup_was_set 
= true;
+                       dm->external_triggers[trigger_num].resumegroup_num = 
group;
+               }
+       }
+
        return ERROR_OK;
 }
 
@@ -2152,8 +2185,9 @@ static int examine(struct target *target)
        }
 
        if (target->smp) {
-               if (set_group(target, &info->haltgroup_supported, target->smp, 
HALT_GROUP) != ERROR_OK)
+               if (set_group(target, &info->haltgroup_supported, target->smp, 
HALT_GROUP, false, 0) != ERROR_OK)
                        return ERROR_FAIL;
+
                if (info->haltgroup_supported)
                        LOG_TARGET_INFO(target, "Core %d made part of halt 
group %d.", info->index,
                                        target->smp);
@@ -2888,6 +2922,8 @@ static int init_target(struct command_context *cmd_ctx,
        generic_info->handle_became_unavailable = &handle_became_unavailable;
        generic_info->tick = &tick;
 
+       generic_info->set_group = &set_group;
+
        if (!generic_info->version_specific) {
                generic_info->version_specific = calloc(1, 
sizeof(riscv013_info_t));
                if (!generic_info->version_specific)
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 8054a1c9b7..6f272dd959 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -5576,6 +5576,80 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(riscv_set_group)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       RISCV_INFO(r);
+
+       if (CMD_ARGC < 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       enum grouptype grouptype;
+       if (!strcmp("halt_group", CMD_ARGV[0])) {
+               grouptype = HALT_GROUP;
+       } else if (!strcmp("resume_group", CMD_ARGV[0])) {
+               /* Ext. triggers for resume groups are not supported: neither 
OpenOCD nor GDB
+                * have a concept of hart resuming on its own due to an 
external reason, without
+                * an explicit resume request. */
+               LOG_WARNING("triggers for resume groups are not supported, 
please use with caution.");
+               grouptype = RESUME_GROUP;
+       } else {
+               LOG_ERROR("%s is not a valid argument.", CMD_ARGV[1]);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       unsigned int group;
+       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], group);
+       if (group > 31) {
+               LOG_ERROR("%d is not a valid group number - expecting a number 
in range 0..31.",
+                       group);
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       if (!r->set_group) {
+               LOG_TARGET_ERROR(target, "set_group is not implemented for this 
target.");
+               return ERROR_FAIL;
+       }
+
+       bool is_trigger = false;
+       unsigned int trigger_num = 0;
+       switch (CMD_ARGC) {
+       case 2:
+               break;
+       case 4:
+               if (strcmp("trigger", CMD_ARGV[2]))
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               is_trigger = true;
+               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], trigger_num);
+               if (trigger_num > 15) {
+                       LOG_ERROR("%d is not a valid external trigger number - 
expecting a number in range 0..15.",
+                               trigger_num);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+               break;
+       default:
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       bool supported;
+       if (r->set_group(target, &supported, group, grouptype, is_trigger, 
trigger_num) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (supported)
+               LOG_TARGET_INFO(target, "%s %d made part of %s group %d.",
+                       (is_trigger ? "External trigger" : "Core"),
+                       (is_trigger ? trigger_num : (unsigned 
int)target->coreid),
+                       (grouptype == HALT_GROUP) ? "halt" : "resume", group);
+       else
+               LOG_TARGET_WARNING(target, "%s %d could not be made part of %s 
group %d.",
+                       (is_trigger ? "External trigger" : "Core"),
+                       (is_trigger ? trigger_num : (unsigned 
int)target->coreid),
+                       (grouptype == HALT_GROUP) ? "halt" : "resume", group);
+
+       return ERROR_OK;
+}
+
+
 static const struct command_registration riscv_exec_command_handlers[] = {
        {
                .name = "dump_sample_buf",
@@ -5838,6 +5912,13 @@ static const struct command_registration 
riscv_exec_command_handlers[] = {
                        "When off, users need to take care of memory coherency 
themselves, for example by using "
                        "`riscv exec_progbuf` to execute fence or CMO 
instructions."
        },
+       {
+               .name = "set_group",
+               .handler = riscv_set_group,
+               .mode = COMMAND_ANY,
+               .usage = "<'halt_group'|'resume_group'> group ['trigger' 
triggernum]",
+               .help = "Set a hart or a given external trigger to the 
halt/resume group."
+       },
        {
                .chain = smp_command_handlers
        },
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 2a0a9b95f0..91e62fc692 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -21,6 +21,7 @@ struct riscv_program;
 #define RISCV_MAX_TRIGGERS 32
 #define RISCV_MAX_HWBPS 16
 #define RISCV_MAX_DMS 100
+#define RISCV_MAX_EXTTRIGGERS 16
 
 #define DEFAULT_COMMAND_TIMEOUT_SEC 5
 
@@ -122,6 +123,11 @@ typedef struct {
        char *name;
 } range_list_t;
 
+enum grouptype {
+       HALT_GROUP,
+       RESUME_GROUP
+};
+
 #define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1)
 #define RISCV_TINFO_VERSION_UNKNOWN (-1)
 
@@ -144,6 +150,13 @@ struct riscv_mem_access_args {
        uint32_t increment;
 };
 
+struct riscv_ext_trigger {
+       bool haltgroup_was_set;
+       unsigned int haltgroup_num;
+       bool resumegroup_was_set;
+       unsigned int resumegroup_num;
+};
+
 static inline bool
 riscv_mem_access_is_valid(const struct riscv_mem_access_args args)
 {
@@ -307,6 +320,9 @@ struct riscv_info {
 
        unsigned int (*data_bits)(struct target *target);
 
+       int (*set_group)(struct target *target, bool *supported, unsigned int 
group,
+               enum grouptype grouptype, bool is_trigger, unsigned int 
trigger_num);
+
        COMMAND_HELPER((*print_info), struct target *target);
 
        /* Storage for arch_info of non-custom registers. */

-- 

Reply via email to