flash/nor/at91samd: Use 32-bit register writes for ST-Link compat
[fw/openocd] / src / target / arm_dpm.c
index 0c84be5440cef355ceeff28207cd3697afa56e90..5f7e9291b5f3b0c30f762348e4c2a771665e59a8 100644 (file)
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /*
  * Copyright (C) 2009 by David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -21,6 +10,7 @@
 
 #include "arm.h"
 #include "arm_dpm.h"
+#include "armv8_dpm.h"
 #include <jtag/jtag.h>
 #include "register.h"
 #include "breakpoints.h"
@@ -49,7 +39,7 @@
 
 /* Read coprocessor */
 static int dpm_mrc(struct target *target, int cpnum,
-       uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
+       uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm,
        uint32_t *value)
 {
        struct arm *arm = target_to_arm(target);
@@ -61,12 +51,12 @@ static int dpm_mrc(struct target *target, int cpnum,
                return retval;
 
        LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum,
-               (int) op1, (int) CRn,
-               (int) CRm, (int) op2);
+               (int) op1, (int) crn,
+               (int) crm, (int) op2);
 
        /* read coprocessor register into R0; return via DCC */
        retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2),
+                       ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2),
                        value);
 
        /* (void) */ dpm->finish(dpm);
@@ -74,7 +64,7 @@ static int dpm_mrc(struct target *target, int cpnum,
 }
 
 static int dpm_mcr(struct target *target, int cpnum,
-       uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
+       uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm,
        uint32_t value)
 {
        struct arm *arm = target_to_arm(target);
@@ -86,12 +76,12 @@ static int dpm_mcr(struct target *target, int cpnum,
                return retval;
 
        LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum,
-               (int) op1, (int) CRn,
-               (int) CRm, (int) op2);
+               (int) op1, (int) crn,
+               (int) crm, (int) op2);
 
        /* read DCC into r0; then write coprocessor register from R0 */
        retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2),
+                       ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2),
                        value);
 
        /* (void) */ dpm->finish(dpm);
@@ -107,7 +97,7 @@ static int dpm_mcr(struct target *target, int cpnum,
 /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
  * Routines *must* restore the original mode before returning!!
  */
-int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
+int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
 {
        int retval;
        uint32_t cpsr;
@@ -130,11 +120,50 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
        return retval;
 }
 
+/* Read 64bit VFP registers */
+static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+{
+       int retval = ERROR_FAIL;
+       uint32_t value_r0, value_r1;
+
+       switch (regnum) {
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       /* move from double word register to r0:r1: "vmov r0, r1, vm"
+                        * then read r0 via dcc
+                        */
+                       retval = dpm->instr_read_data_r0(dpm,
+                               ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+                               ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0);
+                       if (retval != ERROR_OK)
+                               break;
+
+                       /* read r1 via dcc */
+                       retval = dpm->instr_read_data_dcc(dpm,
+                               ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
+                               &value_r1);
+                       break;
+               default:
+
+                       break;
+       }
 
-static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+       if (retval == ERROR_OK) {
+               buf_set_u32(r->value, 0, 32, value_r0);
+               buf_set_u32(r->value + 4, 0, 32, value_r1);
+               r->valid = true;
+               r->dirty = false;
+               LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name,
+                               (unsigned) value_r0, (unsigned) value_r1);
+       }
+
+       return retval;
+}
+
+/* just read the register -- rely on the core mode being right */
+int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
        uint32_t value;
-       int retval = ERROR_FAIL;
+       int retval;
 
        switch (regnum) {
                case 0 ... 14:
@@ -165,11 +194,18 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                                        /* core-specific ... ? */
                                        LOG_WARNING("Jazelle PC adjustment unknown");
                                        break;
-                               case ARM_STATE_AARCH64:
-                                       LOG_ERROR("AARCH64: 32bit read requested");
+                               default:
+                                       LOG_WARNING("unknown core state");
                                        break;
                        }
                        break;
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       return dpm_read_reg_u64(dpm, r, regnum);
+               case ARM_VFP_V3_FPSCR:
+                       /* "VMRS r0, FPSCR"; then return via DCC */
+                       retval = dpm->instr_read_data_r0(dpm,
+                               ARMV4_5_VMRS(0), &value);
+                       break;
                default:
                        /* 16: "MRS r0, CPSR"; then return via DCC
                         * 17: "MRS r0, SPSR"; then return via DCC
@@ -190,57 +226,47 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
        return retval;
 }
 
-static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* Write 64bit VFP registers */
+static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
-       uint64_t value;
-       uint32_t i;
        int retval = ERROR_FAIL;
