aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Savin <43152568+SiFiveGregS@users.noreply.github.com>2019-04-23 16:25:22 -0700
committerGitHub <noreply@github.com>2019-04-23 16:25:22 -0700
commit5190dd4cef6a8a71e592aa637f02e2b9cdbd80e3 (patch)
treef47ef9d54a1526870c92ea4f24980d95c8e8e7ae
parent15f2d35bc6413d89453c64eff39a80dfc52243f5 (diff)
downloadriscv-openocd-5190dd4cef6a8a71e592aa637f02e2b9cdbd80e3.zip
riscv-openocd-5190dd4cef6a8a71e592aa637f02e2b9cdbd80e3.tar.gz
riscv-openocd-5190dd4cef6a8a71e592aa637f02e2b9cdbd80e3.tar.bz2
Support for driving RISC-V DM via Arty's own JTAG chain using BSCAN tunnel (#370)
Including adjustments in response to review comments.
-rw-r--r--doc/openocd.texi5
-rw-r--r--src/target/riscv/riscv-013.c54
-rw-r--r--src/target/riscv/riscv.c159
-rw-r--r--src/target/riscv/riscv.h10
-rw-r--r--tcl/board/sifive-e31arty-onboard-ftdi-raw.cfg10
-rw-r--r--tcl/board/sifive-e31arty-onboard-ftdi.cfg25
-rw-r--r--tcl/interface/ftdi/arty-onboard-ftdi.cfg7
7 files changed, 268 insertions, 2 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 9dfb04b..025e9e1 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -9502,6 +9502,11 @@ When utilizing version 0.11 of the RISC-V Debug Specification,
and DBUS registers, respectively.
@end deffn
+@deffn Command {riscv use_bscan_tunnel} value
+Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of
+the DM transport TAP's instruction register to enable. Supply a value of 0 to disable.
+@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 86820df..27e20d7 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -406,6 +406,10 @@ static void dump_field(int idle, const struct scan_field *field)
static void select_dmi(struct target *target)
{
+ if (bscan_tunnel_ir_width != 0) {
+ select_dmi_via_bscan(target);
+ return;
+ }
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
}
@@ -415,6 +419,9 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
uint8_t in_value[4];
uint8_t out_value[4];
+ if (bscan_tunnel_ir_width != 0)
+ return dtmcontrol_scan_via_bscan(target, out);
+
buf_set_u32(out_value, 0, 32, out);
jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
@@ -469,6 +476,8 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
.out_value = out,
.in_value = in
};
+ uint8_t tunneled_dr_width;
+ struct scan_field tunneled_dr[4];
if (r->reset_delays_wait >= 0) {
r->reset_delays_wait--;
@@ -486,8 +495,44 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out);
buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out);
- /* Assume dbus is already selected. */
- jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
+ /* I wanted to place this code in a different function, but the way JTAG command
+ queueing works in the jtag handling functions, the scan fields either have to be
+ heap allocated, global/static, or else they need to stay on the stack until
+ the jtag_execute_queue() call. Heap or static fields in this case doesn't seem
+ the best fit. Declaring stack based field values in a subsidiary function call wouldn't
+ work. */
+ if (bscan_tunnel_ir_width != 0) {
+ jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+
+ /* I wanted to use struct initialization syntax, but that would involve either
+ declaring the variable within this scope (which would go out of scope at runtime
+ before the JTAG queue gets executed, which is an error waiting to happen), or
+ initializing outside of the check for whether a BSCAN tunnel was active (which
+ would be a waste of CPU time when BSCAN tunnel is not being used. So I declared the
+ struct at the function's top-level, so its lifetime exceeds the point at which
+ the queue is executed, and initializing with assignments here. */
+ memset(tunneled_dr, 0, sizeof(tunneled_dr));
+ tunneled_dr[0].num_bits = 1;
+ tunneled_dr[0].out_value = bscan_one;
+
+ tunneled_dr[1].num_bits = 7;
+ tunneled_dr_width = num_bits;
+ tunneled_dr[1].out_value = &tunneled_dr_width;
+
+ /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so
+ scanning num_bits + 1, and then will right shift the input field after executing the queues */
+ tunneled_dr[2].num_bits = num_bits+1;
+ tunneled_dr[2].out_value = out;
+ tunneled_dr[2].in_value = in;
+
+ tunneled_dr[3].num_bits = 3;
+ tunneled_dr[3].out_value = bscan_zero;
+
+ jtag_add_dr_scan(target->tap, DIM(tunneled_dr), tunneled_dr, TAP_IDLE);
+ } else {
+ /* Assume dbus is already selected. */
+ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
+ }
int idle_count = info->dmi_busy_delay;
if (exec)
@@ -502,6 +547,11 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
return DMI_STATUS_FAILED;
}
+ if (bscan_tunnel_ir_width != 0) {
+ /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
+ buffer_shr(in, num_bytes, 1);
+ }
+
if (data_in)
*data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 2fc3757..34854d0 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -170,6 +170,44 @@ struct scan_field select_idcode = {
.out_value = ir_idcode
};
+
+int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */
+uint8_t bscan_zero[4] = {0};
+uint8_t bscan_one[4] = {1};
+
+uint8_t ir_user4[4] = {0x23};
+struct scan_field select_user4 = {
+ .in_value = NULL,
+ .out_value = ir_user4
+};
+
+
+uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */
+struct scan_field _bscan_tunneled_select_dmi[] = {
+ {
+ .num_bits = 1,
+ .out_value = bscan_zero,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 7,
+ .out_value = bscan_tunneled_ir_width,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 0, /* initialized in riscv_init_target to ir width of DM */
+ .out_value = ir_dbus,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 3,
+ .out_value = bscan_zero,
+ .in_value = NULL,
+ }
+};
+struct scan_field *bscan_tunneled_select_dmi = _bscan_tunneled_select_dmi;
+uint32_t bscan_tunneled_select_dmi_num_fields = DIM(_bscan_tunneled_select_dmi);
+
struct trigger {
uint64_t address;
uint32_t length;
@@ -201,12 +239,101 @@ range_t *expose_custom;
static int riscv_resume_go_all_harts(struct target *target);
+void select_dmi_via_bscan(struct target *target)
+{
+ jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+ jtag_add_dr_scan(target->tap, bscan_tunneled_select_dmi_num_fields, bscan_tunneled_select_dmi, TAP_IDLE);
+}
+
+
+uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out)
+{
+ /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */
+ uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width};
+ uint8_t tunneled_dr_width[4] = {32};
+ uint8_t out_value[5] = {0};
+ uint8_t in_value[5] = {0};
+
+ buf_set_u32(out_value, 0, 32, out);
+
+ struct scan_field tunneled_ir[] = {
+ {
+ .num_bits = 1,
+ .out_value = bscan_zero,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 7,
+ .out_value = tunneled_ir_width,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = bscan_tunnel_ir_width,
+ .out_value = ir_dtmcontrol,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 3,
+ .out_value = bscan_zero,
+ .in_value = NULL,
+ }
+ };
+ struct scan_field tunneled_dr[] = {
+ {
+ .num_bits = 1,
+ .out_value = bscan_one,
+ .in_value = NULL,
+ },
+ {
+ .num_bits = 7,
+ .out_value = tunneled_dr_width,
+ .in_value = NULL,
+ },
+ /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out,
+ so scanning 33 bits and then right shifting the in_value after the scan is completed */
+ {
+ .num_bits = 32+1,
+ .out_value = out_value,
+ .in_value = in_value,
+ },
+ {
+ .num_bits = 3,
+ .out_value = bscan_zero,
+ .in_value = NULL,
+ }
+ };
+
+ jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
+ jtag_add_dr_scan(target->tap, DIM(tunneled_ir), tunneled_ir, TAP_IDLE);
+ jtag_add_dr_scan(target->tap, DIM(tunneled_dr), tunneled_dr, TAP_IDLE);
+ select_dmi_via_bscan(target);
+
+ int retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ LOG_ERROR("failed jtag scan: %d", retval);
+ return retval;
+ }
+
+ /* Note the starting offset is bit 1, not bit 0. In BSCAN tunnel, there is a one-bit TCK skew between
+ output and input */
+ uint32_t in = buf_get_u32(in_value, 1, 32);
+ LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in);
+
+ return in;
+}
+
+
+
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
{
struct scan_field field;
uint8_t in_value[4];
uint8_t out_value[4];
+ if (bscan_tunnel_ir_width != 0)
+ return dtmcontrol_scan_via_bscan(target, out);
+
+
buf_set_u32(out_value, 0, 32, out);
jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
@@ -266,6 +393,12 @@ static int riscv_init_target(struct command_context *cmd_ctx,
select_dbus.num_bits = target->tap->ir_length;
select_idcode.num_bits = target->tap->ir_length;
+ if (bscan_tunnel_ir_width != 0) {
+ select_user4.num_bits = target->tap->ir_length;
+ bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width;
+ bscan_tunneled_select_dmi[2].num_bits = bscan_tunnel_ir_width;
+ }
+
riscv_semihosting_init(target);
target->debug_reason = DBG_REASON_DBGRQ;
@@ -1827,6 +1960,23 @@ COMMAND_HANDLER(riscv_set_ir)
}
}
+COMMAND_HANDLER(riscv_use_bscan_tunnel)
+{
+ int irwidth = 0;
+
+ if (CMD_ARGC > 1) {
+ LOG_ERROR("Command takes at most one argument");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ if (CMD_ARGC == 1)
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth);
+
+ bscan_tunnel_ir_width = irwidth;
+ return ERROR_OK;
+}
+
+
static const struct command_registration riscv_exec_command_handlers[] = {
{
.name = "test_compliance",
@@ -1933,6 +2083,15 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.usage = "riscv set_ir_idcode [idcode|dtmcs|dmi] value",
.help = "Set IR value for specified JTAG register."
},
+ {
+ .name = "use_bscan_tunnel",
+ .handler = riscv_use_bscan_tunnel,
+ .mode = COMMAND_ANY,
+ .usage = "riscv use_bscan_tunnel value",
+ .help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply "
+ "the width of the DM transport TAP's instruction register to "
+ "enable. Supply a value of 0 to disable."
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index ade1bf0..0662efd 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -166,6 +166,16 @@ extern struct scan_field select_dbus;
extern uint8_t ir_idcode[4];
extern struct scan_field select_idcode;
+extern struct scan_field select_user4;
+extern struct scan_field *bscan_tunneled_select_dmi;
+extern uint32_t bscan_tunneled_select_dmi_num_fields;
+extern uint8_t bscan_zero[4];
+extern uint8_t bscan_one[4];
+extern int bscan_tunnel_ir_width;
+
+uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out);
+void select_dmi_via_bscan(struct target *target);
+
/*** OpenOCD Interface */
int riscv_openocd_poll(struct target *target);
diff --git a/tcl/board/sifive-e31arty-onboard-ftdi-raw.cfg b/tcl/board/sifive-e31arty-onboard-ftdi-raw.cfg
new file mode 100644
index 0000000..b7d1ee6
--- /dev/null
+++ b/tcl/board/sifive-e31arty-onboard-ftdi-raw.cfg
@@ -0,0 +1,10 @@
+#
+# Be sure you include the speed and interface before this file
+# Example:
+# -c "adapter_khz 5000" -f "interface/ftdi/arty-onboard-ftdi.cfg" -f "board/sifive-e31arty-onboard-ftdi.cfg"
+
+set _CHIPNAME arty
+jtag newtap $_CHIPNAME bs -irlen 6 -expected-id 0x0362d093
+
+
+echo "Ready for Remote Connections"
diff --git a/tcl/board/sifive-e31arty-onboard-ftdi.cfg b/tcl/board/sifive-e31arty-onboard-ftdi.cfg
new file mode 100644
index 0000000..3d40cfa
--- /dev/null
+++ b/tcl/board/sifive-e31arty-onboard-ftdi.cfg
@@ -0,0 +1,25 @@
+#
+# Be sure you include the speed and interface before this file
+# Example:
+# -c "adapter_khz 5000" -f "interface/ftdi/arty-onboard-ftdi.cfg" -f "board/sifive-e31arty-onboard-ftdi.cfg"
+
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 6; # -expected-id 0x0362d093
+
+set _TARGETNAME $_CHIPNAME.cpu
+
+target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
+$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
+riscv use_bscan_tunnel 5
+
+# Uncomment if hardware has flash
+# flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000
+init
+if {[ info exists pulse_srst]} {
+ ftdi_set_signal nSRST 0
+ ftdi_set_signal nSRST z
+}
+halt
+# Uncomment if hardware has flash
+# flash protect 0 64 last off
+echo "Ready for Remote Connections"
diff --git a/tcl/interface/ftdi/arty-onboard-ftdi.cfg b/tcl/interface/ftdi/arty-onboard-ftdi.cfg
new file mode 100644
index 0000000..825be7d
--- /dev/null
+++ b/tcl/interface/ftdi/arty-onboard-ftdi.cfg
@@ -0,0 +1,7 @@
+interface ftdi
+# ftdi_device_desc "Arty On-board FTDI interface"
+ftdi_vid_pid 0x0403 0x6010
+ftdi_channel 0
+ftdi_layout_init 0x0088 0x008b
+reset_config none
+