riscv: Retry failed memory reads
parent
98420e377a
commit
c61b3efe9a
|
@ -1830,72 +1830,82 @@ static int read_memory(struct target *target, uint32_t address,
|
||||||
{
|
{
|
||||||
select_dmi(target);
|
select_dmi(target);
|
||||||
|
|
||||||
abstract_write_register(target, S0, xlen(target), address);
|
while (1) {
|
||||||
|
abstract_write_register(target, S0, xlen(target), address);
|
||||||
|
|
||||||
program_t *program = program_new();
|
program_t *program = program_new();
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
program_add32(program, lb(S1, S0, 0));
|
program_add32(program, lb(S1, S0, 0));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
program_add32(program, lh(S1, S0, 0));
|
program_add32(program, lh(S1, S0, 0));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
program_add32(program, lw(S1, S0, 0));
|
program_add32(program, lw(S1, S0, 0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Unsupported size: %d", size);
|
LOG_ERROR("Unsupported size: %d", size);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
program_add32(program, addi(S0, S0, size));
|
program_add32(program, addi(S0, S0, size));
|
||||||
program_add32(program, ebreak());
|
program_add32(program, ebreak());
|
||||||
write_program(target, program);
|
write_program(target, program);
|
||||||
program_delete(program);
|
program_delete(program);
|
||||||
|
|
||||||
if (execute_abstract_command(target,
|
if (execute_abstract_command(target,
|
||||||
AC_ACCESS_REGISTER_PREEXEC |
|
AC_ACCESS_REGISTER_PREEXEC |
|
||||||
abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) {
|
abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) {
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||||
|
|
||||||
uint32_t abstractcs;
|
uint32_t abstractcs;
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
uint32_t value = dmi_read(target, DMI_DATA0);
|
uint32_t value = dmi_read(target, DMI_DATA0);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
buffer[i] = value;
|
buffer[i] = value;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
buffer[2*i] = value;
|
buffer[2*i] = value;
|
||||||
buffer[2*i+1] = value >> 8;
|
buffer[2*i+1] = value >> 8;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
buffer[4*i] = value;
|
buffer[4*i] = value;
|
||||||
buffer[4*i+1] = value >> 8;
|
buffer[4*i+1] = value >> 8;
|
||||||
buffer[4*i+2] = value >> 16;
|
buffer[4*i+2] = value >> 16;
|
||||||
buffer[4*i+3] = value >> 24;
|
buffer[4*i+3] = value >> 24;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
// The above dmi_read started an abstract command. If we just
|
// The above dmi_read started an abstract command. If we just
|
||||||
// immediately read here, we'll probably get a busy error. Wait for idle first,
|
// immediately read here, we'll probably get a busy error. Wait for idle first,
|
||||||
// or otherwise take ac_command_busy into account (this defeats the purpose
|
// or otherwise take ac_command_busy into account (this defeats the purpose
|
||||||
// of autoexec, this whole code needs optimization).
|
// of autoexec, this whole code needs optimization).
|
||||||
if (wait_for_idle(target, &abstractcs) != ERROR_OK) {
|
if (wait_for_idle(target, &abstractcs) != ERROR_OK) {
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
dmi_write(target, DMI_ABSTRACTAUTO, 0);
|
||||||
|
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||||
|
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
unsigned cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||||
|
if (cmderr == CMDERR_BUSY) {
|
||||||
|
dmi_write(target, DMI_ABSTRACTCS, 0);
|
||||||
|
increase_ac_busy_delay(target);
|
||||||
|
} else if (cmderr) {
|
||||||
|
LOG_ERROR("cmderr=%d", get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
|
||||||
|
return ERROR_FAIL;
|
||||||
|
} else {
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
// Should not get here.
|
||||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
assert(0);
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
return ERROR_OK;
|
||||||
// TODO: retry with more delay?
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue