Merge remote-tracking branch 'origin/riscv' into riscv-compliance

compliance_dev
mwachs5 2017-07-05 11:02:30 -07:00
commit 87abbe4a51
4 changed files with 208 additions and 87 deletions

View File

@ -764,10 +764,10 @@ static void cache_set32(struct target *target, unsigned int index, uint32_t data
if (info->dram_cache[index].valid &&
info->dram_cache[index].data == data) {
// This is already preset on the target.
LOG_DEBUG("cache[0x%x] = 0x%x (hit)", index, data);
LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data);
return;
}
LOG_DEBUG("cache[0x%x] = 0x%x", index, data);
LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x)", index, data, data);
info->dram_cache[index].data = data;
info->dram_cache[index].valid = true;
info->dram_cache[index].dirty = true;
@ -1033,6 +1033,7 @@ static int wait_for_state(struct target *target, enum target_state state)
static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
{
riscv011_info_t *info = get_info(target);
cache_set32(target, 0, csrr(S0, csr));
cache_set_store(target, 1, S0, SLOT0);
cache_set_jump(target, 2);
@ -1042,6 +1043,13 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
*value = cache_get(target, SLOT0);
LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value);
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_ERROR("Got exception 0x%x when reading CSR 0x%x", exception, csr);
*value = ~0;
return ERROR_FAIL;
}
return ERROR_OK;
}
@ -1496,6 +1504,104 @@ static void deinit_target(struct target *target)
info->version_specific = NULL;
}
static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger,
uint64_t tdata1)
{
riscv011_info_t *info = get_info(target);
const uint32_t bpcontrol_x = 1<<0;
const uint32_t bpcontrol_w = 1<<1;
const uint32_t bpcontrol_r = 1<<2;
const uint32_t bpcontrol_u = 1<<3;
const uint32_t bpcontrol_s = 1<<4;
const uint32_t bpcontrol_h = 1<<5;
const uint32_t bpcontrol_m = 1<<6;
const uint32_t bpcontrol_bpmatch = 0xf << 7;
const uint32_t bpcontrol_bpaction = 0xff << 11;
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
// Trigger is already in use, presumably by user code.
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
tdata1 = set_field(tdata1, bpcontrol_r, trigger->read);
tdata1 = set_field(tdata1, bpcontrol_w, trigger->write);
tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute);
tdata1 = set_field(tdata1, bpcontrol_u, !!(info->misa & (1 << ('U' - 'A'))));
tdata1 = set_field(tdata1, bpcontrol_s, !!(info->misa & (1 << ('S' - 'A'))));
tdata1 = set_field(tdata1, bpcontrol_h, !!(info->misa & (1 << ('H' - 'A'))));
tdata1 |= bpcontrol_m;
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); // exact match
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); // cause bp exception
write_csr(target, CSR_TDATA1, tdata1);
uint64_t tdata1_rb;
read_csr(target, &tdata1_rb, CSR_TDATA1);
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
write_csr(target, CSR_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
write_csr(target, CSR_TDATA2, trigger->address);
return ERROR_OK;
}
static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger,
uint64_t tdata1)
{
riscv011_info_t *info = get_info(target);
// tselect is already set
if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) {
// Trigger is already in use, presumably by user code.
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
// address/data match trigger
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
tdata1 = set_field(tdata1, MCONTROL_ACTION,
MCONTROL_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
tdata1 |= MCONTROL_M;
if (info->misa & (1 << ('H' - 'A')))
tdata1 |= MCONTROL_H;
if (info->misa & (1 << ('S' - 'A')))
tdata1 |= MCONTROL_S;
if (info->misa & (1 << ('U' - 'A')))
tdata1 |= MCONTROL_U;
if (trigger->execute)
tdata1 |= MCONTROL_EXECUTE;
if (trigger->read)
tdata1 |= MCONTROL_LOAD;
if (trigger->write)
tdata1 |= MCONTROL_STORE;
write_csr(target, CSR_TDATA1, tdata1);
uint64_t tdata1_rb;
read_csr(target, &tdata1_rb, CSR_TDATA1);
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
write_csr(target, CSR_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
write_csr(target, CSR_TDATA2, trigger->address);
return ERROR_OK;
}
static int add_trigger(struct target *target, struct trigger *trigger)
{
riscv011_info_t *info = get_info(target);
@ -1514,51 +1620,23 @@ static int add_trigger(struct target *target, struct trigger *trigger)
read_csr(target, &tdata1, CSR_TDATA1);
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
if (type != 2) {
continue;
int result;
switch (type) {
case 1:
result = maybe_add_trigger_t1(target, trigger, tdata1);
break;
case 2:
result = maybe_add_trigger_t2(target, trigger, tdata1);
break;
default:
LOG_DEBUG("trigger %d has unknown type %d", i, type);
continue;
}
if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) {
// Trigger is already in use, presumably by user code.
if (result != ERROR_OK) {
continue;
}
// address/data match trigger
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
tdata1 = set_field(tdata1, MCONTROL_ACTION,
MCONTROL_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
tdata1 |= MCONTROL_M;
if (info->misa & (1 << ('H' - 'A')))
tdata1 |= MCONTROL_H;
if (info->misa & (1 << ('S' - 'A')))
tdata1 |= MCONTROL_S;
if (info->misa & (1 << ('U' - 'A')))
tdata1 |= MCONTROL_U;
if (trigger->execute)
tdata1 |= MCONTROL_EXECUTE;
if (trigger->read)
tdata1 |= MCONTROL_LOAD;
if (trigger->write)
tdata1 |= MCONTROL_STORE;
write_csr(target, CSR_TDATA1, tdata1);
uint64_t tdata1_rb;
read_csr(target, &tdata1_rb, CSR_TDATA1);
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
i, tdata1, tdata1_rb);
write_csr(target, CSR_TDATA1, 0);
continue;
}
write_csr(target, CSR_TDATA2, trigger->address);
LOG_DEBUG("Using resource %d for bp %d", i,
trigger->unique_id);
info->trigger_unique_id[i] = trigger->unique_id;
@ -1898,8 +1976,13 @@ static int examine(struct target *target)
update_reg_list(target);
if (read_csr(target, &info->misa, CSR_MISA) != ERROR_OK) {
LOG_ERROR("Failed to read misa.");
return ERROR_FAIL;
LOG_WARNING("Failed to read misa at 0x%x.", CSR_MISA);
if (read_csr(target, &info->misa, 0xf10) != ERROR_OK) {
// Maybe this is an old core that still has $misa at the old
// address.
LOG_ERROR("Failed to read misa at 0x%x.", 0xf10);
return ERROR_FAIL;
}
}
info->never_halted = true;
@ -2129,6 +2212,9 @@ static int handle_halt(struct target *target, bool announce)
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;

View File

@ -707,7 +707,7 @@ static int init_target(struct command_context *cmd_ctx,
LOG_DEBUG("init");
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
riscv_info_init(generic_info);
riscv_info_init(target, generic_info);
generic_info->get_register = &riscv013_get_register;
generic_info->set_register = &riscv013_set_register;
generic_info->select_current_hart = &riscv013_select_current_hart;
@ -834,6 +834,9 @@ static int add_trigger(struct target *target, struct trigger *trigger)
uint64_t tdata1_rb;
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
riscv_set_current_hartid(target, hartid);
if (hartid > 0) {
@ -920,6 +923,9 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
}
LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id);
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
if (!riscv_hart_enabled(target, hartid))
continue;
riscv_set_current_hartid(target, hartid);
register_write_direct(target, GDB_REGNO_TSELECT, i);
register_write_direct(target, GDB_REGNO_TDATA1, 0);
@ -1125,17 +1131,23 @@ static int examine(struct target *target)
/* Before doing anything else we must first enumerate the harts. */
RISCV_INFO(r);
if (riscv_rtos_enabled(target)) {
for (int i = 0; i < RISCV_MAX_HARTS; ++i) {
riscv_set_current_hartid(target, i);
uint32_t s = dmi_read(target, DMI_DMSTATUS);
if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT))
break;
r->hart_count = i + 1;
int original_coreid = target->coreid;
for (int i = 0; i < RISCV_MAX_HARTS; ++i) {
/* Fake being a non-RTOS targeted to this core so we can see if
* it exists. This avoids the assertion in
* riscv_set_current_hartid() that ensures non-RTOS targets
* don't touch the harts they're not assigned to. */
target->coreid = i;
r->hart_count = i + 1;
riscv_set_current_hartid(target, i);
uint32_t s = dmi_read(target, DMI_DMSTATUS);
if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) {
r->hart_count--;
break;
}
} else {
r->hart_count = 1;
}
target->coreid = original_coreid;
LOG_DEBUG("Enumerated %d harts", r->hart_count);
@ -1145,6 +1157,9 @@ static int examine(struct target *target)
/* Find the address of the program buffer, which must be done without
* knowing anything about the target. */
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
riscv_set_current_hartid(target, i);
/* Without knowing anything else we can at least mess with the
@ -1177,6 +1192,16 @@ static int examine(struct target *target)
* In order to make this work we first need to */
int offset = (progbuf_addr % 8 == 0) ? -4 : 0;
/* This program uses a temporary register. If the core can not
* execute 64 bit instruction, the original value of temporary
* register (s0) will not be restored due to an exception.
* So we have to save it and restore manually in that case.
* If the core can execute 64 bit instruction, the saved value
* is wrong, because it was read with 32 bit lw instruction,
* but the value of s0 will be restored by the reverse swap
* of s0 and dscratch registers. */
uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0);
struct riscv_program program64;
riscv_program_init(&program64, target);
riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH);
@ -1192,6 +1217,8 @@ static int examine(struct target *target)
+ dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4)
- 4;
r->xlen[i] = 64;
} else {
riscv_set_register(target, GDB_REGNO_S0, s0);
}
/* Display this as early as possible to help people who are using
@ -1215,6 +1242,9 @@ 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);
@ -1229,6 +1259,7 @@ static int examine(struct target *target)
/* Resumes all the harts, so the debugger can later pause them. */
riscv_resume_all_harts(target);
target->state = TARGET_RUNNING;
target_set_examined(target);
if (target->rtos) {
@ -1323,9 +1354,6 @@ static int read_memory(struct target *target, target_addr_t address,
size, address);
select_dmi(target);
/* There was a bug in the memory system and only accesses from hart 0 actually
* worked correctly. This should be obselete now. -palmer */
riscv_set_current_hartid(target, 0);
/* This program uses two temporary registers. A word of data and the
* associated address are stored at some location in memory. The
@ -1521,9 +1549,6 @@ static int write_memory(struct target *target, target_addr_t address,
LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address);
select_dmi(target);
/* There was a bug in the memory system and only accesses from hart 0 actually
* worked correctly. This should be obselete now. -palmer */
riscv_set_current_hartid(target, 0);
/* This program uses two temporary registers. A word of data and the
* associated address are stored at some location in memory. The

View File

@ -448,11 +448,12 @@ static int riscv_get_gdb_reg_list(struct target *target,
{
RISCV_INFO(r);
LOG_DEBUG("reg_class=%d", reg_class);
LOG_DEBUG("riscv_get_gdb_reg_list: rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid);
if (r->rtos_hartid != -1)
LOG_DEBUG("rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid);
if (r->rtos_hartid != -1 && riscv_rtos_enabled(target))
riscv_set_current_hartid(target, r->rtos_hartid);
else
riscv_set_current_hartid(target, 0);
riscv_set_current_hartid(target, target->coreid);
switch (reg_class) {
case REG_CLASS_GENERAL:
@ -877,11 +878,12 @@ struct target_type riscv_target =
/*** RISC-V Interface ***/
void riscv_info_init(riscv_info_t *r)
void riscv_info_init(struct target *target, riscv_info_t *r)
{
memset(r, 0, sizeof(*r));
r->dtm_version = 1;
r->registers_initialized = false;
r->current_hartid = target->coreid;
for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) {
r->xlen[h] = -1;
@ -894,11 +896,11 @@ void riscv_info_init(riscv_info_t *r)
int riscv_halt_all_harts(struct target *target)
{
if (riscv_rtos_enabled(target)) {
for (int i = 0; i < riscv_count_harts(target); ++i)
riscv_halt_one_hart(target, i);
} else {
riscv_halt_one_hart(target, riscv_current_hartid(target));
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
riscv_halt_one_hart(target, i);
}
return ERROR_OK;
@ -920,11 +922,11 @@ int riscv_halt_one_hart(struct target *target, int hartid)
int riscv_resume_all_harts(struct target *target)
{
if (riscv_rtos_enabled(target)) {
for (int i = 0; i < riscv_count_harts(target); ++i)
riscv_resume_one_hart(target, i);
} else {
riscv_resume_one_hart(target, riscv_current_hartid(target));
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
riscv_resume_one_hart(target, i);
}
riscv_invalidate_register_cache(target);
@ -948,11 +950,11 @@ int riscv_resume_one_hart(struct target *target, int hartid)
int riscv_reset_all_harts(struct target *target)
{
if (riscv_rtos_enabled(target)) {
for (int i = 0; i < riscv_count_harts(target); ++i)
riscv_reset_one_hart(target, i);
} else {
riscv_reset_one_hart(target, riscv_current_hartid(target));
for (int i = 0; i < riscv_count_harts(target); ++i) {
if (!riscv_hart_enabled(target, i))
continue;
riscv_reset_one_hart(target, i);
}
riscv_invalidate_register_cache(target);
@ -1022,10 +1024,9 @@ void riscv_set_current_hartid(struct target *target, int hartid)
int previous_hartid = riscv_current_hartid(target);
r->current_hartid = hartid;
assert(riscv_rtos_enabled(target) || target->coreid == hartid);
assert(riscv_hart_enabled(target, hartid));
LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid);
if (riscv_rtos_enabled(target))
r->select_current_hart(target);
r->select_current_hart(target);
/* This might get called during init, in which case we shouldn't be
* setting up the register cache. */
@ -1073,10 +1074,7 @@ void riscv_invalidate_register_cache(struct target *target)
int riscv_current_hartid(const struct target *target)
{
RISCV_INFO(r);
if (riscv_rtos_enabled(target))
return r->current_hartid;
else
return target->coreid;
return r->current_hartid;
}
void riscv_set_all_rtos_harts(struct target *target)
@ -1242,6 +1240,15 @@ int riscv_dmi_write_u64_bits(struct target *target)
return r->dmi_write_u64_bits(target);
}
bool riscv_hart_enabled(struct target *target, int hartid)
{
/* FIXME: Add a hart mask to the RTOS. */
if (riscv_rtos_enabled(target))
return hartid < riscv_count_harts(target);
return hartid == target->coreid;
}
/* Command Handlers */
COMMAND_HANDLER(riscv_test_compliance) {

View File

@ -135,7 +135,7 @@ int riscv_openocd_deassert_reset(struct target *target);
/*** RISC-V Interface ***/
/* Initializes the shared RISC-V structure. */
void riscv_info_init(riscv_info_t *r);
void riscv_info_init(struct target *target, riscv_info_t *r);
/* Run control, possibly for multiple harts. The _all_harts versions resume
* all the enabled harts, which when running in RTOS mode is all the harts on
@ -216,4 +216,7 @@ int riscv_dmi_write_u64_bits(struct target *target);
/* Invalidates the register cache. */
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);
#endif