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/+/9222

-- gerrit

commit 846ee2cfd679364d9e4652eb2e63499c30af0a17
Author: liangzhen <[email protected]>
Date:   Tue May 27 17:56:09 2025 +0800

    target/riscv: extend `trigger` controls
    
    * Add control for action mode.
    * Introduce `riscv mtrigger` command.
    * Introduce `riscv *trigger list` command
    
    Change-Id: I4c031a9c442b175baccfdf1bec226a969342c786
    Signed-off-by: liangzhen <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 63d07533e6..7994f88ca2 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11928,13 +11928,26 @@ the target supports, these commands let you
 set those triggers directly. (It's also possible to do so by writing the
 appropriate CSRs.)
 
-@deffn {Command} {riscv etrigger set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] exception_codes
+@option{trigger_action} selects one of the configurable RISC-V trigger actions:
+
+@itemize @minus
+@item @option{exception}:  Raise a breakpoint exception
+@item @option{halt}: Enter Debug Mode
+@item @option{trace_on}:  Trace on
+@item @option{trace_off}: Trace off
+@item @option{trace_notify}: Trace notify
+@item @option{external0}: Send a signal to TM external trigger output 0
+@item @option{external1}: Send a signal to TM external trigger output 1
+@end itemize
+
+@deffn {Command} {riscv etrigger set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] exception_codes [@option{trigger_action}]
 Set an exception trigger (type 5) on the current target, which halts the 
target when it
 fires.  @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} 
control
 which execution modes the trigger fires in. @var{exception_codes} is a bit
 field, where each bit corresponds to an exception code in mcause (defined in 
the
 RISC-V Privileged Spec). The etrigger will fire on the exceptions whose bits 
are
-set in @var{exception_codes}.
+set in @var{exception_codes}. @option{trigger_action} control the desired 
behavior
+on the target when the trigger fires. Defaults to @option{halt}, which halts 
the target.
 
 For details on this trigger type, see the RISC-V Debug Specification.
 @end deffn
@@ -11943,7 +11956,11 @@ For details on this trigger type, see the RISC-V Debug 
Specification.
 Clear the type 5 trigger that was set using @command{riscv etrigger set}.
 @end deffn
 
-@deffn {Command} {riscv icount set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] [@option{pending}] count
+@deffn {Command} {riscv etrigger list}
+List the type 5 trigger that was set using @command{riscv etrigger set}.
+@end deffn
+
+@deffn {Command} {riscv icount set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] [@option{pending}] count [@option{trigger_action}]
 Set an instruction count
 trigger (type 3) on the current target, which halts the target when it fires.
 @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control which
@@ -11952,6 +11969,8 @@ pending bit is set, which is unlikely to be useful 
unless you're debugging the
 hardware implementation of this trigger.
 @var{count} sets the number of instructions to execute before the trigger is
 taken.
+@option{trigger_action} control the desired behavior on the target when the
+trigger fires. Defaults to @option{halt}, which halts the target.
 
 For details on this trigger type, see the RISC-V Debug Specification.
 @end deffn
@@ -11960,21 +11979,56 @@ For details on this trigger type, see the RISC-V 
Debug Specification.
 Clear the type 3 trigger that was set using @command{riscv icount set}.
 @end deffn
 
-@deffn {Command} {riscv itrigger set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] [@option{nmi}] mie_bits
+@deffn {Command} {riscv icount list}
+List the type 3 trigger that was set using @command{riscv icount set}.
+@end deffn
+
+@deffn {Command} {riscv itrigger set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] [@option{nmi}] mie_bits [@option{trigger_action}]
 Set an interrupt trigger (type 4) on the current target, which halts the 
target when it
 fires.  @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} 
control
 which execution modes the trigger fires in.  If [@option{nmi}] is passed then
 the trigger will fire on non-maskable interrupts in those modes. @var{mie_bits}
 controls which interrupts the trigger fires on, using the same bit assignments
 as in the mie CSR (defined in the RISC-V Privileged Spec).
