diff --git a/doc/openocd.texi b/doc/openocd.texi index 025e9e105..e70b53a4a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9491,6 +9491,17 @@ When on, prefer to use System Bus Access to access memory. When off, prefer to use the Program Buffer to access memory. @end deffn +@deffn Command {riscv resume_order} normal|reversed +Some software assumes all harts are executing nearly continuously. Such +software may be sensitive to the order that harts are resumed in. On harts +that don't support hasel, this option allows the user to choose the order the +harts are resumed in. If you are using this option, it's probably masking a +race condition problem in your code. + +Normal order is from lowest hart index to highest. This is the default +behavior. Reversed order is from highest hart index to lowest. +@end deffn + @deffn Command {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value] Set the IR value for the specified JTAG register. This is useful, for example, when using the existing JTAG interface on a Xilinx FPGA by diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 0218a98ce..2e3813d9f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -264,6 +264,11 @@ range_t *expose_csr; /* Same, but for custom registers. */ range_t *expose_custom; +static enum { + RO_NORMAL, + RO_REVERSED +} resume_order; + static int riscv_resume_go_all_harts(struct target *target); void select_dmi_via_bscan(struct target *target) @@ -2141,18 +2146,35 @@ COMMAND_HANDLER(riscv_set_ir) uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - if (!strcmp(CMD_ARGV[0], "idcode")) { + if (!strcmp(CMD_ARGV[0], "idcode")) buf_set_u32(ir_idcode, 0, 32, value); - return ERROR_OK; - } else if (!strcmp(CMD_ARGV[0], "dtmcs")) { + else if (!strcmp(CMD_ARGV[0], "dtmcs")) buf_set_u32(ir_dtmcontrol, 0, 32, value); - return ERROR_OK; - } else if (!strcmp(CMD_ARGV[0], "dmi")) { + else if (!strcmp(CMD_ARGV[0], "dmi")) buf_set_u32(ir_dbus, 0, 32, value); - return ERROR_OK; + else + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_resume_order) +{ + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!strcmp(CMD_ARGV[0], "normal")) { + resume_order = RO_NORMAL; + } else if (!strcmp(CMD_ARGV[0], "reversed")) { + resume_order = RO_REVERSED; } else { + LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]); return ERROR_FAIL; } + + return ERROR_OK; } COMMAND_HANDLER(riscv_use_bscan_tunnel) @@ -2280,6 +2302,15 @@ static const struct command_registration riscv_exec_command_handlers[] = { "command resets those learned values after `wait` scans. It's only " "useful for testing OpenOCD itself." }, + { + .name = "resume_order", + .handler = riscv_resume_order, + .mode = COMMAND_ANY, + .usage = "resume_order normal|reversed", + .help = "Choose the order that harts are resumed in when `hasel` is not " + "supported. Normal order is from lowest hart index to highest. " + "Reversed order is from highest hart index to lowest." + }, { .name = "set_ir", .handler = riscv_set_ir, @@ -2437,7 +2468,27 @@ void riscv_info_init(struct target *target, riscv_info_t *r) static int riscv_resume_go_all_harts(struct target *target) { RISCV_INFO(r); - for (int i = 0; i < riscv_count_harts(target); ++i) { + + /* Dummy variables to make mingw32-gcc happy. */ + int first = 0; + int last = 1; + int step = 1; + switch (resume_order) { + case RO_NORMAL: + first = 0; + last = riscv_count_harts(target) - 1; + step = 1; + break; + case RO_REVERSED: + first = riscv_count_harts(target) - 1; + last = 0; + step = -1; + break; + default: + assert(0); + } + + for (int i = first; i != last + step; i += step) { if (!riscv_hart_enabled(target, i)) continue;