Deal with exceptions on register read.

Cache dpc, so we can restore it when it's clobbered by an exception.
This commit is contained in:
Tim Newsome 2016-06-10 13:58:57 -07:00
parent b81a846be5
commit cb57aa55fa
1 changed files with 24 additions and 14 deletions

View File

@ -120,6 +120,7 @@ typedef struct {
* RAM. */ * RAM. */
uint64_t dram_valid; uint64_t dram_valid;
uint32_t dcsr; uint32_t dcsr;
uint32_t dpc;
struct reg *reg_list; struct reg *reg_list;
/* Single buffer that contains all register names, instead of calling /* Single buffer that contains all register names, instead of calling
@ -497,6 +498,13 @@ static int resume(struct target *target, int current, uint32_t address,
return ERROR_FAIL; return ERROR_FAIL;
} }
// TODO: check if dpc is dirty (which also is true if an exception was hit
// at any time)
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, csrw(S0, CSR_DPC), false);
dram_write_jump(target, 2, false);
dram_write32(target, 4, info->dpc, true);
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU; info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
info->dcsr &= ~DCSR_HALT; info->dcsr &= ~DCSR_HALT;
@ -570,9 +578,9 @@ static int register_get(struct reg *reg)
dram_write_jump(target, 1, false); dram_write_jump(target, 1, false);
dram_write32(target, 0, sw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START), true); dram_write32(target, 0, sw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START), true);
} else if (reg->number == REG_PC) { } else if (reg->number == REG_PC) {
dram_write32(target, 0, csrr(S0, CSR_DPC), false); buf_set_u32(reg->value, 0, 32, info->dpc);
dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START), false); LOG_DEBUG("%s=0x%x (cached)", reg->name, value);
dram_write_jump(target, 2, true); return ERROR_OK;
} else if (reg->number >= REG_FPR0 && reg->number <= REG_FPR31) { } else if (reg->number >= REG_FPR0 && reg->number <= REG_FPR31) {
dram_write32(target, 0, fsw(reg->number - REG_FPR0, 0, DEBUG_RAM_START), false); dram_write32(target, 0, fsw(reg->number - REG_FPR0, 0, DEBUG_RAM_START), false);
dram_write_jump(target, 1, true); dram_write_jump(target, 1, true);
@ -590,6 +598,13 @@ static int register_get(struct reg *reg)
return ERROR_FAIL; return ERROR_FAIL;
} }
uint32_t exception = dram_read32(target, info->dramsize-1);
if (exception) {
LOG_ERROR("Got exception 0x%x when reading register %d", exception,
reg->number);
return ERROR_FAIL;
}
LOG_DEBUG("%s=0x%x", reg->name, value); LOG_DEBUG("%s=0x%x", reg->name, value);
buf_set_u32(reg->value, 0, 32, value); buf_set_u32(reg->value, 0, 32, value);
@ -615,9 +630,8 @@ static int register_write(struct target *target, unsigned int number,
dram_write32(target, 0, lw(number - REG_XPR0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 0, lw(number - REG_XPR0, ZERO, DEBUG_RAM_START + 16), false);
dram_write_jump(target, 1, false); dram_write_jump(target, 1, false);
} else if (number == REG_PC) { } else if (number == REG_PC) {
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); info->dpc = value;
dram_write32(target, 1, csrw(S0, CSR_DPC), false); return ERROR_OK;
dram_write_jump(target, 2, false);
} else if (number >= REG_FPR0 && number <= REG_FPR31) { } else if (number >= REG_FPR0 && number <= REG_FPR31) {
dram_write32(target, 0, flw(number - REG_FPR0, 0, DEBUG_RAM_START + 16), false); dram_write32(target, 0, flw(number - REG_FPR0, 0, DEBUG_RAM_START + 16), false);
dram_write_jump(target, 1, false); dram_write_jump(target, 1, false);
@ -741,16 +755,13 @@ static int riscv_halt(struct target *target)
static int riscv_step(struct target *target, int current, uint32_t address, static int riscv_step(struct target *target, int current, uint32_t address,
int handle_breakpoints) int handle_breakpoints)
{ {
riscv_info_t *info = (riscv_info_t *) target->arch_info;
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
// Hardware single step doesn't exist yet. // Hardware single step doesn't exist yet.
#if 0 #if 0
return resume(target, current, address, handle_breakpoints, 0, true); return resume(target, current, address, handle_breakpoints, 0, true);
#else #else
uint32_t dpc; uint32_t next_pc = info->dpc + 4;
if (read_csr(target, &dpc, CSR_DPC) != ERROR_OK) {
return ERROR_FAIL;
}
uint32_t next_pc = dpc + 4;
// TODO: write better next pc prediction code // TODO: write better next pc prediction code
if (breakpoint_add(target, next_pc, 4, BKPT_SOFT) != ERROR_OK) { if (breakpoint_add(target, next_pc, 4, BKPT_SOFT) != ERROR_OK) {
return ERROR_FAIL; return ERROR_FAIL;
@ -959,8 +970,7 @@ static int handle_halt(struct target *target)
riscv_info_t *info = (riscv_info_t *) target->arch_info; riscv_info_t *info = (riscv_info_t *) target->arch_info;
target->state = TARGET_HALTED; target->state = TARGET_HALTED;
uint32_t dpc; if (read_csr(target, &info->dpc, CSR_DPC) != ERROR_OK) {
if (read_csr(target, &dpc, CSR_DPC) != ERROR_OK) {
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -988,7 +998,7 @@ static int handle_halt(struct target *target)
target_call_event_callbacks(target, TARGET_EVENT_HALTED); target_call_event_callbacks(target, TARGET_EVENT_HALTED);
LOG_DEBUG("halted at 0x%x", dpc); LOG_DEBUG("halted at 0x%x", info->dpc);
return ERROR_OK; return ERROR_OK;
} }