ARM11: basic watchpoint support
authorDavid Brownell <dbrownell@users.sourceforge.net>
Sat, 5 Dec 2009 02:57:31 +0000 (18:57 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Sat, 5 Dec 2009 02:57:31 +0000 (18:57 -0800)
Use the DPM watchpoint support; remove old incomplete stubs.

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

diff --git a/NEWS b/NEWS
index 38ae4da6211ff815fad7cc587a9984cb662a62f4..498797b1f4855cd5732f8789330890c487179155 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,10 +24,12 @@ Target Layer:
                - accelerated GDB memory checksum
                - support "arm regs" command
                - can access all core modes and registers
+               - watchpoint support
        Cortex-A8
                - support "arm regs" command
                - can access all core modes and registers
                - supports "reset-assert" event (used on OMAP3530)
+               - watchpoint support
        Cortex-M3
                - Exposed DWT registers like cycle counter
 
index b05ef302aa3a14eec65b1be4dfb1346b5f9cbaa9..943ab8ae804d95059cea0a179116ed12d22c3d4e 100644 (file)
@@ -286,6 +286,8 @@ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp)
         */
        retval = arm_dpm_write_dirty_registers(&arm11->dpm, bpwp);
 
+       retval = arm11_bpwp_flush(arm11);
+
        register_cache_invalidate(arm11->arm.core_cache);
 
        /* restore DSCR */
@@ -1212,7 +1214,6 @@ static int arm11_examine(struct target *target)
        }
 
        arm11->brp = ((didr >> 24) & 0x0F) + 1;
-       arm11->wrp = ((didr >> 28) & 0x0F) + 1;
 
        /** \todo TODO: reserve one brp slot if we allow breakpoints during step */
        arm11->free_brps = arm11->brp;
index f3f0644b08b90af0569ea94f078baf0cdd99e3d8..421f8d185c699997cb64ca7b641aa31570c60a7b 100644 (file)
@@ -53,9 +53,10 @@ struct arm11_common
 
        /** Debug module state. */
        struct arm_dpm dpm;
+       struct arm11_sc7_action *bpwp_actions;
+       unsigned bpwp_n;
 
        size_t  brp;                    /**< Number of Breakpoint Register Pairs from DIDR      */
-       size_t  wrp;                    /**< Number of Watchpoint Register Pairs from DIDR      */
        size_t  free_brps;              /**< Number of breakpoints allocated */
 
        uint32_t dscr;                  /**< Last retrieved DSCR value. */
index e37ad56ca3567401d7a704500c717c2f162f1647..9ad566222bf5f14a1089af963825ab6ed8d5530f 100644 (file)
@@ -892,7 +892,7 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions
  */
 void arm11_sc7_clear_vbw(struct arm11_common * arm11)
 {
-       size_t clear_bw_size = arm11->brp + arm11->wrp + 1;
+       size_t clear_bw_size = arm11->brp + 1;
        struct arm11_sc7_action         *clear_bw = malloc(sizeof(struct arm11_sc7_action) * clear_bw_size);
        struct arm11_sc7_action *       pos = clear_bw;
 
@@ -905,11 +905,6 @@ void arm11_sc7_clear_vbw(struct arm11_common * arm11)
        for (size_t i = 0; i < arm11->brp; i++)
                (pos++)->address = ARM11_SC7_BCR0 + i;
 
-
-       for (size_t i = 0; i < arm11->wrp; i++)
-               (pos++)->address = ARM11_SC7_WCR0 + i;
-
-
        (pos++)->address = ARM11_SC7_VCR;
 
        arm11_sc7_run(arm11, clear_bw, clear_bw_size);
@@ -1013,6 +1008,88 @@ static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm,
                        opcode, data);
 }
 
+/* Because arm11_sc7_run() takes a vector of actions, we batch breakpoint
+ * and watchpoint operations instead of running them right away.  Since we
+ * pre-allocated our vector, we don't need to worry about space.
+ */
+static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index,
+               uint32_t addr, uint32_t control)
+{
+       struct arm11_common *arm11 = dpm_to_arm11(dpm);
+       struct arm11_sc7_action *action;
+
+       action = arm11->bpwp_actions + arm11->bpwp_n;
+
+       /* Invariant:  this bp/wp is disabled.
+        * It also happens that the core is halted here, but for
+        * DPM-based cores we don't actually care about that.
+        */
+
+       action[0].write = action[1].write = true;
+
+       action[0].value = addr;
+       action[1].value = control;
+
+       switch (index) {
+       case 0 ... 15:
+               action[0].address = ARM11_SC7_BVR0 + index;
+               action[1].address = ARM11_SC7_BCR0 + index;
+               break;
+       case 16 ... 32:
+               index -= 16;
+               action[0].address = ARM11_SC7_WVR0 + index;
+               action[1].address = ARM11_SC7_WCR0 + index;
+               break;
+       default:
+               return ERROR_FAIL;
+       }
+
+       arm11->bpwp_n += 2;
+
+       return ERROR_OK;
+}
+
+static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index)
+{
+       struct arm11_common *arm11 = dpm_to_arm11(dpm);
+       struct arm11_sc7_action *action;
+
+       action = arm11->bpwp_actions + arm11->bpwp_n;
+
+       action[0].write = true;
+       action[0].value = 0;
+
+       switch (index) {
+       case 0 ... 15:
+               action[0].address = ARM11_SC7_BCR0 + index;
+               break;
+       case 16 ... 32:
+               index -= 16;
+               action[0].address = ARM11_SC7_WCR0 + index;
+               break;
+       default:
+               return ERROR_FAIL;
+       }
+
+       arm11->bpwp_n += 1;
+
+       return ERROR_OK;
+}
+
+/** Flush any pending breakpoint and watchpoint updates. */
+int arm11_bpwp_flush(struct arm11_common *arm11)
+{
+       int retval;
+
+       if (!arm11->bpwp_n)
+               return ERROR_OK;
+
+       retval = arm11_sc7_run(arm11, arm11->bpwp_actions, arm11->bpwp_n);
+       arm11->bpwp_n = 0;
+
+       return retval;
+}
+
 /** Set up high-level debug module utilities */
 int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr)
 {
@@ -1032,11 +1109,22 @@ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr)
        dpm->instr_read_data_dcc = arm11_dpm_instr_read_data_dcc;
        dpm->instr_read_data_r0 = arm11_dpm_instr_read_data_r0;
 
+       dpm->bpwp_enable = arm11_bpwp_enable;
+       dpm->bpwp_disable = arm11_bpwp_disable;
+
        retval = arm_dpm_setup(dpm);
        if (retval != ERROR_OK)
                return retval;
 
+       /* alloc enough to enable all breakpoints and watchpoints at once */
+       arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp),
+                       sizeof *arm11->bpwp_actions);
+       if (!arm11->bpwp_actions)
+               return ERROR_FAIL;
+
        retval = arm_dpm_initialize(dpm);
+       if (retval != ERROR_OK)
+               return retval;
 
-       return retval;
+       return arm11_bpwp_flush(arm11);
 }
index 2c586cc9fcc4bdc97bdd15d6ffaf04e9fb2de64a..3139a09afe99bc1cb43d620854e03884950fb813 100644 (file)
@@ -59,5 +59,6 @@ int arm11_read_memory_word(struct arm11_common *arm11,
                uint32_t address, uint32_t *result);
 
 int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr);
+int arm11_bpwp_flush(struct arm11_common *arm11);
 
 #endif // ARM11_DBGTAP_H