Merge remote-tracking branch 'origin/riscv' into riscv-compliance
commit
20d46b8bf0
|
@ -0,0 +1,18 @@
|
|||
language: c
|
||||
dist: trusty
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: BUILD=x86_64-linux-gnu
|
||||
|
||||
- os: linux
|
||||
env: BUILD=i686-linux-gnu CFLAGS=-m32
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
|
||||
script:
|
||||
- ./bootstrap && ./configure && make
|
||||
- file src/openocd
|
|
@ -114,7 +114,7 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info,
|
|||
int mips32_cp0_write(struct mips_ejtag *ejtag_info,
|
||||
uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel);
|
||||
|
||||
inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count)
|
||||
static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count)
|
||||
{
|
||||
if (ejtag_info->isa && ejtag_info->endianness)
|
||||
for (int i = 0; i != count; i++)
|
||||
|
|
|
@ -94,7 +94,9 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
|
|||
riscv_batch_add_nop(batch);
|
||||
|
||||
batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
|
||||
LOG_DEBUG("read key %ld for batch 0x%p is %ld (0x%p)", batch->read_keys_used, batch, batch->used_scans - 1, (uint64_t*)batch->data_in + (batch->used_scans + 1));
|
||||
LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)",
|
||||
(unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1),
|
||||
(uint64_t*)batch->data_in + (batch->used_scans + 1));
|
||||
return batch->read_keys_used++;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
*/
|
||||
#define DTM_DMI_DATA_OFFSET 2
|
||||
#define DTM_DMI_DATA_LENGTH 32
|
||||
#define DTM_DMI_DATA (0xffffffffL << DTM_DMI_DATA_OFFSET)
|
||||
#define DTM_DMI_DATA (0xffffffffLL << DTM_DMI_DATA_OFFSET)
|
||||
/*
|
||||
* When the debugger writes this field, it has the following meaning:
|
||||
*
|
||||
|
@ -151,7 +151,7 @@
|
|||
*/
|
||||
#define DTM_DMI_OP_OFFSET 0
|
||||
#define DTM_DMI_OP_LENGTH 2
|
||||
#define DTM_DMI_OP (0x3L << DTM_DMI_OP_OFFSET)
|
||||
#define DTM_DMI_OP (0x3LL << DTM_DMI_OP_OFFSET)
|
||||
#define CSR_DCSR 0x7b0
|
||||
/*
|
||||
* 0: There is no external debug support.
|
||||
|
@ -285,7 +285,7 @@
|
|||
*/
|
||||
#define CSR_TDATA1_TYPE_OFFSET XLEN-4
|
||||
#define CSR_TDATA1_TYPE_LENGTH 4
|
||||
#define CSR_TDATA1_TYPE (0xfL << CSR_TDATA1_TYPE_OFFSET)
|
||||
#define CSR_TDATA1_TYPE (0xfLL << CSR_TDATA1_TYPE_OFFSET)
|
||||
/*
|
||||
* 0: Both Debug and M Mode can write the {\tt tdata} registers at the
|
||||
* selected \Rtselect.
|
||||
|
@ -297,7 +297,7 @@
|
|||
*/
|
||||
#define CSR_TDATA1_HMODE_OFFSET XLEN-5
|
||||
#define CSR_TDATA1_HMODE_LENGTH 1
|
||||
#define CSR_TDATA1_HMODE (0x1L << CSR_TDATA1_HMODE_OFFSET)
|
||||
#define CSR_TDATA1_HMODE (0x1LL << CSR_TDATA1_HMODE_OFFSET)
|
||||
/*
|
||||
* Trigger-specific data.
|
||||
*/
|
||||
|
@ -315,10 +315,10 @@
|
|||
#define CSR_MCONTROL 0x7a1
|
||||
#define CSR_MCONTROL_TYPE_OFFSET XLEN-4
|
||||
#define CSR_MCONTROL_TYPE_LENGTH 4
|
||||
#define CSR_MCONTROL_TYPE (0xfL << CSR_MCONTROL_TYPE_OFFSET)
|
||||
#define CSR_MCONTROL_TYPE (0xfLL << CSR_MCONTROL_TYPE_OFFSET)
|
||||
#define CSR_MCONTROL_DMODE_OFFSET XLEN-5
|
||||
#define CSR_MCONTROL_DMODE_LENGTH 1
|
||||
#define CSR_MCONTROL_DMODE (0x1L << CSR_MCONTROL_DMODE_OFFSET)
|
||||
#define CSR_MCONTROL_DMODE (0x1LL << CSR_MCONTROL_DMODE_OFFSET)
|
||||
/*
|
||||
* Specifies the largest naturally aligned powers-of-two (NAPOT) range
|
||||
* supported by the hardware. The value is the logarithm base 2 of the
|
||||
|
@ -329,7 +329,7 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_MASKMAX_OFFSET XLEN-11
|
||||
#define CSR_MCONTROL_MASKMAX_LENGTH 6
|
||||
#define CSR_MCONTROL_MASKMAX (0x3fL << CSR_MCONTROL_MASKMAX_OFFSET)
|
||||
#define CSR_MCONTROL_MASKMAX (0x3fLL << CSR_MCONTROL_MASKMAX_OFFSET)
|
||||
/*
|
||||
* 0: Perform a match on the virtual address.
|
||||
*
|
||||
|
@ -338,7 +338,7 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_SELECT_OFFSET 19
|
||||
#define CSR_MCONTROL_SELECT_LENGTH 1
|
||||
#define CSR_MCONTROL_SELECT (0x1L << CSR_MCONTROL_SELECT_OFFSET)
|
||||
#define CSR_MCONTROL_SELECT (0x1LL << CSR_MCONTROL_SELECT_OFFSET)
|
||||
/*
|
||||
* 0: The action for this trigger will be taken just before the
|
||||
* instruction that triggered it is executed, but after all preceding
|
||||
|
@ -366,7 +366,7 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_TIMING_OFFSET 18
|
||||
#define CSR_MCONTROL_TIMING_LENGTH 1
|
||||
#define CSR_MCONTROL_TIMING (0x1L << CSR_MCONTROL_TIMING_OFFSET)
|
||||
#define CSR_MCONTROL_TIMING (0x1LL << CSR_MCONTROL_TIMING_OFFSET)
|
||||
/*
|
||||
* Determines what happens when this trigger matches.
|
||||
*
|
||||
|
@ -387,7 +387,7 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_ACTION_OFFSET 12
|
||||
#define CSR_MCONTROL_ACTION_LENGTH 6
|
||||
#define CSR_MCONTROL_ACTION (0x3fL << CSR_MCONTROL_ACTION_OFFSET)
|
||||
#define CSR_MCONTROL_ACTION (0x3fLL << CSR_MCONTROL_ACTION_OFFSET)
|
||||
/*
|
||||
* 0: When this trigger matches, the configured action is taken.
|
||||
*
|
||||
|
@ -396,7 +396,7 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_CHAIN_OFFSET 11
|
||||
#define CSR_MCONTROL_CHAIN_LENGTH 1
|
||||
#define CSR_MCONTROL_CHAIN (0x1L << CSR_MCONTROL_CHAIN_OFFSET)
|
||||
#define CSR_MCONTROL_CHAIN (0x1LL << CSR_MCONTROL_CHAIN_OFFSET)
|
||||
/*
|
||||
* 0: Matches when the value equals \Rtdatatwo.
|
||||
*
|
||||
|
@ -420,57 +420,57 @@
|
|||
*/
|
||||
#define CSR_MCONTROL_MATCH_OFFSET 7
|
||||
#define CSR_MCONTROL_MATCH_LENGTH 4
|
||||
#define CSR_MCONTROL_MATCH (0xfL << CSR_MCONTROL_MATCH_OFFSET)
|
||||
#define CSR_MCONTROL_MATCH (0xfLL << CSR_MCONTROL_MATCH_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger in M mode.
|
||||
*/
|
||||
#define CSR_MCONTROL_M_OFFSET 6
|
||||
#define CSR_MCONTROL_M_LENGTH 1
|
||||
#define CSR_MCONTROL_M (0x1L << CSR_MCONTROL_M_OFFSET)
|
||||
#define CSR_MCONTROL_M (0x1LL << CSR_MCONTROL_M_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger in H mode.
|
||||
*/
|
||||
#define CSR_MCONTROL_H_OFFSET 5
|
||||
#define CSR_MCONTROL_H_LENGTH 1
|
||||
#define CSR_MCONTROL_H (0x1L << CSR_MCONTROL_H_OFFSET)
|
||||
#define CSR_MCONTROL_H (0x1LL << CSR_MCONTROL_H_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger in S mode.
|
||||
*/
|
||||
#define CSR_MCONTROL_S_OFFSET 4
|
||||
#define CSR_MCONTROL_S_LENGTH 1
|
||||
#define CSR_MCONTROL_S (0x1L << CSR_MCONTROL_S_OFFSET)
|
||||
#define CSR_MCONTROL_S (0x1LL << CSR_MCONTROL_S_OFFSET)
|
||||
/*
|
||||
* When set, enable this trigger in U mode.
|
||||
*/
|
||||
#define CSR_MCONTROL_U_OFFSET 3
|
||||
#define CSR_MCONTROL_U_LENGTH 1
|
||||
#define CSR_MCONTROL_U (0x1L << CSR_MCONTROL_U_OFFSET)
|
||||
#define CSR_MCONTROL_U (0x1LL << CSR_MCONTROL_U_OFFSET)
|
||||
/*
|
||||
* When set, the trigger fires on the virtual address or opcode of an
|
||||
* instruction that is executed.
|
||||
*/
|
||||
#define CSR_MCONTROL_EXECUTE_OFFSET 2
|
||||
#define CSR_MCONTROL_EXECUTE_LENGTH 1
|
||||
#define CSR_MCONTROL_EXECUTE (0x1L << CSR_MCONTROL_EXECUTE_OFFSET)
|
||||
#define CSR_MCONTROL_EXECUTE (0x1LL << CSR_MCONTROL_EXECUTE_OFFSET)
|
||||
/*
|
||||
* When set, the trigger fires on the virtual address or data of a store.
|
||||
*/
|
||||
#define CSR_MCONTROL_STORE_OFFSET 1
|
||||
#define CSR_MCONTROL_STORE_LENGTH 1
|
||||
#define CSR_MCONTROL_STORE (0x1L << CSR_MCONTROL_STORE_OFFSET)
|
||||
#define CSR_MCONTROL_STORE (0x1LL << CSR_MCONTROL_STORE_OFFSET)
|
||||
/*
|
||||
* When set, the trigger fires on the virtual address or data of a load.
|
||||
*/
|
||||
#define CSR_MCONTROL_LOAD_OFFSET 0
|
||||
#define CSR_MCONTROL_LOAD_LENGTH 1
|
||||
#define CSR_MCONTROL_LOAD (0x1L << CSR_MCONTROL_LOAD_OFFSET)
|
||||
#define CSR_MCONTROL_LOAD (0x1LL << CSR_MCONTROL_LOAD_OFFSET)
|
||||
#define CSR_ICOUNT 0x7a1
|
||||
#define CSR_ICOUNT_TYPE_OFFSET XLEN-4
|
||||
#define CSR_ICOUNT_TYPE_LENGTH 4
|
||||
#define CSR_ICOUNT_TYPE (0xfL << CSR_ICOUNT_TYPE_OFFSET)
|
||||
#define CSR_ICOUNT_TYPE (0xfLL << CSR_ICOUNT_TYPE_OFFSET)
|
||||
#define CSR_ICOUNT_DMODE_OFFSET XLEN-5
|
||||
#define CSR_ICOUNT_DMODE_LENGTH 1
|
||||
#define CSR_ICOUNT_DMODE (0x1L << CSR_ICOUNT_DMODE_OFFSET)
|
||||
#define CSR_ICOUNT_DMODE (0x1LL << CSR_ICOUNT_DMODE_OFFSET)
|
||||
/*
|
||||
* When count is decremented to 0, the trigger fires. Instead of
|
||||
* changing \Fcount from 1 to 0, it is also acceptable for hardware to
|
||||
|
@ -479,35 +479,35 @@
|
|||
*/
|
||||
#define CSR_ICOUNT_COUNT_OFFSET 10
|
||||
#define CSR_ICOUNT_COUNT_LENGTH 14
|
||||
#define CSR_ICOUNT_COUNT (0x3fffL << CSR_ICOUNT_COUNT_OFFSET)
|
||||
#define CSR_ICOUNT_COUNT (0x3fffLL << CSR_ICOUNT_COUNT_OFFSET)
|
||||
/*
|
||||
* When set, every instruction completed or exception taken in M mode decrements \Fcount
|
||||
* by 1.
|
||||
*/
|
||||
#define CSR_ICOUNT_M_OFFSET 9
|
||||
#define CSR_ICOUNT_M_LENGTH 1
|
||||
#define CSR_ICOUNT_M (0x1L << CSR_ICOUNT_M_OFFSET)
|
||||
#define CSR_ICOUNT_M (0x1LL << CSR_ICOUNT_M_OFFSET)
|
||||
/*
|
||||
* When set, every instruction completed or exception taken in in H mode decrements \Fcount
|
||||
* by 1.
|
||||
*/
|
||||
#define CSR_ICOUNT_H_OFFSET 8
|
||||
#define CSR_ICOUNT_H_LENGTH 1
|
||||
#define CSR_ICOUNT_H (0x1L << CSR_ICOUNT_H_OFFSET)
|
||||
#define CSR_ICOUNT_H (0x1LL << CSR_ICOUNT_H_OFFSET)
|
||||
/*
|
||||
* When set, every instruction completed or exception taken in S mode decrements \Fcount
|
||||
* by 1.
|
||||
*/
|
||||
#define CSR_ICOUNT_S_OFFSET 7
|
||||
#define CSR_ICOUNT_S_LENGTH 1
|
||||
#define CSR_ICOUNT_S (0x1L << CSR_ICOUNT_S_OFFSET)
|
||||
#define CSR_ICOUNT_S (0x1LL << CSR_ICOUNT_S_OFFSET)
|
||||
/*
|
||||
* When set, every instruction completed or exception taken in U mode decrements \Fcount
|
||||
* by 1.
|
||||
*/
|
||||
#define CSR_ICOUNT_U_OFFSET 6
|
||||
#define CSR_ICOUNT_U_LENGTH 1
|
||||
#define CSR_ICOUNT_U (0x1L << CSR_ICOUNT_U_OFFSET)
|
||||
#define CSR_ICOUNT_U (0x1LL << CSR_ICOUNT_U_OFFSET)
|
||||
/*
|
||||
* Determines what happens when this trigger matches.
|
||||
*
|
||||
|
@ -528,7 +528,7 @@
|
|||
*/
|
||||
#define CSR_ICOUNT_ACTION_OFFSET 0
|
||||
#define CSR_ICOUNT_ACTION_LENGTH 6
|
||||
#define CSR_ICOUNT_ACTION (0x3fL << CSR_ICOUNT_ACTION_OFFSET)
|
||||
#define CSR_ICOUNT_ACTION (0x3fLL << CSR_ICOUNT_ACTION_OFFSET)
|
||||
#define DMI_DMSTATUS 0x11
|
||||
/*
|
||||
* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq.
|
||||
|
|
|
@ -216,8 +216,6 @@ typedef struct {
|
|||
// unique_id of the breakpoint/watchpoint that is using it.
|
||||
int trigger_unique_id[MAX_HWBPS];
|
||||
|
||||
unsigned int trigger_count;
|
||||
|
||||
// Number of run-test/idle cycles the target requests we do after each dbus
|
||||
// access.
|
||||
unsigned int dtmcontrol_idle;
|
||||
|
@ -1045,7 +1043,7 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
|
|||
|
||||
uint32_t exception = cache_get32(target, info->dramsize-1);
|
||||
if (exception) {
|
||||
LOG_ERROR("Got exception 0x%x when reading CSR 0x%x", exception, csr);
|
||||
LOG_WARNING("Got exception 0x%x when reading CSR 0x%x", exception, csr);
|
||||
*value = ~0;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -1260,22 +1258,54 @@ static int update_mstatus_actual(struct target *target)
|
|||
|
||||
/*** OpenOCD target functions. ***/
|
||||
|
||||
static int register_read(struct target *target, riscv_reg_t *value, int regnum)
|
||||
{
|
||||
riscv011_info_t *info = get_info(target);
|
||||
if (regnum >= REG_CSR0 && regnum <= REG_CSR4095) {
|
||||
cache_set32(target, 0, csrr(S0, regnum - REG_CSR0));
|
||||
cache_set_store(target, 1, S0, SLOT0);
|
||||
cache_set_jump(target, 2);
|
||||
} else {
|
||||
LOG_ERROR("Don't know how to read register %d", regnum);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (cache_write(target, 4, true) != ERROR_OK) {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint32_t exception = cache_get32(target, info->dramsize-1);
|
||||
if (exception) {
|
||||
LOG_WARNING("Got exception 0x%x when reading register %d", exception,
|
||||
regnum);
|
||||
*value = ~0;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
*value = cache_get(target, SLOT0);
|
||||
LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value);
|
||||
|
||||
if (regnum == REG_MSTATUS) {
|
||||
info->mstatus_actual = *value;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int register_get(struct reg *reg)
|
||||
{
|
||||
struct target *target = (struct target *) reg->arch_info;
|
||||
riscv011_info_t *info = get_info(target);
|
||||
|
||||
maybe_write_tselect(target);
|
||||
riscv_reg_t value = ~0;
|
||||
|
||||
if (reg->number <= REG_XPR31) {
|
||||
buf_set_u64(reg->value, 0, riscv_xlen(target), reg_cache_get(target, reg->number));
|
||||
value = reg_cache_get(target, reg->number);
|
||||
LOG_DEBUG("%s=0x%" PRIx64, reg->name, reg_cache_get(target, reg->number));
|
||||
return ERROR_OK;
|
||||
} else if (reg->number == REG_PC) {
|
||||
buf_set_u32(reg->value, 0, 32, info->dpc);
|
||||
reg->valid = true;
|
||||
value = info->dpc;
|
||||
LOG_DEBUG("%s=0x%" PRIx64 " (cached)", reg->name, info->dpc);
|
||||
return ERROR_OK;
|
||||
} else if (reg->number >= REG_FPR0 && reg->number <= REG_FPR31) {
|
||||
int result = update_mstatus_actual(target);
|
||||
if (result != ERROR_OK) {
|
||||
|
@ -1295,44 +1325,24 @@ static int register_get(struct reg *reg)
|
|||
cache_set32(target, i++, fsd(reg->number - REG_FPR0, 0, DEBUG_RAM_START + 16));
|
||||
}
|
||||
cache_set_jump(target, i++);
|
||||
} else if (reg->number >= REG_CSR0 && reg->number <= REG_CSR4095) {
|
||||
cache_set32(target, 0, csrr(S0, reg->number - REG_CSR0));
|
||||
cache_set_store(target, 1, S0, SLOT0);
|
||||
cache_set_jump(target, 2);
|
||||
} else if (reg->number == REG_PRIV) {
|
||||
buf_set_u64(reg->value, 0, 8, get_field(info->dcsr, DCSR_PRV));
|
||||
LOG_DEBUG("%s=%d (cached)", reg->name,
|
||||
(int) get_field(info->dcsr, DCSR_PRV));
|
||||
return ERROR_OK;
|
||||
|
||||
if (cache_write(target, 4, true) != ERROR_OK) {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Don't know how to read register %d (%s)", reg->number, reg->name);
|
||||
return ERROR_FAIL;
|
||||
if (register_read(target, &value, reg->number) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (cache_write(target, 4, true) != ERROR_OK) {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint32_t exception = cache_get32(target, info->dramsize-1);
|
||||
if (exception) {
|
||||
LOG_ERROR("Got exception 0x%x when reading register %d", exception,
|
||||
reg->number);
|
||||
buf_set_u64(reg->value, 0, riscv_xlen(target), ~0);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint64_t value = cache_get(target, SLOT0);
|
||||
LOG_DEBUG("%s=0x%" PRIx64, reg->name, value);
|
||||
buf_set_u64(reg->value, 0, riscv_xlen(target), value);
|
||||
|
||||
if (reg->number == REG_MSTATUS) {
|
||||
info->mstatus_actual = value;
|
||||
reg->valid = true;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
// Write the register. No caching or games.
|
||||
static int register_write(struct target *target, unsigned int number,
|
||||
uint64_t value)
|
||||
{
|
||||
|
@ -1396,7 +1406,7 @@ static int register_write(struct target *target, unsigned int number,
|
|||
|
||||
uint32_t exception = cache_get32(target, info->dramsize-1);
|
||||
if (exception) {
|
||||
LOG_ERROR("Got exception 0x%x when writing register %d", exception,
|
||||
LOG_WARNING("Got exception 0x%x when writing register %d", exception,
|
||||
number);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -1423,6 +1433,25 @@ static struct reg_arch_type riscv_reg_arch_type = {
|
|||
.set = register_set
|
||||
};
|
||||
|
||||
static riscv_reg_t get_register(struct target *target, int hartid, int regid)
|
||||
{
|
||||
assert(hartid == 0);
|
||||
riscv_reg_t value;
|
||||
if (register_read(target, &value, regid) != ERROR_OK) {
|
||||
// TODO: propagate errors
|
||||
value = ~0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static void set_register(struct target *target, int hartid, int regid,
|
||||
uint64_t value)
|
||||
{
|
||||
assert(hartid == 0);
|
||||
// TODO: propagate errors
|
||||
register_write(target, regid, value);
|
||||
}
|
||||
|
||||
static int halt(struct target *target)
|
||||
{
|
||||
LOG_DEBUG("riscv_halt()");
|
||||
|
@ -1446,7 +1475,8 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
{
|
||||
LOG_DEBUG("init");
|
||||
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
||||
generic_info->get_register = NULL;
|
||||
generic_info->get_register = get_register;
|
||||
generic_info->set_register = set_register;
|
||||
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
||||
if (!generic_info->version_specific)
|
||||
return ERROR_FAIL;
|
||||
|
@ -1605,11 +1635,12 @@ static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger,
|
|||
static int add_trigger(struct target *target, struct trigger *trigger)
|
||||
{
|
||||
riscv011_info_t *info = get_info(target);
|
||||
RISCV_INFO(r);
|
||||
|
||||
maybe_read_tselect(target);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < info->trigger_count; i++) {
|
||||
for (i = 0; i < r->trigger_count[0]; i++) {
|
||||
if (info->trigger_unique_id[i] != -1) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1642,7 +1673,7 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
|||
info->trigger_unique_id[i] = trigger->unique_id;
|
||||
break;
|
||||
}
|
||||
if (i >= info->trigger_count) {
|
||||
if (i >= r->trigger_count[0]) {
|
||||
LOG_ERROR("Couldn't find an available hardware trigger.");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
@ -1652,17 +1683,18 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
|||
|
||||
static int remove_trigger(struct target *target, struct trigger *trigger)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
riscv011_info_t *info = get_info(target);
|
||||
|
||||
maybe_read_tselect(target);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < info->trigger_count; i++) {
|
||||
for (i = 0; i < r->trigger_count[0]; i++) {
|
||||
if (info->trigger_unique_id[i] == trigger->unique_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= info->trigger_count) {
|
||||
if (i >= r->trigger_count[0]) {
|
||||
LOG_ERROR("Couldn't find the hardware resources used by hardware "
|
||||
"trigger.");
|
||||
return ERROR_FAIL;
|
||||
|
@ -2200,30 +2232,10 @@ static int handle_halt(struct target *target, bool announce)
|
|||
if (info->never_halted) {
|
||||
info->never_halted = false;
|
||||
|
||||
// Disable any hardware triggers that have dmode set. We can't have set
|
||||
// them ourselves. Maybe they're left over from some killed debug
|
||||
// session.
|
||||
// Count the number of triggers while we're at it.
|
||||
|
||||
int result = maybe_read_tselect(target);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
for (info->trigger_count = 0; info->trigger_count < MAX_HWBPS; info->trigger_count++) {
|
||||
write_csr(target, CSR_TSELECT, info->trigger_count);
|
||||
uint64_t tselect_rb;
|
||||
read_csr(target, &tselect_rb, CSR_TSELECT);
|
||||
// Mask off the top bit, which is used as tdrmode in old
|
||||
// implementations.
|
||||
tselect_rb &= ~(1ULL << (riscv_xlen(target)-1));
|
||||
if (info->trigger_count != tselect_rb)
|
||||
break;
|
||||
uint64_t tdata1;
|
||||
read_csr(target, &tdata1, CSR_TDATA1);
|
||||
if ((tdata1 & MCONTROL_DMODE(riscv_xlen(target))) &&
|
||||
(tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD))) {
|
||||
write_csr(target, CSR_TDATA1, 0);
|
||||
}
|
||||
}
|
||||
riscv_enumerate_triggers(target);
|
||||
}
|
||||
|
||||
if (announce) {
|
||||
|
|
|
@ -188,55 +188,65 @@ typedef struct {
|
|||
|
||||
// Some memoized values
|
||||
int progbuf_size, progbuf_addr, data_addr, data_size;
|
||||
|
||||
bool abstract_read_csr_supported;
|
||||
bool abstract_write_csr_supported;
|
||||
bool abstract_read_fpr_supported;
|
||||
bool abstract_write_fpr_supported;
|
||||
|
||||
// When a function returns some error due to a failure indicated by the
|
||||
// target in cmderr, the caller can look here to see what that error was.
|
||||
// (Compare with errno.)
|
||||
unsigned cmderr;
|
||||
} riscv013_info_t;
|
||||
|
||||
static void decode_dmi(char *text, unsigned address, unsigned data)
|
||||
{
|
||||
static const struct {
|
||||
unsigned address;
|
||||
uint64_t mask;
|
||||
const char *name;
|
||||
} description[] = {
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYNONEXISTENT, "anynonexistent" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLUNAVAIL, "allunavail" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYUNAVAIL, "anyunavail" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRUNNING, "allrunning" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRUNNING, "anyrunning" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLHALTED, "allhalted" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_CFGSTRVALID, "cfgstrvalid" },
|
||||
{ DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" },
|
||||
|
||||
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" },
|
||||
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" },
|
||||
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" },
|
||||
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" },
|
||||
|
||||
{ DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" },
|
||||
};
|
||||
|
||||
text[0] = 0;
|
||||
switch (address) {
|
||||
case DMI_DMSTATUS:
|
||||
if (get_field(data, DMI_DMSTATUS_ALLRESUMEACK)) {
|
||||
strcat(text, " allresumeack");
|
||||
for (unsigned i = 0; i < DIM(description); i++) {
|
||||
if (description[i].address == address) {
|
||||
uint64_t mask = description[i].mask;
|
||||
unsigned value = get_field(data, mask);
|
||||
if (value) {
|
||||
if (i > 0)
|
||||
*(text++) = ' ';
|
||||
if (mask & (mask >> 1)) {
|
||||
// If the field is more than 1 bit wide.
|
||||
sprintf(text, "%s=%d", description[i].name, value);
|
||||
} else {
|
||||
strcpy(text, description[i].name);
|
||||
}
|
||||
text += strlen(text);
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ANYRESUMEACK)) {
|
||||
strcat(text, " anyresumeack");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ALLNONEXISTENT)) {
|
||||
strcat(text, " allnonexistent");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ANYNONEXISTENT)) {
|
||||
strcat(text, " anynonexistent");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ALLUNAVAIL)) {
|
||||
strcat(text, " allunavail");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ANYUNAVAIL)) {
|
||||
strcat(text, " anyunavail");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ALLRUNNING)) {
|
||||
strcat(text, " allrunning");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ANYRUNNING)) {
|
||||
strcat(text, " anyrunning");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ALLHALTED)) {
|
||||
strcat(text, " allhalted");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_ANYHALTED)) {
|
||||
strcat(text, " anyhalted");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_AUTHENTICATED)) {
|
||||
strcat(text, " authenticated");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_AUTHBUSY)) {
|
||||
strcat(text, " authbusy");
|
||||
}
|
||||
if (get_field(data, DMI_DMSTATUS_CFGSTRVALID)) {
|
||||
strcat(text, " cfgstrvalid");
|
||||
}
|
||||
sprintf(text + strlen(text), " version=%d", get_field(data,
|
||||
DMI_DMSTATUS_VERSION));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,6 +552,7 @@ uint32_t abstract_register_size(unsigned width)
|
|||
|
||||
static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
time_t start = time(NULL);
|
||||
while (1) {
|
||||
*abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
|
@ -551,7 +562,8 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
|||
}
|
||||
|
||||
if (time(NULL) - start > WALL_CLOCK_TIMEOUT) {
|
||||
if (get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR) != CMDERR_NONE) {
|
||||
info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||
if (info->cmderr != CMDERR_NONE) {
|
||||
const char *errors[8] = {
|
||||
"none",
|
||||
"busy",
|
||||
|
@ -563,8 +575,7 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
|||
"other" };
|
||||
|
||||
LOG_ERROR("Abstract command ended in error '%s' (abstractcs=0x%x)",
|
||||
errors[get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR)],
|
||||
*abstractcs);
|
||||
errors[info->cmderr], *abstractcs);
|
||||
}
|
||||
|
||||
LOG_ERROR("Timed out waiting for busy to go low. (abstractcs=0x%x)",
|
||||
|
@ -574,16 +585,193 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
|||
}
|
||||
}
|
||||
|
||||
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number);
|
||||
static int execute_abstract_command(struct target *target, uint32_t command)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
LOG_DEBUG("command=0x%x", command);
|
||||
dmi_write(target, DMI_COMMAND, command);
|
||||
|
||||
{
|
||||
uint32_t dmstatus = 0;
|
||||
wait_for_idle(target, &dmstatus);
|
||||
}
|
||||
|
||||
uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR);
|
||||
if (info->cmderr != 0) {
|
||||
LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs);
|
||||
// Clear the error.
|
||||
dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR,
|
||||
info->cmderr));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static riscv_reg_t read_abstract_arg(struct target *target, unsigned index)
|
||||
{
|
||||
riscv_reg_t value = 0;
|
||||
unsigned xlen = riscv_xlen(target);
|
||||
unsigned offset = index * xlen / 32;
|
||||
switch (xlen) {
|
||||
default:
|
||||
LOG_ERROR("Unsupported xlen: %d", xlen);
|
||||
return ~0;
|
||||
case 64:
|
||||
value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32;
|
||||
case 32:
|
||||
value |= dmi_read(target, DMI_DATA0 + offset);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int write_abstract_arg(struct target *target, unsigned index,
|
||||
riscv_reg_t value)
|
||||
{
|
||||
unsigned xlen = riscv_xlen(target);
|
||||
unsigned offset = index * xlen / 32;
|
||||
switch (xlen) {
|
||||
default:
|
||||
LOG_ERROR("Unsupported xlen: %d", xlen);
|
||||
return ~0;
|
||||
case 64:
|
||||
dmi_write(target, DMI_DATA0 + offset + 1, value >> 32);
|
||||
case 32:
|
||||
dmi_write(target, DMI_DATA0 + offset, value);
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int register_read_abstract(struct target *target, uint64_t *value,
|
||||
uint32_t number, unsigned size)
|
||||
{
|
||||
RISCV013_INFO(r);
|
||||
|
||||
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
|
||||
switch (size) {
|
||||
case 32:
|
||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
|
||||
break;
|
||||
case 64:
|
||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unsupported abstract register read size: %d", size);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
|
||||
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
|
||||
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0);
|
||||
|
||||
if (number <= GDB_REGNO_XPR31) {
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
0x1000 + number - GDB_REGNO_XPR0);
|
||||
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
if (!r->abstract_read_fpr_supported)
|
||||
return ERROR_FAIL;
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
0x1020 + number - GDB_REGNO_FPR0);
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
if (!r->abstract_read_csr_supported)
|
||||
return ERROR_FAIL;
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
number - GDB_REGNO_CSR0);
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int result = execute_abstract_command(target, command);
|
||||
if (result != ERROR_OK) {
|
||||
if (r->cmderr == CMDERR_NOT_SUPPORTED) {
|
||||
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
r->abstract_read_fpr_supported = false;
|
||||
LOG_INFO("Disabling abstract command reads from FPRs.");
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
r->abstract_read_csr_supported = false;
|
||||
LOG_INFO("Disabling abstract command reads from CSRs.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
*value = read_abstract_arg(target, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int register_write_abstract(struct target *target, uint32_t number,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
|
||||
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
|
||||
switch (size) {
|
||||
case 32:
|
||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
|
||||
break;
|
||||
case 64:
|
||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unsupported abstract register read size: %d", size);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
|
||||
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
|
||||
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1);
|
||||
|
||||
if (number <= GDB_REGNO_XPR31) {
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
0x1000 + number - GDB_REGNO_XPR0);
|
||||
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
if (!info->abstract_read_fpr_supported)
|
||||
return ERROR_FAIL;
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
0x1020 + number - GDB_REGNO_FPR0);
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
if (!info->abstract_read_csr_supported)
|
||||
return ERROR_FAIL;
|
||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||
number - GDB_REGNO_CSR0);
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (write_abstract_arg(target, 0, value) != ERROR_OK) {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int result = execute_abstract_command(target, command);
|
||||
if (result != ERROR_OK) {
|
||||
if (info->cmderr == CMDERR_NOT_SUPPORTED) {
|
||||
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
info->abstract_write_fpr_supported = false;
|
||||
LOG_INFO("Disabling abstract command writes to FPRs.");
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
info->abstract_write_csr_supported = false;
|
||||
LOG_INFO("Disabling abstract command writes to CSRs.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int register_write_direct(struct target *target, unsigned number,
|
||||
uint64_t value)
|
||||
{
|
||||
struct riscv_program program;
|
||||
|
||||
LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target),
|
||||
number, value);
|
||||
|
||||
int result = register_write_abstract(target, number, value,
|
||||
riscv_xlen(target));
|
||||
if (result == ERROR_OK)
|
||||
return ERROR_OK;
|
||||
|
||||
struct riscv_program program;
|
||||
|
||||
riscv_program_init(&program, target);
|
||||
|
||||
riscv_addr_t input = riscv_program_alloc_d(&program);
|
||||
|
@ -616,36 +804,42 @@ static int register_write_direct(struct target *target, unsigned number,
|
|||
/** Actually read registers from the target right now. */
|
||||
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
|
||||
{
|
||||
struct riscv_program program;
|
||||
riscv_program_init(&program, target);
|
||||
riscv_addr_t output = riscv_program_alloc_d(&program);
|
||||
riscv_program_write_ram(&program, output + 4, 0);
|
||||
riscv_program_write_ram(&program, output, 0);
|
||||
int result = register_read_abstract(target, value, number,
|
||||
riscv_xlen(target));
|
||||
|
||||
assert(GDB_REGNO_XPR0 == 0);
|
||||
if (number <= GDB_REGNO_XPR31) {
|
||||
riscv_program_sx(&program, number, output);
|
||||
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
riscv_program_fsd(&program, number, output);
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0);
|
||||
enum gdb_regno temp = riscv_program_gettemp(&program);
|
||||
riscv_program_csrr(&program, temp, number);
|
||||
riscv_program_sx(&program, temp, output);
|
||||
} else {
|
||||
LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number);
|
||||
abort();
|
||||
if (result != ERROR_OK) {
|
||||
struct riscv_program program;
|
||||
riscv_program_init(&program, target);
|
||||
riscv_addr_t output = riscv_program_alloc_d(&program);
|
||||
riscv_program_write_ram(&program, output + 4, 0);
|
||||
riscv_program_write_ram(&program, output, 0);
|
||||
|
||||
assert(GDB_REGNO_XPR0 == 0);
|
||||
if (number <= GDB_REGNO_XPR31) {
|
||||
riscv_program_sx(&program, number, output);
|
||||
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
riscv_program_fsd(&program, number, output);
|
||||
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||
LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0);
|
||||
enum gdb_regno temp = riscv_program_gettemp(&program);
|
||||
riscv_program_csrr(&program, temp, number);
|
||||
riscv_program_sx(&program, temp, output);
|
||||
} else {
|
||||
LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number);
|
||||
abort();
|
||||
}
|
||||
|
||||
int exec_out = riscv_program_exec(&program, target);
|
||||
if (exec_out != ERROR_OK) {
|
||||
riscv013_clear_abstract_error(target);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
*value = 0;
|
||||
*value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32;
|
||||
*value |= riscv_program_read_ram(&program, output);
|
||||
}
|
||||
|
||||
int exec_out = riscv_program_exec(&program, target);
|
||||
if (exec_out != ERROR_OK) {
|
||||
riscv013_clear_abstract_error(target);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
*value = 0;
|
||||
*value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32;
|
||||
*value |= riscv_program_read_ram(&program, output);
|
||||
LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target),
|
||||
number, *value);
|
||||
return ERROR_OK;
|
||||
|
@ -744,6 +938,13 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
info->dmi_busy_delay = 0;
|
||||
info->ac_busy_delay = 0;
|
||||
|
||||
// Assume all these abstract commands are supported until we learn
|
||||
// otherwise.
|
||||
info->abstract_read_csr_supported = true;
|
||||
info->abstract_write_csr_supported = true;
|
||||
info->abstract_read_fpr_supported = true;
|
||||
info->abstract_write_fpr_supported = true;
|
||||
|
||||
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
|
||||
target->reg_cache->name = "RISC-V Registers";
|
||||
target->reg_cache->num_regs = GDB_REGNO_COUNT;
|
||||
|
@ -1209,9 +1410,9 @@ static int examine(struct target *target)
|
|||
riscv_program_insert(&program64, sd(GDB_REGNO_S0, GDB_REGNO_S0, offset));
|
||||
riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH);
|
||||
riscv_program_fence(&program64);
|
||||
riscv_program_exec(&program64, target);
|
||||
int result = riscv_program_exec(&program64, target);
|
||||
|
||||
if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0) {
|
||||
if (result == ERROR_OK) {
|
||||
r->debug_buffer_addr[i] =
|
||||
(dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32)
|
||||
+ dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4)
|
||||
|
@ -1227,7 +1428,7 @@ static int examine(struct target *target)
|
|||
r->xlen[i], r->debug_buffer_addr[i]);
|
||||
|
||||
if (riscv_program_gah(&program64, r->debug_buffer_addr[i])) {
|
||||
LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx\n", i,
|
||||
LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx\n", i,
|
||||
(long)r->debug_buffer_addr[i]);
|
||||
abort();
|
||||
}
|
||||
|
@ -1241,21 +1442,7 @@ static int examine(struct target *target)
|
|||
}
|
||||
|
||||
/* Then we check the number of triggers availiable to each hart. */
|
||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||
if (!riscv_hart_enabled(target, i))
|
||||
continue;
|
||||
|
||||
for (uint32_t t = 0; t < RISCV_MAX_TRIGGERS; ++t) {
|
||||
riscv_set_current_hartid(target, i);
|
||||
|
||||
r->trigger_count[i] = t;
|
||||
register_write_direct(target, GDB_REGNO_TSELECT, t);
|
||||
uint64_t tselect = t+1;
|
||||
register_read_direct(target, &tselect, GDB_REGNO_TSELECT);
|
||||
if (tselect != t)
|
||||
break;
|
||||
}
|
||||
}
|
||||
riscv_enumerate_triggers(target);
|
||||
|
||||
/* Resumes all the harts, so the debugger can later pause them. */
|
||||
riscv_resume_all_harts(target);
|
||||
|
@ -1305,7 +1492,7 @@ static int assert_reset(struct target *target)
|
|||
static int deassert_reset(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
RISCV013_INFO(info);
|
||||
RISCV013_INFO(info);
|
||||
select_dmi(target);
|
||||
|
||||
/*FIXME -- this only works for Single Hart*/
|
||||
|
@ -1463,7 +1650,7 @@ static int read_memory(struct target *target, target_addr_t address,
|
|||
size_t reads = 0;
|
||||
size_t rereads = reads;
|
||||
for (riscv_addr_t i = start; i < count; ++i) {
|
||||
size_t index =
|
||||
size_t index =
|
||||
riscv_batch_add_dmi_read(
|
||||
batch,
|
||||
riscv013_debug_buffer_register(target, r_data));
|
||||
|
@ -1516,7 +1703,8 @@ static int read_memory(struct target *target, target_addr_t address,
|
|||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
switch (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
||||
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||
switch (info->cmderr) {
|
||||
case CMDERR_NONE:
|
||||
LOG_DEBUG("successful (partial?) memory write");
|
||||
break;
|
||||
|
@ -1644,9 +1832,10 @@ static int write_memory(struct target *target, target_addr_t address,
|
|||
* the data was all copied. */
|
||||
riscv_addr_t cur_addr = 0xbadbeef;
|
||||
riscv_addr_t fin_addr = address + (count * size);
|
||||
LOG_DEBUG("writing until final address 0x%016lx", fin_addr);
|
||||
LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr);
|
||||
while ((cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) {
|
||||
LOG_DEBUG("transferring burst starting at address 0x%016lx", cur_addr);
|
||||
LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64,
|
||||
cur_addr);
|
||||
riscv_addr_t start = (cur_addr - address) / size;
|
||||
assert (cur_addr > address);
|
||||
struct riscv_batch *batch = riscv_batch_alloc(
|
||||
|
@ -1699,7 +1888,8 @@ static int write_memory(struct target *target, target_addr_t address,
|
|||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
switch (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
||||
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||
switch (info->cmderr) {
|
||||
case CMDERR_NONE:
|
||||
LOG_DEBUG("successful (partial?) memory write");
|
||||
break;
|
||||
|
@ -1757,7 +1947,7 @@ struct target_type riscv013_target =
|
|||
.arch_state = arch_state,
|
||||
};
|
||||
|
||||
/*** 0.13-specific implementations of various RISC-V hepler functions. ***/
|
||||
/*** 0.13-specific implementations of various RISC-V helper functions. ***/
|
||||
static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid)
|
||||
{
|
||||
LOG_DEBUG("reading register 0x%08x on hart %d", rid, hid);
|
||||
|
@ -1771,7 +1961,7 @@ static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid
|
|||
register_read_direct(target, &out, rid);
|
||||
} else if (rid == GDB_REGNO_PC) {
|
||||
register_read_direct(target, &out, GDB_REGNO_DPC);
|
||||
LOG_DEBUG("read PC from DPC: 0x%016lx", out);
|
||||
LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, out);
|
||||
} else if (rid == GDB_REGNO_PRIV) {
|
||||
uint64_t dcsr;
|
||||
register_read_direct(target, &dcsr, CSR_DCSR);
|
||||
|
@ -1799,11 +1989,11 @@ static void riscv013_set_register(struct target *target, int hid, int rid, uint6
|
|||
if (rid <= GDB_REGNO_XPR31) {
|
||||
register_write_direct(target, rid, value);
|
||||
} else if (rid == GDB_REGNO_PC) {
|
||||
LOG_DEBUG("writing PC to DPC: 0x%016lx", value);
|
||||
LOG_DEBUG("writing PC to DPC: 0x%016" PRIx64, value);
|
||||
register_write_direct(target, GDB_REGNO_DPC, value);
|
||||
uint64_t actual_value;
|
||||
register_read_direct(target, &actual_value, GDB_REGNO_DPC);
|
||||
LOG_DEBUG(" actual DPC written: 0x%016lx", actual_value);
|
||||
LOG_DEBUG(" actual DPC written: 0x%016" PRIx64, actual_value);
|
||||
assert(value == actual_value);
|
||||
} else if (rid == GDB_REGNO_PRIV) {
|
||||
uint64_t dcsr;
|
||||
|
@ -1929,28 +2119,13 @@ riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index)
|
|||
|
||||
int riscv013_execute_debug_buffer(struct target *target)
|
||||
{
|
||||
riscv013_clear_abstract_error(target);
|
||||
|
||||
uint32_t run_program = 0;
|
||||
run_program = set_field(run_program, AC_ACCESS_REGISTER_SIZE, 2);
|
||||
run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1);
|
||||
run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0);
|
||||
run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000);
|
||||
dmi_write(target, DMI_COMMAND, run_program);
|
||||
|
||||
{
|
||||
uint32_t dmstatus = 0;
|
||||
wait_for_idle(target, &dmstatus);
|
||||
}
|
||||
|
||||
uint32_t cs = dmi_read(target, DMI_ABSTRACTCS);
|
||||
if (get_field(cs, DMI_ABSTRACTCS_CMDERR) != 0) {
|
||||
LOG_ERROR("unable to execute program: (abstractcs=0x%08x)", cs);
|
||||
dmi_read(target, DMI_DMSTATUS);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return execute_abstract_command(target, run_program);
|
||||
}
|
||||
|
||||
void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d)
|
||||
|
|
|
@ -1036,7 +1036,7 @@ void riscv_set_current_hartid(struct target *target, int hartid)
|
|||
/* Avoid invalidating the register cache all the time. */
|
||||
if (r->registers_initialized
|
||||
&& (!riscv_rtos_enabled(target) || (previous_hartid == hartid))
|
||||
&& target->reg_cache->reg_list[GDB_REGNO_XPR0].size == (long)riscv_xlen(target)
|
||||
&& target->reg_cache->reg_list[GDB_REGNO_XPR0].size == (unsigned)riscv_xlen(target)
|
||||
&& (!riscv_rtos_enabled(target) || (r->rtos_hartid != -1))) {
|
||||
LOG_DEBUG("registers already initialized, skipping");
|
||||
return;
|
||||
|
@ -1108,10 +1108,12 @@ void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v)
|
|||
return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v);
|
||||
}
|
||||
|
||||
void riscv_set_register_on_hart(struct target *target, int hartid, enum gdb_regno regid, uint64_t value)
|
||||
void riscv_set_register_on_hart(struct target *target, int hartid,
|
||||
enum gdb_regno regid, uint64_t value)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
LOG_DEBUG("writing register %d on hart %d", regid, hartid);
|
||||
LOG_DEBUG("[%d] reg[%d] <- %" PRIx64, hartid, regid, value);
|
||||
assert(r->set_register);
|
||||
return r->set_register(target, hartid, regid, value);
|
||||
}
|
||||
|
||||
|
@ -1249,6 +1251,57 @@ bool riscv_hart_enabled(struct target *target, int hartid)
|
|||
return hartid == target->coreid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count triggers, and initialize trigger_count for each hart.
|
||||
* trigger_count is initialized even if this function fails to discover
|
||||
* something.
|
||||
* Disable any hardware triggers that have dmode set. We can't have set them
|
||||
* ourselves. Maybe they're left over from some killed debug session.
|
||||
* */
|
||||
int riscv_enumerate_triggers(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
|
||||
if (!riscv_hart_enabled(target, hartid))
|
||||
continue;
|
||||
|
||||
for (unsigned t = 0; t < RISCV_MAX_TRIGGERS; ++t) {
|
||||
r->trigger_count[hartid] = t;
|
||||
|
||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t);
|
||||
uint64_t tselect = riscv_get_register_on_hart(target, hartid,
|
||||
GDB_REGNO_TSELECT);
|
||||
// Mask off the top bit, which is used as tdrmode in old
|
||||
// implementations.
|
||||
tselect &= ~(1ULL << (riscv_xlen(target)-1));
|
||||
if (tselect != t)
|
||||
break;
|
||||
|
||||
uint64_t tdata1 = riscv_get_register_on_hart(target, hartid,
|
||||
GDB_REGNO_TDATA1);
|
||||
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
|
||||
switch (type) {
|
||||
case 1:
|
||||
// On these older cores we don't support software using
|
||||
// triggers.
|
||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
||||
break;
|
||||
case 2:
|
||||
if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) {
|
||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("[%d] Found %d triggers", hartid, r->trigger_count[hartid]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Command Handlers */
|
||||
|
||||
COMMAND_HANDLER(riscv_test_compliance) {
|
||||
|
|
|
@ -57,7 +57,7 @@ typedef struct {
|
|||
int xlen[RISCV_MAX_HARTS];
|
||||
|
||||
/* The number of triggers per hart. */
|
||||
int trigger_count[RISCV_MAX_HARTS];
|
||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
||||
|
||||
/* The address of the debug RAM buffer. */
|
||||
riscv_addr_t debug_buffer_addr[RISCV_MAX_HARTS];
|
||||
|
@ -70,8 +70,9 @@ typedef struct {
|
|||
|
||||
/* Helper functions that target the various RISC-V debug spec
|
||||
* implementations. */
|
||||
riscv_reg_t (*get_register)(struct target *, int, int);
|
||||
void (*set_register)(struct target *, int, int, uint64_t);
|
||||
riscv_reg_t (*get_register)(struct target *, int hartid, int regid);
|
||||
void (*set_register)(struct target *, int hartid, int regid,
|
||||
uint64_t value);
|
||||
void (*select_current_hart)(struct target *);
|
||||
bool (*is_halted)(struct target *target);
|
||||
void (*halt_current_hart)(struct target *);
|
||||
|
@ -219,4 +220,6 @@ void riscv_invalidate_register_cache(struct target *target);
|
|||
/* Returns TRUE when a hart is enabled in this target. */
|
||||
bool riscv_hart_enabled(struct target *target, int hartid);
|
||||
|
||||
int riscv_enumerate_triggers(struct target *target);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue