Merge pull request #1100 from en-sc/en-sc/single-as-batch
target/riscv: single DMI accesses via batch
This commit is contained in:
commit
5afed58fcd
|
@ -190,8 +190,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
||||||
|
|
||||||
for (size_t i = start_idx; i < batch->used_scans; ++i) {
|
for (size_t i = start_idx; i < batch->used_scans; ++i) {
|
||||||
const int delay = get_delay(batch, i, delays);
|
const int delay = get_delay(batch, i, delays);
|
||||||
riscv_log_dmi_scan(batch->target, delay, batch->fields + i,
|
riscv_log_dmi_scan(batch->target, delay, batch->fields + i);
|
||||||
/*discard_in*/ false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
batch->was_run = true;
|
batch->was_run = true;
|
||||||
|
@ -199,14 +198,14 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
||||||
bool read_back, enum riscv_scan_delay_class delay_class)
|
bool read_back, enum riscv_scan_delay_class delay_class)
|
||||||
{
|
{
|
||||||
assert(batch->used_scans < batch->allocated_scans);
|
assert(batch->used_scans < batch->allocated_scans);
|
||||||
struct scan_field *field = batch->fields + batch->used_scans;
|
struct scan_field *field = batch->fields + batch->used_scans;
|
||||||
field->num_bits = riscv_get_dmi_scan_length(batch->target);
|
field->num_bits = riscv_get_dmi_scan_length(batch->target);
|
||||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data);
|
riscv_fill_dmi_write(batch->target, (char *)field->out_value, address, data);
|
||||||
if (read_back) {
|
if (read_back) {
|
||||||
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dm_nop(batch->target, (char *)field->in_value);
|
riscv_fill_dm_nop(batch->target, (char *)field->in_value);
|
||||||
|
@ -218,7 +217,7 @@ void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint3
|
||||||
batch->used_scans++;
|
batch->used_scans++;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address,
|
size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address,
|
||||||
enum riscv_scan_delay_class delay_class)
|
enum riscv_scan_delay_class delay_class)
|
||||||
{
|
{
|
||||||
assert(batch->used_scans < batch->allocated_scans);
|
assert(batch->used_scans < batch->allocated_scans);
|
||||||
|
@ -226,7 +225,7 @@ size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address,
|
||||||
field->num_bits = riscv_get_dmi_scan_length(batch->target);
|
field->num_bits = riscv_get_dmi_scan_length(batch->target);
|
||||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dm_read(batch->target, (char *)field->out_value, address);
|
riscv_fill_dmi_read(batch->target, (char *)field->out_value, address);
|
||||||
riscv_fill_dm_nop(batch->target, (char *)field->in_value);
|
riscv_fill_dm_nop(batch->target, (char *)field->in_value);
|
||||||
batch->delay_classes[batch->used_scans] = delay_class;
|
batch->delay_classes[batch->used_scans] = delay_class;
|
||||||
batch->last_scan = RISCV_SCAN_TYPE_READ;
|
batch->last_scan = RISCV_SCAN_TYPE_READ;
|
||||||
|
|
|
@ -190,14 +190,32 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
|
||||||
size_t riscv_batch_finished_scans(const struct riscv_batch *batch);
|
size_t riscv_batch_finished_scans(const struct riscv_batch *batch);
|
||||||
|
|
||||||
/* Adds a DM register write to this batch. */
|
/* Adds a DM register write to this batch. */
|
||||||
void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
||||||
bool read_back, enum riscv_scan_delay_class delay_class);
|
bool read_back, enum riscv_scan_delay_class delay_class);
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data,
|
||||||
|
bool read_back, enum riscv_scan_delay_class delay_type)
|
||||||
|
{
|
||||||
|
return riscv_batch_add_dmi_write(batch,
|
||||||
|
riscv_get_dmi_address(batch->target, address), data,
|
||||||
|
read_back, delay_type);
|
||||||
|
}
|
||||||
|
|
||||||
/* DM register reads must be handled in two parts: the first one schedules a read and
|
/* DM register reads must be handled in two parts: the first one schedules a read and
|
||||||
* provides a key, the second one actually obtains the result of the read -
|
* provides a key, the second one actually obtains the result of the read -
|
||||||
* status (op) and the actual data. */
|
* status (op) and the actual data. */
|
||||||
size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address,
|
size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address,
|
||||||
enum riscv_scan_delay_class delay_class);
|
enum riscv_scan_delay_class delay_class);
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address,
|
||||||
|
enum riscv_scan_delay_class delay_type)
|
||||||
|
{
|
||||||
|
return riscv_batch_add_dmi_read(batch,
|
||||||
|
riscv_get_dmi_address(batch->target, address), delay_type);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key);
|
unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key);
|
||||||
uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key);
|
uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key);
|
||||||
|
|
||||||
|
@ -213,7 +231,7 @@ bool riscv_batch_was_batch_busy(const struct riscv_batch *batch);
|
||||||
/* TODO: The function is defined in `riscv-013.c`. This is done to reduce the
|
/* TODO: The function is defined in `riscv-013.c`. This is done to reduce the
|
||||||
* diff of the commit. The intention is to move the function definition to
|
* diff of the commit. The intention is to move the function definition to
|
||||||
* a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */
|
* a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */
|
||||||
void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field,
|
void riscv_log_dmi_scan(const struct target *target, int idle,
|
||||||
bool discard_in);
|
const struct scan_field *field);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,10 +56,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target);
|
||||||
static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr);
|
static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr);
|
||||||
static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d);
|
static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d);
|
||||||
static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a);
|
static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a);
|
||||||
static void riscv013_fill_dmi_nop(struct target *target, char *buf);
|
|
||||||
static int riscv013_get_dmi_scan_length(struct target *target);
|
static int riscv013_get_dmi_scan_length(struct target *target);
|
||||||
static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d);
|
|
||||||
static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a);
|
|
||||||
static void riscv013_fill_dm_nop(struct target *target, char *buf);
|
static void riscv013_fill_dm_nop(struct target *target, char *buf);
|
||||||
static unsigned int register_size(struct target *target, enum gdb_regno number);
|
static unsigned int register_size(struct target *target, enum gdb_regno number);
|
||||||
static int register_read_direct(struct target *target, riscv_reg_t *value,
|
static int register_read_direct(struct target *target, riscv_reg_t *value,
|
||||||
|
@ -376,7 +373,9 @@ static unsigned int decode_dmi(const struct target *target, char *text, uint32_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, bool discard_in)
|
/* TODO: Move this function to "batch.c" and make it static. */
|
||||||
|
void riscv_log_dmi_scan(const struct target *target, int idle,
|
||||||
|
const struct scan_field *field)
|
||||||
{
|
{
|
||||||
static const char * const op_string[] = {"-", "r", "w", "?"};
|
static const char * const op_string[] = {"-", "r", "w", "?"};
|
||||||
static const char * const status_string[] = {"+", "?", "F", "b"};
|
static const char * const status_string[] = {"+", "?", "F", "b"};
|
||||||
|
@ -400,7 +399,7 @@ void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan
|
||||||
field->num_bits, op_string[out_op], out_data, out_address,
|
field->num_bits, op_string[out_op], out_data, out_address,
|
||||||
status_string[in_op], in_data, in_address, idle);
|
status_string[in_op], in_data, in_address, idle);
|
||||||
|
|
||||||
if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) {
|
if (in_op == DTM_DMI_OP_SUCCESS) {
|
||||||
char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1];
|
char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1];
|
||||||
decode_dmi(target, in_decoded, in_address, in_data);
|
decode_dmi(target, in_decoded, in_address, in_data);
|
||||||
/* FIXME: The current code assumes that the hardware
|
/* FIXME: The current code assumes that the hardware
|
||||||
|
@ -506,220 +505,6 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe
|
||||||
"resetting learned delays (reset_delays_wait counter expired)");
|
"resetting learned delays (reset_delays_wait counter expired)");
|
||||||
reset_learned_delays(target);
|
reset_learned_delays(target);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* exec: If this is set, assume the scan results in an execution, so more
|
|
||||||
* run-test/idle cycles may be required.
|
|
||||||
*/
|
|
||||||
static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
|
||||||
uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out,
|
|
||||||
bool exec)
|
|
||||||
{
|
|
||||||
riscv013_info_t *info = get_info(target);
|
|
||||||
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];
|
|
||||||
uint8_t out[num_bytes];
|
|
||||||
struct scan_field field = {
|
|
||||||
.num_bits = num_bits,
|
|
||||||
.out_value = out,
|
|
||||||
.in_value = in
|
|
||||||
};
|
|
||||||
riscv_bscan_tunneled_scan_context_t bscan_ctxt;
|
|
||||||
|
|
||||||
decrement_reset_delays_counter(target, 1);
|
|
||||||
|
|
||||||
memset(in, 0, num_bytes);
|
|
||||||
memset(out, 0, num_bytes);
|
|
||||||
|
|
||||||
if (info->abits == 0) {
|
|
||||||
LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0.");
|
|
||||||
return DMI_STATUS_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op);
|
|
||||||
buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out);
|
|
||||||
buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out);
|
|
||||||
|
|
||||||
/* I wanted to place this code in a different function, but the way JTAG command
|
|
||||||
queueing works in the jtag handling functions, the scan fields either have to be
|
|
||||||
heap allocated, global/static, or else they need to stay on the stack until
|
|
||||||
the jtag_execute_queue() call. Heap or static fields in this case doesn't seem
|
|
||||||
the best fit. Declaring stack based field values in a subsidiary function call wouldn't
|
|
||||||
work. */
|
|
||||||
if (bscan_tunnel_ir_width != 0) {
|
|
||||||
riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt);
|
|
||||||
} else {
|
|
||||||
/* Assume dbus is already selected. */
|
|
||||||
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
int retval = jtag_execute_queue();
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("dmi_scan failed jtag scan");
|
|
||||||
if (data_in)
|
|
||||||
*data_in = ~0;
|
|
||||||
return DMI_STATUS_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bscan_tunnel_ir_width != 0) {
|
|
||||||
/* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
|
|
||||||
buffer_shr(in, num_bytes, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data_in)
|
|
||||||
*data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
|
|
||||||
|
|
||||||
if (address_in)
|
|
||||||
*address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits);
|
|
||||||
riscv_log_dmi_scan(target, idle_count, &field, /*discard_in*/ !data_in);
|
|
||||||
return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param target
|
|
||||||
* @param data_in The data we received from the target.
|
|
||||||
* @param dmi_busy_encountered
|
|
||||||
* If non-NULL, will be updated to reflect whether DMI busy was
|
|
||||||
* encountered while executing this operation or not.
|
|
||||||
* @param op The operation to perform (read/write/nop).
|
|
||||||
* @param address The address argument to that operation.
|
|
||||||
* @param data_out The data to send to the target.
|
|
||||||
* @param timeout_sec
|
|
||||||
* @param exec When true, this scan will execute something, so extra RTI
|
|
||||||
* cycles may be added.
|
|
||||||
* @param ensure_success
|
|
||||||
* Scan a nop after the requested operation, ensuring the
|
|
||||||
* DMI operation succeeded.
|
|
||||||
*/
|
|
||||||
static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
|
||||||
bool *dmi_busy_encountered, int op, uint32_t address,
|
|
||||||
uint32_t data_out, int timeout_sec, bool exec, bool ensure_success)
|
|
||||||
{
|
|
||||||
select_dmi(target);
|
|
||||||
|
|
||||||
dmi_status_t status;
|
|
||||||
|
|
||||||
if (dmi_busy_encountered)
|
|
||||||
*dmi_busy_encountered = false;
|
|
||||||
|
|
||||||
const char *op_name;
|
|
||||||
switch (op) {
|
|
||||||
case DMI_OP_NOP:
|
|
||||||
op_name = "nop";
|
|
||||||
break;
|
|
||||||
case DMI_OP_READ:
|
|
||||||
op_name = "read";
|
|
||||||
break;
|
|
||||||
case DMI_OP_WRITE:
|
|
||||||
op_name = "write";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Invalid DMI operation: %d", op);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_alive();
|
|
||||||
|
|
||||||
time_t start = time(NULL);
|
|
||||||
/* This first loop performs the request. Note that if for some reason this
|
|
||||||
* stays busy, it is actually due to the previous access. */
|
|
||||||
while (1) {
|
|
||||||
status = dmi_scan(target, NULL, NULL, op, address, data_out,
|
|
||||||
exec);
|
|
||||||
if (status == DMI_STATUS_BUSY) {
|
|
||||||
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) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (time(NULL) - start > timeout_sec)
|
|
||||||
return ERROR_TIMEOUT_REACHED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != DMI_STATUS_SUCCESS) {
|
|
||||||
LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ensure_success) {
|
|
||||||
/* This second loop ensures the request succeeded, and gets back data.
|
|
||||||
* Note that NOP can result in a 'busy' result as well, but that would be
|
|
||||||
* noticed on the next DMI access we do. */
|
|
||||||
while (1) {
|
|
||||||
status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0,
|
|
||||||
false);
|
|
||||||
if (status == DMI_STATUS_BUSY) {
|
|
||||||
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) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (data_in) {
|
|
||||||
LOG_TARGET_ERROR(target,
|
|
||||||
"Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d",
|
|
||||||
op_name, address, *data_in, status);
|
|
||||||
} else {
|
|
||||||
LOG_TARGET_ERROR(target,
|
|
||||||
"Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address,
|
|
||||||
status);
|
|
||||||
}
|
|
||||||
dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (time(NULL) - start > timeout_sec)
|
|
||||||
return ERROR_TIMEOUT_REACHED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dmi_op(struct target *target, uint32_t *data_in,
|
|
||||||
bool *dmi_busy_encountered, int op, uint32_t address,
|
|
||||||
uint32_t data_out, bool exec, bool ensure_success)
|
|
||||||
{
|
|
||||||
int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op,
|
|
||||||
address, data_out, riscv_get_command_timeout_sec(), exec, ensure_success);
|
|
||||||
if (result == ERROR_TIMEOUT_REACHED) {
|
|
||||||
LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is "
|
|
||||||
"either really slow or broken. You could increase the "
|
|
||||||
"timeout with riscv set_command_timeout_sec.",
|
|
||||||
riscv_get_command_timeout_sec());
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
|
||||||
{
|
|
||||||
return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address)
|
|
||||||
{
|
|
||||||
return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dmi_write(struct target *target, uint32_t address, uint32_t value)
|
|
||||||
{
|
|
||||||
return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address)
|
static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address)
|
||||||
{
|
{
|
||||||
|
@ -731,12 +516,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a
|
||||||
return address + base;
|
return address + base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int batch_run_timeout(struct target *target, struct riscv_batch *batch);
|
||||||
|
|
||||||
|
static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
||||||
|
{
|
||||||
|
struct riscv_batch *batch = riscv_batch_alloc(target, 1);
|
||||||
|
riscv_batch_add_dmi_read(batch, address, RISCV_DELAY_BASE);
|
||||||
|
int res = batch_run_timeout(target, batch);
|
||||||
|
if (res == ERROR_OK && value)
|
||||||
|
*value = riscv_batch_get_dmi_read_data(batch, 0);
|
||||||
|
riscv_batch_free(batch);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int dm_read(struct target *target, uint32_t *value, uint32_t address)
|
static int dm_read(struct target *target, uint32_t *value, uint32_t address)
|
||||||
{
|
{
|
||||||
dm013_info_t *dm = get_dm(target);
|
return dmi_read(target, value, riscv013_get_dmi_address(target, address));
|
||||||
if (!dm)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return dmi_read(target, value, address + dm->base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address)
|
static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address)
|
||||||
|
@ -744,16 +539,29 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address
|
||||||
dm013_info_t *dm = get_dm(target);
|
dm013_info_t *dm = get_dm(target);
|
||||||
if (!dm)
|
if (!dm)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
struct riscv_batch *batch = riscv_batch_alloc(target, 1);
|
||||||
|
riscv_batch_add_dm_read(batch, address, RISCV_DELAY_ABSTRACT_COMMAND);
|
||||||
dm->abstract_cmd_maybe_busy = true;
|
dm->abstract_cmd_maybe_busy = true;
|
||||||
return dmi_read_exec(target, value, address + dm->base);
|
int res = batch_run_timeout(target, batch);
|
||||||
|
if (res == ERROR_OK && value)
|
||||||
|
*value = riscv_batch_get_dmi_read_data(batch, 0);
|
||||||
|
riscv_batch_free(batch);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dmi_write(struct target *target, uint32_t address, uint32_t value)
|
||||||
|
{
|
||||||
|
struct riscv_batch *batch = riscv_batch_alloc(target, 1);
|
||||||
|
riscv_batch_add_dmi_write(batch, address, value, /*read_back*/ true,
|
||||||
|
RISCV_DELAY_BASE);
|
||||||
|
int res = batch_run_timeout(target, batch);
|
||||||
|
riscv_batch_free(batch);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dm_write(struct target *target, uint32_t address, uint32_t value)
|
static int dm_write(struct target *target, uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
dm013_info_t *dm = get_dm(target);
|
return dmi_write(target, riscv013_get_dmi_address(target, address), value);
|
||||||
if (!dm)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return dmi_write(target, address + dm->base, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_dbgbase_exists(struct target *target)
|
static bool check_dbgbase_exists(struct target *target)
|
||||||
|
@ -919,8 +727,6 @@ clear_cmderr:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int batch_run_timeout(struct target *target, struct riscv_batch *batch);
|
|
||||||
|
|
||||||
static int execute_abstract_command(struct target *target, uint32_t command,
|
static int execute_abstract_command(struct target *target, uint32_t command,
|
||||||
uint32_t *cmderr)
|
uint32_t *cmderr)
|
||||||
{
|
{
|
||||||
|
@ -3095,8 +2901,8 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->write_progbuf = &riscv013_write_progbuf;
|
generic_info->write_progbuf = &riscv013_write_progbuf;
|
||||||
generic_info->execute_progbuf = &riscv013_execute_progbuf;
|
generic_info->execute_progbuf = &riscv013_execute_progbuf;
|
||||||
generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf;
|
generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf;
|
||||||
generic_info->fill_dm_write = &riscv013_fill_dm_write;
|
generic_info->fill_dmi_write = &riscv013_fill_dmi_write;
|
||||||
generic_info->fill_dm_read = &riscv013_fill_dm_read;
|
generic_info->fill_dmi_read = &riscv013_fill_dmi_read;
|
||||||
generic_info->fill_dm_nop = &riscv013_fill_dm_nop;
|
generic_info->fill_dm_nop = &riscv013_fill_dm_nop;
|
||||||
generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length;
|
generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length;
|
||||||
generic_info->authdata_read = &riscv013_authdata_read;
|
generic_info->authdata_read = &riscv013_authdata_read;
|
||||||
|
@ -5533,7 +5339,7 @@ static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a)
|
||||||
buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a);
|
buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void riscv013_fill_dmi_nop(struct target *target, char *buf)
|
static void riscv013_fill_dm_nop(struct target *target, char *buf)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP);
|
buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP);
|
||||||
|
@ -5547,27 +5353,6 @@ static int riscv013_get_dmi_scan_length(struct target *target)
|
||||||
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
|
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d)
|
|
||||||
{
|
|
||||||
dm013_info_t *dm = get_dm(target);
|
|
||||||
if (!dm)
|
|
||||||
return;
|
|
||||||
riscv013_fill_dmi_write(target, buf, a + dm->base, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a)
|
|
||||||
{
|
|
||||||
dm013_info_t *dm = get_dm(target);
|
|
||||||
if (!dm)
|
|
||||||
return;
|
|
||||||
riscv013_fill_dmi_read(target, buf, a + dm->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
void riscv013_fill_dm_nop(struct target *target, char *buf)
|
|
||||||
{
|
|
||||||
riscv013_fill_dmi_nop(target, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int maybe_execute_fence_i(struct target *target)
|
static int maybe_execute_fence_i(struct target *target)
|
||||||
{
|
{
|
||||||
if (has_sufficient_progbuf(target, 2))
|
if (has_sufficient_progbuf(target, 2))
|
||||||
|
|
|
@ -5587,16 +5587,16 @@ int riscv_execute_progbuf(struct target *target, uint32_t *cmderr)
|
||||||
return r->execute_progbuf(target, cmderr);
|
return r->execute_progbuf(target, cmderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d)
|
void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
r->fill_dm_write(target, buf, a, d);
|
r->fill_dmi_write(target, buf, a, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a)
|
void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
r->fill_dm_read(target, buf, a);
|
r->fill_dmi_read(target, buf, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_fill_dm_nop(struct target *target, char *buf)
|
void riscv_fill_dm_nop(struct target *target, char *buf)
|
||||||
|
|
|
@ -226,8 +226,8 @@ struct riscv_info {
|
||||||
int (*execute_progbuf)(struct target *target, uint32_t *cmderr);
|
int (*execute_progbuf)(struct target *target, uint32_t *cmderr);
|
||||||
int (*invalidate_cached_progbuf)(struct target *target);
|
int (*invalidate_cached_progbuf)(struct target *target);
|
||||||
int (*get_dmi_scan_length)(struct target *target);
|
int (*get_dmi_scan_length)(struct target *target);
|
||||||
void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d);
|
void (*fill_dmi_write)(struct target *target, char *buf, uint64_t a, uint32_t d);
|
||||||
void (*fill_dm_read)(struct target *target, char *buf, uint64_t a);
|
void (*fill_dmi_read)(struct target *target, char *buf, uint64_t a);
|
||||||
void (*fill_dm_nop)(struct target *target, char *buf);
|
void (*fill_dm_nop)(struct target *target, char *buf);
|
||||||
|
|
||||||
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
|
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
|
||||||
|
@ -408,8 +408,8 @@ int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn);
|
||||||
int riscv_execute_progbuf(struct target *target, uint32_t *cmderr);
|
int riscv_execute_progbuf(struct target *target, uint32_t *cmderr);
|
||||||
|
|
||||||
void riscv_fill_dm_nop(struct target *target, char *buf);
|
void riscv_fill_dm_nop(struct target *target, char *buf);
|
||||||
void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d);
|
void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d);
|
||||||
void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a);
|
void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a);
|
||||||
int riscv_get_dmi_scan_length(struct target *target);
|
int riscv_get_dmi_scan_length(struct target *target);
|
||||||
|
|
||||||
uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address);
|
uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address);
|
||||||
|
|
Loading…
Reference in New Issue