+/************************************************************************/
+
+/*
+ * ARM11 provider for the OpenOCD implementation of the standard
+ * architectural ARM v6/v7 "Debug Programmer's Model" (DPM).
+ */
+
+static inline struct arm11_common *dpm_to_arm11(struct arm_dpm *dpm)
+{
+ return container_of(dpm, struct arm11_common, dpm);
+}
+
+static int arm11_dpm_prepare(struct arm_dpm *dpm)
+{
+ return arm11_run_instr_data_prepare(dpm_to_arm11(dpm));
+}
+
+static int arm11_dpm_finish(struct arm_dpm *dpm)
+{
+ return arm11_run_instr_data_finish(dpm_to_arm11(dpm));
+}
+
+static int arm11_dpm_instr_write_data_dcc(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t data)
+{
+ return arm11_run_instr_data_to_core(dpm_to_arm11(dpm),
+ opcode, &data, 1);
+}
+
+static int arm11_dpm_instr_write_data_r0(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t data)
+{
+ return arm11_run_instr_data_to_core_via_r0(dpm_to_arm11(dpm),
+ opcode, data);
+}
+
+static int arm11_dpm_instr_read_data_dcc(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t *data)
+{
+ return arm11_run_instr_data_from_core(dpm_to_arm11(dpm),
+ opcode, data, 1);
+}
+
+static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm,
+ uint32_t opcode, uint32_t *data)
+{
+ return arm11_run_instr_data_from_core_via_r0(dpm_to_arm11(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_t,
+ 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_t) {
+ case 0 ... 15:
+ action[0].address = ARM11_SC7_BVR0 + index_t;
+ action[1].address = ARM11_SC7_BCR0 + index_t;
+ break;
+ case 16 ... 32:
+ index_t -= 16;
+ action[0].address = ARM11_SC7_WVR0 + index_t;
+ action[1].address = ARM11_SC7_WCR0 + index_t;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ arm11->bpwp_n += 2;
+
+ return ERROR_OK;
+}
+
+static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index_t)
+{
+ 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_t) {
+ case 0 ... 15:
+ action[0].address = ARM11_SC7_BCR0 + index_t;
+ break;
+ case 16 ... 32:
+ index_t -= 16;
+ action[0].address = ARM11_SC7_WCR0 + index_t;
+ 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)
+{
+ struct arm_dpm *dpm = &arm11->dpm;
+ int retval;
+
+ dpm->arm = &arm11->arm;
+
+ dpm->didr = didr;
+
+ dpm->prepare = arm11_dpm_prepare;
+ dpm->finish = arm11_dpm_finish;
+
+ dpm->instr_write_data_dcc = arm11_dpm_instr_write_data_dcc;
+ dpm->instr_write_data_r0 = arm11_dpm_instr_write_data_r0;
+
+ 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 arm11_bpwp_flush(arm11);
+}