From 41e5272adc21e6479ad89f3cc43127bca145c29c Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 4 Dec 2018 12:38:51 -0800 Subject: [PATCH] Add `riscv reset_delays` for testing. This allows me to test corner cases in block read/write errors. Change-Id: I3ccfe707851dbc578277ea0d5e278eab81a3c7ef --- src/target/riscv/riscv-011.c | 18 ++++++++++++++++++ src/target/riscv/riscv-013.c | 36 ++++++++++++++++++++++++++++++++++-- src/target/riscv/riscv.c | 27 +++++++++++++++++++++++++++ src/target/riscv/riscv.h | 4 ++++ 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 4ddc0e9a9..1de72b103 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -206,6 +206,8 @@ typedef struct { bool need_strict_step; bool never_halted; + + int reset_delays_wait; } riscv011_info_t; typedef struct { @@ -359,6 +361,14 @@ static void add_dbus_scan(const struct target *target, struct scan_field *field, { riscv011_info_t *info = get_info(target); + if (info->reset_delays_wait >= 0) { + info->reset_delays_wait--; + if (info->reset_delays_wait < 0) { + info->dbus_busy_delay = 0; + info->interrupt_high_delay = 0; + } + } + field->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE; field->in_value = in_value; field->out_value = out_value; @@ -1375,6 +1385,13 @@ static int halt(struct target *target) return ERROR_OK; } +static int reset_delays(struct target *target, int wait) +{ + riscv011_info_t *info = get_info(target); + info->reset_delays_wait = wait; + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -1382,6 +1399,7 @@ static int init_target(struct command_context *cmd_ctx, riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; generic_info->get_register = get_register; generic_info->set_register = set_register; + generic_info->reset_delays = &reset_delays; generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f0f007fd5..0660de453 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -215,6 +215,8 @@ typedef struct { /* DM that provides access to this target. */ dm013_info_t *dm; + + int reset_delays_wait; } riscv013_info_t; LIST_HEAD(dm_list); @@ -468,6 +470,14 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, .in_value = in }; + if (info->reset_delays_wait >= 0) { + info->reset_delays_wait--; + if (info->reset_delays_wait < 0) { + info->dmi_busy_delay = 0; + info->ac_busy_delay = 0; + } + } + memset(in, 0, num_bytes); assert(info->abits != 0); @@ -1595,6 +1605,13 @@ int riscv013_authdata_write(struct target *target, uint32_t value) return ERROR_OK; } +static int reset_delays(struct target *target, int wait) +{ + riscv013_info_t *info = get_info(target); + info->reset_delays_wait = wait; + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -1625,6 +1642,7 @@ static int init_target(struct command_context *cmd_ctx, generic_info->dmi_write = &dmi_write; generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg; generic_info->test_compliance = &riscv013_test_compliance; + generic_info->reset_delays = &reset_delays; generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; @@ -2086,6 +2104,20 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_OK; } +static int batch_run(const struct target *target, struct riscv_batch *batch) +{ + RISCV013_INFO(info); + if (info->reset_delays_wait >= 0) { + info->reset_delays_wait -= batch->used_scans; + if (info->reset_delays_wait <= 0) { + batch->idle_count = 0; + info->dmi_busy_delay = 0; + info->ac_busy_delay = 0; + } + } + return riscv_batch_run(batch); +} + /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. @@ -2157,7 +2189,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres break; } - riscv_batch_run(batch); + batch_run(target, batch); /* Wait for the target to finish performing the last abstract command, * and update our copy of cmderr. If we see that DMI is busy here, @@ -2715,7 +2747,7 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, } } - result = riscv_batch_run(batch); + result = batch_run(target, batch); riscv_batch_free(batch); if (result != ERROR_OK) goto error; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 1c89e6de4..fc7f777df 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1608,6 +1608,23 @@ COMMAND_HANDLER(riscv_test_sba_config_reg) } } +COMMAND_HANDLER(riscv_reset_delays) +{ + int wait = 0; + + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait); + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + return r->reset_delays(target, wait); +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "test_compliance", @@ -1697,6 +1714,16 @@ static const struct command_registration riscv_exec_command_handlers[] = { ", an illegal, 128-byte aligned address for error flag/handling cases," "and whether sbbusyerror test should be run." }, + { + .name = "reset_delays", + .handler = riscv_reset_delays, + .mode = COMMAND_ANY, + .usage = "reset_delays [wait]", + .help = "OpenOCD learns how many Run-Test/Idle cycles are required " + "between scans to avoid encountering the target being busy. This " + "command resets those learned values after `wait` scans. It's only " + "useful for testing OpenOCD itself." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index deca21e26..82c191667 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -130,6 +130,10 @@ typedef struct { uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); int (*test_compliance)(struct target *target); + + /* After wait scans, reset the number of Run-Test/Idle cycles we've learned + * are required. */ + int (*reset_delays)(struct target *target, int wait); } riscv_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/