+@option{trigger_action} control the desired behavior on the target when the
+trigger fires. Defaults to @option{halt}, which halts the target.
+
+For details on this trigger type, see the RISC-V Debug Specification.
+@end deffn
+
+@deffn {Command} {riscv itrigger clear}
+Clear the type 4 trigger that was set using @command{riscv itrigger set}.
+@end deffn
+
+@deffn {Command} {riscv itrigger list}
+List the type 4 trigger that was set using @command{riscv itrigger set}.
+@end deffn
+
+@deffn {Command} {riscv mcontrol set} [@option{m}] [@option{s}] [@option{u}] 
[@option{vs}] [@option{vu}] address [@option{trigger_action}]
+Set a match trigger (type 2 or 6) on the current target, which sets the 
desired behavior on
+the target when it fires.  @option{m}, @option{s}, @option{u}, @option{vs}, 
and @option{vu}
+control which execution modes the trigger fires in. @option{execute}, 
@option{store},
+and @option{load} control the trigger how to fire.
+@option{trigger_action} control the desired behavior on the target when the
+trigger fires. Defaults to @option{halt}, which halts the target.
 
 For details on this trigger type, see the RISC-V Debug Specification.
 @end deffn
 
+@deffn {Command} {riscv mcontrol clear} [trigger_id]
+Clear the type 2 or 6 trigger that was set using @command{riscv mcontrol set}.
+@option{trigger_id} specifies the trigger id of a match trigger to clear.
+@end deffn
+
+@deffn {Command} {riscv mcontrol list}
+List the type 2 or 6 trigger that was set using @command{riscv mcontrol set}.
+@end deffn
+
 @deffn {Command} {riscv reserve_trigger} [index @option{on|off}]
 Manages the set of reserved triggers. Reserving a trigger results in OpenOCD
-not using it internally (e.g. skipping it when setting a watchpoint or a
-hardware breakpoint), so that the user or the application has unfettered
+not using it internally (e.g. skipping it when setting a watchpoint, a
+hardware breakpoint, an exception trigger, an instruction trigger or a
+match trigger), so that the user or the application has unfettered
 control over the trigger. By default there are no reserved triggers.
 
 @enumerate
@@ -11986,10 +12040,6 @@ control over the trigger. By default there are no 
reserved triggers.
 
 @end deffn
 
-@deffn {Command} {riscv itrigger clear}
-Clear the type 4 trigger that was set using @command{riscv itrigger set}.
-@end deffn
-
 @subsection RISC-V Program Buffer Commands
 
 Program Buffer is an optional feature of RISC-V targets - it is a mechanism 
that debuggers
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 8054a1c9b7..8eca3fdbb9 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -121,12 +121,24 @@ static uint32_t 
bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bsca
 static struct scan_field *bscan_tunnel_data_register_select_dmi = 
_bscan_tunnel_data_register_select_dmi;
 static uint32_t bscan_tunnel_data_register_select_dmi_num_fields = 
ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi);
 
+enum trigger_action {
+       TRIGGER_ACTION_BREAKPOINT = 0,
+       TRIGGER_ACTION_DEBUG_MODE = 1,
+       TRIGGER_ACTION_TRACE_ON = 2,
+       TRIGGER_ACTION_TRACE_OFF = 3,
+       TRIGGER_ACTION_TRACE_NOTIFY = 4,
+       TRIGGER_ACTION_EXTERNAL0 = 8,
+       TRIGGER_ACTION_EXTERNAL1 = 9
+};
+
 struct trigger {
        uint64_t address;
        uint32_t length;
        uint64_t mask;
        uint64_t value;
        bool is_read, is_write, is_execute;
+       bool is_vs, is_vu, is_m, is_s, is_u;
+       enum trigger_action action;
        int unique_id;
 };
 
@@ -768,6 +780,12 @@ static void trigger_from_breakpoint(struct trigger 
*trigger,
        trigger->is_read = false;
        trigger->is_write = false;
        trigger->is_execute = true;
+       trigger->is_vs = true;
+       trigger->is_vu = true;
+       trigger->is_m = true;
+       trigger->is_s = true;
+       trigger->is_u = true;
+       trigger->action = TRIGGER_ACTION_DEBUG_MODE;
        /* unique_id is unique across both breakpoints and watchpoints. */
        trigger->unique_id = breakpoint->unique_id;
 }
