Add back support for type 1 triggers.

They were implemented, and people want to keep using them.
Also make OpenOCD tolerate cores that have $misa at 0xf10 instead of the
current address of 0x301.
Actually return an error when we fail to read a CSR.
Tweak cache_set32() debug output.
This commit is contained in:
Tim Newsome 2017-06-29 10:06:06 -07:00
parent b6f8efbf44
commit 6c627e9ea9
1 changed files with 120 additions and 42 deletions

View File

@ -1504,31 +1504,63 @@ static void deinit_target(struct target *target)
info->version_specific = NULL;
}
static int add_trigger(struct target *target, struct trigger *trigger)
static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger,
uint64_t tdata1)
{
riscv011_info_t *info = get_info(target);
maybe_read_tselect(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;
unsigned int i;
for (i = 0; i < info->trigger_count; i++) {
if (info->trigger_unique_id[i] != -1) {
continue;
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
// Trigger is already in use, presumably by user code.
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
write_csr(target, CSR_TSELECT, i);
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
uint64_t tdata1;
read_csr(target, &tdata1, CSR_TDATA1);
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
write_csr(target, CSR_TDATA1, tdata1);
if (type != 2) {
continue;
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.
continue;
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
// address/data match trigger
@ -1558,15 +1590,53 @@ static int add_trigger(struct target *target, struct trigger *trigger)
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%"
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
i, tdata1, tdata1_rb);
tdata1, tdata1_rb);
write_csr(target, CSR_TDATA1, 0);
continue;
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);
maybe_read_tselect(target);
unsigned int i;
for (i = 0; i < info->trigger_count; i++) {
if (info->trigger_unique_id[i] != -1) {
continue;
}
write_csr(target, CSR_TSELECT, i);
uint64_t tdata1;
read_csr(target, &tdata1, CSR_TDATA1);
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
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 (result != ERROR_OK) {
continue;
}
LOG_DEBUG("Using resource %d for bp %d", i,
trigger->unique_id);
info->trigger_unique_id[i] = trigger->unique_id;
@ -1906,9 +1976,14 @@ 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.");
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;
@ -2137,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;