summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-12-11 15:26:10 -0800
committerDavid Brownell <dbrownell@users.sourceforge.net>2009-12-11 15:26:10 -0800
commit75c706cc043183d98592dbe3c6f170d627849d0f (patch)
tree4cb1ab35d34e372a3e21826a121f575c479c1b40
parent838d41af29c0b703fd55ebb5c3aebcb4e0bea460 (diff)
downloadopenocd_libswd-75c706cc043183d98592dbe3c6f170d627849d0f.tar.gz
openocd_libswd-75c706cc043183d98592dbe3c6f170d627849d0f.tar.bz2
openocd_libswd-75c706cc043183d98592dbe3c6f170d627849d0f.tar.xz
openocd_libswd-75c706cc043183d98592dbe3c6f170d627849d0f.zip
ARM DPM: support updating HW breakpoints
Abstract the DPM breakpoint and watchpoint data structures to have a shared core for housekeeping. Abstract the code updating the watchpoint registers so that it can be used to update breakpoint registers. Then do so, when something has set up the breakpoint state used by this code. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r--src/target/arm_dpm.c107
-rw-r--r--src/target/arm_dpm.h20
2 files changed, 75 insertions, 52 deletions
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index bd9c5d16..0908ca92 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -277,6 +277,51 @@ fail:
return retval;
}
+/* Avoid needless I/O ... leave breakpoints and watchpoints alone
+ * unless they're removed, or need updating because of single-stepping
+ * or running debugger code.
+ */
+static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp,
+ struct dpm_bpwp *xp, int *set_p)
+{
+ int retval = ERROR_OK;
+ bool disable;
+
+ if (!set_p) {
+ if (!xp->dirty)
+ goto done;
+ xp->dirty = false;
+ /* removed or startup; we must disable it */
+ disable = true;
+ } else if (bpwp) {
+ if (!xp->dirty)
+ goto done;
+ /* disabled, but we must set it */
+ xp->dirty = disable = false;
+ *set_p = true;
+ } else {
+ if (!*set_p)
+ goto done;
+ /* set, but we must temporarily disable it */
+ xp->dirty = disable = true;
+ *set_p = false;
+ }
+
+ if (disable)
+ retval = dpm->bpwp_disable(dpm, xp->number);
+ else
+ retval = dpm->bpwp_enable(dpm, xp->number,
+ xp->address, xp->control);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s: can't %s HW bp/wp %d",
+ disable ? "disable" : "enable",
+ target_name(dpm->arm->target),
+ xp->number);
+done:
+ return retval;
+}
+
/**
* Writes all modified core registers for all processor modes. In normal
* operation this is called on exit from halting debug state.
@@ -296,47 +341,22 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
if (retval != ERROR_OK)
goto done;
+ /* enable/disable hardware breakpoints */
+ for (unsigned i = 0; i < dpm->nbp; i++) {
+ struct dpm_bp *dbp = dpm->dbp + i;
+ struct breakpoint *bp = dbp->bp;
+
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
+ bp ? &bp->set : NULL);
+ }
+
/* enable/disable watchpoints */
for (unsigned i = 0; i < dpm->nwp; i++) {
struct dpm_wp *dwp = dpm->dwp + i;
struct watchpoint *wp = dwp->wp;
- bool disable;
-
- /* Avoid needless I/O ... leave watchpoints alone
- * unless they're removed, or need updating because
- * of single-stepping or running debugger code.
- */
- if (!wp) {
- if (!dwp->dirty)
- continue;
- dwp->dirty = false;
- /* removed or startup; we must disable it */
- disable = true;
- } else if (bpwp) {
- if (!dwp->dirty)
- continue;
- /* disabled, but we must set it */
- dwp->dirty = disable = false;
- wp->set = true;
- } else {
- if (!wp->set)
- continue;
- /* set, but we must temporarily disable it */
- dwp->dirty = disable = true;
- wp->set = false;
- }
-
- if (disable)
- retval = dpm->bpwp_disable(dpm, 16 + i);
- else
- retval = dpm->bpwp_enable(dpm, 16 + i,
- wp->address & ~3, dwp->control);
- if (retval != ERROR_OK)
- LOG_ERROR("%s: can't %s HW watchpoint %d",
- target_name(arm->target),
- disable ? "disable" : "enable",
- i);
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+ wp ? &wp->set : NULL);
}
/* NOTE: writes to breakpoint and watchpoint registers might
@@ -696,8 +716,9 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index,
*/
dpm->dwp[index].wp = wp;
- dpm->dwp[index].control = control;
- dpm->dwp[index].dirty = true;
+ dpm->dwp[index].bpwp.address = addr & ~3;
+ dpm->dwp[index].bpwp.control = control;
+ dpm->dwp[index].bpwp.dirty = true;
/* hardware is updated in write_dirty_registers() */
return ERROR_OK;
@@ -731,7 +752,7 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp)
for (unsigned i = 0; i < dpm->nwp; i++) {
if (dpm->dwp[i].wp == wp) {
dpm->dwp[i].wp = NULL;
- dpm->dwp[i].dirty = true;
+ dpm->dwp[i].bpwp.dirty = true;
/* hardware is updated in write_dirty_registers() */
retval = ERROR_OK;
@@ -869,10 +890,14 @@ int arm_dpm_initialize(struct arm_dpm *dpm)
if (dpm->bpwp_disable) {
unsigned i;
- for (i = 0; i < dpm->nbp; i++)
+ for (i = 0; i < dpm->nbp; i++) {
+ dpm->dbp[i].bpwp.number = i;
(void) dpm->bpwp_disable(dpm, i);
- for (i = 0; i < dpm->nwp; i++)
+ }
+ for (i = 0; i < dpm->nwp; i++) {
+ dpm->dwp[i].bpwp.number = 16 + i;
(void) dpm->bpwp_disable(dpm, 16 + i);
+ }
} else
LOG_WARNING("%s: can't disable breakpoints and watchpoints",
target_name(dpm->arm->target));
diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h
index 135e3db8..5d75ed41 100644
--- a/src/target/arm_dpm.h
+++ b/src/target/arm_dpm.h
@@ -31,24 +31,22 @@
* registers are compatible.
*/
-struct dpm_bp {
- struct breakpoint *bp;
- /* bp->address == breakpoint value register
- * control == breakpoint control register
- */
+struct dpm_bpwp {
+ unsigned number;
+ uint32_t address;
uint32_t control;
/* true if hardware state needs flushing */
bool dirty;
};
+struct dpm_bp {
+ struct breakpoint *bp;
+ struct dpm_bpwp bpwp;
+};
+
struct dpm_wp {
struct watchpoint *wp;
- /* wp->address == watchpoint value register
- * control == watchpoint control register
- */
- uint32_t control;
- /* true if hardware state needs flushing */
- bool dirty;
+ struct dpm_bpwp bpwp;
};
/**