BSCAN batch fix (#422)

* fix for batch scans not honoring presence of BSCAN tunnel

* fix formatting to placate checkpatch

* replace DIM with ARRAY_SIZE

* Refactor code that adds a bscan tunneled scan.

* Move bscan tunnel context to the batch structure, and in array
form, one per scan

* adjust code that was inconsistent with project code formatting standards
mem64
Greg Savin 2019-11-12 09:00:35 -08:00 committed by Tim Newsome
parent f93ede5401
commit b7bd3f8d47
5 changed files with 73 additions and 45 deletions

View File

@ -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_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t));
out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t)); out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t));
out->fields = malloc(sizeof(*out->fields) * (scans)); 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->last_scan = RISCV_SCAN_TYPE_INVALID;
out->read_keys = malloc(sizeof(*out->read_keys) * (scans)); out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
return out; return out;
@ -31,6 +33,8 @@ void riscv_batch_free(struct riscv_batch *batch)
free(batch->data_in); free(batch->data_in);
free(batch->data_out); free(batch->data_out);
free(batch->fields); free(batch->fields);
if (batch->bscan_ctxt)
free(batch->bscan_ctxt);
free(batch->read_keys); free(batch->read_keys);
free(batch); free(batch);
} }
@ -52,7 +56,11 @@ int riscv_batch_run(struct riscv_batch *batch)
riscv_batch_add_nop(batch); riscv_batch_add_nop(batch);
for (size_t i = 0; i < batch->used_scans; ++i) { for (size_t i = 0; i < batch->used_scans; ++i) {
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); jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
if (batch->idle_count > 0) if (batch->idle_count > 0)
jtag_add_runtest(batch->idle_count, TAP_IDLE); jtag_add_runtest(batch->idle_count, TAP_IDLE);
} }
@ -62,6 +70,12 @@ int riscv_batch_run(struct riscv_batch *batch)
return ERROR_FAIL; 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) for (size_t i = 0; i < batch->used_scans; ++i)
dump_field(batch->idle_count, batch->fields + i); dump_field(batch->idle_count, batch->fields + i);

View File

@ -3,6 +3,7 @@
#include "target/target.h" #include "target/target.h"
#include "jtag/jtag.h" #include "jtag/jtag.h"
#include "riscv.h"
enum riscv_scan_type { enum riscv_scan_type {
RISCV_SCAN_TYPE_INVALID, RISCV_SCAN_TYPE_INVALID,
@ -27,6 +28,11 @@ struct riscv_batch {
uint8_t *data_in; uint8_t *data_in;
struct scan_field *fields; 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 /* 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 * 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. * illusion of not having to do this by eliding all but the last NOP.

View File

@ -484,8 +484,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
.out_value = out, .out_value = out,
.in_value = in .in_value = in
}; };
uint8_t tunneled_dr_width; riscv_bscan_tunneled_scan_context_t bscan_ctxt;
struct scan_field tunneled_dr[4];
if (r->reset_delays_wait >= 0) { if (r->reset_delays_wait >= 0) {
r->reset_delays_wait--; 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 the best fit. Declaring stack based field values in a subsidiary function call wouldn't
work. */ work. */
if (bscan_tunnel_ir_width != 0) { if (bscan_tunnel_ir_width != 0) {
jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt);
/* 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);
} else { } else {
/* Assume dbus is already selected. */ /* Assume dbus is already selected. */
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);

View File

@ -3550,3 +3550,43 @@ int riscv_init_registers(struct target *target)
return ERROR_OK; 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);
}

View File

@ -6,6 +6,7 @@ struct riscv_program;
#include <stdint.h> #include <stdint.h>
#include "opcodes.h" #include "opcodes.h"
#include "gdb_regs.h" #include "gdb_regs.h"
#include "jtag/jtag.h"
/* The register cache is statically allocated. */ /* The register cache is statically allocated. */
#define RISCV_MAX_HARTS 32 #define RISCV_MAX_HARTS 32
@ -147,6 +148,12 @@ typedef struct {
int (*hart_count)(struct target *target); int (*hart_count)(struct target *target);
} riscv_info_t; } 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.*/ /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
extern int riscv_command_timeout_sec; extern int riscv_command_timeout_sec;
@ -291,4 +298,7 @@ int riscv_init_registers(struct target *target);
void riscv_semihosting_init(struct target *target); void riscv_semihosting_init(struct target *target);
int riscv_semihosting(struct target *target, int *retval); 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 #endif