@@ -1171,10 +1189,10 @@ static struct match_triggers_tdata1_fields 
fill_match_triggers_tdata1_fields_t2(
                .common =
                        field_value(CSR_MCONTROL_TYPE(riscv_xlen(target)), 
CSR_TDATA1_TYPE_MCONTROL) |
                        field_value(CSR_MCONTROL_DMODE(riscv_xlen(target)), 1) |
-                       field_value(CSR_MCONTROL_ACTION, 
CSR_MCONTROL_ACTION_DEBUG_MODE) |
-                       field_value(CSR_MCONTROL_M, 1) |
-                       field_value(CSR_MCONTROL_S, !!(r->misa & BIT('S' - 
'A'))) |
-                       field_value(CSR_MCONTROL_U, !!(r->misa & BIT('U' - 
'A'))) |
+                       field_value(CSR_MCONTROL_ACTION, trigger->action) |
+                       field_value(CSR_MCONTROL_M, trigger->is_m) |
+                       field_value(CSR_MCONTROL_S, trigger->is_s && !!(r->misa 
& BIT('S' - 'A'))) |
+                       field_value(CSR_MCONTROL_U, trigger->is_u && !!(r->misa 
& BIT('U' - 'A'))) |
                        field_value(CSR_MCONTROL_EXECUTE, trigger->is_execute) |
                        field_value(CSR_MCONTROL_LOAD, trigger->is_read) |
                        field_value(CSR_MCONTROL_STORE, trigger->is_write),
@@ -1208,12 +1226,12 @@ static struct match_triggers_tdata1_fields 
fill_match_triggers_tdata1_fields_t6(
                .common =
                        field_value(CSR_MCONTROL6_TYPE(riscv_xlen(target)), 
CSR_TDATA1_TYPE_MCONTROL6) |
                        field_value(CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1) 
|
-                       field_value(CSR_MCONTROL6_ACTION, 
CSR_MCONTROL_ACTION_DEBUG_MODE) |
-                       field_value(CSR_MCONTROL6_M, 1) |
-                       field_value(CSR_MCONTROL6_S, misa_s) |
-                       field_value(CSR_MCONTROL6_U, misa_u) |
-                       field_value(CSR_MCONTROL6_VS, misa_h && misa_s) |
-                       field_value(CSR_MCONTROL6_VU, misa_h && misa_u) |
+                       field_value(CSR_MCONTROL6_ACTION, trigger->action) |
+                       field_value(CSR_MCONTROL6_M, trigger->is_m) |
+                       field_value(CSR_MCONTROL6_S, misa_s && trigger->is_s) |
+                       field_value(CSR_MCONTROL6_U, misa_u && trigger->is_u) |
+                       field_value(CSR_MCONTROL6_VS, misa_h && misa_s && 
trigger->is_vs) |
+                       field_value(CSR_MCONTROL6_VU, misa_h && misa_u && 
trigger->is_vu) |
                        field_value(CSR_MCONTROL6_EXECUTE, trigger->is_execute) 
|
                        field_value(CSR_MCONTROL6_LOAD, trigger->is_read) |
                        field_value(CSR_MCONTROL6_STORE, trigger->is_write),
@@ -1356,8 +1374,8 @@ static int maybe_add_trigger_t2_t6(struct target *target,
 }
 
 static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
-                               bool m, bool s, bool u, bool pending, unsigned 
int count,
-                               int unique_id)
+                               bool m, bool s, bool u, bool pending, enum 
trigger_action action,
+                               unsigned int count, int unique_id)
 {
        int ret;
        riscv_reg_t tdata1;
@@ -1367,7 +1385,7 @@ static int maybe_add_trigger_t3(struct target *target, 
bool vs, bool vu,
        tdata1 = 0;
        tdata1 = set_field(tdata1, CSR_ICOUNT_TYPE(riscv_xlen(target)), 
CSR_TDATA1_TYPE_ICOUNT);
        tdata1 = set_field(tdata1, CSR_ICOUNT_DMODE(riscv_xlen(target)), 1);
-       tdata1 = set_field(tdata1, CSR_ICOUNT_ACTION, 
CSR_ICOUNT_ACTION_DEBUG_MODE);
+       tdata1 = set_field(tdata1, CSR_ICOUNT_ACTION, action);
        tdata1 = set_field(tdata1, CSR_ICOUNT_VS, vs);
        tdata1 = set_field(tdata1, CSR_ICOUNT_VU, vu);
        tdata1 = set_field(tdata1, CSR_ICOUNT_PENDING, pending);
@@ -1388,8 +1406,8 @@ static int maybe_add_trigger_t3(struct target *target, 
bool vs, bool vu,
 }
 
 static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu,
-                               bool nmi, bool m, bool s, bool u, riscv_reg_t 
interrupts,
-                               int unique_id)
+                               bool nmi, bool m, bool s, bool u, enum 
trigger_action action,
+                               riscv_reg_t interrupts, int unique_id)
 {
        int ret;
        riscv_reg_t tdata1, tdata2;
@@ -1399,7 +1417,7 @@ static int maybe_add_trigger_t4(struct target *target, 
bool vs, bool vu,
        tdata1 = 0;
        tdata1 = set_field(tdata1, CSR_ITRIGGER_TYPE(riscv_xlen(target)), 
CSR_TDATA1_TYPE_ITRIGGER);
        tdata1 = set_field(tdata1, CSR_ITRIGGER_DMODE(riscv_xlen(target)), 1);
-       tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, 
CSR_ITRIGGER_ACTION_DEBUG_MODE);
+       tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, action);
        tdata1 = set_field(tdata1, CSR_ITRIGGER_VS, vs);
        tdata1 = set_field(tdata1, CSR_ITRIGGER_VU, vu);
        tdata1 = set_field(tdata1, CSR_ITRIGGER_NMI, nmi);
