diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 5c5e78c14..0d84c4289 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -21,6 +21,8 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_ out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t)); out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t)); out->fields = malloc(sizeof(*out->fields) * (scans)); + if (bscan_tunnel_ir_width != 0) + out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans)); out->last_scan = RISCV_SCAN_TYPE_INVALID; out->read_keys = malloc(sizeof(*out->read_keys) * (scans)); return out; @@ -31,6 +33,8 @@ void riscv_batch_free(struct riscv_batch *batch) free(batch->data_in); free(batch->data_out); free(batch->fields); + if (batch->bscan_ctxt) + free(batch->bscan_ctxt); free(batch->read_keys); free(batch); } @@ -52,7 +56,11 @@ int riscv_batch_run(struct riscv_batch *batch) riscv_batch_add_nop(batch); for (size_t i = 0; i < batch->used_scans; ++i) { - jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); + if (bscan_tunnel_ir_width != 0) + riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i); + else + jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); + if (batch->idle_count > 0) jtag_add_runtest(batch->idle_count, TAP_IDLE); } @@ -62,6 +70,12 @@ int riscv_batch_run(struct riscv_batch *batch) return ERROR_FAIL; } + if (bscan_tunnel_ir_width != 0) { + /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ + for (size_t i = 0; i < batch->used_scans; ++i) + buffer_shr((batch->fields + i)->in_value, sizeof(uint64_t), 1); + } + for (size_t i = 0; i < batch->used_scans; ++i) dump_field(batch->idle_count, batch->fields + i); diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 2ae247250..c409625e9 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -3,6 +3,7 @@ #include "target/target.h" #include "jtag/jtag.h" +#include "riscv.h" enum riscv_scan_type { RISCV_SCAN_TYPE_INVALID, @@ -27,6 +28,11 @@ struct riscv_batch { uint8_t *data_in; struct scan_field *fields; + /* If in BSCAN mode, this field will be allocated (one per scan), + and utilized to tunnel all the scans in the batch. If not in + BSCAN mode, this field is unallocated and stays NULL */ + riscv_bscan_tunneled_scan_context_t *bscan_ctxt; + /* In JTAG we scan out the previous value's output when performing a * scan. This is a pain for users, so we just provide them the * illusion of not having to do this by eliding all but the last NOP. diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index dda639eda..26f8b20c6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -484,8 +484,7 @@ 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]; + riscv_bscan_tunneled_scan_context_t bscan_ctxt; if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; @@ -510,48 +509,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, 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)); - if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { - tunneled_dr[3].num_bits = 1; - tunneled_dr[3].out_value = bscan_one; - tunneled_dr[2].num_bits = 7; - tunneled_dr_width = num_bits; - tunneled_dr[2].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[1].num_bits = num_bits+1; - tunneled_dr[1].out_value = out; - tunneled_dr[1].in_value = in; - - - tunneled_dr[0].num_bits = 3; - tunneled_dr[0].out_value = bscan_zero; - } else { - /* BSCAN_TUNNEL_NESTED_TAP */ - 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); + riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); } else { /* Assume dbus is already selected. */ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 963f67076..41ac87c3a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -3550,3 +3550,43 @@ int riscv_init_registers(struct target *target) return ERROR_OK; } + + +void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, + riscv_bscan_tunneled_scan_context_t *ctxt) +{ + jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + + memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr)); + if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { + ctxt->tunneled_dr[3].num_bits = 1; + ctxt->tunneled_dr[3].out_value = bscan_one; + ctxt->tunneled_dr[2].num_bits = 7; + ctxt->tunneled_dr_width = field->num_bits; + ctxt->tunneled_dr[2].out_value = &ctxt->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 */ + + ctxt->tunneled_dr[1].num_bits = field->num_bits+1; + ctxt->tunneled_dr[1].out_value = field->out_value; + ctxt->tunneled_dr[1].in_value = field->in_value; + + ctxt->tunneled_dr[0].num_bits = 3; + ctxt->tunneled_dr[0].out_value = bscan_zero; + } else { + /* BSCAN_TUNNEL_NESTED_TAP */ + ctxt->tunneled_dr[0].num_bits = 1; + ctxt->tunneled_dr[0].out_value = bscan_one; + ctxt->tunneled_dr[1].num_bits = 7; + ctxt->tunneled_dr_width = field->num_bits; + ctxt->tunneled_dr[1].out_value = &ctxt->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 */ + ctxt->tunneled_dr[2].num_bits = field->num_bits+1; + ctxt->tunneled_dr[2].out_value = field->out_value; + ctxt->tunneled_dr[2].in_value = field->in_value; + ctxt->tunneled_dr[3].num_bits = 3; + ctxt->tunneled_dr[3].out_value = bscan_zero; + } + jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE); +} diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 0b0bc50f2..3dfb4e58d 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -6,6 +6,7 @@ struct riscv_program; #include #include "opcodes.h" #include "gdb_regs.h" +#include "jtag/jtag.h" /* The register cache is statically allocated. */ #define RISCV_MAX_HARTS 32 @@ -147,6 +148,12 @@ typedef struct { int (*hart_count)(struct target *target); } riscv_info_t; +typedef struct { + uint8_t tunneled_dr_width; + struct scan_field tunneled_dr[4]; +} riscv_bscan_tunneled_scan_context_t; + + /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ extern int riscv_command_timeout_sec; @@ -291,4 +298,7 @@ int riscv_init_registers(struct target *target); void riscv_semihosting_init(struct target *target); int riscv_semihosting(struct target *target, int *retval); +void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, + riscv_bscan_tunneled_scan_context_t *ctxt); + #endif