Merge pull request #1087 from en-sc/en-sc/delay-types
target/riscv: replace `info->*_delay` with `riscv_scan_delays`
This commit is contained in:
commit
4b5668bdaa
|
@ -29,7 +29,7 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans)
|
|||
out->allocated_scans = scans;
|
||||
out->last_scan = RISCV_SCAN_TYPE_INVALID;
|
||||
out->was_run = false;
|
||||
out->used_delay = 0;
|
||||
out->last_scan_delay = 0;
|
||||
|
||||
out->data_out = NULL;
|
||||
out->data_in = NULL;
|
||||
|
@ -109,7 +109,7 @@ static bool riscv_batch_was_scan_busy(const struct riscv_batch *batch,
|
|||
}
|
||||
|
||||
static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_idx,
|
||||
struct riscv_scan_delays delays)
|
||||
const struct riscv_scan_delays *delays)
|
||||
{
|
||||
if (!batch->was_run)
|
||||
return;
|
||||
|
@ -121,9 +121,9 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_
|
|||
? batch->delay_classes[start_idx - 1]
|
||||
: RISCV_DELAY_BASE;
|
||||
const unsigned int new_delay = riscv_scan_get_delay(delays, delay_class);
|
||||
if (new_delay <= batch->used_delay)
|
||||
if (new_delay <= batch->last_scan_delay)
|
||||
return;
|
||||
const unsigned int idle_change = new_delay - batch->used_delay;
|
||||
const unsigned int idle_change = new_delay - batch->last_scan_delay;
|
||||
LOG_TARGET_DEBUG(batch->target, "Adding %u idle cycles before the batch.",
|
||||
idle_change);
|
||||
assert(idle_change <= INT_MAX);
|
||||
|
@ -131,19 +131,19 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_
|
|||
}
|
||||
|
||||
static int get_delay(const struct riscv_batch *batch, size_t scan_idx,
|
||||
struct riscv_scan_delays delays)
|
||||
const struct riscv_scan_delays *delays)
|
||||
{
|
||||
assert(batch);
|
||||
assert(scan_idx < batch->used_scans);
|
||||
const enum riscv_scan_delay_class delay_class =
|
||||
batch->delay_classes[scan_idx];
|
||||
const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
|
||||
const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
|
||||
assert(delay <= INT_MAX);
|
||||
return delay;
|
||||
}
|
||||
|
||||
int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
||||
struct riscv_scan_delays delays, bool resets_delays,
|
||||
const struct riscv_scan_delays *delays, bool resets_delays,
|
||||
size_t reset_delays_after)
|
||||
{
|
||||
assert(batch->used_scans);
|
||||
|
@ -195,7 +195,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
|||
}
|
||||
|
||||
batch->was_run = true;
|
||||
batch->used_delay = get_delay(batch, batch->used_scans - 1, delays);
|
||||
batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,40 +25,66 @@ enum riscv_scan_delay_class {
|
|||
/* Delay for System Bus read operation: */
|
||||
RISCV_DELAY_SYSBUS_READ,
|
||||
/* Delay for System Bus write operation: */
|
||||
RISCV_DELAY_SYSBUS_WRITE,
|
||||
RISCV_DELAY_SYSBUS_WRITE
|
||||
};
|
||||
|
||||
static inline const char *
|
||||
riscv_scan_delay_class_name(enum riscv_scan_delay_class delay_class)
|
||||
{
|
||||
switch (delay_class) {
|
||||
case RISCV_DELAY_BASE:
|
||||
return "DM access";
|
||||
case RISCV_DELAY_ABSTRACT_COMMAND:
|
||||
return "Abstract Command";
|
||||
case RISCV_DELAY_SYSBUS_READ:
|
||||
return "System Bus read";
|
||||
case RISCV_DELAY_SYSBUS_WRITE:
|
||||
return "System Bus write";
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The scan delay values are passed to "jtag_add_runtest()", which accepts an
|
||||
* "int". Therefore, the passed value should be no greater than "INT_MAX".
|
||||
*
|
||||
* Since the resulting delay value can be a sum of two individual delays,
|
||||
* individual delays are limited to "INT_MAX / 2" to prevent overflow of the
|
||||
* final sum.
|
||||
*/
|
||||
#define RISCV_SCAN_DELAY_MAX (INT_MAX / 2)
|
||||
|
||||
struct riscv_scan_delays {
|
||||
/* The purpose of these delays is to be passed to "jtag_add_runtest()",
|
||||
* which accepts an "int".
|
||||
* Therefore, they should be no greater then "INT_MAX".
|
||||
*/
|
||||
unsigned int base_delay;
|
||||
unsigned int ac_delay;
|
||||
unsigned int sb_read_delay;
|
||||
unsigned int sb_write_delay;
|
||||
};
|
||||
|
||||
static inline unsigned int riscv_scan_get_delay(struct riscv_scan_delays delays,
|
||||
static inline unsigned int
|
||||
riscv_scan_get_delay(const struct riscv_scan_delays *delays,
|
||||
enum riscv_scan_delay_class delay_class)
|
||||
{
|
||||
switch (delay_class) {
|
||||
case RISCV_DELAY_BASE:
|
||||
return delays.base_delay;
|
||||
return delays->base_delay;
|
||||
case RISCV_DELAY_ABSTRACT_COMMAND:
|
||||
return delays.ac_delay;
|
||||
return delays->base_delay + delays->ac_delay;
|
||||
case RISCV_DELAY_SYSBUS_READ:
|
||||
return delays.sb_read_delay;
|
||||
return delays->base_delay + delays->sb_read_delay;
|
||||
case RISCV_DELAY_SYSBUS_WRITE:
|
||||
return delays.sb_write_delay;
|
||||
return delays->base_delay + delays->sb_write_delay;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays,
|
||||
enum riscv_scan_delay_class delay_class, unsigned int delay)
|
||||
{
|
||||
assert(delay <= INT_MAX);
|
||||
assert(delay <= RISCV_SCAN_DELAY_MAX);
|
||||
LOG_DEBUG("%s delay is set to %u.",
|
||||
riscv_scan_delay_class_name(delay_class), delay);
|
||||
switch (delay_class) {
|
||||
case RISCV_DELAY_BASE:
|
||||
delays->base_delay = delay;
|
||||
|
@ -73,6 +99,25 @@ static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays,
|
|||
delays->sb_write_delay = delay;
|
||||
return;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static inline int riscv_scan_increase_delay(struct riscv_scan_delays *delays,
|
||||
enum riscv_scan_delay_class delay_class)
|
||||
{
|
||||
const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
|
||||
const unsigned int delay_step = delay / 10 + 1;
|
||||
if (delay > RISCV_SCAN_DELAY_MAX - delay_step) {
|
||||
/* It's not clear if this issue actually occurs in real
|
||||
* use-cases, so stick with a simple solution until the
|
||||
* first bug report.
|
||||
*/
|
||||
LOG_ERROR("Delay for %s (%d) is not increased anymore (maximum was reached).",
|
||||
riscv_scan_delay_class_name(delay_class), delay);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
riscv_scan_set_delay(delays, delay_class, delay + delay_step);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* A batch of multiple JTAG scans, which are grouped together to avoid the
|
||||
|
@ -113,7 +158,7 @@ struct riscv_batch {
|
|||
/* Number of RTI cycles used by the last scan on the last run.
|
||||
* Only valid when `was_run` is set.
|
||||
*/
|
||||
unsigned int used_delay;
|
||||
unsigned int last_scan_delay;
|
||||
};
|
||||
|
||||
/* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG
|
||||
|
@ -138,7 +183,7 @@ bool riscv_batch_full(struct riscv_batch *batch);
|
|||
* OpenOCD that are based on batches.
|
||||
*/
|
||||
int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
||||
struct riscv_scan_delays delays, bool resets_delays,
|
||||
const struct riscv_scan_delays *delays, bool resets_delays,
|
||||
size_t reset_delays_after);
|
||||
|
||||
/* Get the number of scans successfully executed form this batch. */
|
||||
|
|
|
@ -169,21 +169,12 @@ typedef struct {
|
|||
* access. */
|
||||
unsigned int dtmcs_idle;
|
||||
|
||||
/* This value is incremented every time a dbus access comes back as "busy".
|
||||
* It's used to determine how many run-test/idle cycles to feed the target
|
||||
* in between accesses. */
|
||||
unsigned int dmi_busy_delay;
|
||||
|
||||
/* Number of run-test/idle cycles to add between consecutive bus master
|
||||
* reads/writes respectively. */
|
||||
unsigned int bus_master_write_delay, bus_master_read_delay;
|
||||
|
||||
/* This value is increased every time we tried to execute two commands
|
||||
* consecutively, and the second one failed because the previous hadn't
|
||||
* completed yet. It's used to add extra run-test/idle cycles after
|
||||
* starting a command, so we don't have to waste time checking for busy to
|
||||
* go low. */
|
||||
unsigned int ac_busy_delay;
|
||||
/* This structure is used to determine how many run-test/idle to use after
|
||||
* an access of corresponding "riscv_scan_delay_class".
|
||||
* Values are incremented every time an access results in a busy
|
||||
* response.
|
||||
*/
|
||||
struct riscv_scan_delays learned_delays;
|
||||
|
||||
bool abstract_read_csr_supported;
|
||||
bool abstract_write_csr_supported;
|
||||
|
@ -478,15 +469,25 @@ static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void increase_dmi_busy_delay(struct target *target)
|
||||
static int increase_dmi_busy_delay(struct target *target)
|
||||
{
|
||||
riscv013_info_t *info = get_info(target);
|
||||
info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1;
|
||||
LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
|
||||
info->dtmcs_idle, info->dmi_busy_delay,
|
||||
info->ac_busy_delay);
|
||||
RISCV013_INFO(info);
|
||||
|
||||
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */);
|
||||
int res = dtmcontrol_scan(target, DTM_DTMCS_DMIRESET,
|
||||
NULL /* discard result */);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
res = riscv_scan_increase_delay(&info->learned_delays,
|
||||
RISCV_DELAY_BASE);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void reset_learned_delays(struct target *target)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
assert(info);
|
||||
memset(&info->learned_delays, 0, sizeof(info->learned_delays));
|
||||
}
|
||||
|
||||
static void decrement_reset_delays_counter(struct target *target, size_t finished_scans)
|
||||
|
@ -503,9 +504,7 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe
|
|||
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;
|
||||
reset_learned_delays(target);
|
||||
}
|
||||
/**
|
||||
* exec: If this is set, assume the scan results in an execution, so more
|
||||
|
@ -554,9 +553,9 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
|||
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
|
||||
}
|
||||
|
||||
int idle_count = info->dmi_busy_delay;
|
||||
if (exec)
|
||||
idle_count += info->ac_busy_delay;
|
||||
int idle_count = exec
|
||||
? riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_ABSTRACT_COMMAND)
|
||||
: riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE);
|
||||
|
||||
if (idle_count)
|
||||
jtag_add_runtest(idle_count, TAP_IDLE);
|
||||
|
@ -635,7 +634,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
|||
status = dmi_scan(target, NULL, NULL, op, address, data_out,
|
||||
exec);
|
||||
if (status == DMI_STATUS_BUSY) {
|
||||
increase_dmi_busy_delay(target);
|
||||
int result = increase_dmi_busy_delay(target);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
if (dmi_busy_encountered)
|
||||
*dmi_busy_encountered = true;
|
||||
} else if (status == DMI_STATUS_SUCCESS) {
|
||||
|
@ -661,7 +662,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
|||
status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0,
|
||||
false);
|
||||
if (status == DMI_STATUS_BUSY) {
|
||||
increase_dmi_busy_delay(target);
|
||||
int result = increase_dmi_busy_delay(target);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
if (dmi_busy_encountered)
|
||||
*dmi_busy_encountered = true;
|
||||
} else if (status == DMI_STATUS_SUCCESS) {
|
||||
|
@ -837,13 +840,11 @@ static int dmstatus_read(struct target *target, uint32_t *dmstatus,
|
|||
return result;
|
||||
}
|
||||
|
||||
static void increase_ac_busy_delay(struct target *target)
|
||||
static int increase_ac_busy_delay(struct target *target)
|
||||
{
|
||||
riscv013_info_t *info = get_info(target);
|
||||
info->ac_busy_delay += info->ac_busy_delay / 10 + 1;
|
||||
LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
|
||||
info->dtmcs_idle, info->dmi_busy_delay,
|
||||
info->ac_busy_delay);
|
||||
return riscv_scan_increase_delay(&info->learned_delays,
|
||||
RISCV_DELAY_ABSTRACT_COMMAND);
|
||||
}
|
||||
|
||||
static uint32_t __attribute__((unused)) abstract_register_size(unsigned width)
|
||||
|
@ -911,13 +912,13 @@ static int dm013_select_target(struct target *target)
|
|||
return dm013_select_hart(target, info->index);
|
||||
}
|
||||
|
||||
#define EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE 2
|
||||
#define ABSTRACT_COMMAND_BATCH_SIZE 2
|
||||
|
||||
static size_t abstract_cmd_fill_batch(struct riscv_batch *batch,
|
||||
uint32_t command)
|
||||
{
|
||||
assert(riscv_batch_available_scans(batch)
|
||||
>= EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE);
|
||||
>= ABSTRACT_COMMAND_BATCH_SIZE);
|
||||
riscv_batch_add_dm_write(batch, DM_COMMAND, command, /* read_back */ true,
|
||||
RISCV_DELAY_ABSTRACT_COMMAND);
|
||||
return riscv_batch_add_dm_read(batch, DM_ABSTRACTCS, RISCV_DELAY_BASE);
|
||||
|
@ -935,7 +936,9 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target,
|
|||
res = wait_for_idle(target, &abstractcs);
|
||||
if (res != ERROR_OK)
|
||||
goto clear_cmderr;
|
||||
increase_ac_busy_delay(target);
|
||||
res = increase_ac_busy_delay(target);
|
||||
if (res != ERROR_OK)
|
||||
goto clear_cmderr;
|
||||
}
|
||||
*cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR);
|
||||
if (*cmderr == CMDERR_NONE)
|
||||
|
@ -975,7 +978,7 @@ static int execute_abstract_command(struct target *target, uint32_t command,
|
|||
return ERROR_FAIL;
|
||||
|
||||
struct riscv_batch *batch = riscv_batch_alloc(target,
|
||||
EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE);
|
||||
ABSTRACT_COMMAND_BATCH_SIZE);
|
||||
const size_t abstractcs_read_key = abstract_cmd_fill_batch(batch, command);
|
||||
|
||||
/* Abstract commands are executed while running the batch. */
|
||||
|
@ -1203,7 +1206,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
|
|||
assert(size_bits % 32 == 0);
|
||||
const unsigned int size_in_words = size_bits / 32;
|
||||
const unsigned int batch_size = size_in_words
|
||||
+ EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE;
|
||||
+ ABSTRACT_COMMAND_BATCH_SIZE;
|
||||
struct riscv_batch * const batch = riscv_batch_alloc(target, batch_size);
|
||||
|
||||
abstract_data_write_fill_batch(batch, value, /*index*/ 0, size_bits);
|
||||
|
@ -2757,29 +2760,13 @@ static int sb_write_address(struct target *target, target_addr_t address,
|
|||
(uint32_t)address, false, ensure_success);
|
||||
}
|
||||
|
||||
/* TODO: store delays in "struct riscv_scan_delays" and remove this function. */
|
||||
struct riscv_scan_delays get_scan_delays(struct target *target)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
assert(info);
|
||||
struct riscv_scan_delays delays;
|
||||
riscv_scan_set_delay(&delays, RISCV_DELAY_BASE, info->dmi_busy_delay);
|
||||
riscv_scan_set_delay(&delays, RISCV_DELAY_ABSTRACT_COMMAND, info->dmi_busy_delay +
|
||||
info->ac_busy_delay);
|
||||
riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_READ, info->dmi_busy_delay +
|
||||
info->bus_master_read_delay);
|
||||
riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_WRITE, info->dmi_busy_delay +
|
||||
info->bus_master_write_delay);
|
||||
return delays;
|
||||
}
|
||||
|
||||
static int batch_run(struct target *target, struct riscv_batch *batch)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
RISCV013_INFO(info);
|
||||
select_dmi(target);
|
||||
riscv_batch_add_nop(batch);
|
||||
const int result = riscv_batch_run_from(batch, 0,
|
||||
get_scan_delays(target),
|
||||
const int result = riscv_batch_run_from(batch, 0, &info->learned_delays,
|
||||
/*resets_delays*/ r->reset_delays_wait >= 0,
|
||||
r->reset_delays_wait);
|
||||
/* TODO: To use `riscv_batch_finished_scans()` here, it is needed for
|
||||
|
@ -2796,18 +2783,18 @@ static int batch_run(struct target *target, struct riscv_batch *batch)
|
|||
static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
|
||||
select_dmi(target);
|
||||
riscv_batch_add_nop(batch);
|
||||
|
||||
size_t finished_scans = 0;
|
||||
const time_t start = time(NULL);
|
||||
const unsigned int old_dmi_busy_delay = info->dmi_busy_delay;
|
||||
const unsigned int old_base_delay = riscv_scan_get_delay(&info->learned_delays,
|
||||
RISCV_DELAY_BASE);
|
||||
int result;
|
||||
do {
|
||||
RISCV_INFO(r);
|
||||
result = riscv_batch_run_from(batch, finished_scans,
|
||||
get_scan_delays(target),
|
||||
&info->learned_delays,
|
||||
/*resets_delays*/ r->reset_delays_wait >= 0,
|
||||
r->reset_delays_wait);
|
||||
const size_t new_finished_scans = riscv_batch_finished_scans(batch);
|
||||
|
@ -2820,16 +2807,20 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
|
|||
assert(finished_scans == batch->used_scans);
|
||||
return ERROR_OK;
|
||||
}
|
||||
increase_dmi_busy_delay(target);
|
||||
result = increase_dmi_busy_delay(target);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
} while (time(NULL) - start < riscv_command_timeout_sec);
|
||||
|
||||
assert(result == ERROR_OK);
|
||||
assert(riscv_batch_was_batch_busy(batch));
|
||||
|
||||
/* Reset dmi_busy_delay, so the value doesn't get too big. */
|
||||
LOG_TARGET_DEBUG(target, "dmi_busy_delay is restored to %u.",
|
||||
old_dmi_busy_delay);
|
||||
info->dmi_busy_delay = old_dmi_busy_delay;
|
||||
LOG_TARGET_DEBUG(target, "%s delay is restored to %u.",
|
||||
riscv_scan_delay_class_name(RISCV_DELAY_BASE),
|
||||
old_base_delay);
|
||||
riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE,
|
||||
old_base_delay);
|
||||
|
||||
LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. "
|
||||
"The target is either really slow or broken. You could increase "
|
||||
|
@ -2968,7 +2959,11 @@ static int sample_memory_bus_v1(struct target *target,
|
|||
* with a larger DMI delay. */
|
||||
unsigned int sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index);
|
||||
if (sbcs_read_op == DTM_DMI_OP_BUSY) {
|
||||
increase_dmi_busy_delay(target);
|
||||
result = increase_dmi_busy_delay(target);
|
||||
if (result != ERROR_OK) {
|
||||
riscv_batch_free(batch);
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2976,9 +2971,12 @@ static int sample_memory_bus_v1(struct target *target,
|
|||
if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) {
|
||||
/* Discard this batch when we encounter "busy error" state on the System Bus level.
|
||||
* We'll try next time with a larger System Bus read delay. */
|
||||
info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
|
||||
dm_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR);
|
||||
int res = riscv_scan_increase_delay(&info->learned_delays,
|
||||
RISCV_DELAY_SYSBUS_READ);
|
||||
riscv_batch_free(batch);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
continue;
|
||||
}
|
||||
if (get_field(sbcs_read, DM_SBCS_SBERROR)) {
|
||||
|
@ -3135,11 +3133,7 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
riscv013_info_t *info = get_info(target);
|
||||
|
||||
info->progbufsize = -1;
|
||||
|
||||
info->dmi_busy_delay = 0;
|
||||
info->bus_master_read_delay = 0;
|
||||
info->bus_master_write_delay = 0;
|
||||
info->ac_busy_delay = 0;
|
||||
reset_learned_delays(target);
|
||||
|
||||
/* Assume all these abstract commands are supported until we learn
|
||||
* otherwise.
|
||||
|
@ -3226,7 +3220,8 @@ static int deassert_reset(struct target *target)
|
|||
return result;
|
||||
|
||||
uint32_t dmstatus;
|
||||
const int orig_dmi_busy_delay = info->dmi_busy_delay;
|
||||
const unsigned int orig_base_delay = riscv_scan_get_delay(&info->learned_delays,
|
||||
RISCV_DELAY_BASE);
|
||||
time_t start = time(NULL);
|
||||
LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset.");
|
||||
do {
|
||||
|
@ -3259,7 +3254,8 @@ static int deassert_reset(struct target *target)
|
|||
} while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) &&
|
||||
!get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET));
|
||||
|
||||
info->dmi_busy_delay = orig_dmi_busy_delay;
|
||||
riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE,
|
||||
orig_base_delay);
|
||||
|
||||
if (target->reset_halt) {
|
||||
target->state = TARGET_HALTED;
|
||||
|
@ -3588,10 +3584,12 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
if (sb_write_address(target, next_address, true) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (info->bus_master_read_delay) {
|
||||
unsigned int bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays,
|
||||
RISCV_DELAY_SYSBUS_READ);
|
||||
if (bus_master_read_delay) {
|
||||
LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
|
||||
info->bus_master_read_delay);
|
||||
jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
|
||||
bus_master_read_delay);
|
||||
jtag_add_runtest(bus_master_read_delay, TAP_IDLE);
|
||||
if (jtag_execute_queue() != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
|
||||
return ERROR_FAIL;
|
||||
|
@ -3621,10 +3619,12 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
DMI_OP_READ, sbdata[j] + dm->base, 0, false);
|
||||
/* By reading from sbdata0, we have just initiated another system bus read.
|
||||
* If necessary add a delay so the read can finish. */
|
||||
if (j == 0 && info->bus_master_read_delay) {
|
||||
bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays,
|
||||
RISCV_DELAY_SYSBUS_READ);
|
||||
if (j == 0 && bus_master_read_delay) {
|
||||
LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
|
||||
info->bus_master_read_delay);
|
||||
jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
|
||||
bus_master_read_delay);
|
||||
jtag_add_runtest(bus_master_read_delay, TAP_IDLE);
|
||||
if (jtag_execute_queue() != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
|
||||
return ERROR_FAIL;
|
||||
|
@ -3711,9 +3711,10 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
|
||||
LOG_TARGET_DEBUG(target, "Increasing bus_master_read_delay to %d.",
|
||||
info->bus_master_read_delay);
|
||||
int res = riscv_scan_increase_delay(&info->learned_delays,
|
||||
RISCV_DELAY_SYSBUS_READ);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4129,8 +4130,12 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target,
|
|||
uint32_t start_index, uint32_t *elements_read,
|
||||
struct memory_access_info access)
|
||||
{
|
||||
increase_ac_busy_delay(target);
|
||||
riscv013_clear_abstract_error(target);
|
||||
int res = riscv013_clear_abstract_error(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
res = increase_ac_busy_delay(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
@ -4828,8 +4833,11 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
|
|||
LOG_TARGET_DEBUG(target, "Sbbusyerror encountered during system bus write.");
|
||||
/* Clear the sticky error flag. */
|
||||
dm_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR);
|
||||
/* Slow down before trying again. */
|
||||
info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1;
|
||||
/* Slow down before trying again.
|
||||
* FIXME: Possible overflow is ignored here.
|
||||
*/
|
||||
riscv_scan_increase_delay(&info->learned_delays,
|
||||
RISCV_DELAY_SYSBUS_WRITE);
|
||||
}
|
||||
|
||||
if (get_field(sbcs, DM_SBCS_SBBUSYERROR) || dmi_busy_encountered) {
|
||||
|
@ -4940,8 +4948,12 @@ static int write_memory_progbuf_teardown(struct target *target)
|
|||
static int write_memory_progbuf_handle_busy(struct target *target,
|
||||
target_addr_t *address_p, uint32_t size, const uint8_t *buffer)
|
||||
{
|
||||
riscv013_clear_abstract_error(target);
|
||||
increase_ac_busy_delay(target);
|
||||
int res = riscv013_clear_abstract_error(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
res = increase_ac_busy_delay(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
if (write_memory_progbuf_teardown(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
|
Loading…
Reference in New Issue