@@ -1421,8 +1439,8 @@ static int maybe_add_trigger_t4(struct target *target, 
bool vs, bool vu,
 }
 
 static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
-                               bool m, bool s, bool u, riscv_reg_t 
exception_codes,
-                               int unique_id)
+                               bool m, bool s, bool u, enum trigger_action 
action,
+                               riscv_reg_t exception_codes, int unique_id)
 {
        int ret;
        riscv_reg_t tdata1, tdata2;
@@ -1432,7 +1450,7 @@ static int maybe_add_trigger_t5(struct target *target, 
bool vs, bool vu,
        tdata1 = 0;
        tdata1 = set_field(tdata1, CSR_ETRIGGER_TYPE(riscv_xlen(target)), 
CSR_TDATA1_TYPE_ETRIGGER);
        tdata1 = set_field(tdata1, CSR_ETRIGGER_DMODE(riscv_xlen(target)), 1);
-       tdata1 = set_field(tdata1, CSR_ETRIGGER_ACTION, 
CSR_ETRIGGER_ACTION_DEBUG_MODE);
+       tdata1 = set_field(tdata1, CSR_ETRIGGER_ACTION, action);
        tdata1 = set_field(tdata1, CSR_ETRIGGER_VS, vs);
        tdata1 = set_field(tdata1, CSR_ETRIGGER_VU, vu);
        tdata1 = set_field(tdata1, CSR_ETRIGGER_M, m);
@@ -1728,6 +1746,12 @@ static void trigger_from_watchpoint(struct trigger 
*trigger,
        trigger->is_read = (watchpoint->rw == WPT_READ || watchpoint->rw == 
WPT_ACCESS);
        trigger->is_write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == 
WPT_ACCESS);
        trigger->is_execute = false;
+       trigger->is_vs = true;
+       trigger->is_vu = true;
+       trigger->is_m = true;
+       trigger->is_s = true;
+       trigger->is_u = true;
+       trigger->action = TRIGGER_ACTION_DEBUG_MODE;
        /* unique_id is unique across both breakpoints and watchpoints. */
        trigger->unique_id = watchpoint->unique_id;
 }
@@ -4989,7 +5013,7 @@ COMMAND_HANDLER(riscv_set_ebreaku)
 COMMAND_HELPER(riscv_clear_trigger, int trigger_id, const char *name)
 {
        struct target *target = get_current_target(CMD_CTX);
-       if (CMD_ARGC != 1)
+       if (CMD_ARGC > 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (find_first_trigger_by_id(target, trigger_id) < 0) {
@@ -4999,6 +5023,92 @@ COMMAND_HELPER(riscv_clear_trigger, int trigger_id, 
const char *name)
        return remove_trigger(target, trigger_id);
 }
 
+static const struct jim_nvp nvp_trigger_actions[] = {
+       { .name = "exception", .value = TRIGGER_ACTION_BREAKPOINT },
+       { .name = "halt", .value = TRIGGER_ACTION_DEBUG_MODE },
+       { .name = "trace_on", .value = TRIGGER_ACTION_TRACE_ON },
+       { .name = "trace_off", .value = TRIGGER_ACTION_TRACE_OFF },
+       { .name = "trace_notify", .value = TRIGGER_ACTION_TRACE_NOTIFY },
+       { .name = "external0", .value = TRIGGER_ACTION_EXTERNAL0 },
+       { .name = "external1", .value = TRIGGER_ACTION_EXTERNAL1 },
+       { .name = NULL, .value = -1 },
+};
+
+COMMAND_HELPER(riscv_list_trigger, int trigger_id, const char *name)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       int trigger_idx = find_first_trigger_by_id(target, trigger_id);
+       if (trigger_idx < 0) {
+               command_print(CMD, "No %s is set.", name);
+               return ERROR_OK;
+       }
+
+       riscv_reg_t tdata1, tdata2;
+       // Select which trigger to use
+       if (riscv_reg_set(target, GDB_REGNO_TSELECT, trigger_idx) != ERROR_OK)
+               return ERROR_FAIL;
+
+       // Read back tdata1, tdata2, (tdata3)
+       if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+               return ERROR_FAIL;
+       if (riscv_reg_get(target, &tdata2, GDB_REGNO_TDATA2) != ERROR_OK)
+               return ERROR_FAIL;
+
+       switch (get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)))) {
+       case CSR_TDATA1_TYPE_ITRIGGER:
+               command_print(CMD, "Interrupt Trigger(%d): vs=%s, vu=%s, 
nmi=%s, m=%s, s=%s, u=%s, "
+                       "interrupts=0x%" PRIx64 ", action=%s", trigger_id,
+                       get_field(tdata1, CSR_ITRIGGER_VS) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_VU) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_NMI) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_M) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_S) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_U) ? "true" : "false",
+                       tdata2, jim_nvp_value2name_simple(nvp_trigger_actions, 
get_field(tdata1, CSR_ITRIGGER_ACTION))->name);
+               break;
+       case CSR_TDATA1_TYPE_ICOUNT:
+                       command_print(CMD, "Icount Trigger(%d): vs=%s, vu=%s, 
pending=%s, m=%s, s=%s, u=%s, "
+                       "count=%" PRIi64 ", action=%s", trigger_id,
+                       get_field(tdata1, CSR_ICOUNT_VS) ? "true" : "false",
+                       get_field(tdata1, CSR_ICOUNT_VU) ? "true" : "false",
+                       get_field(tdata1, CSR_ICOUNT_PENDING) ? "true" : 
"false",
+                       get_field(tdata1, CSR_ICOUNT_M) ? "true" : "false",
+                       get_field(tdata1, CSR_ICOUNT_S) ? "true" : "false",
+                       get_field(tdata1, CSR_ICOUNT_U) ? "true" : "false",
+                       get_field(tdata1, CSR_ICOUNT_COUNT),
+                       jim_nvp_value2name_simple(nvp_trigger_actions, 
get_field(tdata1, CSR_ICOUNT_ACTION))->name);
+               break;
+       case CSR_TDATA1_TYPE_ETRIGGER:
+               command_print(CMD, "Exception Trigger(%d): vs=%s, vu=%s, m=%s, 
s=%s, u=%s, "
+                       "exception_codes=%"  PRIx64 ", action=%s", trigger_id,
+                       get_field(tdata1, CSR_ETRIGGER_VS) ? "true" : "false",
+                       get_field(tdata1, CSR_ETRIGGER_VU) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_M) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_S) ? "true" : "false",
+                       get_field(tdata1, CSR_ITRIGGER_U) ? "true" : "false",
+                       tdata2, jim_nvp_value2name_simple(nvp_trigger_actions, 
get_field(tdata1, CSR_ETRIGGER_ACTION))->name);
+               break;
+       case CSR_TDATA1_TYPE_MCONTROL:
+       case CSR_TDATA1_TYPE_MCONTROL6:
+               command_print(CMD, "Match Trigger(%d): vs=%s, vu=%s, m=%s, 
s=%s, u=%s, execute=%s, "
+                       "store=%s, load=%s, address=0x%" PRIx64 ", action=%s", 
trigger_id,
+                       get_field(tdata1, CSR_MCONTROL6_VS) ? "true" : "false",
+                       get_field(tdata1, CSR_MCONTROL6_VU) ? "true" : "false",
+                       get_field(tdata1, CSR_MCONTROL6_M) ? "true" : "false",
+                       get_field(tdata1, CSR_MCONTROL6_S) ? "true" : "false",
+                       get_field(tdata1, CSR_MCONTROL6_U) ? "true" : "false",
+                       get_field(tdata1, CSR_MCONTROL6_EXECUTE) ? "true" : 
"false",
+                       get_field(tdata1, CSR_MCONTROL6_STORE) ? "true" : 
"false",
+                       get_field(tdata1, CSR_MCONTROL6_LOAD) ? "true" : 
"false",
+                       tdata2, jim_nvp_value2name_simple(nvp_trigger_actions, 
get_field(tdata1, CSR_MCONTROL6_ACTION))->name);
+               break;
+       }
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(riscv_itrigger)
 {
        if (CMD_ARGC < 1)
@@ -5022,6 +5132,7 @@ COMMAND_HANDLER(riscv_itrigger)
                bool m = false;
                bool s = false;
                bool u = false;
+               enum trigger_action action = TRIGGER_ACTION_DEBUG_MODE;
                riscv_reg_t interrupts = 0;
 
                for (unsigned int i = 1; i < CMD_ARGC; i++) {
@@ -5037,6 +5148,8 @@ COMMAND_HANDLER(riscv_itrigger)
                                s = true;
                        else if (!strcmp(CMD_ARGV[i], "u"))
                                u = true;
+                       else if (jim_nvp_name2value_simple(nvp_trigger_actions, 
CMD_ARGV[i])->name)
+                               action = 
jim_nvp_name2value_simple(nvp_trigger_actions, (CMD_ARGV[i]))->value;
                        else
                                COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], 
interrupts);
                }
