In theory assert_reset/deassert_reset work.

This commit is contained in:
Tim Newsome 2016-05-24 16:59:57 -07:00
parent ea6836c5f6
commit 76fe7db0db
2 changed files with 109 additions and 41 deletions

View File

@ -36,6 +36,14 @@ static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
MATCH_SW;
}
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LW;
}
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
{
return (bits(imm, 11, 0) << 20) |
@ -58,15 +66,15 @@ static uint32_t csrci(unsigned int csr, uint16_t imm) {
MATCH_CSRRCI;
}
static uint32_t csrw(unsigned int source, unsigned int csr) {
return (csr << 20) | (source << 15) | MATCH_CSRRW;
}
/*
static uint32_t csrr(unsigned int rd, unsigned int csr) {
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
}
static uint32_t csrw(unsigned int source, unsigned int csr) {
return (csr << 20) | (source << 15) | MATCH_CSRRW;
}
static uint32_t fence_i(void)
{
return MATCH_FENCE_I;
@ -107,14 +115,6 @@ static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
MATCH_LD;
}
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |
(base << 15) |
(bits(rd, 4, 0) << 7) |
MATCH_LW;
}
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
{
return (bits(offset, 11, 0) << 20) |

View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <time.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -46,8 +47,8 @@ typedef enum {
/*** Debug Bus registers. ***/
#define DMCONTROL 0x10
#define DMCONTROL_HALTNOT (1L<<33)
#define DMCONTROL_INTERRUPT (1L<<32)
#define DMCONTROL_INTERRUPT (1L<<33)
#define DMCONTROL_HALTNOT (1L<<32)
#define DMCONTROL_BUSERROR (7<<19)
#define DMCONTROL_SERIAL (3<<16)
#define DMCONTROL_AUTOINCREMENT (1<<15)
@ -95,6 +96,11 @@ typedef struct {
uint32_t dcsr;
} riscv_info_t;
typedef struct {
bool haltnot;
bool interrupt;
} bits_t;
/*** Necessary prototypes. ***/
static int riscv_poll(struct target *target);
@ -172,11 +178,13 @@ static uint64_t dbus_read(struct target *target, uint16_t address, uint16_t next
if (result != DBUS_RESULT_SUCCESS) {
LOG_ERROR("dbus_read failed read at 0x%x; result=%d\n", address, result);
}
LOG_DEBUG("address=0x%x, value=0x%lx", address, value);
return value;
}
static void dbus_write(struct target *target, uint16_t address, uint64_t value)
{
LOG_DEBUG("address=0x%x, value=0x%lx", address, value);
dbus_result_t result = DBUS_RESULT_BUSY;
while (result == DBUS_RESULT_BUSY) {
result = dbus_scan(target, NULL, DBUS_OP_WRITE, address, value);
@ -242,6 +250,25 @@ static void dram_check32(struct target *target, unsigned int index,
}
}
/* Read the haltnot and interrupt bits. */
static bits_t read_bits(struct target *target)
{
riscv_info_t *info = (riscv_info_t *) target->arch_info;
uint64_t value;
if (info->dbus_address < 0x10 || info->dbus_address == DMCONTROL) {
value = dbus_read(target, info->dbus_address, 0);
} else {
value = dbus_read(target, 0, 0);
}
bits_t result = {
.haltnot = get_field(value, DMCONTROL_HALTNOT),
.interrupt = get_field(value, DMCONTROL_INTERRUPT)
};
return result;
}
/* Write instruction that jumps from the specified word in Debug RAM to resume
* in Debug ROM. */
static void dram_write_jump(struct target *target, unsigned int index, bool set_interrupt)
@ -251,16 +278,38 @@ static void dram_write_jump(struct target *target, unsigned int index, bool set_
set_interrupt);
}
static int wait_until_halted(struct target *target)
static int wait_for_state(struct target *target, enum target_state state)
{
do {
time_t start = time(NULL);
while (1) {
int result = riscv_poll(target);
if (result != ERROR_OK) {
return result;
}
} while (target->state != TARGET_HALTED);
if (target->state == state) {
return ERROR_OK;
}
if (time(NULL) - start > 2) {
LOG_ERROR("Timed out waiting for state %d.", state);
return ERROR_FAIL;
}
}
}
static int wait_for_debugint_clear(struct target *target)
{
time_t start = time(NULL);
while (1) {
bits_t bits = read_bits(target);
if (!bits.interrupt) {
return ERROR_OK;
}
if (time(NULL) - start > 2) {
LOG_ERROR("Timed out waiting for debug int to clear.");
return ERROR_FAIL;
}
}
}
static int resume(struct target *target, int current, uint32_t address,
int handle_breakpoints, int debug_execution, bool step)
@ -371,7 +420,10 @@ static int riscv_examine(struct target *target)
// Execute.
dram_write_jump(target, 5, true);
wait_until_halted(target);
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
uint32_t word0 = dram_read32(target, 0, false);
uint32_t word1 = dram_read32(target, 1, false);
@ -394,26 +446,15 @@ static int riscv_examine(struct target *target)
static int riscv_poll(struct target *target)
{
LOG_DEBUG("riscv_poll()");
riscv_info_t *info = (riscv_info_t *) target->arch_info;
bits_t bits = read_bits(target);
uint64_t value;
if (info->dbus_address < 0x10 || info->dbus_address == DMCONTROL) {
value = dbus_read(target, info->dbus_address, 0);
} else {
value = dbus_read(target, 0, 0);
}
bool haltnot = get_field(value, DMCONTROL_HALTNOT);
bool interrupt = get_field(value, DMCONTROL_INTERRUPT);
if (haltnot && interrupt) {
if (bits.haltnot && bits.interrupt) {
target->state = TARGET_DEBUG_RUNNING;
} else if (haltnot && !interrupt) {
} else if (bits.haltnot && !bits.interrupt) {
target->state = TARGET_HALTED;
} else if (!haltnot && interrupt) {
} else if (!bits.haltnot && bits.interrupt) {
// Target is halting. There is no state for that, so don't change anything.
} else if (!haltnot && !interrupt) {
} else if (!bits.haltnot && !bits.interrupt) {
target->state = TARGET_RUNNING;
}
@ -444,14 +485,41 @@ static int riscv_step(struct target *target, int current, uint32_t address,
static int riscv_assert_reset(struct target *target)
{
// TODO
// TODO: Maybe what I implemented here is more like soft_reset_halt()?
// The only assumption we can make is that the TAP was reset.
if (wait_for_debugint_clear(target) != ERROR_OK) {
LOG_ERROR("Debug interrupt didn't clear.");
return ERROR_FAIL;
}
// Not sure what we should do when there are multiple cores.
// Here just reset the single hart we're talking to.
uint32_t dcsr = DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
DCSR_EBREAKU | DCSR_HALT;
if (target->reset_halt) {
dcsr |= DCSR_NDRESET;
} else {
dcsr |= DCSR_FULLRESET;
}
dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false);
dram_write32(target, 1, csrw(S0, CSR_DCSR), false);
// We shouldn't actually need the jump because a reset should happen.
dram_write_jump(target, 2, false);
dram_write32(target, 4, dcsr, true);
target->state = TARGET_RESET;
return ERROR_OK;
}
static int riscv_deassert_reset(struct target *target)
{
// TODO
return ERROR_OK;
if (target->reset_halt) {
return wait_for_state(target, TARGET_HALTED);
} else {
return wait_for_state(target, TARGET_RUNNING);
}
}
struct target_type riscv_target = {