Finally nailed memory read on slow targets

The downloaded program now post-increments, and there's no longer an
attempt to read the current address from the target. This made it easier
to fix the problem where at the start of the loop the current address
was already read (in regular entry) or has not yet been read (when the
first round through the loop encountered busy more than once, or busy
was encountered at least once later on).
This commit is contained in:
Tim Newsome 2017-08-27 13:25:54 -07:00
parent 5f53655e65
commit 2efc415db4
1 changed files with 21 additions and 36 deletions

View File

@ -1273,7 +1273,6 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_addr_t r_addr = riscv_program_alloc_x(&program);
riscv_program_fence(&program);
riscv_program_lx(&program, GDB_REGNO_S0, r_addr);
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
switch (size) {
case 1:
riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0);
@ -1288,6 +1287,7 @@ static int read_memory(struct target *target, target_addr_t address,
LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL;
}
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
riscv_program_sw(&program, GDB_REGNO_S1, r_data);
riscv_program_sx(&program, GDB_REGNO_S0, r_addr);
@ -1295,9 +1295,9 @@ static int read_memory(struct target *target, target_addr_t address,
* program execution mechanism. */
switch (riscv_xlen(target)) {
case 64:
riscv_program_write_ram(&program, r_addr + 4, (((riscv_addr_t) address) - size) >> 32);
riscv_program_write_ram(&program, r_addr + 4, ((riscv_addr_t) address) >> 32);
case 32:
riscv_program_write_ram(&program, r_addr, ((riscv_addr_t) address) - size);
riscv_program_write_ram(&program, r_addr, (riscv_addr_t) address);
break;
default:
LOG_ERROR("unknown XLEN %d", riscv_xlen(target));
@ -1314,27 +1314,6 @@ static int read_memory(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
uint32_t value = riscv_program_read_ram(&program, r_data);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", address, value);
switch (size) {
case 1:
buffer[0] = value;
break;
case 2:
buffer[0] = value;
buffer[1] = value >> 8;
break;
case 4:
buffer[0] = value;
buffer[1] = value >> 8;
buffer[2] = value >> 16;
buffer[3] = value >> 24;
break;
default:
LOG_ERROR("unsupported access size: %d", size);
return ERROR_FAIL;
}
/* The rest of this program is designed to be fast so it reads various
* DMI registers directly. */
int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4;
@ -1346,22 +1325,16 @@ static int read_memory(struct target *target, target_addr_t address,
* case we need to back off a bit and try again. There's two
* termination conditions to this loop: a non-BUSY error message, or
* the data was all copied. */
riscv_addr_t cur_addr = 0xbadbeef;
riscv_addr_t cur_addr = address;
riscv_addr_t fin_addr = address + (count * size);
riscv_addr_t prev_addr = ((riscv_addr_t) address) - size;
bool ignore_prev_addr = true;
bool this_is_last_read = false;
LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr);
while (count > 1 && !this_is_last_read) {
cur_addr = riscv_read_debug_buffer_x(target, d_addr);
while (!this_is_last_read) {
riscv_addr_t start = (cur_addr - address) / size;
LOG_DEBUG("reading burst at address 0x%" TARGET_PRIxADDR
"; prev_addr=0x%" TARGET_PRIxADDR "; start=0x%"
TARGET_PRIxADDR, cur_addr, prev_addr, start);
assert(ignore_prev_addr || prev_addr < cur_addr);
prev_addr = cur_addr;
ignore_prev_addr = false;
assert (cur_addr >= address);
"; start=0x%"
TARGET_PRIxADDR, cur_addr, start);
assert(cur_addr >= address && cur_addr < fin_addr);
struct riscv_batch *batch = riscv_batch_alloc(
target,
32,
@ -1426,7 +1399,6 @@ static int read_memory(struct target *target, target_addr_t address,
}
if (retry_batch_transaction) {
this_is_last_read = false;
ignore_prev_addr = true;
switch (riscv_xlen(target)) {
case 64:
@ -1439,6 +1411,16 @@ static int read_memory(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
if (riscv013_execute_debug_buffer(target) != ERROR_OK) {
uint32_t acs = dmi_read(target, DMI_ABSTRACTCS);
LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs);
riscv013_clear_abstract_error(target);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
LOG_ERROR(" exiting with ERROR_FAIL");
return ERROR_FAIL;
}
continue;
}
@ -1446,6 +1428,7 @@ static int read_memory(struct target *target, target_addr_t address,
riscv_addr_t offset = size*i;
riscv_addr_t t_addr = address + offset;
uint8_t *t_buffer = buffer + offset;
uint32_t value;
if (this_is_last_read && i == start + reads - 1) {
riscv013_set_autoexec(target, d_data, 0);
@ -1485,6 +1468,8 @@ static int read_memory(struct target *target, target_addr_t address,
LOG_DEBUG("M[0x%08lx] reads 0x%08x", (long)t_addr, value);
}
riscv_batch_free(batch);
cur_addr += reads * size;
}
riscv013_set_autoexec(target, d_data, 0);