@@ -5049,7 +5162,7 @@ COMMAND_HANDLER(riscv_itrigger)
                                  "least one of vs, vu, m, s, or u.");
                        return ERROR_FAIL;
                }
-               int result = maybe_add_trigger_t4(target, vs, vu, nmi, m, s, u, 
interrupts, ITRIGGER_UNIQUE_ID);
+               int result = maybe_add_trigger_t4(target, vs, vu, nmi, m, s, u, 
action, interrupts, ITRIGGER_UNIQUE_ID);
                if (result != ERROR_OK)
                        LOG_TARGET_ERROR(target, "Failed to set requested 
itrigger.");
                return result;
@@ -5057,8 +5170,11 @@ COMMAND_HANDLER(riscv_itrigger)
        } else if (!strcmp(CMD_ARGV[0], "clear")) {
                return riscv_clear_trigger(CMD, ITRIGGER_UNIQUE_ID, "itrigger");
 
+       } else if (!strcmp(CMD_ARGV[0], "list")) {
+               return riscv_list_trigger(CMD, ITRIGGER_UNIQUE_ID, "itrigger");
+
        } else {
-               LOG_ERROR("First argument must be either 'set' or 'clear'.");
+               LOG_ERROR("First argument must be either 'set', 'clear' or 
'list'.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
        return ERROR_OK;
@@ -5087,6 +5203,7 @@ COMMAND_HANDLER(riscv_icount)
                bool s = false;
                bool u = false;
                bool pending = false;
+               enum trigger_action action = TRIGGER_ACTION_DEBUG_MODE;
                unsigned int count = 0;
 
                for (unsigned int i = 1; i < CMD_ARGC; i++) {
@@ -5102,6 +5219,8 @@ COMMAND_HANDLER(riscv_icount)
                                s = true;
                        else if (!strcmp(CMD_ARGV[i], "u"))
                                u = true;
+                       else if (jim_nvp_name2value_simple(nvp_trigger_actions, 
CMD_ARGV[i])->name)
+                               action = 
jim_nvp_name2value_simple(nvp_trigger_actions, (CMD_ARGV[i]))->value;
                        else
                                COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], count);
                }
