Reading/writing s1 now works.
This commit is contained in:
parent
0881092d9b
commit
90f458e63f
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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()?
|
||||||
|
|
Loading…
Reference in New Issue