+       uint32_t value_r0 = buf_get_u32(r->value, 0, 32);
+       uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32);
 
        switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */
-                       retval = dpm->instr_read_data_dcc_64(dpm, i, &value);
-                       break;
-               case 31: /* SP */
-                       i = 0x910003e0;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 32: /* PC */
-                       i = 0xd53b4520;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 33: /* CPSR */
-                       i = 0xd53b4500;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       /* write value_r1 to r1 via dcc */
+                       retval = dpm->instr_write_data_dcc(dpm,
+                               ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
+                               value_r1);
+                       if (retval != ERROR_OK)
+                               break;
 
+                       /* write value_r0 to r0 via dcc then,
+                        * move to double word register from r0:r1: "vmov vm, r0, r1"
+                        */
+                       retval = dpm->instr_write_data_r0(dpm,
+                               ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+                               ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0);
+                       break;
                default:
+
                        break;
        }
 
        if (retval == ERROR_OK) {
-               buf_set_u64(r->value, 0, 64, value);
-               r->valid = true;
                r->dirty = false;
-               LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value);
+               LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name,
+                               (unsigned) value_r0, (unsigned) value_r1);
        }
 
        return retval;
 }
 
-
-/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_read_reg64(dpm, r, regnum);
-       else
-               return dpm_read_reg32(dpm, r, regnum);
-}
-
-static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just write the register -- rely on the core mode being right */
+static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
-       int retval = ERROR_FAIL;
+       int retval;
        uint32_t value = buf_get_u32(r->value, 0, 32);
 
        switch (regnum) {
@@ -254,6 +280,13 @@ static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                         * read r0 from DCC; then "MOV pc, r0" */
                        retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
                        break;
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+                       return dpm_write_reg_u64(dpm, r, regnum);
+               case ARM_VFP_V3_FPSCR:
+                       /* move to r0 from DCC, then "VMSR FPSCR, r0" */
+                       retval = dpm->instr_write_data_r0(dpm,
+                               ARMV4_5_VMSR(0), value);
+                       break;
                default:
                        /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
                         * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
@@ -290,80 +323,49 @@ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
        return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
 }
 
