diff --git a/doc/openocd.texi b/doc/openocd.texi index 59923204a..79145156f 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9145,6 +9145,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 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 +way of BSCANE2 primitives that only permit a limited selection of IR +values. + +When utilizing version 0.11 of the RISC-V Debug Specification, +@option{dtmcs} and @option{dmi} set the IR values for the DTMCONTROL +and DBUS registers, respectively. +@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 87f384617..1ef730771 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -396,16 +396,7 @@ static void dump_field(int idle, const struct scan_field *field) static void select_dmi(struct target *target) { - static uint8_t ir_dmi[1] = {DTM_DMI}; - struct scan_field field = { - .num_bits = target->tap->ir_length, - .out_value = ir_dmi, - .in_value = NULL, - .check_value = NULL, - .check_mask = NULL - }; - - jtag_add_ir_scan(target->tap, &field, TAP_IDLE); + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index ee576b966..6e56218ed 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -154,17 +154,17 @@ typedef enum slot { #define MAX_HWBPS 16 #define DRAM_CACHE_SIZE 16 -uint8_t ir_dtmcontrol[1] = {DTMCONTROL}; +uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; struct scan_field select_dtmcontrol = { .in_value = NULL, .out_value = ir_dtmcontrol }; -uint8_t ir_dbus[1] = {DBUS}; +uint8_t ir_dbus[4] = {DBUS}; struct scan_field select_dbus = { .in_value = NULL, .out_value = ir_dbus }; -uint8_t ir_idcode[1] = {0x1}; +uint8_t ir_idcode[4] = {0x1}; struct scan_field select_idcode = { .in_value = NULL, .out_value = ir_idcode @@ -1626,6 +1626,30 @@ COMMAND_HANDLER(riscv_reset_delays) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_ir) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (!strcmp(CMD_ARGV[0], "idcode")) { + buf_set_u32(ir_idcode, 0, 32, value); + return ERROR_OK; + } 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")) { + buf_set_u32(ir_dbus, 0, 32, value); + return ERROR_OK; + } else { + return ERROR_FAIL; + } +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "test_compliance", @@ -1725,6 +1749,13 @@ 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 = "set_ir", + .handler = riscv_set_ir, + .mode = COMMAND_ANY, + .usage = "riscv set_ir_idcode [idcode|dtmcs|dmi] value", + .help = "Set IR value for specified JTAG register." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 4b6ab8cc1..59414fc08 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -151,11 +151,11 @@ static inline riscv_info_t *riscv_info(const struct target *target) { return target->arch_info; } #define RISCV_INFO(R) riscv_info_t *R = riscv_info(target); -extern uint8_t ir_dtmcontrol[1]; +extern uint8_t ir_dtmcontrol[4]; extern struct scan_field select_dtmcontrol; -extern uint8_t ir_dbus[1]; +extern uint8_t ir_dbus[4]; extern struct scan_field select_dbus; -extern uint8_t ir_idcode[1]; +extern uint8_t ir_idcode[4]; extern struct scan_field select_idcode; /*** OpenOCD Interface */