Cortex-M3: expose most DWT registers
authorDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 5 Nov 2009 09:04:08 +0000 (01:04 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 5 Nov 2009 09:04:08 +0000 (01:04 -0800)
Expose most DWT registers via Tcl; there are a few more, but
those are mostly for profiling along with the ITM.  Having
this set available enables operations which aren't possible
with just the standard watchpoint operations.

The cycle counter may be interesting.  Turn it on after reset
by setting the LSB of the dwt_ctrl register, and it counts
CPU clocks.  You can program the comparator 0 watchpoint to
trigger on a given cycle count, rather than a data address.

Likewise, comparator 1 may be able to match data values given
address matches from one or two other comparators.  (Not all
hardware supports this capability though; try it.  That is
something the standard watchpoint methods should eventually
handle, for the single address case.)

Minor cleanup:  remove needless functional indirection for
exposing the v7m architctural registers.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
src/target/cortex_m3.c
src/target/cortex_m3.h

index d8a28796a25c066f53370165575014612c923bcb..eb37add3d2e39bb13b14cb84bf2a1dc6254e6934 100644 (file)
@@ -1480,22 +1480,157 @@ static int cortex_m3_bulk_write_memory(target_t *target, uint32_t address,
        return cortex_m3_write_memory(target, address, 4, count, buffer);
 }
 
-static void cortex_m3_build_reg_cache(target_t *target)
+static int cortex_m3_init_target(struct command_context_s *cmd_ctx,
+               struct target_s *target)
 {
        armv7m_build_reg_cache(target);
+       return ERROR_OK;
 }
 
-static int cortex_m3_init_target(struct command_context_s *cmd_ctx,
-               struct target_s *target)
+/* REVISIT cache valid/dirty bits are unmaintained.  We could set "valid"
+ * on r/w if the core is not running, and clear on resume or reset ... or
+ * at least, in a post_restore_context() method.
+ */
+
+struct dwt_reg_state {
+       struct target_s *target;
+       uint32_t        addr;
+       uint32_t        value;  /* scratch/cache */
+};
+
+static int cortex_m3_dwt_get_reg(struct reg_s *reg)
 {
-       cortex_m3_build_reg_cache(target);
-       return ERROR_OK;
+       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_s *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, },
+       { 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 int dwt_reg_type = -1;
+
+static void
+cortex_m3_dwt_addreg(struct target_s *t, struct reg_s *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->arch_type = dwt_reg_type;
+}
+
+static void
+cortex_m3_dwt_setup(cortex_m3_common_t *cm3, struct target_s *target)
+{
+       uint32_t dwtcr;
+       struct reg_cache_s *cache;
+       cortex_m3_dwt_comparator_t *comparator;
+       int reg, i;
+
+       target_read_u32(target, DWT_CTRL, &dwtcr);
+       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_INFO("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, dwtcr;
+       uint32_t cpuid, fpcr;
        int i;
 
        /* get pointers to arch-specific information */
@@ -1537,21 +1672,7 @@ static int cortex_m3_examine(struct target_s *target)
                LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m3->fp_num_code, cortex_m3->fp_num_lit);
 
                /* Setup DWT */
-               target_read_u32(target, DWT_CTRL, &dwtcr);
-               cortex_m3->dwt_num_comp = (dwtcr >> 28) & 0xF;
-               cortex_m3->dwt_comp_available = cortex_m3->dwt_num_comp;
-               cortex_m3->dwt_comparator_list = calloc(
-                               cortex_m3->dwt_num_comp,
-                               sizeof(cortex_m3_dwt_comparator_t));
-               for (i = 0; i < cortex_m3->dwt_num_comp; i++)
-               {
-                       cortex_m3->dwt_comparator_list[i]
-                               .dwt_comparator_address = DWT_COMP0 + 0x10 * i;
-               }
-               if (cortex_m3->dwt_num_comp)
-                       LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s",
-                               dwtcr, cortex_m3->dwt_num_comp,
-                               (dwtcr & (0xf << 24)) ? " only" : "/trigger");
+               cortex_m3_dwt_setup(cortex_m3, target);
        }
 
        return ERROR_OK;
index a7074d36c992ab5599652e84f860791f68b7cbb7..1dd724c8c8769ed342a4dbcb752ce7c335905764 100644 (file)
@@ -45,6 +45,7 @@
 #define DCRSR_WnR      (1 << 16)
 
 #define DWT_CTRL       0xE0001000
+#define DWT_CYCCNT     0xE0001004
 #define DWT_COMP0      0xE0001020
 #define DWT_MASK0      0xE0001024
 #define DWT_FUNCTION0  0xE0001028
@@ -157,6 +158,7 @@ typedef struct cortex_m3_common_s
        int dwt_num_comp;
        int dwt_comp_available;
        cortex_m3_dwt_comparator_t *dwt_comparator_list;
+       struct reg_cache_s *dwt_cache;
 
        armv7m_common_t armv7m;
        void *arch_info;

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)