-static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       int retval = ERROR_FAIL;
-       uint32_t i;
-       uint64_t value = buf_get_u64(r->value, 0, 64);
-
-       switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5330400 + regnum;
-                       retval = dpm->instr_write_data_dcc(dpm, i, value);
-                       break;
-
-               default:
-                       break;
-       }
-
-       if (retval == ERROR_OK) {
-               r->dirty = false;
-               LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value);
-       }
-
-       return retval;
-}
-
-/* just write the register -- rely on the core mode being right */
-static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_write_reg64(dpm, r, regnum);
-       else
-               return dpm_write_reg32(dpm, r, regnum);
-}
-
-static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
+/**
+ * Read basic registers of the current context:  R0 to R15, and CPSR;
+ * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
+ * In normal operation this is called on entry to halting debug state,
+ * possibly after some other operations supporting restore of debug state
+ * or making sure the CPU is fully idle (drain write buffer, etc).
+ */
+int arm_dpm_read_current_registers(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
-       uint32_t cpsr, instr, core_regs;
+       uint32_t cpsr;
        int retval;
        struct reg *r;
-       enum arm_state core_state = arm->core_state;
 
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                return retval;
 
-       /* read R0 first (it's used for scratch), then CPSR */
-       r = arm->core_cache->reg_list + 0;
-       if (!r->valid) {
-               retval = dpm_read_reg(dpm, r, 0);
-               if (retval != ERROR_OK)
-                       goto fail;
+       /* read R0 and R1 first (it's used for scratch), then CPSR */
+       for (unsigned i = 0; i < 2; i++) {
+               r = arm->core_cache->reg_list + i;
+               if (!r->valid) {
+                       retval = arm_dpm_read_reg(dpm, r, i);
+                       if (retval != ERROR_OK)
+                               goto fail;
+               }
+               r->dirty = true;
        }
-       r->dirty = true;
 
-       if (core_state == ARM_STATE_AARCH64)
-               instr = 0xd53b4500;  /* mrs x0, dspsr_el0 */
-       else
-               instr = ARMV4_5_MRS(0, 0);
-       retval = dpm->instr_read_data_r0(dpm, instr, &cpsr);
+       retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
        if (retval != ERROR_OK)
                goto fail;
 
        /* update core mode and state, plus shadow mapping for R8..R14 */
        arm_set_cpsr(arm, cpsr);
 
-       core_regs = arm->core_cache->num_regs;
-
        /* REVISIT we can probably avoid reading R1..R14, saving time... */
-       for (unsigned i = 1; i < core_regs; i++) {
-               r = dpm->arm_reg_current(arm, i);
+       for (unsigned i = 2; i < 16; i++) {
+               r = arm_reg_current(arm, i);
                if (r->valid)
                        continue;
 
-               retval = dpm_read_reg(dpm, r, i);
+               retval = arm_dpm_read_reg(dpm, r, i);
                if (retval != ERROR_OK)
                        goto fail;
        }
@@ -380,29 +382,12 @@ fail:
        return retval;
 }
 
-/**
- * Read basic registers of the the current context:  R0 to R15, and CPSR;
- * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
- * In normal operation this is called on entry to halting debug state,
- * possibly after some other operations supporting restore of debug state
- * or making sure the CPU is fully idle (drain write buffer, etc).
- */
-int arm_dpm_read_current_registers(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
-int arm_dpm_read_current_registers_64(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
 /* 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)
+       struct dpm_bpwp *xp, bool *set_p)
 {
        int retval = ERROR_OK;
        bool disable;
@@ -445,14 +430,59 @@ done:
 
 static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
 
-
-static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
+/**
+ * Writes all modified core registers for all processor modes.  In normal
+ * operation this is called on exit from halting debug state.
+ *
+ * @param dpm: represents the processor
+ * @param bpwp: true ensures breakpoints and watchpoints are set,
+ *     false ensures they are cleared
+ */
+int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
 {
        struct arm *arm = dpm->arm;
        struct reg_cache *cache = arm->core_cache;
        int retval;
        bool did_write;
 
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       /* If we're managing hardware breakpoints for this core, enable
+        * or disable them as requested.
+        *
+        * REVISIT We don't yet manage them for ANY cores.  Eventually
+        * we should be able to assume we handle them; but until then,
+        * cope with the hand-crafted breakpoint code.
+        */
+       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
+               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->is_set : NULL);
+                       if (retval != ERROR_OK)
+                               goto done;
+               }
+       }
+
+       /* enable/disable watchpoints */
+       for (unsigned i = 0; i < dpm->nwp; i++) {
+               struct dpm_wp *dwp = dpm->dwp + i;
+               struct watchpoint *wp = dwp->wp;
+
+               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+                               wp ? &wp->is_set : NULL);
+               if (retval != ERROR_OK)
+                       goto done;
+       }
+
+       /* NOTE:  writes to breakpoint and watchpoint registers might
+        * be queued, and need (efficient/batched) flushing later.
+        */
+
        /* Scan the registers until we find one that's both dirty and
         * eligible for flushing.  Flush that and everything else that
         * shares the same core mode setting.  Typically this won't
@@ -463,8 +493,8 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
 
                did_write = false;
 
-               /* check everything except our scratch register R0 */
-               for (unsigned i = 1; i < cache->num_regs; i++) {
+               /* check everything except our scratch registers R0 and R1 */
+               for (unsigned i = 2; i < cache->num_regs; i++) {
                        struct arm_reg *r;
                        unsigned regnum;
 
@@ -473,7 +503,7 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
                                continue;
                        if (arm->cpsr == cache->reg_list + i)
                                continue;
-                       if (!cache->reg_list[i].dirty)
+                       if (!cache->reg_list[i].exist || !cache->reg_list[i].dirty)
                                continue;
 
                        r = cache->reg_list[i].arch_info;
@@ -506,7 +536,7 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
 
                                /* REVISIT error checks */
                                if (tmode != ARM_MODE_ANY) {
-                                       retval = dpm_modeswitch(dpm, tmode);
+                                       retval = arm_dpm_modeswitch(dpm, tmode);
                                        if (retval != ERROR_OK)
                                                goto done;
                                }
@@ -527,7 +557,7 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
         * or it's dirty.  Must write PC to ensure the return address is
         * defined, and must not write it before CPSR.
         */
-       retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+       retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
        if (retval != ERROR_OK)
                goto done;
        arm->cpsr->dirty = false;
@@ -550,112 +580,14 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
                goto done;
        arm->pc->dirty = false;
 
-       /* flush R0 -- it's *very* dirty by now */
-       retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
-       if (retval != ERROR_OK)
-               goto done;
-       cache->reg_list[0].dirty = false;
-
-done:
-       return retval;
-}
-
-static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       /* Scan the registers until we find one that's both dirty and
-        * eligible for flushing.  Flush that and everything else that
-        * shares the same core mode setting.  Typically this won't
-        * actually find anything to do...
-        */
-
-       /* check everything except our scratch register R0 */
-       for (unsigned i = 1; i < 32; i++) {
-               struct arm_reg *r;
-               unsigned regnum;
-
-               if (!cache->reg_list[i].dirty)
-                       continue;
-
-               r = cache->reg_list[i].arch_info;
-               regnum = r->num;
-               retval = dpm_write_reg(dpm,
-                                      &cache->reg_list[i],
-                                      regnum);
+       /* flush R0 and R1 (our scratch registers) */
+       for (unsigned i = 0; i < 2; i++) {
+               retval = dpm_write_reg(dpm, &cache->reg_list[i], i);
                if (retval != ERROR_OK)
                        goto done;
+               cache->reg_list[i].dirty = false;
        }
 
-       /* flush R0 -- it's *very* dirty by now */
-       retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
-       if (retval != ERROR_OK)
-               goto done;
-       cache->reg_list[0].dirty = false;
-
-done:
-       return retval;
-}
-
-/**
- * Writes all modified core registers for all processor modes.  In normal
- * operation this is called on exit from halting debug state.
- *
- * @param dpm: represents the processor
- * @param bpwp: true ensures breakpoints and watchpoints are set,
- *     false ensures they are cleared
- */
-int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* If we're managing hardware breakpoints for this core, enable
-        * or disable them as requested.
-        *
-        * REVISIT We don't yet manage them for ANY cores.  Eventually
-        * we should be able to assume we handle them; but until then,
-        * cope with the hand-crafted breakpoint code.
-        */
-       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
-               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);
-                       if (retval != ERROR_OK)
-                               goto done;
-               }
-       }
-
-       /* enable/disable watchpoints */
-       for (unsigned i = 0; i < dpm->nwp; i++) {
-               struct dpm_wp *dwp = dpm->dwp + i;
-               struct watchpoint *wp = dwp->wp;
-
-               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
-                               wp ? &wp->set : NULL);
-               if (retval != ERROR_OK)
-                       goto done;
-       }
-
-       /* NOTE:  writes to breakpoint and watchpoint registers might
-        * be queued, and need (efficient/batched) flushing later.
-        */
-
-       if (cache->reg_list[0].size == 64)
-               retval = arm_dpm_write_dirty_registers_64(dpm);
-       else
-               retval = arm_dpm_write_dirty_registers_32(dpm);
-
        /* (void) */ dpm->finish(dpm);
 done:
        return retval;
