+ if (!dwtcr) {
+ LOG_DEBUG("no DWT");
+ return;
+ }
+
+ if (dwt_reg_type < 0)
+ dwt_reg_type = register_reg_arch_type(cortex_m3_dwt_get_reg,
+ cortex_m3_dwt_set_reg);
+
+ 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(cortex_m3_dwt_comparator_t));
+ 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.
+ */
+}
+
+static int cortex_m3_examine(struct target_s *target)
+{
+ int retval;
+ uint32_t cpuid, fpcr;
+ int i;
+ struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
+ struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info;
+
+ if ((retval = ahbap_debugport_init(swjdp)) != ERROR_OK)
+ return retval;
+
+ if (!target_was_examined(target))
+ {
+ target_set_examined(target);
+
+ /* Read from Device Identification Registers */
+ retval = target_read_u32(target, CPUID, &cpuid);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (((cpuid >> 4) & 0xc3f) == 0xc23)
+ LOG_DEBUG("CORTEX-M3 processor detected");
+ LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
+
+ /* NOTE: FPB and DWT are both optional. */
+
+ /* Setup FPB */
+ target_read_u32(target, FP_CTRL, &fpcr);
+ cortex_m3->auto_bp_type = 1;
+ cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); /* bits [14:12] and [7:4] */
+ cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF;
+ cortex_m3->fp_code_available = cortex_m3->fp_num_code;
+ cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code + cortex_m3->fp_num_lit, sizeof(cortex_m3_fp_comparator_t));
+ cortex_m3->fpb_enabled = fpcr & 1;
+ for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++)
+ {
+ cortex_m3->fp_comparator_list[i].type = (i < cortex_m3->fp_num_code) ? FPCR_CODE : FPCR_LITERAL;
+ cortex_m3->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i;
+ }
+ LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m3->fp_num_code, cortex_m3->fp_num_lit);
+
+ /* Setup DWT */
+ cortex_m3_dwt_setup(cortex_m3, target);
+ }
+
+ return ERROR_OK;
+}
+
+static int cortex_m3_dcc_read(struct swjdp_common *swjdp, uint8_t *value, uint8_t *ctrl)
+{
+ uint16_t dcrdr;
+
+ mem_ap_read_buf_u16(swjdp, (uint8_t*)&dcrdr, 1, DCB_DCRDR);
+ *ctrl = (uint8_t)dcrdr;
+ *value = (uint8_t)(dcrdr >> 8);
+
+ LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl);
+
+ /* write ack back to software dcc register
+ * signify we have read data */
+ if (dcrdr & (1 << 0))