Create `riscv repeat_read` command (#510)
* WIP, apply stash with conflicts. Change-Id: Ia794bde419aa29161c68898d20e30527e69f5a31 * Fix conflict resolution problems. Change-Id: I4cedc348cf613f98cc5a36886f37c568ca644238 * Add repeat_read command. Only implemented for sba v1 right now, and poorly tested at that. Change-Id: I1d9ff63e1dea14b3f6a9f8ba4dad53668bf8038b * Hide bogus address in repeat_read Change-Id: Ib66c1fa60df9c7fc7cc87880b0fddc52825b48aa * WIP make repeat read work with progbuf. Change-Id: I555f8b880c8bf0d1ed0f3f90c7987a5b516a7a79 * WIP Change-Id: Ic567cea68355ae907e94bd25185a2c9be6fd798d * Fix error handling when increment is non-zero. Change-Id: I5a2f3f2ee948fd4e12c0443a542e85b7b5c5791a * Correctly(?) handle failures when increment is 0. I'm not 100% convinced that this ensures every read value shows up in the output, but it ought to work. Change-Id: I1af3e7174cf9d5e6f293456fb5ead629e17faaaa * Don't crash when asked to read no data. Change-Id: I4061b5c720a43a4f828384ab9eacc89557adfa05 * Remove unnecessary comment. Change-Id: I1be3d699b86299339b3a830ca1ef13c9f5b9fe0f * Document `riscv repeat_read`. Change-Id: I4a0f071f38784b2de034f8c1b0ce75d6d2d326b2
This commit is contained in:
parent
c1c88dccee
commit
53ec10b61d
|
@ -9659,6 +9659,12 @@ indicates the first custom register, whose abstract command number is 0xc000.
|
||||||
This command must be executed before `init`.
|
This command must be executed before `init`.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv repeat_read} count address [size=4]
|
||||||
|
Quickly read count words of the given size from address. This can be useful
|
||||||
|
to read out a buffer that's memory-mapped to be accessed through a single
|
||||||
|
address, or to sample a changing value in a memory-mapped device.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_command_timeout_sec} [seconds]
|
@deffn Command {riscv set_command_timeout_sec} [seconds]
|
||||||
Set the wall-clock timeout (in seconds) for individual commands. The default
|
Set the wall-clock timeout (in seconds) for individual commands. The default
|
||||||
should work fine for all but the slowest targets (eg. simulators).
|
should work fine for all but the slowest targets (eg. simulators).
|
||||||
|
|
|
@ -681,7 +681,8 @@ COMMAND_HANDLER(handle_flash_md_command)
|
||||||
|
|
||||||
retval = flash_driver_read(bank, buffer, offset, sizebytes);
|
retval = flash_driver_read(bank, buffer, offset, sizebytes);
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK)
|
||||||
target_handle_md_output(CMD, target, address, wordsize, count, buffer);
|
target_handle_md_output(CMD, target, address, wordsize, count,
|
||||||
|
buffer, true);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
|
|
|
@ -2148,7 +2148,8 @@ COMMAND_HANDLER(dsp563xx_mem_command)
|
||||||
err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t),
|
err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t),
|
||||||
count, buffer);
|
count, buffer);
|
||||||
if (err == ERROR_OK)
|
if (err == ERROR_OK)
|
||||||
target_handle_md_output(CMD, target, address, sizeof(uint32_t), count, buffer);
|
target_handle_md_output(CMD, target, address, sizeof(uint32_t),
|
||||||
|
count, buffer, true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
b = buffer;
|
b = buffer;
|
||||||
|
|
|
@ -1386,25 +1386,6 @@ static int halt(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_target(struct command_context *cmd_ctx,
|
|
||||||
struct target *target)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("init");
|
|
||||||
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
|
||||||
generic_info->get_register = get_register;
|
|
||||||
generic_info->set_register = set_register;
|
|
||||||
|
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
|
||||||
if (!generic_info->version_specific)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* Assume 32-bit until we discover the real value in examine(). */
|
|
||||||
generic_info->xlen[0] = 32;
|
|
||||||
riscv_init_registers(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deinit_target(struct target *target)
|
static void deinit_target(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("riscv_deinit_target()");
|
LOG_DEBUG("riscv_deinit_target()");
|
||||||
|
@ -1980,8 +1961,13 @@ static int deassert_reset(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_memory(struct target *target, target_addr_t address,
|
static int read_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
|
if (increment != size) {
|
||||||
|
LOG_ERROR("read_memory with custom increment not implemented");
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
||||||
|
|
||||||
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
|
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
|
||||||
|
@ -2283,6 +2269,26 @@ static int arch_state(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
|
struct target *target)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("init");
|
||||||
|
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
||||||
|
generic_info->get_register = get_register;
|
||||||
|
generic_info->set_register = set_register;
|
||||||
|
generic_info->read_memory = read_memory;
|
||||||
|
|
||||||
|
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
||||||
|
if (!generic_info->version_specific)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
/* Assume 32-bit until we discover the real value in examine(). */
|
||||||
|
generic_info->xlen[0] = 32;
|
||||||
|
riscv_init_registers(target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct target_type riscv011_target = {
|
struct target_type riscv011_target = {
|
||||||
.name = "riscv",
|
.name = "riscv",
|
||||||
|
|
||||||
|
@ -2300,7 +2306,6 @@ struct target_type riscv011_target = {
|
||||||
.assert_reset = assert_reset,
|
.assert_reset = assert_reset,
|
||||||
.deassert_reset = deassert_reset,
|
.deassert_reset = deassert_reset,
|
||||||
|
|
||||||
.read_memory = read_memory,
|
|
||||||
.write_memory = write_memory,
|
.write_memory = write_memory,
|
||||||
|
|
||||||
.arch_state = arch_state,
|
.arch_state = arch_state,
|
||||||
|
|
|
@ -64,7 +64,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
|
||||||
static int register_write_direct(struct target *target, unsigned number,
|
static int register_write_direct(struct target *target, unsigned number,
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
static int read_memory(struct target *target, target_addr_t address,
|
static int read_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
||||||
static int write_memory(struct target *target, target_addr_t address,
|
static int write_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
uint32_t size, uint32_t count, const uint8_t *buffer);
|
||||||
static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address,
|
static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address,
|
||||||
|
@ -1226,7 +1226,7 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch,
|
||||||
case SPACE_DMI_RAM:
|
case SPACE_DMI_RAM:
|
||||||
{
|
{
|
||||||
uint8_t buffer[8] = {0};
|
uint8_t buffer[8] = {0};
|
||||||
if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK)
|
if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
*value = buffer[0] |
|
*value = buffer[0] |
|
||||||
(((uint64_t) buffer[1]) << 8) |
|
(((uint64_t) buffer[1]) << 8) |
|
||||||
|
@ -2030,6 +2030,7 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->authdata_write = &riscv013_authdata_write;
|
generic_info->authdata_write = &riscv013_authdata_write;
|
||||||
generic_info->dmi_read = &dmi_read;
|
generic_info->dmi_read = &dmi_read;
|
||||||
generic_info->dmi_write = &dmi_write;
|
generic_info->dmi_write = &dmi_write;
|
||||||
|
generic_info->read_memory = read_memory;
|
||||||
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
|
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
|
||||||
generic_info->test_compliance = &riscv013_test_compliance;
|
generic_info->test_compliance = &riscv013_test_compliance;
|
||||||
generic_info->hart_count = &riscv013_hart_count;
|
generic_info->hart_count = &riscv013_hart_count;
|
||||||
|
@ -2424,8 +2425,13 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_memory_bus_v0(struct target *target, target_addr_t address,
|
static int read_memory_bus_v0(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
|
if (size != increment) {
|
||||||
|
LOG_ERROR("sba v0 reads only support size==increment");
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08"
|
LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08"
|
||||||
TARGET_PRIxADDR, size, count, address);
|
TARGET_PRIxADDR, size, count, address);
|
||||||
uint8_t *t_buffer = buffer;
|
uint8_t *t_buffer = buffer;
|
||||||
|
@ -2504,8 +2510,13 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address,
|
||||||
* Read the requested memory using the system bus interface.
|
* Read the requested memory using the system bus interface.
|
||||||
*/
|
*/
|
||||||
static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
|
if (increment != size && increment != 0) {
|
||||||
|
LOG_ERROR("sba v1 reads only support increment of size or 0");
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
target_addr_t next_address = address;
|
target_addr_t next_address = address;
|
||||||
target_addr_t end_address = address + count * size;
|
target_addr_t end_address = address + count * size;
|
||||||
|
@ -2513,6 +2524,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
|
||||||
while (next_address < end_address) {
|
while (next_address < end_address) {
|
||||||
uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1);
|
uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1);
|
||||||
sbcs_write |= sb_sbaccess(size);
|
sbcs_write |= sb_sbaccess(size);
|
||||||
|
if (increment == size)
|
||||||
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1);
|
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1);
|
||||||
if (count > 1)
|
if (count > 1)
|
||||||
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1);
|
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1);
|
||||||
|
@ -2651,8 +2663,13 @@ static int batch_run(const struct target *target, struct riscv_batch *batch)
|
||||||
* aamsize fields in the memory access abstract command.
|
* aamsize fields in the memory access abstract command.
|
||||||
*/
|
*/
|
||||||
static int read_memory_abstract(struct target *target, target_addr_t address,
|
static int read_memory_abstract(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
|
if (size != increment) {
|
||||||
|
LOG_ERROR("abstract command reads only support size==increment");
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
|
|
||||||
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count,
|
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count,
|
||||||
|
@ -2771,7 +2788,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address,
|
||||||
* even if cmderr=busy is encountered.
|
* even if cmderr=busy is encountered.
|
||||||
*/
|
*/
|
||||||
static int read_memory_progbuf_inner(struct target *target, target_addr_t address,
|
static int read_memory_progbuf_inner(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
|
|
||||||
|
@ -2781,6 +2798,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
result = register_write_direct(target, GDB_REGNO_S0, address);
|
result = register_write_direct(target, GDB_REGNO_S0, address);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
if (increment == 0 &&
|
||||||
|
register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint32_t command = access_register_command(target, GDB_REGNO_S1,
|
uint32_t command = access_register_command(target, GDB_REGNO_S1,
|
||||||
riscv_xlen(target),
|
riscv_xlen(target),
|
||||||
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
|
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
|
||||||
|
@ -2808,11 +2830,10 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
|
|
||||||
/* read_addr is the next address that the hart will read from, which is the
|
/* read_addr is the next address that the hart will read from, which is the
|
||||||
* value in s0. */
|
* value in s0. */
|
||||||
riscv_addr_t read_addr = address + 2 * size;
|
unsigned index = 2;
|
||||||
riscv_addr_t fin_addr = address + (count * size);
|
while (index < count) {
|
||||||
while (read_addr < fin_addr) {
|
riscv_addr_t read_addr = address + index * increment;
|
||||||
LOG_DEBUG("read_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr,
|
LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr);
|
||||||
fin_addr);
|
|
||||||
/* The pipeline looks like this:
|
/* The pipeline looks like this:
|
||||||
* memory -> s1 -> dm_data0 -> debugger
|
* memory -> s1 -> dm_data0 -> debugger
|
||||||
* Right now:
|
* Right now:
|
||||||
|
@ -2821,14 +2842,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
* dm_data0 contains[read_addr-size*2]
|
* dm_data0 contains[read_addr-size*2]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOG_DEBUG("creating burst to read from 0x%" PRIx64
|
|
||||||
" up to 0x%" PRIx64, read_addr, fin_addr);
|
|
||||||
assert(read_addr >= address && read_addr < fin_addr);
|
|
||||||
struct riscv_batch *batch = riscv_batch_alloc(target, 32,
|
struct riscv_batch *batch = riscv_batch_alloc(target, 32,
|
||||||
info->dmi_busy_delay + info->ac_busy_delay);
|
info->dmi_busy_delay + info->ac_busy_delay);
|
||||||
|
|
||||||
size_t reads = 0;
|
unsigned reads = 0;
|
||||||
for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) {
|
for (unsigned j = index; j < count; j++) {
|
||||||
if (size > 4)
|
if (size > 4)
|
||||||
riscv_batch_add_dmi_read(batch, DMI_DATA1);
|
riscv_batch_add_dmi_read(batch, DMI_DATA1);
|
||||||
riscv_batch_add_dmi_read(batch, DMI_DATA0);
|
riscv_batch_add_dmi_read(batch, DMI_DATA0);
|
||||||
|
@ -2851,12 +2869,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||||
|
|
||||||
riscv_addr_t next_read_addr;
|
unsigned next_index;
|
||||||
unsigned ignore_last = 0;
|
unsigned ignore_last = 0;
|
||||||
switch (info->cmderr) {
|
switch (info->cmderr) {
|
||||||
case CMDERR_NONE:
|
case CMDERR_NONE:
|
||||||
LOG_DEBUG("successful (partial?) memory read");
|
LOG_DEBUG("successful (partial?) memory read");
|
||||||
next_read_addr = read_addr + reads * size;
|
next_index = index + reads;
|
||||||
break;
|
break;
|
||||||
case CMDERR_BUSY:
|
case CMDERR_BUSY:
|
||||||
LOG_DEBUG("memory read resulted in busy response");
|
LOG_DEBUG("memory read resulted in busy response");
|
||||||
|
@ -2880,21 +2898,30 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See how far we got, clobbering dmi_data0. */
|
/* See how far we got, clobbering dmi_data0. */
|
||||||
|
if (increment == 0) {
|
||||||
|
uint64_t counter;
|
||||||
|
result = register_read_direct(target, &counter, GDB_REGNO_S2);
|
||||||
|
next_index = counter;
|
||||||
|
} else {
|
||||||
|
uint64_t next_read_addr;
|
||||||
result = register_read_direct(target, &next_read_addr,
|
result = register_read_direct(target, &next_read_addr,
|
||||||
GDB_REGNO_S0);
|
GDB_REGNO_S0);
|
||||||
|
next_index = (next_read_addr - address) / increment;
|
||||||
|
}
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK) {
|
||||||
riscv_batch_free(batch);
|
riscv_batch_free(batch);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0;
|
uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0;
|
||||||
write_to_buf(buffer + next_read_addr - 2 * size - address, value64, size);
|
write_to_buf(buffer + (next_index - 2) * size, value64, size);
|
||||||
log_memory_access(next_read_addr - 2 * size, value64, size, true);
|
log_memory_access(address + (next_index - 2) * size, value64, size, true);
|
||||||
|
|
||||||
/* Restore the command, and execute it.
|
/* Restore the command, and execute it.
|
||||||
* Now DMI_DATA0 contains the next value just as it would if no
|
* Now DMI_DATA0 contains the next value just as it would if no
|
||||||
* error had occurred. */
|
* error had occurred. */
|
||||||
dmi_write_exec(target, DMI_COMMAND, command, true);
|
dmi_write_exec(target, DMI_COMMAND, command, true);
|
||||||
next_read_addr += size;
|
next_index++;
|
||||||
|
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO,
|
dmi_write(target, DMI_ABSTRACTAUTO,
|
||||||
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||||
|
@ -2912,13 +2939,13 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
|
|
||||||
/* Now read whatever we got out of the batch. */
|
/* Now read whatever we got out of the batch. */
|
||||||
dmi_status_t status = DMI_STATUS_SUCCESS;
|
dmi_status_t status = DMI_STATUS_SUCCESS;
|
||||||
riscv_addr_t receive_addr = read_addr - size * 2;
|
|
||||||
unsigned read = 0;
|
unsigned read = 0;
|
||||||
for (size_t i = 0; i < reads; i++) {
|
assert(index >= 2);
|
||||||
assert(receive_addr < address + size * count);
|
for (unsigned j = index - 2; j < index + reads; j++) {
|
||||||
if (receive_addr < address)
|
assert(j < count);
|
||||||
continue;
|
LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d",
|
||||||
if (receive_addr > next_read_addr - (3 + ignore_last) * size)
|
index, reads, next_index, ignore_last, j);
|
||||||
|
if (j + 3 + ignore_last > next_index)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
status = riscv_batch_get_dmi_read_op(batch, read);
|
status = riscv_batch_get_dmi_read_op(batch, read);
|
||||||
|
@ -2952,14 +2979,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
||||||
value |= riscv_batch_get_dmi_read_data(batch, read);
|
value |= riscv_batch_get_dmi_read_data(batch, read);
|
||||||
read++;
|
read++;
|
||||||
}
|
}
|
||||||
riscv_addr_t offset = receive_addr - address;
|
riscv_addr_t offset = j * size;
|
||||||
write_to_buf(buffer + offset, value, size);
|
write_to_buf(buffer + offset, value, size);
|
||||||
log_memory_access(receive_addr, value, size, true);
|
log_memory_access(address + j * increment, value, size, true);
|
||||||
|
|
||||||
receive_addr += size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read_addr = next_read_addr;
|
index = next_index;
|
||||||
|
|
||||||
riscv_batch_free(batch);
|
riscv_batch_free(batch);
|
||||||
}
|
}
|
||||||
|
@ -3069,7 +3094,7 @@ static int read_memory_progbuf_one(struct target *target, target_addr_t address,
|
||||||
* Read the requested memory, silently handling memory access errors.
|
* Read the requested memory, silently handling memory access errors.
|
||||||
*/
|
*/
|
||||||
static int read_memory_progbuf(struct target *target, target_addr_t address,
|
static int read_memory_progbuf(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
if (riscv_xlen(target) < size * 8) {
|
if (riscv_xlen(target) < size * 8) {
|
||||||
LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.",
|
LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.",
|
||||||
|
@ -3099,12 +3124,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
/* s0 holds the next address to write to
|
/* s0 holds the next address to write to
|
||||||
* s1 holds the next data value to write
|
* s1 holds the next data value to write
|
||||||
|
* s2 is a counter in case increment is 0
|
||||||
*/
|
*/
|
||||||
uint64_t s0, s1;
|
uint64_t s0, s1, s2;
|
||||||
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
|
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
if (increment == 0 && register_read(target, &s2, GDB_REGNO_S1) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* Write the program (load, increment) */
|
/* Write the program (load, increment) */
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
|
@ -3132,36 +3160,39 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV))
|
if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV))
|
||||||
riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR);
|
riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR);
|
||||||
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
|
if (increment == 0)
|
||||||
|
riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1);
|
||||||
|
else
|
||||||
|
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment);
|
||||||
|
|
||||||
if (riscv_program_ebreak(&program) != ERROR_OK)
|
if (riscv_program_ebreak(&program) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (riscv_program_write(&program) != ERROR_OK)
|
if (riscv_program_write(&program) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
result = read_memory_progbuf_inner(target, address, size, count, buffer);
|
result = read_memory_progbuf_inner(target, address, size, count, buffer, increment);
|
||||||
|
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK) {
|
||||||
/* The full read did not succeed, so we will try to read each word individually. */
|
/* The full read did not succeed, so we will try to read each word individually. */
|
||||||
/* This will not be fast, but reading outside actual memory is a special case anyway. */
|
/* This will not be fast, but reading outside actual memory is a special case anyway. */
|
||||||
/* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */
|
/* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */
|
||||||
target_addr_t address_i = address;
|
target_addr_t address_i = address;
|
||||||
uint32_t size_i = size;
|
|
||||||
uint32_t count_i = 1;
|
uint32_t count_i = 1;
|
||||||
uint8_t *buffer_i = buffer;
|
uint8_t *buffer_i = buffer;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; i++, address_i += size_i, buffer_i += size_i) {
|
for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) {
|
||||||
|
keep_alive();
|
||||||
/* TODO: This is much slower than it needs to be because we end up
|
/* TODO: This is much slower than it needs to be because we end up
|
||||||
* writing the address to read for every word we read. */
|
* writing the address to read for every word we read. */
|
||||||
result = read_memory_progbuf_inner(target, address_i, size_i, count_i, buffer_i);
|
result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment);
|
||||||
|
|
||||||
/* The read of a single word failed, so we will just return 0 for that instead */
|
/* The read of a single word failed, so we will just return 0 for that instead */
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK) {
|
||||||
LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR,
|
LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR,
|
||||||
size_i, address_i);
|
size, address_i);
|
||||||
|
|
||||||
uint64_t value_i = 0;
|
uint64_t value_i = 0;
|
||||||
write_to_buf(buffer_i, value_i, size_i);
|
write_to_buf(buffer_i, value_i, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = ERROR_OK;
|
result = ERROR_OK;
|
||||||
|
@ -3169,6 +3200,8 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
riscv_set_register(target, GDB_REGNO_S0, s0);
|
riscv_set_register(target, GDB_REGNO_S0, s0);
|
||||||
riscv_set_register(target, GDB_REGNO_S1, s1);
|
riscv_set_register(target, GDB_REGNO_S1, s1);
|
||||||
|
if (increment == 0)
|
||||||
|
riscv_set_register(target, GDB_REGNO_S2, s2);
|
||||||
|
|
||||||
/* Restore MSTATUS */
|
/* Restore MSTATUS */
|
||||||
if (mstatus != mstatus_old)
|
if (mstatus != mstatus_old)
|
||||||
|
@ -3179,12 +3212,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_memory(struct target *target, target_addr_t address,
|
static int read_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
if (count == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
RISCV013_INFO(info);
|
||||||
if (has_sufficient_progbuf(target, 3) && !riscv_prefer_sba)
|
if (has_sufficient_progbuf(target, 3) && !riscv_prefer_sba)
|
||||||
return read_memory_progbuf(target, address, size, count, buffer);
|
return read_memory_progbuf(target, address, size, count, buffer,
|
||||||
|
increment);
|
||||||
|
|
||||||
if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
|
if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
|
||||||
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) ||
|
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) ||
|
||||||
|
@ -3192,15 +3228,19 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
(get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) ||
|
(get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) ||
|
||||||
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) {
|
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) {
|
||||||
if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0)
|
if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0)
|
||||||
return read_memory_bus_v0(target, address, size, count, buffer);
|
return read_memory_bus_v0(target, address, size, count, buffer,
|
||||||
|
increment);
|
||||||
else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1)
|
else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1)
|
||||||
return read_memory_bus_v1(target, address, size, count, buffer);
|
return read_memory_bus_v1(target, address, size, count, buffer,
|
||||||
|
increment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_sufficient_progbuf(target, 3))
|
if (has_sufficient_progbuf(target, 3))
|
||||||
return read_memory_progbuf(target, address, size, count, buffer);
|
return read_memory_progbuf(target, address, size, count, buffer,
|
||||||
|
increment);
|
||||||
|
|
||||||
return read_memory_abstract(target, address, size, count, buffer);
|
return read_memory_abstract(target, address, size, count, buffer,
|
||||||
|
increment);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_memory_bus_v0(struct target *target, target_addr_t address,
|
static int write_memory_bus_v0(struct target *target, target_addr_t address,
|
||||||
|
@ -3643,7 +3683,6 @@ struct target_type riscv013_target = {
|
||||||
.assert_reset = assert_reset,
|
.assert_reset = assert_reset,
|
||||||
.deassert_reset = deassert_reset,
|
.deassert_reset = deassert_reset,
|
||||||
|
|
||||||
.read_memory = read_memory,
|
|
||||||
.write_memory = write_memory,
|
.write_memory = write_memory,
|
||||||
|
|
||||||
.arch_state = arch_state,
|
.arch_state = arch_state,
|
||||||
|
|
|
@ -1487,12 +1487,12 @@ static int riscv_mmu(struct target *target, int *enabled)
|
||||||
static int riscv_address_translate(struct target *target,
|
static int riscv_address_translate(struct target *target,
|
||||||
target_addr_t virtual, target_addr_t *physical)
|
target_addr_t virtual, target_addr_t *physical)
|
||||||
{
|
{
|
||||||
|
RISCV_INFO(r);
|
||||||
riscv_reg_t satp_value;
|
riscv_reg_t satp_value;
|
||||||
int mode;
|
int mode;
|
||||||
uint64_t ppn_value;
|
uint64_t ppn_value;
|
||||||
target_addr_t table_address;
|
target_addr_t table_address;
|
||||||
virt2phys_info_t *info;
|
virt2phys_info_t *info;
|
||||||
struct target_type *tt = get_target_type(target);
|
|
||||||
uint64_t pte;
|
uint64_t pte;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1545,8 +1545,8 @@ static int riscv_address_translate(struct target *target,
|
||||||
(vpn << info->pte_shift);
|
(vpn << info->pte_shift);
|
||||||
uint8_t buffer[8];
|
uint8_t buffer[8];
|
||||||
assert(info->pte_shift <= 3);
|
assert(info->pte_shift <= 3);
|
||||||
int retval = tt->read_memory(target, pte_address,
|
int retval = r->read_memory(target, pte_address,
|
||||||
4, (1 << info->pte_shift) / 4, buffer);
|
4, (1 << info->pte_shift) / 4, buffer, 4);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
@ -1610,10 +1610,10 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
|
||||||
static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
|
static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
|
RISCV_INFO(r);
|
||||||
if (riscv_select_current_hart(target) != ERROR_OK)
|
if (riscv_select_current_hart(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
struct target_type *tt = get_target_type(target);
|
return r->read_memory(target, phys_address, size, count, buffer, size);
|
||||||
return tt->read_memory(target, phys_address, size, count, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_read_memory(struct target *target, target_addr_t address,
|
static int riscv_read_memory(struct target *target, target_addr_t address,
|
||||||
|
@ -1631,8 +1631,8 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
|
||||||
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
|
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
|
||||||
address = physical_addr;
|
address = physical_addr;
|
||||||
|
|
||||||
struct target_type *tt = get_target_type(target);
|
RISCV_INFO(r);
|
||||||
return tt->read_memory(target, address, size, count, buffer);
|
return r->read_memory(target, address, size, count, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
|
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
|
||||||
|
@ -2656,7 +2656,53 @@ COMMAND_HANDLER(riscv_set_ebreaku)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(handle_repeat_read)
|
||||||
|
{
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
RISCV_INFO(r);
|
||||||
|
|
||||||
|
if (CMD_ARGC < 2) {
|
||||||
|
LOG_ERROR("Command requires at least count and address arguments.");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
if (CMD_ARGC > 3) {
|
||||||
|
LOG_ERROR("Command takes at most 3 arguments.");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count);
|
||||||
|
target_addr_t address;
|
||||||
|
COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address);
|
||||||
|
uint32_t size = 4;
|
||||||
|
if (CMD_ARGC > 2)
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
uint8_t *buffer = malloc(size * count);
|
||||||
|
if (!buffer) {
|
||||||
|
LOG_ERROR("malloc failed");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
int result = r->read_memory(target, address, size, count, buffer, 0);
|
||||||
|
if (result == ERROR_OK) {
|
||||||
|
target_handle_md_output(cmd, target, address, size, count, buffer,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command_registration riscv_exec_command_handlers[] = {
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "repeat_read",
|
||||||
|
.handler = handle_repeat_read,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "riscv repeat_read count address [size=4]",
|
||||||
|
.help = "Repeatedly read the value at address."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "test_compliance",
|
.name = "test_compliance",
|
||||||
.handler = riscv_test_compliance,
|
.handler = riscv_test_compliance,
|
||||||
|
|
|
@ -152,6 +152,9 @@ typedef struct {
|
||||||
|
|
||||||
int (*test_compliance)(struct target *target);
|
int (*test_compliance)(struct target *target);
|
||||||
|
|
||||||
|
int (*read_memory)(struct target *target, target_addr_t address,
|
||||||
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
||||||
|
|
||||||
/* How many harts are attached to the DM that this target is attached to? */
|
/* How many harts are attached to the DM that this target is attached to? */
|
||||||
int (*hart_count)(struct target *target);
|
int (*hart_count)(struct target *target);
|
||||||
unsigned (*data_bits)(struct target *target);
|
unsigned (*data_bits)(struct target *target);
|
||||||
|
|
|
@ -3184,7 +3184,7 @@ COMMAND_HANDLER(handle_step_command)
|
||||||
|
|
||||||
void target_handle_md_output(struct command_invocation *cmd,
|
void target_handle_md_output(struct command_invocation *cmd,
|
||||||
struct target *target, target_addr_t address, unsigned size,
|
struct target *target, target_addr_t address, unsigned size,
|
||||||
unsigned count, const uint8_t *buffer)
|
unsigned count, const uint8_t *buffer, bool include_address)
|
||||||
{
|
{
|
||||||
const unsigned line_bytecnt = 32;
|
const unsigned line_bytecnt = 32;
|
||||||
unsigned line_modulo = line_bytecnt / size;
|
unsigned line_modulo = line_bytecnt / size;
|
||||||
|
@ -3213,7 +3213,7 @@ void target_handle_md_output(struct command_invocation *cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; i++) {
|
for (unsigned i = 0; i < count; i++) {
|
||||||
if (i % line_modulo == 0) {
|
if (include_address && (i % line_modulo == 0)) {
|
||||||
output_len += snprintf(output + output_len,
|
output_len += snprintf(output + output_len,
|
||||||
sizeof(output) - output_len,
|
sizeof(output) - output_len,
|
||||||
TARGET_ADDR_FMT ": ",
|
TARGET_ADDR_FMT ": ",
|
||||||
|
@ -3297,7 +3297,8 @@ COMMAND_HANDLER(handle_md_command)
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
int retval = fn(target, address, size, count, buffer);
|
int retval = fn(target, address, size, count, buffer);
|
||||||
if (ERROR_OK == retval)
|
if (ERROR_OK == retval)
|
||||||
target_handle_md_output(CMD, target, address, size, count, buffer);
|
target_handle_md_output(CMD, target, address, size, count, buffer,
|
||||||
|
true);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
|
|
|
@ -753,7 +753,7 @@ void target_handle_event(struct target *t, enum target_event e);
|
||||||
|
|
||||||
void target_handle_md_output(struct command_invocation *cmd,
|
void target_handle_md_output(struct command_invocation *cmd,
|
||||||
struct target *target, target_addr_t address, unsigned size,
|
struct target *target, target_addr_t address, unsigned size,
|
||||||
unsigned count, const uint8_t *buffer);
|
unsigned count, const uint8_t *buffer, bool include_address);
|
||||||
|
|
||||||
#define ERROR_TARGET_INVALID (-300)
|
#define ERROR_TARGET_INVALID (-300)
|
||||||
#define ERROR_TARGET_INIT_FAILED (-301)
|
#define ERROR_TARGET_INIT_FAILED (-301)
|
||||||
|
|
Loading…
Reference in New Issue