Add `riscv reset_delays` for testing.
This allows me to test corner cases in block read/write errors. Change-Id: I3ccfe707851dbc578277ea0d5e278eab81a3c7ef
This commit is contained in:
parent
d650ef6089
commit
41e5272adc
|
@ -206,6 +206,8 @@ typedef struct {
|
||||||
|
|
||||||
bool need_strict_step;
|
bool need_strict_step;
|
||||||
bool never_halted;
|
bool never_halted;
|
||||||
|
|
||||||
|
int reset_delays_wait;
|
||||||
} riscv011_info_t;
|
} riscv011_info_t;
|
||||||
|
|
||||||
typedef struct {
|
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);
|
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->num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE;
|
||||||
field->in_value = in_value;
|
field->in_value = in_value;
|
||||||
field->out_value = out_value;
|
field->out_value = out_value;
|
||||||
|
@ -1375,6 +1385,13 @@ static int halt(struct target *target)
|
||||||
return ERROR_OK;
|
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,
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
struct target *target)
|
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;
|
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
||||||
generic_info->get_register = get_register;
|
generic_info->get_register = get_register;
|
||||||
generic_info->set_register = set_register;
|
generic_info->set_register = set_register;
|
||||||
|
generic_info->reset_delays = &reset_delays;
|
||||||
|
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
||||||
if (!generic_info->version_specific)
|
if (!generic_info->version_specific)
|
||||||
|
|
|
@ -215,6 +215,8 @@ typedef struct {
|
||||||
|
|
||||||
/* DM that provides access to this target. */
|
/* DM that provides access to this target. */
|
||||||
dm013_info_t *dm;
|
dm013_info_t *dm;
|
||||||
|
|
||||||
|
int reset_delays_wait;
|
||||||
} riscv013_info_t;
|
} riscv013_info_t;
|
||||||
|
|
||||||
LIST_HEAD(dm_list);
|
LIST_HEAD(dm_list);
|
||||||
|
@ -468,6 +470,14 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
||||||
.in_value = 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);
|
memset(in, 0, num_bytes);
|
||||||
|
|
||||||
assert(info->abits != 0);
|
assert(info->abits != 0);
|
||||||
|
@ -1595,6 +1605,13 @@ int riscv013_authdata_write(struct target *target, uint32_t value)
|
||||||
return ERROR_OK;
|
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,
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
struct target *target)
|
struct target *target)
|
||||||
{
|
{
|
||||||
|
@ -1625,6 +1642,7 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->dmi_write = &dmi_write;
|
generic_info->dmi_write = &dmi_write;
|
||||||
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
|
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
|
||||||
generic_info->test_compliance = &riscv013_test_compliance;
|
generic_info->test_compliance = &riscv013_test_compliance;
|
||||||
|
generic_info->reset_delays = &reset_delays;
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
|
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
|
||||||
if (!generic_info->version_specific)
|
if (!generic_info->version_specific)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -2086,6 +2104,20 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
||||||
return ERROR_OK;
|
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,
|
* Read the requested memory, taking care to execute every read exactly once,
|
||||||
* even if cmderr=busy is encountered.
|
* even if cmderr=busy is encountered.
|
||||||
|
@ -2157,7 +2189,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_batch_run(batch);
|
batch_run(target, batch);
|
||||||
|
|
||||||
/* Wait for the target to finish performing the last abstract command,
|
/* 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,
|
* 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);
|
riscv_batch_free(batch);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -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[] = {
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "test_compliance",
|
.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,"
|
", an illegal, 128-byte aligned address for error flag/handling cases,"
|
||||||
"and whether sbbusyerror test should be run."
|
"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
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,10 @@ typedef struct {
|
||||||
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
|
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
|
||||||
|
|
||||||
int (*test_compliance)(struct target *target);
|
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;
|
} riscv_info_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.*/
|
||||||
|
|
Loading…
Reference in New Issue