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 standardsmem64
parent
f93ede5401
commit
b7bd3f8d47
|
@ -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) {
|
||||||
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)
|
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);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue