target/riscv: reset delays during batch scans
This commit is related to testing how OpenOCD responds to `dmi.busy`. Consider testing on Spike (e.g. `riscv-tests/debug` testsuite). Spike returns `dmi.busy` if there were less then a given number of RTI cycles (`required_rti_cycles`) between DR_UPDATE and DR_CAPTURE: https://github.com/riscv-software-src/riscv-isa-sim/blob/master/riscv/jtag_dtm.cc#L145 https://github.com/riscv-software-src/riscv-isa-sim/blob/master/riscv/jtag_dtm.cc#L202 `required_rti_cycles` gets it's value from `--dmi-rti` CLI argument and is constant throughout the run. OpenOCD learns this required number of RTI cycles by starting with zero and increasing it if `dmi.busy` is encountered. So the required number of RTI cycles is learned during the first DMI access in the `examine()`. To induce `dmi.busy` on demand `riscv reset_delays <x>` command is provided. This command initializes `riscv_info::reset_delays_wait` counter to the provided `<x>` value. The counter is decreased before a DMI access and when it reaches zero the learned value of RTI cycles required is reset, so the DMI access results in `dmi.busy`. Now consider running a batch of accesses. Before the change all the accesses in the batch had the same number of RIT cycles in between them. So either: * Number of accesses in the batch was greater then the value of `riscv_info::reset_delays_wait` counter and there was no `dmi.busy` throughout the batch. * Number of accesses in the batch was less or equal then the value of `riscv_info::reset_delays_wait` counter and the first access of the batch resulted in `dmi.busy`. Therefore it was impossible to encounter `dmi.busy` on any scan of the batch except the first one. Change-Id: Ib0714ecaf7d2e11878140d16d9aa6152ff20f1e9 Signed-off-by: Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
This commit is contained in:
parent
e51f8695ed
commit
68fcd1c5b7
|
@ -89,7 +89,8 @@ bool riscv_batch_full(struct riscv_batch *batch)
|
|||
return riscv_batch_available_scans(batch) == 0;
|
||||
}
|
||||
|
||||
int riscv_batch_run(struct riscv_batch *batch)
|
||||
int riscv_batch_run(struct riscv_batch *batch, bool resets_delays,
|
||||
size_t reset_delays_after)
|
||||
{
|
||||
if (batch->used_scans == 0) {
|
||||
LOG_TARGET_DEBUG(batch->target, "Ignoring empty batch.");
|
||||
|
@ -104,7 +105,9 @@ int riscv_batch_run(struct riscv_batch *batch)
|
|||
else
|
||||
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
|
||||
|
||||
if (batch->idle_count > 0)
|
||||
const bool delays_were_reset = resets_delays
|
||||
&& (i >= reset_delays_after);
|
||||
if (batch->idle_count > 0 && !delays_were_reset)
|
||||
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,15 @@ void riscv_batch_free(struct riscv_batch *batch);
|
|||
/* Checks to see if this batch is full. */
|
||||
bool riscv_batch_full(struct riscv_batch *batch);
|
||||
|
||||
/* Executes this scan batch. */
|
||||
int riscv_batch_run(struct riscv_batch *batch);
|
||||
/* Executes this batch of JTAG DTM DMI scans.
|
||||
*
|
||||
* If resets_delays is true, the algorithm will stop inserting idle cycles
|
||||
* (JTAG Run-Test Idle) after "reset_delays_after" number of scans is
|
||||
* performed. This is useful for stress-testing of RISC-V algorithms in
|
||||
* OpenOCD that are based on batches.
|
||||
*/
|
||||
int riscv_batch_run(struct riscv_batch *batch, bool resets_delays,
|
||||
size_t reset_delays_after);
|
||||
|
||||
/* Adds a DM register write to this batch. */
|
||||
void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
||||
|
|
|
@ -496,6 +496,24 @@ static void increase_dmi_busy_delay(struct target *target)
|
|||
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */);
|
||||
}
|
||||
|
||||
static void decrement_reset_delays_counter(struct target *target, size_t finished_scans)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
if (r->reset_delays_wait < 0) {
|
||||
assert(r->reset_delays_wait == -1);
|
||||
return;
|
||||
}
|
||||
if ((size_t)r->reset_delays_wait >= finished_scans) {
|
||||
r->reset_delays_wait -= finished_scans;
|
||||
return;
|
||||
}
|
||||
r->reset_delays_wait = -1;
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"resetting learned delays (reset_delays_wait counter expired)");
|
||||
RISCV013_INFO(info);
|
||||
info->dmi_busy_delay = 0;
|
||||
info->ac_busy_delay = 0;
|
||||
}
|
||||
/**
|
||||
* exec: If this is set, assume the scan results in an execution, so more
|
||||
* run-test/idle cycles may be required.
|
||||
|
@ -505,7 +523,6 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
|||
bool exec)
|
||||
{
|
||||
riscv013_info_t *info = get_info(target);
|
||||
RISCV_INFO(r);
|
||||
unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH;
|
||||
size_t num_bytes = (num_bits + 7) / 8;
|
||||
uint8_t in[num_bytes];
|
||||
|
@ -517,14 +534,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
|||
};
|
||||
riscv_bscan_tunneled_scan_context_t bscan_ctxt;
|
||||
|
||||
if (r->reset_delays_wait >= 0) {
|
||||
r->reset_delays_wait--;
|
||||
if (r->reset_delays_wait < 0) {
|
||||
LOG_TARGET_DEBUG(target, "reset_delays_wait done");
|
||||
info->dmi_busy_delay = 0;
|
||||
info->ac_busy_delay = 0;
|
||||
}
|
||||
}
|
||||
decrement_reset_delays_counter(target, 1);
|
||||
|
||||
memset(in, 0, num_bytes);
|
||||
memset(out, 0, num_bytes);
|
||||
|
@ -2617,19 +2627,16 @@ static int sb_write_address(struct target *target, target_addr_t address,
|
|||
(uint32_t)address, false, ensure_success);
|
||||
}
|
||||
|
||||
static int batch_run(const struct target *target, struct riscv_batch *batch)
|
||||
static int batch_run(struct target *target, struct riscv_batch *batch)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
RISCV_INFO(r);
|
||||
if (r->reset_delays_wait >= 0) {
|
||||
r->reset_delays_wait -= batch->used_scans;
|
||||
if (r->reset_delays_wait <= 0) {
|
||||
batch->idle_count = 0;
|
||||
info->dmi_busy_delay = 0;
|
||||
info->ac_busy_delay = 0;
|
||||
}
|
||||
}
|
||||
return riscv_batch_run(batch);
|
||||
const int result = riscv_batch_run(batch, /*resets_delays*/ r->reset_delays_wait >= 0,
|
||||
r->reset_delays_wait);
|
||||
/* TODO: `finished_scans` should be the number of scans that have
|
||||
* finished, not the number of scans scheduled. */
|
||||
const size_t finished_scans = batch->used_scans;
|
||||
decrement_reset_delays_counter(target, finished_scans);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int sba_supports_access(struct target *target, unsigned int size_bytes)
|
||||
|
|
|
@ -450,6 +450,7 @@ static int riscv_init_target(struct command_context *cmd_ctx,
|
|||
LOG_TARGET_DEBUG(target, "riscv_init_target()");
|
||||
RISCV_INFO(info);
|
||||
info->cmd_ctx = cmd_ctx;
|
||||
info->reset_delays_wait = -1;
|
||||
|
||||
select_dtmcontrol.num_bits = target->tap->ir_length;
|
||||
select_dbus.num_bits = target->tap->ir_length;
|
||||
|
@ -3850,10 +3851,8 @@ COMMAND_HANDLER(riscv_reset_delays)
|
|||
{
|
||||
int wait = 0;
|
||||
|
||||
if (CMD_ARGC > 1) {
|
||||
LOG_ERROR("Command takes at most one argument");
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait);
|
||||
|
@ -6455,7 +6454,7 @@ int riscv_init_registers(struct target *target)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||
void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field,
|
||||
riscv_bscan_tunneled_scan_context_t *ctxt)
|
||||
{
|
||||
jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
|
||||
|
|
|
@ -454,7 +454,7 @@ void riscv_semihosting_init(struct target *target);
|
|||
|
||||
enum semihosting_result riscv_semihosting(struct target *target, int *retval);
|
||||
|
||||
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||
void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field,
|
||||
riscv_bscan_tunneled_scan_context_t *ctxt);
|
||||
|
||||
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
|
||||
|
|
Loading…
Reference in New Issue