aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/openocd.texi5
-rw-r--r--src/target/riscv/batch.c11
-rw-r--r--src/target/riscv/batch.h26
-rw-r--r--src/target/riscv/riscv-011.c10
-rw-r--r--src/target/riscv/riscv-013.c539
-rw-r--r--src/target/riscv/riscv.c24
-rw-r--r--src/target/riscv/riscv.h16
-rw-r--r--src/target/riscv/riscv_reg.c8
8 files changed, 193 insertions, 446 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index a0c8ebb..5bd4e89 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11290,11 +11290,6 @@ Set the wall-clock timeout (in seconds) for individual commands. The default
should work fine for all but the slowest targets (eg. simulators).
@end deffn
-@deffn {Command} {riscv set_reset_timeout_sec} [seconds]
-Set the maximum time to wait for a hart to come out of reset after reset is
-deasserted.
-@end deffn
-
@deffn {Command} {riscv set_mem_access} method1 [method2] [method3]
Specify which RISC-V memory access method(s) shall be used, and in which order
of priority. At least one method must be specified.
diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c
index bb1070a..afea316 100644
--- a/src/target/riscv/batch.c
+++ b/src/target/riscv/batch.c
@@ -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) {
const int delay = get_delay(batch, i, delays);
- riscv_log_dmi_scan(batch->target, delay, batch->fields + i,
- /*discard_in*/ false);
+ riscv_log_dmi_scan(batch->target, delay, batch->fields + i);
}
batch->was_run = true;
@@ -199,14 +198,14 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
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)
{
assert(batch->used_scans < batch->allocated_scans);
struct scan_field *field = batch->fields + batch->used_scans;
field->num_bits = riscv_get_dmi_scan_length(batch->target);
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) {
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
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++;
}
-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)
{
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->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);
- 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);
batch->delay_classes[batch->used_scans] = delay_class;
batch->last_scan = RISCV_SCAN_TYPE_READ;
diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h
index 1a39939..660a63f 100644
--- a/src/target/riscv/batch.h
+++ b/src/target/riscv/batch.h
@@ -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);
/* 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);
+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
* provides a key, the second one actually obtains the result of the read -
* 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);
+
+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);
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
* 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. */
-void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field,
- bool discard_in);
+void riscv_log_dmi_scan(const struct target *target, int idle,
+ const struct scan_field *field);
#endif /* OPENOCD_TARGET_RISCV_BATCH_H */
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index cd30a52..0715de5 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -741,7 +741,7 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first)
if (!bits.interrupt)
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for debug int to clear."
"Increase timeout with riscv set_command_timeout_sec.");
return ERROR_FAIL;
@@ -1025,7 +1025,7 @@ static int wait_for_state(struct target *target, enum target_state state)
return result;
if (target->state == state)
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for state %d. "
"Increase timeout with riscv set_command_timeout_sec.", state);
return ERROR_FAIL;
@@ -1186,7 +1186,7 @@ static int full_step(struct target *target, bool announce)
return result;
if (target->state != TARGET_DEBUG_RUNNING)
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for step to complete."
"Increase timeout with riscv set_command_timeout_sec");
return ERROR_FAIL;
@@ -2344,10 +2344,10 @@ static int wait_for_authbusy(struct target *target)
uint32_t dminfo = dbus_read(target, DMINFO);
if (!get_field(dminfo, DMINFO_AUTHBUSY))
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
dminfo);
return ERROR_FAIL;
}
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 07b6da0..ae36a06 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -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 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_nop(struct target *target, char *buf);
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 unsigned int register_size(struct target *target, enum gdb_regno number);
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;
}
-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 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,
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];
decode_dmi(target, in_decoded, in_address, in_data);
/* 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)");
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_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_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)
{
@@ -731,34 +516,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a
return address + base;
}
-static int dm_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)
-{
- dm013_info_t *dm = get_dm(target);
- if (!dm)
- return ERROR_FAIL;
- return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base,
- data_out, timeout_sec, exec, ensure_success);
-}
+static int batch_run_timeout(struct target *target, struct riscv_batch *batch);
-static int dm_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)
+static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
{
- dm013_info_t *dm = get_dm(target);
- if (!dm)
- return ERROR_FAIL;
- return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base,
- data_out, exec, ensure_success);
+ 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)
{
- dm013_info_t *dm = get_dm(target);
- if (!dm)
- return ERROR_FAIL;
- return dmi_read(target, value, address + dm->base);
+ return dmi_read(target, value, riscv013_get_dmi_address(target, address));
}
static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address)
@@ -766,16 +539,29 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address
dm013_info_t *dm = get_dm(target);
if (!dm)
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;
- 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)
{
- dm013_info_t *dm = get_dm(target);
- if (!dm)
- return ERROR_FAIL;
- return dmi_write(target, address + dm->base, value);
+ return dmi_write(target, riscv013_get_dmi_address(target, address), value);
}
static bool check_dbgbase_exists(struct target *target)
@@ -805,11 +591,10 @@ static bool check_dbgbase_exists(struct target *target)
return false;
}
-static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
- bool authenticated, unsigned timeout_sec)
+static int dmstatus_read(struct target *target, uint32_t *dmstatus,
+ bool authenticated)
{
- int result = dm_op_timeout(target, dmstatus, NULL, DMI_OP_READ,
- DM_DMSTATUS, 0, timeout_sec, false, true);
+ int result = dm_read(target, dmstatus, DM_DMSTATUS);
if (result != ERROR_OK)
return result;
int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION);
@@ -827,19 +612,6 @@ static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
return ERROR_OK;
}
-static int dmstatus_read(struct target *target, uint32_t *dmstatus,
- bool authenticated)
-{
- int result = dmstatus_read_timeout(target, dmstatus, authenticated,
- riscv_command_timeout_sec);
- if (result == ERROR_TIMEOUT_REACHED)
- LOG_TARGET_ERROR(target, "DMSTATUS read 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_command_timeout_sec);
- return result;
-}
-
static int increase_ac_busy_delay(struct target *target)
{
riscv013_info_t *info = get_info(target);
@@ -890,12 +662,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
dm->abstract_cmd_maybe_busy = false;
return ERROR_OK;
}
- } while ((time(NULL) - start) < riscv_command_timeout_sec);
+ } while ((time(NULL) - start) < riscv_get_command_timeout_sec());
LOG_TARGET_ERROR(target,
"Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
*abstractcs);
if (!dm->abstract_cmd_maybe_busy)
@@ -955,8 +727,6 @@ clear_cmderr:
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,
uint32_t *cmderr)
{
@@ -1898,10 +1668,10 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus)
*dmstatus = value;
if (!get_field(value, DM_DMSTATUS_AUTHBUSY))
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
value);
return ERROR_FAIL;
}
@@ -2091,11 +1861,10 @@ static int reset_dm(struct target *target)
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
- /* TODO: Introduce a separate timeout for this. */
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "DM didn't acknowledge reset in %d s. "
- "Increase the timeout with 'riscv set_reset_timeout_sec'.",
- riscv_reset_timeout_sec);
+ "Increase the timeout with 'riscv set_command_timeout_sec'.",
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
} while (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE));
@@ -2114,11 +1883,10 @@ static int reset_dm(struct target *target)
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
- /* TODO: Introduce a separate timeout for this. */
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Debug Module did not become active in %d s. "
- "Increase the timeout with 'riscv set_reset_timeout_sec'.",
- riscv_reset_timeout_sec);
+ "Increase the timeout with 'riscv set_command_timeout_sec'.",
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
} while (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE));
@@ -2743,21 +2511,42 @@ static uint32_t sb_sbaccess(unsigned int size_bytes)
return 0;
}
-static int sb_write_address(struct target *target, target_addr_t address,
- bool ensure_success)
+static unsigned int get_sbaadress_reg_count(const struct target *target)
{
RISCV013_INFO(info);
- unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE);
+ const unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE);
+ return DIV_ROUND_UP(sbasize, 32);
+}
+
+static void batch_fill_sb_write_address(const struct target *target,
+ struct riscv_batch *batch, target_addr_t address,
+ enum riscv_scan_delay_class sbaddr0_delay)
+{
/* There currently is no support for >64-bit addresses in OpenOCD. */
- if (sbasize > 96)
- dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false);
- if (sbasize > 64)
- dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false);
- if (sbasize > 32)
- dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1,
- (uint32_t)(address >> 32), false, false);
- return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0,
- (uint32_t)address, false, ensure_success);
+ assert(sizeof(target_addr_t) == sizeof(uint64_t));
+ const uint32_t addresses[] = {DM_SBADDRESS0, DM_SBADDRESS1, DM_SBADDRESS2, DM_SBADDRESS3};
+ const uint32_t values[] = {(uint32_t)address, (uint32_t)(address >> 32), 0, 0};
+ const unsigned int reg_count = get_sbaadress_reg_count(target);
+ assert(reg_count > 0);
+ assert(reg_count <= ARRAY_SIZE(addresses));
+ assert(ARRAY_SIZE(addresses) == ARRAY_SIZE(values));
+
+ for (unsigned int i = reg_count - 1; i > 0; --i)
+ riscv_batch_add_dm_write(batch, addresses[i], values[i], /* read back */ true,
+ RISCV_DELAY_BASE);
+ riscv_batch_add_dm_write(batch, addresses[0], values[0], /* read back */ true,
+ sbaddr0_delay);
+}
+
+static int sb_write_address(struct target *target, target_addr_t address,
+ enum riscv_scan_delay_class sbaddr0_delay)
+{
+ struct riscv_batch *batch = riscv_batch_alloc(target,
+ get_sbaadress_reg_count(target));
+ batch_fill_sb_write_address(target, batch, address, sbaddr0_delay);
+ const int res = batch_run_timeout(target, batch);
+ riscv_batch_free(batch);
+ return res;
}
static int batch_run(struct target *target, struct riscv_batch *batch)
@@ -2769,12 +2558,16 @@ static int batch_run(struct target *target, struct riscv_batch *batch)
const int result = riscv_batch_run_from(batch, 0, &info->learned_delays,
/*resets_delays*/ r->reset_delays_wait >= 0,
r->reset_delays_wait);
+ if (result != ERROR_OK)
+ return result;
/* TODO: To use `riscv_batch_finished_scans()` here, it is needed for
* all scans to not discard input, meaning
* "riscv_batch_add_dm_write(..., false)" should not be used. */
const size_t finished_scans = batch->used_scans;
decrement_reset_delays_counter(target, finished_scans);
- return result;
+ if (riscv_batch_was_batch_busy(batch))
+ return increase_dmi_busy_delay(target);
+ return ERROR_OK;
}
/* It is expected that during creation of the batch
@@ -2797,12 +2590,12 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
&info->learned_delays,
/*resets_delays*/ r->reset_delays_wait >= 0,
r->reset_delays_wait);
+ if (result != ERROR_OK)
+ return result;
const size_t new_finished_scans = riscv_batch_finished_scans(batch);
assert(new_finished_scans >= finished_scans);
decrement_reset_delays_counter(target, new_finished_scans - finished_scans);
finished_scans = new_finished_scans;
- if (result != ERROR_OK)
- return result;
if (!riscv_batch_was_batch_busy(batch)) {
assert(finished_scans == batch->used_scans);
return ERROR_OK;
@@ -2810,7 +2603,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
result = increase_dmi_busy_delay(target);
if (result != ERROR_OK)
return result;
- } while (time(NULL) - start < riscv_command_timeout_sec);
+ } while (time(NULL) - start < riscv_get_command_timeout_sec());
assert(result == ERROR_OK);
assert(riscv_batch_was_batch_busy(batch));
@@ -2825,7 +2618,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
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_command_timeout_sec);
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
@@ -3108,8 +2901,8 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->write_progbuf = &riscv013_write_progbuf;
generic_info->execute_progbuf = &riscv013_execute_progbuf;
generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf;
- generic_info->fill_dm_write = &riscv013_fill_dm_write;
- generic_info->fill_dm_read = &riscv013_fill_dm_read;
+ generic_info->fill_dmi_write = &riscv013_fill_dmi_write;
+ generic_info->fill_dmi_read = &riscv013_fill_dmi_read;
generic_info->fill_dm_nop = &riscv013_fill_dm_nop;
generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length;
generic_info->authdata_read = &riscv013_authdata_read;
@@ -3225,21 +3018,15 @@ static int deassert_reset(struct target *target)
time_t start = time(NULL);
LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset.");
do {
- result = dmstatus_read_timeout(target, &dmstatus, true,
- riscv_reset_timeout_sec);
- if (result == ERROR_TIMEOUT_REACHED)
- LOG_TARGET_ERROR(target, "Hart didn't complete a DMI read coming "
- "out of reset in %ds; Increase the timeout with riscv "
- "set_reset_timeout_sec.",
- riscv_reset_timeout_sec);
+ result = dmstatus_read(target, &dmstatus, true);
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; "
"dmstatus=0x%x (allunavail=%s, allhavereset=%s); "
- "Increase the timeout with riscv set_reset_timeout_sec.",
- riscv_reset_timeout_sec, dmstatus,
+ "Increase the timeout with riscv set_command_timeout_sec.",
+ riscv_get_command_timeout_sec(), dmstatus,
get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false",
get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false");
return ERROR_TIMEOUT_REACHED;
@@ -3425,10 +3212,10 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs)
return ERROR_FAIL;
if (!get_field(*sbcs, DM_SBCS_SBBUSY))
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec, *sbcs);
+ riscv_get_command_timeout_sec(), *sbcs);
return ERROR_FAIL;
}
}
@@ -3570,6 +3357,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
target_addr_t next_address = address;
target_addr_t end_address = address + (increment ? count : 1) * size;
+ /* TODO: Reading all the elements in a single batch will boost the
+ * performance.
+ */
while (next_address < end_address) {
uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1);
sbcs_write |= sb_sbaccess(size);
@@ -3581,96 +3371,51 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;
/* This address write will trigger the first read. */
- if (sb_write_address(target, next_address, true) != ERROR_OK)
+ if (sb_write_address(target, next_address, RISCV_DELAY_SYSBUS_READ) != ERROR_OK)
return ERROR_FAIL;
- 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",
- 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;
- }
- }
-
/* First read has been started. Optimistically assume that it has
* completed. */
static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3};
+ /* TODO: The only purpose of "sbvalue" is to be passed to
+ * "log_memory_access()". If "log_memory_access()" were to
+ * accept "uint8_t *" instead of "uint32_t *", "sbvalue" would
+ * be unnecessary.
+ */
uint32_t sbvalue[4] = {0};
assert(size <= 16);
- target_addr_t next_read = address - 1;
- uint32_t buffer_offset = 0;
- int next_read_j = 0;
for (uint32_t i = (next_address - address) / size; i < count - 1; i++) {
- for (int j = (size - 1) / 4; j >= 0; j--) {
- unsigned attempt = 0;
- while (1) {
- if (attempt++ > 100) {
- LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory"
- " just past " TARGET_ADDR_FMT, next_read);
- return ERROR_FAIL;
- }
- keep_alive();
- dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j],
- 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. */
- 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",
- 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;
- }
- }
+ const uint32_t size_in_words = DIV_ROUND_UP(size, 4);
+ struct riscv_batch *batch = riscv_batch_alloc(target, size_in_words);
+ /* Read of sbdata0 must be performed as last because it
+ * starts the new bus data transfer
+ * (in case "sbcs.sbreadondata" was set above).
+ * We don't want to start the next bus read before we
+ * fetch all the data from the last bus read. */
+ for (uint32_t j = size_in_words - 1; j > 0; --j)
+ riscv_batch_add_dm_read(batch, sbdata[j], RISCV_DELAY_BASE);
+ riscv_batch_add_dm_read(batch, sbdata[0], RISCV_DELAY_SYSBUS_READ);
+
+ int res = batch_run_timeout(target, batch);
+ if (res != ERROR_OK) {
+ riscv_batch_free(batch);
+ return res;
+ }
- if (status == DMI_STATUS_BUSY)
- increase_dmi_busy_delay(target);
- else if (status == DMI_STATUS_SUCCESS)
- break;
- else
- return ERROR_FAIL;
- }
- if (next_read != address - 1) {
- buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[next_read_j]);
- if (next_read_j == 0) {
- log_memory_access(next_read, sbvalue, size, true);
- memset(sbvalue, 0, size);
- }
- }
- next_read_j = j;
- next_read = address + i * increment + next_read_j * 4;
- buffer_offset = i * size + next_read_j * 4;
+ const size_t last_key = batch->read_keys_used - 1;
+ for (size_t k = 0; k <= last_key; ++k) {
+ sbvalue[k] = riscv_batch_get_dmi_read_data(batch,
+ last_key - k);
+ buf_set_u32(buffer + i * size + k * 4, 0, 8 * size, sbvalue[k]);
}
+ riscv_batch_free(batch);
+ const target_addr_t read_addr = address + i * increment;
+ log_memory_access(read_addr, sbvalue, size, true);
}
uint32_t sbcs_read = 0;
if (count > 1) {
- unsigned attempt = 0;
- while (1) {
- if (attempt++ > 100) {
- LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory"
- " just past " TARGET_ADDR_FMT, next_read);
- return ERROR_FAIL;
- }
- dmi_status_t status = dmi_scan(target, NULL, &sbvalue[0], DMI_OP_NOP, 0, 0, false);
- if (status == DMI_STATUS_BUSY)
- increase_dmi_busy_delay(target);
- else if (status == DMI_STATUS_SUCCESS)
- break;
- else
- return ERROR_FAIL;
- }
- buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[0]);
- log_memory_access(next_read, sbvalue, size, true);
-
/* "Writes to sbcs while sbbusy is high result in undefined behavior.
* A debugger must not write to sbcs until it reads sbbusy as 0." */
if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK)
@@ -4740,9 +4485,10 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
target_addr_t next_address = address;
target_addr_t end_address = address + count * size;
- int result;
+ int result = sb_write_address(target, next_address, RISCV_DELAY_BASE);
+ if (result != ERROR_OK)
+ return result;
- sb_write_address(target, next_address, true);
while (next_address < end_address) {
LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR,
next_address);
@@ -5593,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);
}
-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);
buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP);
@@ -5607,27 +5353,6 @@ static int riscv013_get_dmi_scan_length(struct target *target)
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)
{
if (has_sufficient_progbuf(target, 2))
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 9c4796d..267d20d 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -140,10 +140,15 @@ struct tdata1_cache {
};
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
-int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
+static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC;
-/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
-int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
+/* DEPRECATED Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
+static int riscv_reset_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
+
+int riscv_get_command_timeout_sec(void)
+{
+ return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec);
+}
static bool riscv_enable_virt2phys = true;
@@ -3853,13 +3858,14 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec)
return ERROR_FAIL;
}
- riscv_command_timeout_sec = timeout;
+ riscv_command_timeout_sec_value = timeout;
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_reset_timeout_sec)
{
+ LOG_WARNING("The command 'riscv set_reset_timeout_sec' is deprecated! Please, use 'riscv set_command_timeout_sec'.");
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter.");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -5066,7 +5072,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.handler = riscv_set_reset_timeout_sec,
.mode = COMMAND_ANY,
.usage = "[sec]",
- .help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
+ .help = "DEPRECATED. Use 'riscv set_command_timeout_sec' instead."
},
{
.name = "set_mem_access",
@@ -5581,16 +5587,16 @@ int riscv_execute_progbuf(struct target *target, uint32_t *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);
- 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);
- r->fill_dm_read(target, buf, a);
+ r->fill_dmi_read(target, buf, a);
}
void riscv_fill_dm_nop(struct target *target, char *buf)
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index c13af8e..a25aac8 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -22,8 +22,7 @@ struct riscv_program;
#define RISCV_MAX_HWBPS 16
#define RISCV_MAX_DMS 100
-#define DEFAULT_COMMAND_TIMEOUT_SEC 2
-#define DEFAULT_RESET_TIMEOUT_SEC 30
+#define DEFAULT_COMMAND_TIMEOUT_SEC 5
#define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE)
#define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN)
@@ -227,8 +226,8 @@ struct riscv_info {
int (*execute_progbuf)(struct target *target, uint32_t *cmderr);
int (*invalidate_cached_progbuf)(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_dm_read)(struct target *target, char *buf, uint64_t a);
+ void (*fill_dmi_write)(struct target *target, char *buf, uint64_t a, uint32_t d);
+ void (*fill_dmi_read)(struct target *target, char *buf, uint64_t a);
void (*fill_dm_nop)(struct target *target, char *buf);
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
@@ -340,10 +339,7 @@ typedef struct {
} virt2phys_info_t;
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
-extern int riscv_command_timeout_sec;
-
-/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
-extern int riscv_reset_timeout_sec;
+int riscv_get_command_timeout_sec(void);
extern bool riscv_enable_virtual;
@@ -412,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);
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_dm_read(struct target *target, char *buf, uint64_t a);
+void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d);
+void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a);
int riscv_get_dmi_scan_length(struct target *target);
uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address);
diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c
index f8e5dfe..6cf67dd 100644
--- a/src/target/riscv/riscv_reg.c
+++ b/src/target/riscv/riscv_reg.c
@@ -397,6 +397,14 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno)
case CSR_FRM:
case CSR_FCSR:
return riscv_supports_extension(target, 'F');
+ case CSR_VSTART:
+ case CSR_VXSAT:
+ case CSR_VXRM:
+ case CSR_VL:
+ case CSR_VCSR:
+ case CSR_VTYPE:
+ case CSR_VLENB:
+ return vlenb_exists(target);
case CSR_SCOUNTEREN:
case CSR_SSTATUS:
case CSR_STVEC: