+ struct dwt_reg_state *state = reg->arch_info;
+
+ return target_read_u32(state->target, state->addr, &state->value);
+}
+
+static int cortex_m3_dwt_set_reg(struct reg *reg, uint8_t *buf)
+{
+ struct dwt_reg_state *state = reg->arch_info;
+
+ return target_write_u32(state->target, state->addr,
+ buf_get_u32(buf, 0, reg->size));
+}
+
+struct dwt_reg {
+ uint32_t addr;
+ char *name;
+ unsigned size;
+};
+
+static struct dwt_reg dwt_base_regs[] = {
+ { DWT_CTRL, "dwt_ctrl", 32, },
+ /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly
+ * increments while the core is asleep.
+ */
+ { DWT_CYCCNT, "dwt_cyccnt", 32, },
+ /* plus some 8 bit counters, useful for profiling with TPIU */
+};
+
+static struct dwt_reg dwt_comp[] = {
+#define DWT_COMPARATOR(i) \
+ { DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \
+ { DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \
+ { DWT_FUNCTION0 + 0x10 * (i), "dwt_" #i "_function", 32, }
+ DWT_COMPARATOR(0),
+ DWT_COMPARATOR(1),
+ DWT_COMPARATOR(2),
+ DWT_COMPARATOR(3),
+#undef DWT_COMPARATOR
+};
+
+static const struct reg_arch_type dwt_reg_type = {
+ .get = cortex_m3_dwt_get_reg,
+ .set = cortex_m3_dwt_set_reg,
+};
+
+static void
+cortex_m3_dwt_addreg(struct target *t, struct reg *r, struct dwt_reg *d)
+{
+ struct dwt_reg_state *state;
+
+ state = calloc(1, sizeof *state);
+ if (!state)
+ return;
+ state->addr = d->addr;
+ state->target = t;
+
+ r->name = d->name;
+ r->size = d->size;
+ r->value = &state->value;
+ r->arch_info = state;
+ r->type = &dwt_reg_type;
+}
+
+static void
+cortex_m3_dwt_setup(struct cortex_m3_common *cm3, struct target *target)
+{
+ uint32_t dwtcr;
+ struct reg_cache *cache;
+ struct cortex_m3_dwt_comparator *comparator;
+ int reg, i;
+
+ target_read_u32(target, DWT_CTRL, &dwtcr);
+ if (!dwtcr) {
+ LOG_DEBUG("no DWT");
+ return;
+ }
+
+ cm3->dwt_num_comp = (dwtcr >> 28) & 0xF;
+ cm3->dwt_comp_available = cm3->dwt_num_comp;
+ cm3->dwt_comparator_list = calloc(cm3->dwt_num_comp,
+ sizeof(struct cortex_m3_dwt_comparator));
+ if (!cm3->dwt_comparator_list) {
+fail0:
+ cm3->dwt_num_comp = 0;
+ LOG_ERROR("out of mem");
+ return;
+ }
+
+ cache = calloc(1, sizeof *cache);
+ if (!cache) {
+fail1:
+ free(cm3->dwt_comparator_list);
+ goto fail0;
+ }
+ cache->name = "cortex-m3 dwt registers";
+ cache->num_regs = 2 + cm3->dwt_num_comp * 3;
+ cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list);
+ if (!cache->reg_list) {
+ free(cache);
+ goto fail1;
+ }
+
+ for (reg = 0; reg < 2; reg++)
+ cortex_m3_dwt_addreg(target, cache->reg_list + reg,
+ dwt_base_regs + reg);
+
+ comparator = cm3->dwt_comparator_list;
+ for (i = 0; i < cm3->dwt_num_comp; i++, comparator++) {
+ int j;
+
+ comparator->dwt_comparator_address = DWT_COMP0 + 0x10 * i;
+ for (j = 0; j < 3; j++, reg++)
+ cortex_m3_dwt_addreg(target, cache->reg_list + reg,
+ dwt_comp + 3 * i + j);
+ }
+
+ *register_get_last_cache_p(&target->reg_cache) = cache;
+ cm3->dwt_cache = cache;
+
+ LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s",
+ dwtcr, cm3->dwt_num_comp,
+ (dwtcr & (0xf << 24)) ? " only" : "/trigger");
+
+ /* REVISIT: if num_comp > 1, check whether comparator #1 can
+ * implement single-address data value watchpoints ... so we
+ * won't need to check it later, when asked to set one up.
+ */