diff --git a/doc/openocd.texi b/doc/openocd.texi index 127887365..1d4a2469b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11476,6 +11476,11 @@ 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_external_trigger} value +Associate the supplied external trigger with the halt group for the harts. When +the external trigger fires the harts in the halt group will be halted. +@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 63ae2f6da..4f7ae4e52 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1703,6 +1703,32 @@ static void deinit_target(struct target *target) info->version_specific = NULL; } +static int set_external_trigger(struct target *target, unsigned int group, + grouptype_t grouptype, unsigned int external_trigger) +{ + uint32_t write_val = DM_DMCS2_HGWRITE | DM_DMCS2_HGSELECT; + assert(group <= 31); + assert(external_trigger < 16); + 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, external_trigger); + 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 (get_field(read_val, DM_DMCS2_GROUP) == group && + get_field(read_val, DM_DMCS2_DMEXTTRIGGER) == external_trigger && + get_field(read_val, DM_DMCS2_HGSELECT) == 1) { + LOG_TARGET_INFO(target, "External trigger %d added to group %d", external_trigger, + group); + } else { + LOG_TARGET_ERROR(target, "External trigger %d not supported", external_trigger); + } + + return ERROR_OK; +} + static int set_group(struct target *target, bool *supported, unsigned int group, grouptype_t grouptype) { @@ -2051,6 +2077,9 @@ static int examine(struct target *target) else LOG_TARGET_INFO(target, "Core %d could not be made part of halt group %d.", info->index, target->smp); + if (r->external_trigger) + if (set_external_trigger(target, target->smp, HALT_GROUP, r->external_trigger) != ERROR_OK) + return ERROR_FAIL; } /* Some regression suites rely on seeing 'Examined RISC-V core' to know diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index c0fb845e6..6061fe9b5 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -5262,6 +5262,26 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_external_trigger) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + int value = atoi(CMD_ARGV[0]); + if (value <= 0 || value > 16) { + LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); + return ERROR_FAIL; + } + + r->external_trigger = value; + + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5524,6 +5544,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_external_trigger", + .handler = riscv_set_external_trigger, + .mode = COMMAND_CONFIG, + .usage = "value", + .help = "Add the given external trigger to the halt group" + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 3c02174ec..e84b403f9 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -191,6 +191,9 @@ struct riscv_info { /* The configured approach to translate virtual addresses to physical */ riscv_virt2phys_mode_t virt2phys_mode; + /* Halt group may be associated with an external trigger */ + unsigned int external_trigger; + bool triggers_enumerated; /* Decremented every scan, and when it reaches 0 we clear the learned