Use DCSR constants from the debug spec.

Replace the constants with the ones from the ISA spec, since those are
not updated as often.

Also delete a bunch of old code.

Change-Id: I9201b1455d64a9d2d203bb362fefaa68cbf35aeb
This commit is contained in:
Tim Newsome 2017-02-25 10:34:46 -08:00
parent 8f6ddc92e8
commit 6f1a498ab9
1 changed files with 21 additions and 170 deletions

View File

@ -52,6 +52,12 @@
#define SETHALTNOT 0x10c
#define CSR_DCSR_CAUSE_SWBP 1
#define CSR_DCSR_CAUSE_TRIGGER 2
#define CSR_DCSR_CAUSE_DEBUGINT 3
#define CSR_DCSR_CAUSE_STEP 4
#define CSR_DCSR_CAUSE_HALT 5
/*** JTAG registers. ***/
#define DBUS 0x11
@ -130,7 +136,6 @@ enum {
};
#define MAX_HWBPS 16
#define DRAM_CACHE_SIZE 16
struct trigger {
uint64_t address;
@ -167,8 +172,6 @@ typedef struct {
* reg_cache. */
uint64_t mstatus_actual;
struct memory_cache_line dram_cache[DRAM_CACHE_SIZE];
/* Single buffer that contains all register names, instead of calling
* malloc for each register. Needs to be freed when reg_list is freed. */
char *reg_names;
@ -362,14 +365,6 @@ bool supports_extension(struct target *target, char letter)
return info->misa & (1 << num);
}
static uint16_t dram_address(unsigned int index)
{
if (index < 0x10)
return index;
else
return 0x40 + index - 0x10;
}
static void select_dmi(struct target *target)
{
static uint8_t ir_dmi[1] = {DTM_DMI};
@ -693,116 +688,6 @@ static void program_set_write(program_t *program, unsigned reg_num, uint64_t val
/*** end of program class ***/
static void dram_write32(struct target *target, unsigned int index, uint32_t value,
bool set_interrupt)
{
uint64_t dmi_value = DMCONTROL_HALTNOT | value;
if (set_interrupt)
dmi_value |= DMCONTROL_INTERRUPT;
dmi_write(target, dram_address(index), dmi_value);
}
/** Read the haltnot and interrupt bits. */
static bits_t read_bits(struct target *target)
{
uint64_t value;
dmi_status_t status;
uint16_t address_in;
riscv013_info_t *info = get_info(target);
bits_t err_result = {
.haltnot = 0,
.interrupt = 0
};
do {
unsigned i = 0;
do {
status = dmi_scan(target, &address_in, &value, DMI_OP_READ, 0, 0,
false);
if (status == DMI_STATUS_BUSY) {
if (address_in == (1<<info->abits) - 1 &&
value == (1ULL<<DMI_DATA_SIZE) - 1) {
LOG_ERROR("TDO seems to be stuck high.");
return err_result;
}
increase_dmi_busy_delay(target);
}
} while (status == DMI_STATUS_BUSY && i++ < 256);
if (i >= 256) {
LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status);
return err_result;
}
} while (address_in > 0x10 && address_in != DMCONTROL);
bits_t result = {
.haltnot = get_field(value, DMCONTROL_HALTNOT),
.interrupt = get_field(value, DMCONTROL_INTERRUPT)
};
return result;
}
static int wait_for_debugint_clear(struct target *target, bool ignore_first)
{
time_t start = time(NULL);
if (ignore_first) {
// 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.)
read_bits(target);
}
while (1) {
bits_t bits = read_bits(target);
if (!bits.interrupt) {
return ERROR_OK;
}
if (time(NULL) - start > WALL_CLOCK_TIMEOUT) {
LOG_ERROR("Timed out waiting for debug int to clear.");
return ERROR_FAIL;
}
}
}
/* Call this if the code you just ran writes to debug RAM entries 0 through 3. */
static void cache_invalidate(struct target *target)
{
riscv013_info_t *info = get_info(target);
for (unsigned int i = 0; i < info->dramsize; i++) {
info->dram_cache[i].valid = false;
info->dram_cache[i].dirty = false;
}
}
/* 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)
{
dram_write32(target, index,
jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))),
set_interrupt);
}
static int wait_for_state(struct target *target, enum target_state state)
{
time_t start = time(NULL);
while (1) {
int result = riscv013_poll(target);
if (result != ERROR_OK) {
return result;
}
if (target->state == state) {
return ERROR_OK;
}
if (time(NULL) - start > WALL_CLOCK_TIMEOUT) {
LOG_ERROR("Timed out waiting for state %d.", state);
return ERROR_FAIL;
}
}
}
static void write_program(struct target *target, const program_t *program)
{
riscv013_info_t *info = get_info(target);
@ -1091,13 +976,13 @@ static int execute_resume(struct target *target, bool step)
}
}
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
info->dcsr &= ~DCSR_HALT;
info->dcsr |= CSR_DCSR_EBREAKM | CSR_DCSR_EBREAKH | CSR_DCSR_EBREAKS |
CSR_DCSR_EBREAKU;
if (step) {
info->dcsr |= DCSR_STEP;
info->dcsr |= CSR_DCSR_STEP;
} else {
info->dcsr &= ~DCSR_STEP;
info->dcsr &= ~CSR_DCSR_STEP;
}
if (register_write_direct(target, REG_DCSR, info->dcsr) != ERROR_OK) {
@ -1208,9 +1093,9 @@ static int register_get(struct reg *reg)
LOG_DEBUG("%s=0x%" PRIx64 " (cached)", reg->name, info->dpc);
return ERROR_OK;
} else if (reg->number == REG_PRIV) {
buf_set_u64(reg->value, 0, 8, get_field(info->dcsr, DCSR_PRV));
buf_set_u64(reg->value, 0, 8, get_field(info->dcsr, CSR_DCSR_PRV));
LOG_DEBUG("%s=%d (cached)", reg->name,
(int) get_field(info->dcsr, DCSR_PRV));
(int) get_field(info->dcsr, CSR_DCSR_PRV));
return ERROR_OK;
} else {
uint64_t value;
@ -1240,7 +1125,7 @@ static int register_write(struct target *target, unsigned int number,
if (number == REG_PC) {
info->dpc = value;
} else if (number == REG_PRIV) {
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
info->dcsr = set_field(info->dcsr, CSR_DCSR_PRV, value);
} else {
return register_write_direct(target, number, value);
}
@ -1870,26 +1755,26 @@ static int handle_halt(struct target *target, bool announce)
int cause = get_field(info->dcsr, CSR_DCSR_CAUSE);
switch (cause) {
case DCSR_CAUSE_SWBP:
case CSR_DCSR_CAUSE_SWBP:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
case DCSR_CAUSE_HWBP:
case CSR_DCSR_CAUSE_TRIGGER:
target->debug_reason = DBG_REASON_WPTANDBKPT;
// If we halted because of a data trigger, gdb doesn't know to do
// the disable-breakpoints-step-enable-breakpoints dance.
info->need_strict_step = true;
break;
case DCSR_CAUSE_DEBUGINT:
case CSR_DCSR_CAUSE_DEBUGINT:
target->debug_reason = DBG_REASON_DBGRQ;
break;
case DCSR_CAUSE_STEP:
case CSR_DCSR_CAUSE_STEP:
target->debug_reason = DBG_REASON_SINGLESTEP;
break;
case DCSR_CAUSE_HALT:
case CSR_DCSR_CAUSE_HALT:
target->debug_reason = DBG_REASON_DBGRQ;
break;
default:
LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")",
LOG_ERROR("Invalid halt cause %d in CSR_DCSR (0x%" PRIx64 ")",
cause, info->dcsr);
}
@ -2007,46 +1892,12 @@ static int riscv013_resume(struct target *target, int current, uint32_t address,
static int assert_reset(struct target *target)
{
riscv013_info_t *info = get_info(target);
// TODO: Maybe what I implemented here is more like soft_reset_halt()?
select_dmi(target);
// The only assumption we can make is that the TAP was reset.
if (wait_for_debugint_clear(target, true) != 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.
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
DCSR_EBREAKU | DCSR_HALT;
if (target->reset_halt) {
info->dcsr |= DCSR_NDRESET;
} else {
info->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, info->dcsr, true);
cache_invalidate(target);
target->state = TARGET_RESET;
return ERROR_OK;
return ERROR_FAIL;
}
static int deassert_reset(struct target *target)
{
select_dmi(target);
if (target->reset_halt) {
return wait_for_state(target, TARGET_HALTED);
} else {
return wait_for_state(target, TARGET_RUNNING);
}
return ERROR_FAIL;
}
static int read_memory(struct target *target, uint32_t address,