diff options
author | Megan Wachs <megan@sifive.com> | 2017-03-22 17:51:46 -0700 |
---|---|---|
committer | Megan Wachs <megan@sifive.com> | 2017-03-22 17:51:46 -0700 |
commit | c61b3efe9a3eafadce256706fde826f55d6abcd6 (patch) | |
tree | b68a54d18cf1158d5f35bf64cc3f6fcc9623710c | |
parent | 98420e377a946c825960a6d6104c209caa1faf6c (diff) | |
download | riscv-openocd-c61b3efe9a3eafadce256706fde826f55d6abcd6.zip riscv-openocd-c61b3efe9a3eafadce256706fde826f55d6abcd6.tar.gz riscv-openocd-c61b3efe9a3eafadce256706fde826f55d6abcd6.tar.bz2 |
riscv: Retry failed memory reads
-rw-r--r-- | src/target/riscv/riscv-013.c | 140 |
1 files changed, 75 insertions, 65 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index e67d69a..1bd31f9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1830,72 +1830,82 @@ static int read_memory(struct target *target, uint32_t address, { select_dmi(target); - abstract_write_register(target, S0, xlen(target), address); - - program_t *program = program_new(); - switch (size) { - case 1: - program_add32(program, lb(S1, S0, 0)); - break; - case 2: - program_add32(program, lh(S1, S0, 0)); - break; - case 4: - program_add32(program, lw(S1, S0, 0)); - break; - default: - LOG_ERROR("Unsupported size: %d", size); - return ERROR_FAIL; - } - program_add32(program, addi(S0, S0, size)); - program_add32(program, ebreak()); - write_program(target, program); - program_delete(program); - - if (execute_abstract_command(target, - AC_ACCESS_REGISTER_PREEXEC | - abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) { - return ERROR_FAIL; - } - dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); - dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); - - uint32_t abstractcs; - for (uint32_t i = 0; i < count; i++) { - uint32_t value = dmi_read(target, DMI_DATA0); - switch (size) { - case 1: - buffer[i] = value; - break; - case 2: - buffer[2*i] = value; - buffer[2*i+1] = value >> 8; - break; - case 4: - buffer[4*i] = value; - buffer[4*i+1] = value >> 8; - buffer[4*i+2] = value >> 16; - buffer[4*i+3] = value >> 24; - break; - default: - return ERROR_FAIL; - } - // 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, - // or otherwise take ac_command_busy into account (this defeats the purpose - // of autoexec, this whole code needs optimization). - if (wait_for_idle(target, &abstractcs) != ERROR_OK) { - return ERROR_FAIL; - } + while (1) { + abstract_write_register(target, S0, xlen(target), address); + + program_t *program = program_new(); + switch (size) { + case 1: + program_add32(program, lb(S1, S0, 0)); + break; + case 2: + program_add32(program, lh(S1, S0, 0)); + break; + case 4: + program_add32(program, lw(S1, S0, 0)); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + program_add32(program, addi(S0, S0, size)); + program_add32(program, ebreak()); + write_program(target, program); + program_delete(program); + + if (execute_abstract_command(target, + AC_ACCESS_REGISTER_PREEXEC | + abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) { + return ERROR_FAIL; + } + dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); + dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + uint32_t abstractcs; + for (uint32_t i = 0; i < count; i++) { + uint32_t value = dmi_read(target, DMI_DATA0); + switch (size) { + case 1: + buffer[i] = value; + break; + case 2: + buffer[2*i] = value; + buffer[2*i+1] = value >> 8; + break; + case 4: + buffer[4*i] = value; + buffer[4*i+1] = value >> 8; + buffer[4*i+2] = value >> 16; + buffer[4*i+3] = value >> 24; + break; + default: + return ERROR_FAIL; + } + // 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, + // or otherwise take ac_command_busy into account (this defeats the purpose + // of autoexec, this whole code needs optimization). + if (wait_for_idle(target, &abstractcs) != ERROR_OK) { + 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); - abstractcs = dmi_read(target, DMI_ABSTRACTCS); - if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) { - // TODO: retry with more delay? - return ERROR_FAIL; - } - - return ERROR_OK; + // Should not get here. + assert(0); + return ERROR_OK; } /** |