@@ -691,6 +623,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm,
                /* r13/sp, and r14/lr are always shadowed */
                case 13:
                case 14:
+               case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR:
                        return mode;
                default:
                        LOG_WARNING("invalid register #%u", num);
@@ -712,7 +645,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
        struct arm_dpm *dpm = target_to_arm(target)->dpm;
        int retval;
 
-       if (regnum < 0 || regnum > 16)
+       if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+               (regnum > ARM_VFP_V3_FPSCR))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (regnum == 16) {
@@ -730,18 +664,18 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
                return retval;
 
        if (mode != ARM_MODE_ANY) {
-               retval = dpm_modeswitch(dpm, mode);
+               retval = arm_dpm_modeswitch(dpm, mode);
                if (retval != ERROR_OK)
                        goto fail;
        }
 
-       retval = dpm_read_reg(dpm, r, regnum);
+       retval = arm_dpm_read_reg(dpm, r, regnum);
        if (retval != ERROR_OK)
                goto fail;
        /* always clean up, regardless of error */
 
        if (mode != ARM_MODE_ANY)
-               /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+               /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
 
 fail:
        /* (void) */ dpm->finish(dpm);
@@ -755,7 +689,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
        int retval;
 
 
-       if (regnum < 0 || regnum > 16)
+       if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+                       (regnum > ARM_VFP_V3_FPSCR))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (regnum == 16) {
@@ -773,7 +708,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
                return retval;
 
        if (mode != ARM_MODE_ANY) {
-               retval = dpm_modeswitch(dpm, mode);
+               retval = arm_dpm_modeswitch(dpm, mode);
                if (retval != ERROR_OK)
                        goto fail;
        }
@@ -782,7 +717,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
        /* always clean up, regardless of error */
 
        if (mode != ARM_MODE_ANY)
-               /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+               /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
 
 fail:
        /* (void) */ dpm->finish(dpm);
@@ -817,7 +752,7 @@ static int arm_dpm_full_context(struct target *target)
                for (unsigned i = 0; i < cache->num_regs; i++) {
                        struct arm_reg *r;
 
-                       if (cache->reg_list[i].valid)
+                       if (!cache->reg_list[i].exist || cache->reg_list[i].valid)
                                continue;
                        r = cache->reg_list[i].arch_info;
 
@@ -831,9 +766,9 @@ static int arm_dpm_full_context(struct target *target)
                                 * in FIQ mode we need to patch mode.
                                 */
                                if (mode != ARM_MODE_ANY)
-                                       retval = dpm_modeswitch(dpm, mode);
+                                       retval = arm_dpm_modeswitch(dpm, mode);
                                else
-                                       retval = dpm_modeswitch(dpm, ARM_MODE_USR);
+                                       retval = arm_dpm_modeswitch(dpm, ARM_MODE_USR);
 
                                if (retval != ERROR_OK)
                                        goto done;
@@ -842,7 +777,7 @@ static int arm_dpm_full_context(struct target *target)
                                continue;
 
                        /* CPSR was read, so "R16" must mean SPSR */
-                       retval = dpm_read_reg(dpm,
+                       retval = arm_dpm_read_reg(dpm,
                                        &cache->reg_list[i],
                                        (r->num == 16) ? 17 : r->num);
                        if (retval != ERROR_OK)
@@ -851,7 +786,7 @@ static int arm_dpm_full_context(struct target *target)
 
        } while (did_read);
 
-       retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+       retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
        /* (void) */ dpm->finish(dpm);
 done:
        return retval;
@@ -1064,7 +999,7 @@ void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr)
                        /* ?? */
                        break;
        }
