Cache registers while halted.

This saves us from re-reading s0 before doing just about anything
program buffer related.

Improves DebugBreakpoint from 3.01s to 2.89s. Feels like the improvement
should be larger than that. Maybe my metric isn't very good.

Change-Id: I85e1a1ddbf09006d76c451a32048be7b773dcfe9
This commit is contained in:
Tim Newsome 2018-04-06 15:52:40 -07:00
parent 5c0a9a9ee4
commit 238b1e9f06
1 changed files with 57 additions and 15 deletions

View File

@ -57,6 +57,7 @@ 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 int riscv013_dmi_write_u64_bits(struct target *target);
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_write_direct(struct target *target, unsigned number,
uint64_t value);
@ -846,7 +847,7 @@ static int examine_progbuf(struct target *target)
}
uint64_t s0;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@ -1055,6 +1056,11 @@ static int register_write_direct(struct target *target, unsigned number,
int result = register_write_abstract(target, number, value,
register_size(target, number));
if (result == ERROR_OK && target->reg_cache) {
struct reg *reg = &target->reg_cache->reg_list[number];
buf_set_u64(reg->value, 0, reg->size, value);
reg->valid = true;
}
if (result == ERROR_OK || info->progbufsize + r->impebreak < 2 ||
!riscv_is_halted(target))
return result;
@ -1063,7 +1069,7 @@ static int register_write_direct(struct target *target, unsigned number,
riscv_program_init(&program, target);
uint64_t s0;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
@ -1103,6 +1109,11 @@ static int register_write_direct(struct target *target, unsigned number,
int exec_out = riscv_program_exec(&program, target);
/* Don't message on error. Probably the register doesn't exist. */
if (exec_out == ERROR_OK && target->reg_cache) {
struct reg *reg = &target->reg_cache->reg_list[number];
buf_set_u64(reg->value, 0, reg->size, value);
reg->valid = true;
}
/* Restore S0. */
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
@ -1111,6 +1122,37 @@ static int register_write_direct(struct target *target, unsigned number,
return exec_out;
}
/** Return the cached value, or read from the target if necessary. */
static int register_read(struct target *target, uint64_t *value, uint32_t number)
{
if (number == GDB_REGNO_ZERO) {
*value = 0;
return ERROR_OK;
}
if (target->reg_cache &&
(number <= GDB_REGNO_XPR31 ||
(number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31))) {
/* Only check the cache for registers that we know won't spontaneously
* change. */
struct reg *reg = &target->reg_cache->reg_list[number];
if (reg && reg->valid) {
*value = buf_get_u64(reg->value, 0, reg->size);
LOG_INFO(">>> cache hit on %s: 0x%" PRIx64,
gdb_regno_name(number), *value);
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);
reg->valid = true;
}
return ERROR_OK;
}
/** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{
@ -1131,14 +1173,14 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
bool use_scratch = false;
uint64_t s0;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
/* Write program to move data into s0. */
uint64_t mstatus;
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
if (register_read_direct(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
if (register_read(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL;
if ((mstatus & MSTATUS_FS) == 0)
if (register_write_direct(target, GDB_REGNO_MSTATUS,
@ -1375,7 +1417,7 @@ static int examine(struct target *target)
else
r->xlen[i] = 32;
if (register_read_direct(target, &r->misa[i], GDB_REGNO_MISA)) {
if (register_read(target, &r->misa[i], GDB_REGNO_MISA)) {
LOG_ERROR("Fatal: Failed to read MISA from hart %d.", i);
return ERROR_FAIL;
}
@ -1948,9 +1990,9 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
* s1 holds the next data value to write
*/
uint64_t s0, s1;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
if (execute_fence(target) != ERROR_OK)
@ -2381,9 +2423,9 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
int result = ERROR_OK;
uint64_t s0, s1;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
/* Write the program (store, increment) */
@ -2607,14 +2649,14 @@ static int riscv013_get_register(struct target *target,
int result = ERROR_OK;
if (rid == GDB_REGNO_PC) {
result = register_read_direct(target, value, GDB_REGNO_DPC);
result = register_read(target, value, GDB_REGNO_DPC);
LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, *value);
} else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
result = register_read(target, &dcsr, GDB_REGNO_DCSR);
*value = get_field(dcsr, CSR_DCSR_PRV);
} else {
result = register_read_direct(target, value, rid);
result = register_read(target, value, rid);
if (result != ERROR_OK)
*value = -1;
}
@ -2644,7 +2686,7 @@ static int riscv013_set_register(struct target *target, int hid, int rid, uint64
}
} else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
register_read(target, &dcsr, GDB_REGNO_DCSR);
dcsr = set_field(dcsr, CSR_DCSR_PRV, value);
return register_write_direct(target, GDB_REGNO_DCSR, dcsr);
} else {
@ -2740,7 +2782,7 @@ static bool riscv013_is_halted(struct target *target)
static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
{
riscv_reg_t dcsr;
int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
int result = register_read(target, &dcsr, GDB_REGNO_DCSR);
if (result != ERROR_OK)
return RISCV_HALT_UNKNOWN;
@ -2839,7 +2881,7 @@ 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. */
riscv_reg_t dcsr;
int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR);
int result = register_read(target, &dcsr, GDB_REGNO_DCSR);
if (result != ERROR_OK)
return result;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);