aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2017-06-29 10:06:06 -0700
committerTim Newsome <tim@sifive.com>2017-07-03 11:01:10 -0700
commit6c627e9ea9a756f725a7b9ce9cd962690af872a8 (patch)
treec17fdfd71e4a384e33e69c137aa5d23c2e8dc443
parentb6f8efbf44e2488ef0eb9c6362a2d9e5a5f28f41 (diff)
downloadriscv-openocd-6c627e9ea9a756f725a7b9ce9cd962690af872a8.zip
riscv-openocd-6c627e9ea9a756f725a7b9ce9cd962690af872a8.tar.gz
riscv-openocd-6c627e9ea9a756f725a7b9ce9cd962690af872a8.tar.bz2
Add back support for type 1 triggers.old_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.
-rw-r--r--src/target/riscv/riscv-011.c162
1 files changed, 120 insertions, 42 deletions
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index bc7d459..9532803 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -1504,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);
@@ -1522,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;
- }
-
- if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) {
- // Trigger is already in use, presumably by user code.
- 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;
}
- // 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);
+ if (result != ERROR_OK) {
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;
@@ -1906,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;
@@ -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;