-       dpm->wp_pc = addr;
+       dpm->wp_addr = addr;
 }
 
 /*----------------------------------------------------------------------*/
@@ -1081,20 +1016,16 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr)
 
        /* Examine debug reason */
        switch (DSCR_ENTRY(dscr)) {
-               case 6: /* Data abort (v6 only) */
-               case 7: /* Prefetch abort (v6 only) */
-               /* FALL THROUGH -- assume a v6 core in abort mode */
-               case 0: /* HALT request from debugger */
-               case 4: /* EDBGRQ */
+               case DSCR_ENTRY_HALT_REQ:       /* HALT request from debugger */
+               case DSCR_ENTRY_EXT_DBG_REQ:    /* EDBGRQ */
                        target->debug_reason = DBG_REASON_DBGRQ;
                        break;
-               case 1: /* HW breakpoint */
-               case 3: /* SW BKPT */
-               case 5: /* vector catch */
+               case DSCR_ENTRY_BREAKPOINT:     /* HW breakpoint */
+               case DSCR_ENTRY_BKPT_INSTR:     /* vector catch */
                        target->debug_reason = DBG_REASON_BREAKPOINT;
                        break;
-               case 2: /* asynch watchpoint */
-               case 10:/* precise watchpoint */
+               case DSCR_ENTRY_IMPRECISE_WATCHPT:      /* asynch watchpoint */
+               case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */
                        target->debug_reason = DBG_REASON_WATCHPOINT;
                        break;
                default:
@@ -1119,17 +1050,16 @@ int arm_dpm_setup(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
        struct target *target = arm->target;
-       struct reg_cache *cache;
+       struct reg_cache *cache = 0;
 
        arm->dpm = dpm;
 
        /* register access setup */
        arm->full_context = arm_dpm_full_context;
-       arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
-       arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
+       arm->read_core_reg = arm_dpm_read_core_reg;
+       arm->write_core_reg = arm_dpm_write_core_reg;
 
-       /* avoid duplicating the register cache */
-       if (arm->core_cache == NULL) {
+       if (!arm->core_cache) {
                cache = arm_build_reg_cache(target, arm);
                if (!cache)
                        return ERROR_FAIL;
@@ -1147,28 +1077,21 @@ int arm_dpm_setup(struct arm_dpm *dpm)
                target->type->remove_breakpoint = dpm_remove_breakpoint;
        }
 
-       /* watchpoint setup */
-       target->type->add_watchpoint = dpm_add_watchpoint;
-       target->type->remove_watchpoint = dpm_remove_watchpoint;
-
-
-       if (dpm->arm_reg_current == 0)
-               dpm->arm_reg_current = arm_reg_current;
+       /* watchpoint setup -- optional until it works everywhere */
+       if (!target->type->add_watchpoint) {
+               target->type->add_watchpoint = dpm_add_watchpoint;
+               target->type->remove_watchpoint = dpm_remove_watchpoint;
+       }
 
        /* FIXME add vector catch support */
 
-       if (arm->core_state == ARM_STATE_AARCH64) {
-               dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
-       } else {
-               dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
-       }
-
-       dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
-       dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
+       dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
+       dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
+       dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp));
+       dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp));
 
        if (!dpm->dbp || !dpm->dwp) {
+               arm_free_reg_cache(arm);
                free(dpm->dbp);
                free(dpm->dwp);
                return ERROR_FAIL;