Reading/writing s1 now works.

This commit is contained in:
Tim Newsome 2016-06-10 10:24:02 -07:00
parent 0881092d9b
commit 90f458e63f
2 changed files with 162 additions and 58 deletions

View File

@ -182,6 +182,11 @@ static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
(dest << 7) | (dest << 7) |
MATCH_ORI; MATCH_ORI;
} }
static uint32_t nop(void)
{
return addi(0, 0, 0);
}
*/ */
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
@ -199,8 +204,3 @@ static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
(dest << 7) | (dest << 7) |
MATCH_SRLI; MATCH_SRLI;
} }
static uint32_t nop(void)
{
return addi(0, 0, 0);
}

View File

@ -330,12 +330,14 @@ static void dram_write32(struct target *target, unsigned int index, uint32_t val
{ {
riscv_info_t *info = (riscv_info_t *) target->arch_info; riscv_info_t *info = (riscv_info_t *) target->arch_info;
#if 1
if (!set_interrupt && if (!set_interrupt &&
info->dram_valid & (1<<index) && info->dram_valid & (1<<index) &&
info->dram[index] == value) { info->dram[index] == value) {
LOG_DEBUG("DRAM cache hit: 0x%x @%d", value, index); LOG_DEBUG("DRAM cache hit: 0x%x @%d", value, index);
return; return;
} }
#endif
uint64_t dbus_value = DMCONTROL_HALTNOT | value; uint64_t dbus_value = DMCONTROL_HALTNOT | value;
if (set_interrupt) if (set_interrupt)
@ -435,6 +437,28 @@ static int wait_for_debugint_clear(struct target *target)
} }
} }
static int wait_and_read(struct target *target, uint32_t *data, uint16_t address)
{
riscv_info_t *info = (riscv_info_t *) target->arch_info;
time_t start = time(NULL);
// Throw away the results of the first read, since they'll contain the
// result of the read that happened just before debugint was set. (Assuming
// the last scan before calling this function was one that sets debugint.)
dbus_read(target, info->dbus_address, address);
while (1) {
uint64_t dbus_value = dbus_read(target, info->dbus_address, address);
*data = dbus_value;
if (!get_field(dbus_value, DMCONTROL_INTERRUPT)) {
return ERROR_OK;
}
if (time(NULL) - start > 2) {
LOG_ERROR("Timed out waiting for debug int to clear.");
return ERROR_FAIL;
}
}
}
static int read_csr(struct target *target, uint32_t *value, uint32_t csr) static int read_csr(struct target *target, uint32_t *value, uint32_t csr)
{ {
dram_write32(target, 0, csrr(S0, csr), false); dram_write32(target, 0, csrr(S0, csr), false);
@ -534,14 +558,23 @@ static int register_get(struct reg *reg)
{ {
struct target *target = (struct target *) reg->arch_info; struct target *target = (struct target *) reg->arch_info;
riscv_info_t *info = (riscv_info_t *) target->arch_info; riscv_info_t *info = (riscv_info_t *) target->arch_info;
uint32_t value = 0;
// TODO: S0 and S1 if (reg->number == S0) {
if (reg->number == ZERO) { dram_write32(target, 0, csrr(S0, CSR_DSCRATCH), false);
buf_set_u64(reg->value, 0, info->xlen, 0); dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START), false);
dram_write_jump(target, 2, true);
} else if (reg->number == S1) {
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 4 * info->dramsize - 4), false);
dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START), false);
dram_write_jump(target, 2, true);
} else if (reg->number == ZERO) {
buf_set_u64(reg->value, 0, info->xlen, value);
LOG_DEBUG("%s=0x%x", reg->name, value);
return ERROR_OK; return ERROR_OK;
} else if (reg->number <= REG_XPR31) { } else if (reg->number <= REG_XPR31) {
dram_write32(target, 0, sw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START), false); dram_write_jump(target, 1, false);
dram_write_jump(target, 1, 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); dram_write32(target, 0, csrr(S0, CSR_DPC), false);
dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START), false); dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START), false);
@ -558,28 +591,37 @@ static int register_get(struct reg *reg)
return ERROR_FAIL; return ERROR_FAIL;
} }
if (wait_for_debugint_clear(target) != ERROR_OK) { if (wait_and_read(target, &value, 0) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear."); LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL; return ERROR_FAIL;
} }
uint32_t value = dram_read32(target, 0);
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);
info->dram_valid &= ~1;
return ERROR_OK; return ERROR_OK;
} }
static int register_set(struct reg *reg, uint8_t *buf) static int register_set(struct reg *reg, uint8_t *buf)
{ {
struct target *target = (struct target *) reg->arch_info; struct target *target = (struct target *) reg->arch_info;
riscv_info_t *info = (riscv_info_t *) target->arch_info;
uint32_t value = buf_get_u32(buf, 0, 32); uint32_t value = buf_get_u32(buf, 0, 32);
LOG_DEBUG("write 0x%x to %s", value, reg->name); LOG_DEBUG("write 0x%x to %s", value, reg->name);
// TODO: S0 and S1 if (reg->number == S0) {
if (reg->number <= REG_XPR31) { dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, csrw(S0, CSR_DSCRATCH), false);
dram_write_jump(target, 2, false);
} else if (reg->number == S1) {
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, sw(S0, ZERO, DEBUG_RAM_START + 4 * info->dramsize - 4), false);
dram_write_jump(target, 2, false);
} else if (reg->number <= REG_XPR31) {
dram_write32(target, 0, lw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 0, lw(reg->number - REG_XPR0, ZERO, DEBUG_RAM_START + 16), false);
dram_write_jump(target, 1, false); dram_write_jump(target, 1, false);
} else if (reg->number == REG_PC) { } else if (reg->number == REG_PC) {
@ -677,6 +719,53 @@ static void riscv_deinit_target(struct target *target)
target->arch_info = NULL; target->arch_info = NULL;
} }
static int riscv_halt(struct target *target)
{
LOG_DEBUG("riscv_halt()");
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
dram_write32(target, 0, csrsi(CSR_DCSR, DCSR_HALT), false);
dram_write32(target, 1, csrr(S0, CSR_MHARTID), false);
dram_write32(target, 2, sw(S0, ZERO, SETHALTNOT), false);
dram_write_jump(target, 3, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int riscv_step(struct target *target, int current, uint32_t address,
int handle_breakpoints)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
// Hardware single step doesn't exist yet.
#if 0
return resume(target, current, address, handle_breakpoints, 0, true);
#else
uint32_t dpc;
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
if (breakpoint_add(target, next_pc, 4, BKPT_SOFT) != ERROR_OK) {
return ERROR_FAIL;
}
if (resume(target, current, address, handle_breakpoints, 0, false) != ERROR_OK) {
return ERROR_FAIL;
}
while (target->state == TARGET_RUNNING) {
riscv_poll(target);
}
breakpoint_remove(target, next_pc);
return ERROR_OK;
#endif
}
#if 0 #if 0
static void dram_test(struct target *target) static void dram_test(struct target *target)
{ {
@ -741,6 +830,22 @@ static void write_constants(struct target *target)
} }
#endif #endif
#if 0
static void test_s1(struct target *target)
{
riscv_info_t *info = (riscv_info_t *) target->arch_info;
riscv_halt(target);
riscv_poll(target);
dram_write32(target, info->dramsize - 1, 0xdeadbed, false);
dram_read32(target, info->dramsize - 1);
riscv_step(target, true, 0, 0);
dram_read32(target, info->dramsize - 1);
exit(0);
}
#endif
static int riscv_examine(struct target *target) static int riscv_examine(struct target *target)
{ {
LOG_DEBUG("riscv_examine()"); LOG_DEBUG("riscv_examine()");
@ -789,10 +894,6 @@ static int riscv_examine(struct target *target)
return ERROR_FAIL; return ERROR_FAIL;
} }
//write_constants(target);
//light_leds(target);
//dram_test(target);
// Figure out XLEN. // Figure out XLEN.
dram_write32(target, 0, xori(S1, ZERO, -1), false); dram_write32(target, 0, xori(S1, ZERO, -1), false);
// 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff // 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff
@ -816,13 +917,7 @@ static int riscv_examine(struct target *target)
} }
// Execute. // Execute.
#if 1
// TODO: Doesn't work without this extra nop.
dram_write32(target, 5, nop(), false);
dram_write_jump(target, 6, true);
#else
dram_write_jump(target, 5, true); dram_write_jump(target, 5, true);
#endif
if (wait_for_debugint_clear(target) != ERROR_OK) { if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear."); LOG_ERROR("Debug interrupt didn't clear.");
@ -850,6 +945,48 @@ static int riscv_examine(struct target *target)
target_set_examined(target); target_set_examined(target);
//write_constants(target);
//light_leds(target);
//dram_test(target);
//test_s1(target);
return ERROR_OK;
}
static int handle_halt(struct target *target)
{
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
target->state = TARGET_HALTED;
uint32_t dpc;
if (read_csr(target, &dpc, CSR_DPC) != ERROR_OK) {
return ERROR_FAIL;
}
uint32_t dcsr;
if (read_csr(target, &dcsr, CSR_DCSR) != ERROR_OK) {
return ERROR_FAIL;
}
int cause = get_field(dcsr, DCSR_CAUSE);
switch (cause) {
case DCSR_CAUSE_SWBP:
case DCSR_CAUSE_HWBP:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case DCSR_CAUSE_DEBUGINT:
target->debug_reason = DBG_REASON_DBGRQ;
break;
case DCSR_CAUSE_STEP:
target->debug_reason = DBG_REASON_SINGLESTEP;
break;
case DCSR_CAUSE_HALT:
default:
LOG_ERROR("Invalid halt cause %d in DCSR (0x%x)",
cause, dcsr);
}
LOG_DEBUG("halted at 0x%x", dpc);
return ERROR_OK; return ERROR_OK;
} }
@ -863,16 +1000,8 @@ static int riscv_poll(struct target *target)
LOG_DEBUG("debug running"); LOG_DEBUG("debug running");
} else if (bits.haltnot && !bits.interrupt) { } else if (bits.haltnot && !bits.interrupt) {
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
target_call_event_callbacks(target, TARGET_EVENT_HALTED); return handle_halt(target);
} }
target->state = TARGET_HALTED;
uint32_t dpc;
if (read_csr(target, &dpc, CSR_DPC) != ERROR_OK) {
return ERROR_FAIL;
}
LOG_DEBUG("halted at 0x%x", dpc);
} else if (!bits.haltnot && bits.interrupt) { } else if (!bits.haltnot && bits.interrupt) {
// Target is halting. There is no state for that, so don't change anything. // Target is halting. There is no state for that, so don't change anything.
LOG_DEBUG("halting"); LOG_DEBUG("halting");
@ -884,24 +1013,6 @@ static int riscv_poll(struct target *target)
return ERROR_OK; return ERROR_OK;
} }
static int riscv_halt(struct target *target)
{
LOG_DEBUG("riscv_halt()");
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
dram_write32(target, 0, csrsi(CSR_DCSR, DCSR_HALT), false);
dram_write32(target, 1, csrr(S0, CSR_MHARTID), false);
dram_write32(target, 2, sw(S0, ZERO, SETHALTNOT), false);
dram_write_jump(target, 3, true);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int riscv_resume(struct target *target, int current, uint32_t address, static int riscv_resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution) int handle_breakpoints, int debug_execution)
{ {
@ -910,13 +1021,6 @@ static int riscv_resume(struct target *target, int current, uint32_t address,
debug_execution, false); debug_execution, false);
} }
static int riscv_step(struct target *target, int current, uint32_t address,
int handle_breakpoints)
{
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
return resume(target, current, address, handle_breakpoints, 0, true);
}
static int riscv_assert_reset(struct target *target) static int riscv_assert_reset(struct target *target)
{ {
// TODO: Maybe what I implemented here is more like soft_reset_halt()? // TODO: Maybe what I implemented here is more like soft_reset_halt()?