Add 'riscv set_ir' command to set IR value for JTAG registers.

This allows using different TAP addresses, for example, if using
BSCANE2 primitives on a Xilinx FPGA.
This commit is contained in:
Darius Rad 2019-01-08 13:30:26 -05:00
parent fe1280438b
commit 00b591a09a
4 changed files with 49 additions and 16 deletions

View File

@ -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

View File

@ -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)

View File

@ -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
};

View File

@ -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 */