ARM11: basic watchpoint support
[openocd.git] / src / target / arm11_dbgtap.c
index 7e1e9cba7493055852d19e1fd7189027e6758e6a..9ad566222bf5f14a1089af963825ab6ed8d5530f 100644 (file)
@@ -27,7 +27,7 @@
 #include "arm_jtag.h"
 #include "arm11_dbgtap.h"
 
-#include "time_support.h"
+#include <helper/time_support.h>
 
 #if 0
 #define JTAG_DEBUG(expr ...)   do { if (1) LOG_DEBUG(expr); } while (0)
@@ -91,6 +91,38 @@ void arm11_setup_field(struct arm11_common * arm11, int num_bits, void * out_dat
        field->in_value                 = in_data;
 }
 
+static const char *arm11_ir_to_string(uint8_t ir)
+{
+       const char *s = "unknown";
+
+       switch (ir) {
+       case ARM11_EXTEST:
+               s = "EXTEST";
+               break;
+       case ARM11_SCAN_N:
+               s = "SCAN_N";
+               break;
+       case ARM11_RESTART:
+               s = "RESTART";
+               break;
+       case ARM11_HALT:
+               s = "HALT";
+               break;
+       case ARM11_INTEST:
+               s = "INTEST";
+               break;
+       case ARM11_ITRSEL:
+               s = "ITRSEL";
+               break;
+       case ARM11_IDCODE:
+               s = "IDCODE";
+               break;
+       case ARM11_BYPASS:
+               s = "BYPASS";
+               break;
+       }
+       return s;
+}
 
 /** Write JTAG instruction register
  *
@@ -110,7 +142,7 @@ void arm11_add_IR(struct arm11_common * arm11, uint8_t instr, tap_state_t state)
                return;
        }
 
-       JTAG_DEBUG("IR <= 0x%02x", instr);
+       JTAG_DEBUG("IR <= %s (0x%02x)", arm11_ir_to_string(instr), instr);
 
        struct scan_field field;
 
@@ -135,7 +167,8 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value)
                jtag_set_error(ERROR_FAIL);
        }
 
-       JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v);
+       if (v != 0x10)
+               JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v);
 }
 
 /** Select and write to Scan Chain Register (SCREG)
@@ -150,6 +183,9 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value)
  * \param state            Pass the final TAP state or ARM11_TAP_DEFAULT for the default
  *                                     value (Pause-DR).
  *
+ * Changes the current scan chain if needed, transitions to the specified
+ * TAP state, and leaves the IR undefined.
+ *
  * The chain takes effect when Update-DR is passed (usually when subsequently
  * the INTEXT/EXTEST instructions are written).
  *
@@ -162,9 +198,19 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value)
  * \remarks                    This adds to the JTAG command queue but does \em not execute it.
  */
 
-int arm11_add_debug_SCAN_N(struct arm11_common * arm11, uint8_t chain, tap_state_t state)
+int arm11_add_debug_SCAN_N(struct arm11_common *arm11,
+               uint8_t chain, tap_state_t state)
 {
-       JTAG_DEBUG("SCREG <= 0x%02x", chain);
+       /* Don't needlessly switch the scan chain.
+        * NOTE:  the ITRSEL instruction fakes SCREG changing;
+        * but leaves its actual value unchanged.
+        */
+       if (arm11->jtag_info.cur_scan_chain == chain) {
+               JTAG_DEBUG("SCREG <= %d SKIPPED", chain);
+               return jtag_add_statemove((state == ARM11_TAP_DEFAULT)
+                                       ? TAP_DRPAUSE : state);
+       }
+       JTAG_DEBUG("SCREG <= %d", chain);
 
        arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT);
 
@@ -288,50 +334,6 @@ int arm11_write_DSCR(struct arm11_common * arm11, uint32_t dscr)
        return ERROR_OK;
 }
 
-
-
-/** Get the debug reason from Debug Status and Control Register (DSCR)
- *
- * \param dscr         DSCR value to analyze
- * \return                     Debug reason
- *
- */
-enum target_debug_reason arm11_get_DSCR_debug_reason(uint32_t dscr)
-{
-       switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK)
-       {
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT:
-               LOG_INFO("Debug entry: JTAG HALT");
-               return DBG_REASON_DBGRQ;
-
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT:
-               LOG_INFO("Debug entry: breakpoint");
-               return DBG_REASON_BREAKPOINT;
-
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT:
-               LOG_INFO("Debug entry: watchpoint");
-               return DBG_REASON_WATCHPOINT;
-
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION:
-               LOG_INFO("Debug entry: BKPT instruction");
-               return DBG_REASON_BREAKPOINT;
-
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ:
-               LOG_INFO("Debug entry: EDBGRQ signal");
-               return DBG_REASON_DBGRQ;
-
-       case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH:
-               LOG_INFO("Debug entry: VCR vector catch");
-               return DBG_REASON_BREAKPOINT;
-
-       default:
-               LOG_INFO("Debug entry: unknown");
-               return DBG_REASON_DBGRQ;
-       }
-};
-
-
-
 /** Prepare the stage for ITR/DTR operations
  * from the arm11_run_instr... group of functions.
  *
@@ -835,30 +837,31 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions
                }
                else
                {
-                       nRW                     = 0;
+                       nRW                     = 1;
                        DataOut         = 0;
                        AddressOut      = 0;
                }
 
                do
                {
-                       JTAG_DEBUG("SC7 <= Address %02x  Data %08x    nRW %d",
+                       JTAG_DEBUG("SC7 <= c%-3d Data %08x %s",
                                        (unsigned) AddressOut,
                                        (unsigned) DataOut,
-                                       nRW);
+                                       nRW ? "write" : "read");
 
                        arm11_add_dr_scan_vc(ARRAY_SIZE(chain7_fields),
                                        chain7_fields, TAP_DRPAUSE);
 
                        CHECK_RETVAL(jtag_execute_queue());
 
-                       JTAG_DEBUG("SC7 => Address %02x  Data %08x  Ready %d",
-                                       (unsigned) AddressIn,
-                                       (unsigned) DataIn,
-                                       Ready);
+                       if (!Ready)
+                               JTAG_DEBUG("SC7 => !ready");
                }
                while (!Ready); /* 'nRW' is 'Ready' on read out */
 
+               if (!nRW)
+                       JTAG_DEBUG("SC7 => Data %08x", (unsigned) DataIn);
+
                if (i > 0)
                {
                        if (actions[i - 1].address != AddressIn)
@@ -879,15 +882,6 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions
                        }
                }
        }
-
-       for (size_t i = 0; i < count; i++)
-       {
-               JTAG_DEBUG("SC7 %02d: %02x %s %08x",
-                       (unsigned) i, actions[i].address,
-                       actions[i].write ? "<=" : "=>",
-                       (unsigned) actions[i].value);
-       }
-
        return ERROR_OK;
 }
 
@@ -898,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;
 
@@ -911,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);
@@ -936,7 +925,6 @@ void arm11_sc7_set_vcr(struct arm11_common * arm11, uint32_t value)
        set_vcr.address         = ARM11_SC7_VCR;
        set_vcr.value           = value;
 
-
        arm11_sc7_run(arm11, &set_vcr, 1);
 }
 
@@ -1020,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)
 {
@@ -1039,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);
 }

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)