Properly cache s0/s1 (#645)

* WIP on register caching.

So we don't have to save/restore S0 all the time.

Change-Id: I9d83a24dbd92a325213f2b25eebc9ede9dca2868

* Seems to work for RV32.

Change-Id: Ide620faa5dfef4f39c3146e094787ea28d041327

* Use caching everywhere.

Change-Id: I0de249437589e1f49811f34c12726528c045c74f

* Getting closer...

Change-Id: I532455f1e416723b79eecc7d33ec6407ccb8e33c

* All spike tests pass again.

Running all tests now takes 2m54s compared to 3m0s. That's probably not
the thing to measure, since the goal is to improve interactive
performance, while the tests do all kinds of other stuff (like sleep,
and start spike, etc.).

Change-Id: Ic7d944454a64b2baf6e6028debb4a1ba896834d8

* Save s0/s1 during examine.

Change-Id: I4795180e3b04d01433a11d4a0ccb38c35074cc44
Signed-off-by: Tim Newsome <tim@sifive.com>

* Check flush registers result.

Change-Id: I8350c4198cb41881e1143816698aed677a312111
Signed-off-by: Tim Newsome <tim@sifive.com>

* Fix upstream style regression.

Change-Id: I4cc7034151ba62fa51aea77e44b0cad9b9b97876
Signed-off-by: Tim Newsome <tim@sifive.com>
This commit is contained in:
Tim Newsome 2021-09-23 15:07:38 -07:00 committed by GitHub
parent 41ffb2dee6
commit 3858878d38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 129 additions and 123 deletions

View File

@ -884,11 +884,10 @@ static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation *
if (rev_id == info->revs[i].rev) if (rev_id == info->revs[i].rev)
rev_str = info->revs[i].str; rev_str = info->revs[i].str;
if (rev_str) { if (rev_str)
command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str); command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str);
} else { else
command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id); command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id);
}
return ERROR_OK; return ERROR_OK;
} }

View File

