diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 94cb16e48f..c83ff97a27 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -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); } diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 954c4707d3..b3a45e5738 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -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, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index adb0206291..71cfcd67b8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -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) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8fe416db4e..8b01546bf7 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -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); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index cdfd98e2de..7a95af69fc 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -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);