@@ -5114,7 +5233,7 @@ COMMAND_HANDLER(riscv_icount)
                                  "least one of vs, vu, m, s, or u.");
                        return ERROR_FAIL;
                }
-               int result = maybe_add_trigger_t3(target, vs, vu, m, s, u, 
pending, count, ICOUNT_UNIQUE_ID);
+               int result = maybe_add_trigger_t3(target, vs, vu, m, s, u, 
pending, action, count, ICOUNT_UNIQUE_ID);
                if (result != ERROR_OK)
                        LOG_TARGET_ERROR(target, "Failed to set requested 
icount trigger.");
                return result;
@@ -5122,8 +5241,11 @@ COMMAND_HANDLER(riscv_icount)
        } else if (!strcmp(CMD_ARGV[0], "clear")) {
                return riscv_clear_trigger(CMD, ICOUNT_UNIQUE_ID, "icount 
trigger");
 
+       } else if (!strcmp(CMD_ARGV[0], "list")) {
+               return riscv_list_trigger(CMD, ICOUNT_UNIQUE_ID, "icount 
trigger");
+
        } else {
-               LOG_ERROR("First argument must be either 'set' or 'clear'.");
+               LOG_ERROR("First argument must be either 'set', 'clear' or 
'list'.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
        return ERROR_OK;
@@ -5151,6 +5273,7 @@ COMMAND_HANDLER(riscv_etrigger)
                bool m = false;
                bool s = false;
                bool u = false;
+               enum trigger_action action = TRIGGER_ACTION_DEBUG_MODE;
                riscv_reg_t exception_codes = 0;
 
                for (unsigned int i = 1; i < CMD_ARGC; i++) {
@@ -5164,6 +5287,8 @@ COMMAND_HANDLER(riscv_etrigger)
                                s = true;
                        else if (!strcmp(CMD_ARGV[i], "u"))
                                u = true;
+                       else if (jim_nvp_name2value_simple(nvp_trigger_actions, 
CMD_ARGV[i])->name)
+                               action = 
jim_nvp_name2value_simple(nvp_trigger_actions, (CMD_ARGV[i]))->value;
                        else
                                COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], 
exception_codes);
                }
@@ -5176,7 +5301,7 @@ COMMAND_HANDLER(riscv_etrigger)
                                  "least one of vs, vu, m, s, or u.");
                        return ERROR_FAIL;
                }