@ -57,7 +57,6 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a,
static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
static int riscv013_dmi_write_u64_bits(struct target *target); static int riscv013_dmi_write_u64_bits(struct target *target);
static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf);
static int register_read(struct target *target, uint64_t *value, uint32_t number);
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); static int register_read_direct(struct target *target, uint64_t *value, uint32_t number);
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);
@ -1022,8 +1021,7 @@ static int examine_progbuf(struct target *target)
return ERROR_OK; return ERROR_OK;
} }
uint64_t s0; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
struct riscv_program program; struct riscv_program program;
@ -1039,9 +1037,6 @@ static int examine_progbuf(struct target *target)
riscv_program_insert(&program, sw(S0, S0, 0)); riscv_program_insert(&program, sw(S0, S0, 0));
int result = riscv_program_exec(&program, target); int result = riscv_program_exec(&program, target);
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
if (result != ERROR_OK) { if (result != ERROR_OK) {
/* This program might have failed if the program buffer is not /* This program might have failed if the program buffer is not
* writable. */ * writable. */
@ -1089,7 +1084,7 @@ static int prep_for_register_access(struct target *target, uint64_t *mstatus,
int regno) int regno)
{ {
if (is_fpu_reg(regno) || is_vector_reg(regno)) { if (is_fpu_reg(regno) || is_vector_reg(regno)) {
if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) { if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) {
if (register_write_direct(target, GDB_REGNO_MSTATUS, if (register_write_direct(target, GDB_REGNO_MSTATUS,
@ -1315,8 +1310,7 @@ static int register_write_direct(struct target *target, unsigned number,
struct riscv_program program; struct riscv_program program;
riscv_program_init(&program, target); riscv_program_init(&program, target);
uint64_t s0; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
uint64_t mstatus; uint64_t mstatus;
@ -1352,9 +1346,6 @@ static int register_write_direct(struct target *target, unsigned number,
riscv_program_insert(&program, vsetvli(ZERO, S0, value)); riscv_program_insert(&program, vsetvli(ZERO, S0, value));
} else { } else {
if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
if (riscv_supports_extension(target, 'D')) if (riscv_supports_extension(target, 'D'))
riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0));
@ -1365,7 +1356,7 @@ static int register_write_direct(struct target *target, unsigned number,
* vsetvli and vsetvl instructions, and the fault-only-rst vector * vsetvli and vsetvl instructions, and the fault-only-rst vector
* load instruction variants." */ * load instruction variants." */
riscv_reg_t vtype; riscv_reg_t vtype;
if (register_read(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) if (register_read_direct(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (riscv_program_insert(&program, vsetvli(ZERO, S0, vtype)) != ERROR_OK) if (riscv_program_insert(&program, vsetvli(ZERO, S0, vtype)) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
@ -1375,6 +1366,8 @@ static int register_write_direct(struct target *target, unsigned number,
LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
} }
int exec_out = riscv_program_exec(&program, target); int exec_out = riscv_program_exec(&program, target);
@ -1390,30 +1383,9 @@ static int register_write_direct(struct target *target, unsigned number,
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Restore S0. */
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return exec_out; return exec_out;
} }
/** Read register value from the target. Also update the cached value. */
static int register_read(struct target *target, uint64_t *value, uint32_t number)
{
if (number == GDB_REGNO_ZERO) {
*value = 0;
return ERROR_OK;
}
int result = register_read_direct(target, value, number);
if (result != ERROR_OK)
return ERROR_FAIL;
if (target->reg_cache) {
struct reg *reg = &target->reg_cache->reg_list[number];
buf_set_u64(reg->value, 0, reg->size, *value);
}
return ERROR_OK;
}
/** Actually read registers from the target right now. */ /** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{ {
@ -1429,8 +1401,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
scratch_mem_t scratch; scratch_mem_t scratch;
bool use_scratch = false; bool use_scratch = false;
riscv_reg_t s0; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Write program to move data into s0. */ /* Write program to move data into s0. */
@ -1485,10 +1456,6 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Restore S0. */
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
} }
if (result == ERROR_OK) { if (result == ERROR_OK) {
@ -1550,7 +1517,7 @@ static int discover_vlenb(struct target *target)
RISCV_INFO(r); RISCV_INFO(r);
riscv_reg_t vlenb; riscv_reg_t vlenb;
if (register_read(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) { if (register_read_direct(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) {
LOG_WARNING("Couldn't read vlenb for %s; vector register access won't work.", LOG_WARNING("Couldn't read vlenb for %s; vector register access won't work.",
target_name(target)); target_name(target));
r->vlenb = 0; r->vlenb = 0;
@ -1737,7 +1704,19 @@ static int examine(struct target *target)
else else
r->xlen = 32; r->xlen = 32;
if (register_read(target, &r->misa, GDB_REGNO_MISA)) { /* Save s0 and s1. The register cache hasn't be initialized yet so we
* need to take care of this manually. */
uint64_t s0, s1;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) {
LOG_ERROR("Fatal: Failed to read s0 from hart %d.", r->current_hartid);
return ERROR_FAIL;
}
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) {
LOG_ERROR("Fatal: Failed to read s1 from hart %d.", r->current_hartid);
return ERROR_FAIL;
}
if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) {
LOG_ERROR("Fatal: Failed to read MISA from hart %d.", r->current_hartid); LOG_ERROR("Fatal: Failed to read MISA from hart %d.", r->current_hartid);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -1756,6 +1735,16 @@ static int examine(struct target *target)
LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen,
r->misa); r->misa);
/* Restore s0 and s1. */
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) {
LOG_ERROR("Fatal: Failed to write s0 back to hart %d.", r->current_hartid);
return ERROR_FAIL;
}
if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) {
LOG_ERROR("Fatal: Failed to write s1 back to hart %d.", r->current_hartid);
return ERROR_FAIL;
}
if (!halted) if (!halted)
riscv013_step_or_resume_current_hart(target, false, false); riscv013_step_or_resume_current_hart(target, false, false);
@ -1927,9 +1916,9 @@ static int prep_for_vector_access(struct target *target, uint64_t *vtype,
} }
/* Save vtype and vl. */ /* Save vtype and vl. */
if (register_read(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK) if (register_read_direct(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (register_read(target, vl, GDB_REGNO_VL) != ERROR_OK) if (register_read_direct(target, vl, GDB_REGNO_VL) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK)
@ -1960,8 +1949,7 @@ static int riscv013_get_register_buf(struct target *target,
if (riscv_select_current_hart(target) != ERROR_OK) if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
riscv_reg_t s0; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
uint64_t mstatus; uint64_t mstatus;
@ -2005,8 +1993,6 @@ static int riscv013_get_register_buf(struct target *target,
if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return result; return result;
} }
@ -2019,8 +2005,7 @@ static int riscv013_set_register_buf(struct target *target,
if (riscv_select_current_hart(target) != ERROR_OK) if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
riscv_reg_t s0; if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
uint64_t mstatus; uint64_t mstatus;
@ -2053,8 +2038,6 @@ static int riscv013_set_register_buf(struct target *target,
if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return result; return result;
} }
@ -2562,11 +2545,11 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *
if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) { if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) {
/* Read DCSR */ /* Read DCSR */
uint64_t dcsr; uint64_t dcsr;
if (register_read(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Read and save MSTATUS */ /* Read and save MSTATUS */
if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
*mstatus_old = *mstatus; *mstatus_old = *mstatus;
@ -3349,10 +3332,9 @@ static int read_memory_progbuf_one(struct target *target, target_addr_t address,
if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
uint64_t s0;
int result = ERROR_FAIL; int result = ERROR_FAIL;
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
goto restore_mstatus; goto restore_mstatus;
/* Write the program (load, increment) */ /* Write the program (load, increment) */
@ -3392,19 +3374,15 @@ static int read_memory_progbuf_one(struct target *target, target_addr_t address,
riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | riscv_xlen(target), AC_ACCESS_REGISTER_WRITE |
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
if (execute_abstract_command(target, command) != ERROR_OK) if (execute_abstract_command(target, command) != ERROR_OK)
goto restore_s0; goto restore_mstatus;
uint64_t value; uint64_t value;
if (register_read(target, &value, GDB_REGNO_S0) != ERROR_OK) if (register_read_direct(target, &value, GDB_REGNO_S0) != ERROR_OK)
goto restore_s0; goto restore_mstatus;
buf_set_u64(buffer, 0, 8 * size, value); buf_set_u64(buffer, 0, 8 * size, value);
log_memory_access(address, value, size, true); log_memory_access(address, value, size, true);
result = ERROR_OK; result = ERROR_OK;
restore_s0:
if (riscv_set_register(target, GDB_REGNO_S0, s0) != ERROR_OK)
result = ERROR_FAIL;
restore_mstatus: restore_mstatus:
if (mstatus != mstatus_old) if (mstatus != mstatus_old)
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old))
@ -3449,12 +3427,11 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
* s1 holds the next data value read * s1 holds the next data value read
* s2 is a counter in case increment is 0 * s2 is a counter in case increment is 0
*/ */
uint64_t s0, s1, s2; if (riscv_save_register(target, 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 (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (increment == 0 && register_read(target, &s2, GDB_REGNO_S2) != ERROR_OK) if (increment == 0 && riscv_save_register(target, GDB_REGNO_S2) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Write the program (load, increment) */ /* Write the program (load, increment) */
@ -3519,11 +3496,6 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
result = ERROR_OK; result = ERROR_OK;
} }
riscv_set_register(target, GDB_REGNO_S0, s0);
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)
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old))
@ -3814,10 +3786,9 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
*/ */
int result = ERROR_OK; int result = ERROR_OK;
uint64_t s0, s1; if (riscv_save_register(target, 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 (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
/* Write the program (store, increment) */ /* Write the program (store, increment) */
@ -3965,11 +3936,6 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
error: error:
dmi_write(target, DM_ABSTRACTAUTO, 0); dmi_write(target, DM_ABSTRACTAUTO, 0);
if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK)
return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
/* Restore MSTATUS */ /* Restore MSTATUS */
if (mstatus != mstatus_old) if (mstatus != mstatus_old)
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old))
@ -4079,16 +4045,16 @@ static int riscv013_get_register(struct target *target,
int result = ERROR_OK; int result = ERROR_OK;
if (rid == GDB_REGNO_PC) { if (rid == GDB_REGNO_PC) {
/* TODO: move this into riscv.c. */ /* TODO: move this into riscv.c. */
result = register_read(target, value, GDB_REGNO_DPC); result = register_read_direct(target, value, GDB_REGNO_DPC);
LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value); LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value);
} else if (rid == GDB_REGNO_PRIV) { } else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr; uint64_t dcsr;
/* TODO: move this into riscv.c. */ /* TODO: move this into riscv.c. */
result = register_read(target, &dcsr, GDB_REGNO_DCSR); result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
*value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V));
*value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV));
} else { } else {
result = register_read(target, value, rid); result = register_read_direct(target, value, rid);
if (result != ERROR_OK) if (result != ERROR_OK)
*value = -1; *value = -1;
} }
@ -4117,7 +4083,7 @@ static int riscv013_set_register(struct target *target, int rid, uint64_t value)
} }
} else if (rid == GDB_REGNO_PRIV) { } else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr; uint64_t dcsr;
register_read(target, &dcsr, GDB_REGNO_DCSR); register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV));
dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V));
return register_write_direct(target, GDB_REGNO_DCSR, dcsr); return register_write_direct(target, GDB_REGNO_DCSR, dcsr);
@ -4319,7 +4285,7 @@ static bool riscv013_is_halted(struct target *target)
static enum riscv_halt_reason riscv013_halt_reason(struct target *target) static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
{ {
riscv_reg_t dcsr; riscv_reg_t dcsr;
int result = register_read(target, &dcsr, GDB_REGNO_DCSR); int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
if (result != ERROR_OK) if (result != ERROR_OK)
return RISCV_HALT_UNKNOWN; return RISCV_HALT_UNKNOWN;
@ -4779,14 +4745,18 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
/* We want to twiddle some bits in the debug CSR so debugging works. */ /* We want to twiddle some bits in the debug CSR so debugging works. */
riscv_reg_t dcsr; riscv_reg_t dcsr;
int result = register_read(target, &dcsr, GDB_REGNO_DCSR); int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
if (result != ERROR_OK) if (result != ERROR_OK)
return result; return result;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku);
return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); if (riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
if (riscv_flush_registers(target) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
} }
static int riscv013_step_or_resume_current_hart(struct target *target, static int riscv013_step_or_resume_current_hart(struct target *target,
@ -4799,6 +4769,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
return ERROR_FAIL; return ERROR_FAIL;
} }
if (riscv_flush_registers(target) != ERROR_OK)
return ERROR_FAIL;
/* Issue the resume command, and then wait for the current hart to resume. */ /* Issue the resume command, and then wait for the current hart to resume. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
if (use_hasel) if (use_hasel)

View File

@ -1155,6 +1155,29 @@ int riscv_select_current_hart(struct target *target)
return riscv_set_current_hartid(target, target->coreid); return riscv_set_current_hartid(target, target->coreid);
} }
int riscv_flush_registers(struct target *target)
{
RISCV_INFO(r);
if (!target->reg_cache)
return ERROR_OK;
for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) {
struct reg *reg = &target->reg_cache->reg_list[number];
if (reg->valid && reg->dirty) {
uint64_t value = buf_get_u64(reg->value, 0, reg->size);
LOG_DEBUG("[%s] %s is dirty; write back 0x%" PRIx64,
target_name(target), reg->name, value);
int result = r->set_register(target, number, value);
if (result != ERROR_OK)
return ERROR_FAIL;
reg->dirty = false;
}
}
return ERROR_OK;
}
int halt_prep(struct target *target) int halt_prep(struct target *target)
{ {
RISCV_INFO(r); RISCV_INFO(r);
@ -1276,27 +1299,6 @@ static int riscv_deassert_reset(struct target *target)
return tt->deassert_reset(target); return tt->deassert_reset(target);
} }
int riscv_resume_prep_all_harts(struct target *target)
{
RISCV_INFO(r);
LOG_DEBUG("[%s] prep hart", target_name(target));
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_is_halted(target)) {
if (r->resume_prep(target) != ERROR_OK)
return ERROR_FAIL;
} else {
LOG_DEBUG("[%s] hart requested resume, but was already resumed",
target_name(target));
}
LOG_DEBUG("[%s] mark as prepped", target_name(target));
r->prepped = true;
return ERROR_OK;
}
/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ /* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */
static int disable_triggers(struct target *target, riscv_reg_t *state) static int disable_triggers(struct target *target, riscv_reg_t *state)
{ {
@ -1411,7 +1413,9 @@ static int resume_prep(struct target *target, int current,
} }
if (r->is_halted) { if (r->is_halted) {
if (riscv_resume_prep_all_harts(target) != ERROR_OK) if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (r->resume_prep(target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -3439,11 +3443,9 @@ int riscv_step_rtos_hart(struct target *target)
LOG_ERROR("Hart isn't halted before single step!"); LOG_ERROR("Hart isn't halted before single step!");
return ERROR_FAIL; return ERROR_FAIL;
} }
riscv_invalidate_register_cache(target);
r->on_step(target); r->on_step(target);
if (r->step_current_hart(target) != ERROR_OK) if (r->step_current_hart(target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
riscv_invalidate_register_cache(target);
r->on_halt(target); r->on_halt(target);
if (!riscv_is_halted(target)) { if (!riscv_is_halted(target)) {
LOG_ERROR("Hart was not halted after single step!"); LOG_ERROR("Hart was not halted after single step!");
@ -3585,14 +3587,17 @@ int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t
struct reg *reg = &target->reg_cache->reg_list[regid]; struct reg *reg = &target->reg_cache->reg_list[regid];
buf_set_u64(reg->value, 0, reg->size, value); buf_set_u64(reg->value, 0, reg->size, value);
int result = r->set_register(target, regid, value); if (gdb_regno_cacheable(regid, true)) {
if (result == ERROR_OK) reg->valid = true;
reg->valid = gdb_regno_cacheable(regid, true); reg->dirty = true;
else } else {
reg->valid = false; if (r->set_register(target, regid, value) != ERROR_OK)
return ERROR_FAIL;
}
LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d", LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d",
target_name(target), value, reg->name, reg->valid); target_name(target), value, reg->name, reg->valid);
return result; return ERROR_OK;
} }
int riscv_get_register(struct target *target, riscv_reg_t *value, int riscv_get_register(struct target *target, riscv_reg_t *value,
@ -3600,8 +3605,6 @@ int riscv_get_register(struct target *target, riscv_reg_t *value,
{ {
RISCV_INFO(r); RISCV_INFO(r);
keep_alive();
struct reg *reg = &target->reg_cache->reg_list[regid]; struct reg *reg = &target->reg_cache->reg_list[regid];
if (!reg->exist) { if (!reg->exist) {
LOG_DEBUG("[%s] %s does not exist.", LOG_DEBUG("[%s] %s does not exist.",
@ -3625,14 +3628,40 @@ int riscv_get_register(struct target *target, riscv_reg_t *value,
int result = r->get_register(target, value, regid); int result = r->get_register(target, value, regid);
if (result == ERROR_OK) if (result == ERROR_OK) {
/* Update the cache in case we're called from
* riscv_save_register(). */
buf_set_u64(reg->value, 0, reg->size, *value);
reg->valid = gdb_regno_cacheable(regid, false); reg->valid = gdb_regno_cacheable(regid, false);
}
LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target), LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target),
gdb_regno_name(regid), *value); gdb_regno_name(regid), *value);
return result; return result;
} }
int riscv_save_register(struct target *target, enum gdb_regno regid)
{
riscv_reg_t value;
if (!target->reg_cache) {
assert(!target_was_examined(target));
return ERROR_OK;
}
struct reg *reg = &target->reg_cache->reg_list[regid];
LOG_DEBUG("[%s] save %s", target_name(target), reg->name);
if (riscv_get_register(target, &value, regid) != ERROR_OK)
return ERROR_FAIL;
if (!reg->valid)
return ERROR_FAIL;
/* Mark the register dirty. We assume that this function is called
* because the caller is about to mess with the underlying value of the
* register. */
reg->dirty = true;
return ERROR_OK;
}
bool riscv_is_halted(struct target *target) bool riscv_is_halted(struct target *target)
{ {
RISCV_INFO(r); RISCV_INFO(r);

View File

@ -350,6 +350,11 @@ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
/** Get register, from the cache if it's in there. */ /** Get register, from the cache if it's in there. */
int riscv_get_register(struct target *target, riscv_reg_t *value, int riscv_get_register(struct target *target, riscv_reg_t *value,
enum gdb_regno r); enum gdb_regno r);
/** Read the register into the cache, and mark it dirty so it will be restored
* before resuming. */
int riscv_save_register(struct target *target, enum gdb_regno regid);
/** Write all dirty registers to the target. */
int riscv_flush_registers(struct target *target);
/* Checks the state of the current hart -- "is_halted" checks the actual /* Checks the state of the current hart -- "is_halted" checks the actual
* on-device register. */ * on-device register. */