-               int result = maybe_add_trigger_t5(target, vs, vu, m, s, u, 
exception_codes, ETRIGGER_UNIQUE_ID);
+               int result = maybe_add_trigger_t5(target, vs, vu, m, s, u, 
action, exception_codes, ETRIGGER_UNIQUE_ID);
                if (result != ERROR_OK)
                        LOG_TARGET_ERROR(target, "Failed to set requested 
etrigger.");
                return result;
@@ -5184,8 +5309,146 @@ COMMAND_HANDLER(riscv_etrigger)
        } else if (!strcmp(CMD_ARGV[0], "clear")) {
                return riscv_clear_trigger(CMD, ETRIGGER_UNIQUE_ID, "etrigger");
 
+       } else if (!strcmp(CMD_ARGV[0], "list")) {
+               return riscv_list_trigger(CMD, ETRIGGER_UNIQUE_ID, "etrigger");
+
        } else {
-               LOG_ERROR("First argument must be either 'set' or 'clear'.");
+               LOG_ERROR("First argument must be either 'set', 'clear' or 
'list'.");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       return ERROR_OK;
+}
+
+/* monotonic counter/id-number for match triggers */
+static int mcontrol_unique_id = -CSR_TDATA1_TYPE_MCONTROL6;
+
+COMMAND_HANDLER(riscv_mcontrol)
+{
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct target *target = get_current_target(CMD_CTX);
+       RISCV_INFO(r);
+       int unique_id;
+
+       if (riscv_enumerate_triggers(target) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (!strcmp(CMD_ARGV[0], "set")) {
+               unique_id = mcontrol_unique_id--;
+               bool vs = false;
+               bool vu = false;
+               bool m = false;
+               bool s = false;
+               bool u = false;
+               bool execute = false;
+               bool store = false;
+               bool load = false;
+               enum trigger_action action = TRIGGER_ACTION_DEBUG_MODE;
+               riscv_addr_t address = ULLONG_MAX;
+               uint32_t length = 4;
+
+               for (unsigned int i = 1; i < CMD_ARGC; i++) {
+                       if (!strcmp(CMD_ARGV[i], "vs"))
+                               vs = true;
+                       else if (!strcmp(CMD_ARGV[i], "vu"))
+                               vu = true;
+                       else if (!strcmp(CMD_ARGV[i], "m"))
+                               m = true;
+                       else if (!strcmp(CMD_ARGV[i], "s"))
+                               s = true;
+                       else if (!strcmp(CMD_ARGV[i], "u"))
+                               u = true;
+                       else if (!strcmp(CMD_ARGV[i], "execute"))
+                               execute = true;
+                       else if (!strcmp(CMD_ARGV[i], "store"))
+                               store = true;
+                       else if (!strcmp(CMD_ARGV[i], "load"))
+                               load = true;
+                       else if (jim_nvp_name2value_simple(nvp_trigger_actions, 
CMD_ARGV[i])->name)
+                               action = 
jim_nvp_name2value_simple(nvp_trigger_actions, (CMD_ARGV[i]))->value;
+                       else
+                               COMMAND_PARSE_ADDRESS(CMD_ARGV[i], address);
+               }
+               if (address == ULLONG_MAX) {
+                       LOG_ERROR("Doesn't make sense to set match trigger 
without address.");
+                       return ERROR_FAIL;
+               } else if (!vs && !vu && !m && !s && !u) {
+                       LOG_ERROR("Doesn't make sense to set match trigger 
without at "
+                                 "least one of vs, vu, m, s, or u.");
+                       return ERROR_FAIL;
+               } else if (!execute && !store && !load) {
+                       LOG_ERROR("Doesn't make sense to set match trigger 
without at "
+                                 "least one of execute, store, load.");
+                       return ERROR_FAIL;
+               } else if (execute && (store || load)) {
+                       LOG_ERROR("Doesn't make sense to set match trigger with 
one of "
+                                 "store, load when execute was set.");
+                       return ERROR_FAIL;
+               }
+               struct trigger trigger = {
+                       .address = address,
+                       .length = length,
+                       .mask = ~0LL,
+                       .is_read = load,
+                       .is_write = store,
+                       .is_execute = execute,
+                       .is_vs = vs,
+                       .is_vu = vu,
+                       .is_m = m,
+                       .is_s = s,
+                       .is_u = u,
+                       .action = action,
+                       .unique_id = unique_id,
+               };
+               int result;
+               do {
+                       result = maybe_add_trigger_t2_t6(target, &trigger,
+                                       
fill_match_triggers_tdata1_fields_t2(target, &trigger));
+                       if (result == ERROR_OK)
+                               break;
+                       result = maybe_add_trigger_t2_t6(target, &trigger,
+                                       
fill_match_triggers_tdata1_fields_t6(target, &trigger));
+                       if (result == ERROR_OK)
+                               break;
+               } while (0);
+               if (result != ERROR_OK)
+                       LOG_TARGET_ERROR(target, "Failed to set requested match 
trigger.");
+               return result;
+
+       } else if (!strcmp(CMD_ARGV[0], "clear")) {
+               switch (CMD_ARGC) {
+               case 1:
+                       for (unsigned int i = 0; i < r->trigger_count; i++) {
+                               if (r->trigger_unique_id[i] <= 
-CSR_TDATA1_TYPE_MCONTROL6) {
+                                       if (riscv_clear_trigger(CMD, 
r->trigger_unique_id[i], "match trigger") != ERROR_OK) {
+                                               LOG_TARGET_ERROR(target, 
"Failed to clear match trigger (unique_id=%" PRIi64 ").",
+                                                               
r->trigger_unique_id[i]);
+                                               return ERROR_FAIL;
+                                       }
+                               }
+                       }
+                       break;
+               case 2:
+                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], unique_id);
+                       return riscv_clear_trigger(CMD, unique_id, "match 
trigger");
+               default:
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+
+       } else if (!strcmp(CMD_ARGV[0], "list")) {
+               for (unsigned int i = 0; i < r->trigger_count; i++) {
+                       if (r->trigger_unique_id[i] <= 
-CSR_TDATA1_TYPE_MCONTROL6) {
+                               if (riscv_list_trigger(CMD, 
r->trigger_unique_id[i], "match trigger") != ERROR_OK) {
+                                       LOG_TARGET_ERROR(target, "Failed to 
list match trigger (unique_id=%" PRIi64 ").",
+                                                       
r->trigger_unique_id[i]);
+                                       return ERROR_FAIL;
+                               }
+                       }
+               }
+
+       } else {
+               LOG_ERROR("First argument must be either 'set', 'clear' or 
'list'.");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
        return ERROR_OK;
@@ -5779,22 +6042,33 @@ static const struct command_registration 
riscv_exec_command_handlers[] = {
                .name = "etrigger",
                .handler = riscv_etrigger,
                .mode = COMMAND_EXEC,
-               .usage = "set [vs] [vu] [m] [s] [u] <exception_codes>|clear",
-               .help = "Set or clear a single exception trigger."
+               .usage = "set [vs] [vu] [m] [s] [u] <exception_codes> "
+                       
"[('exception'|'halt'|'trace_on'|'trace_off'|'trace_notify'|'external0'|'external1')]|clear|list",
+               .help = "Set, clear or list a single exception trigger."
        },
        {
                .name = "icount",
                .handler = riscv_icount,
                .mode = COMMAND_EXEC,
-               .usage = "set [vs] [vu] [m] [s] [u] [pending] <count>|clear",
-               .help = "Set or clear a single instruction count trigger."
+               .usage = "set [vs] [vu] [m] [s] [u] [pending] <count> "
+                       
"[('exception'|'halt'|'trace_on'|'trace_off'|'trace_notify'|'external0'|'external1')]|clear|list",
+               .help = "Set, clear or list a single instruction count trigger."
        },
        {
                .name = "itrigger",
                .handler = riscv_itrigger,
                .mode = COMMAND_EXEC,
-               .usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear",
-               .help = "Set or clear a single interrupt trigger."
+               .usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits> "
+                       
"[('exception'|'halt'|'trace_on'|'trace_off'|'trace_notify'|'external0'|'external1')]|clear|list",
+               .help = "Set, clear or list a single interrupt trigger."
+       },
+       {
+               .name = "mcontrol",
+               .handler = riscv_mcontrol,
+               .mode = COMMAND_EXEC,
+               .usage = "set [vs] [vu] [m] [s] [u] [execute] [store] [load] 
<address> "
+                       
"[('exception'|'halt'|'trace_on'|'trace_off'|'trace_notify'|'external0'|'external1')]
 |clear [trigger_id]|list",
+               .help = "Add, remove or list match triggers."
        },
        {
                .name = "exec_progbuf",

-- 

Reply via email to