target algo: do not write reg_param if direction is PARAM_IN
[openocd.git] / src / target / armv7m.c
index 771613981e90193208785c7f76c860da264ed645..ecca0e752466e1f143be0da7bb3b59542e61cd12 100644 (file)
@@ -11,6 +11,9 @@
  *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
+ *   Copyright (C) 2018 by Liviu Ionescu                                   *
+ *   <ilg@livius.net>                                                      *
+ *                                                                         *
  *   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     *
  *   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     *
@@ -22,9 +25,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
  *   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, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  *                                                                         *
  *   ARMv7-M Architecture, Application Level Reference Manual              *
  *              ARM DDI 0405C (September 2008)                             *
  *                                                                         *
  *   ARMv7-M Architecture, Application Level Reference Manual              *
  *              ARM DDI 0405C (September 2008)                             *
 #include "armv7m.h"
 #include "algorithm.h"
 #include "register.h"
 #include "armv7m.h"
 #include "algorithm.h"
 #include "register.h"
+#include "semihosting_common.h"
 
 #if 0
 #define _DEBUG_INSTRUCTION_EXECUTION_
 #endif
 
 
 #if 0
 #define _DEBUG_INSTRUCTION_EXECUTION_
 #endif
 
-static char *armv7m_exception_strings[] = {
+static const char * const armv7m_exception_strings[] = {
        "", "Reset", "NMI", "HardFault",
        "MemManage", "BusFault", "UsageFault", "RESERVED",
        "RESERVED", "RESERVED", "RESERVED", "SVCall",
        "", "Reset", "NMI", "HardFault",
        "MemManage", "BusFault", "UsageFault", "RESERVED",
        "RESERVED", "RESERVED", "RESERVED", "SVCall",
@@ -52,7 +54,7 @@ static char *armv7m_exception_strings[] = {
 };
 
 /* PSP is used in some thread modes */
 };
 
 /* PSP is used in some thread modes */
-const int armv7m_psp_reg_map[17] = {
+const int armv7m_psp_reg_map[ARMV7M_NUM_CORE_REGS] = {
        ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
        ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
        ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
        ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
        ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
        ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
@@ -61,7 +63,7 @@ const int armv7m_psp_reg_map[17] = {
 };
 
 /* MSP is used in handler and some thread modes */
 };
 
 /* MSP is used in handler and some thread modes */
-const int armv7m_msp_reg_map[17] = {
+const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = {
        ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
        ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
        ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
        ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3,
        ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7,
        ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11,
@@ -110,6 +112,25 @@ static const struct {
        { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
        { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
        { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
        { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
        { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
        { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
+
+       { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+       { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
+
+       { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" },
 };
 
 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
 };
 
 #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
@@ -129,10 +150,10 @@ int armv7m_restore_context(struct target *target)
        if (armv7m->pre_restore_context)
                armv7m->pre_restore_context(target);
 
        if (armv7m->pre_restore_context)
                armv7m->pre_restore_context(target);
 
-       for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
+       for (i = cache->num_regs - 1; i >= 0; i--) {
                if (cache->reg_list[i].dirty) {
                if (cache->reg_list[i].dirty) {
-                       uint32_t value = buf_get_u32(cache->reg_list[i].value, 0, 32);
-                       armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, ARM_MODE_ANY, value);
+                       armv7m->arm.write_core_reg(target, &cache->reg_list[i], i,
+                                                  ARM_MODE_ANY, cache->reg_list[i].value);
                }
        }
 
                }
        }
 
@@ -148,7 +169,7 @@ int armv7m_restore_context(struct target *target)
  * They are assigned by vendors, which generally assign different numbers to
  * peripherals (such as UART0 or a USB peripheral controller).
  */
  * They are assigned by vendors, which generally assign different numbers to
  * peripherals (such as UART0 or a USB peripheral controller).
  */
-char *armv7m_exception_string(int number)
+const char *armv7m_exception_string(int number)
 {
        static char enamebuf[32];
 
 {
        static char enamebuf[32];
 
@@ -179,12 +200,11 @@ static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
 {
        struct arm_reg *armv7m_reg = reg->arch_info;
        struct target *target = armv7m_reg->target;
 {
        struct arm_reg *armv7m_reg = reg->arch_info;
        struct target *target = armv7m_reg->target;
-       uint32_t value = buf_get_u32(buf, 0, 32);
 
        if (target->state != TARGET_HALTED)
                return ERROR_TARGET_NOT_HALTED;
 
 
        if (target->state != TARGET_HALTED)
                return ERROR_TARGET_NOT_HALTED;
 
-       buf_set_u32(reg->value, 0, 32, value);
+       buf_cpy(buf, reg->value, reg->size);
        reg->dirty = 1;
        reg->valid = 1;
 
        reg->dirty = 1;
        reg->valid = 1;
 
@@ -202,10 +222,28 @@ static int armv7m_read_core_reg(struct target *target, struct reg *r,
        assert(num < (int)armv7m->arm.core_cache->num_regs);
 
        armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
        assert(num < (int)armv7m->arm.core_cache->num_regs);
 
        armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
-       retval = armv7m->load_core_reg_u32(target,
-                       armv7m_core_reg->num, &reg_value);
 
 
-       buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
+       if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
+               /* map D0..D15 to S0..S31 */
+               size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
+               retval = armv7m->load_core_reg_u32(target, regidx, &reg_value);
+               if (retval != ERROR_OK)
+                       return retval;
+               buf_set_u32(armv7m->arm.core_cache->reg_list[num].value,
+                           0, 32, reg_value);
+               retval = armv7m->load_core_reg_u32(target, regidx + 1, &reg_value);
+               if (retval != ERROR_OK)
+                       return retval;
+               buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4,
+                           0, 32, reg_value);
+       } else {
+               retval = armv7m->load_core_reg_u32(target,
+                                                  armv7m_core_reg->num, &reg_value);
+               if (retval != ERROR_OK)
+                       return retval;
+               buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
+       }
+
        armv7m->arm.core_cache->reg_list[num].valid = 1;
        armv7m->arm.core_cache->reg_list[num].dirty = 0;
 
        armv7m->arm.core_cache->reg_list[num].valid = 1;
        armv7m->arm.core_cache->reg_list[num].dirty = 0;
 
@@ -213,31 +251,47 @@ static int armv7m_read_core_reg(struct target *target, struct reg *r,
 }
 
 static int armv7m_write_core_reg(struct target *target, struct reg *r,
 }
 
 static int armv7m_write_core_reg(struct target *target, struct reg *r,
-       int num, enum arm_mode mode, uint32_t value)
+       int num, enum arm_mode mode, uint8_t *value)
 {
        int retval;
 {
        int retval;
-       uint32_t reg_value;
        struct arm_reg *armv7m_core_reg;
        struct armv7m_common *armv7m = target_to_armv7m(target);
 
        assert(num < (int)armv7m->arm.core_cache->num_regs);
 
        struct arm_reg *armv7m_core_reg;
        struct armv7m_common *armv7m = target_to_armv7m(target);
 
        assert(num < (int)armv7m->arm.core_cache->num_regs);
 
-       reg_value = buf_get_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32);
        armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
        armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
-       retval = armv7m->store_core_reg_u32(target,
-                       armv7m_core_reg->num,
-                       reg_value);
-       if (retval != ERROR_OK) {
-               LOG_ERROR("JTAG failure");
-               armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
-               return ERROR_JTAG_DEVICE_ERROR;
+
+       if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
+               /* map D0..D15 to S0..S31 */
+               size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
+
+               uint32_t t = buf_get_u32(value, 0, 32);
+               retval = armv7m->store_core_reg_u32(target, regidx, t);
+               if (retval != ERROR_OK)
+                       goto out_error;
+
+               t = buf_get_u32(value + 4, 0, 32);
+               retval = armv7m->store_core_reg_u32(target, regidx + 1, t);
+               if (retval != ERROR_OK)
+                       goto out_error;
+       } else {
+               uint32_t t = buf_get_u32(value, 0, 32);
+
+               LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t);
+               retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t);
+               if (retval != ERROR_OK)
+                       goto out_error;
        }
 
        }
 
-       LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
        armv7m->arm.core_cache->reg_list[num].valid = 1;
        armv7m->arm.core_cache->reg_list[num].dirty = 0;
 
        return ERROR_OK;
        armv7m->arm.core_cache->reg_list[num].valid = 1;
        armv7m->arm.core_cache->reg_list[num].dirty = 0;
 
        return ERROR_OK;
+
+out_error:
+       LOG_ERROR("Error setting register");
+       armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid;
+       return ERROR_JTAG_DEVICE_ERROR;
 }
 
 /**
 }
 
 /**
@@ -250,9 +304,9 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
        int i;
 
        if (reg_class == REG_CLASS_ALL)
        int i;
 
        if (reg_class == REG_CLASS_ALL)
-               *reg_list_size = ARMV7M_NUM_REGS;
+               *reg_list_size = armv7m->arm.core_cache->num_regs;
        else
        else
-               *reg_list_size = 17;
+               *reg_list_size = ARMV7M_NUM_CORE_REGS;
 
        *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
        if (*reg_list == NULL)
 
        *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
        if (*reg_list == NULL)
@@ -268,7 +322,7 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
 int armv7m_run_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
 int armv7m_run_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
-       uint32_t entry_point, uint32_t exit_point,
+       target_addr_t entry_point, target_addr_t exit_point,
        int timeout_ms, void *arch_info)
 {
        int retval;
        int timeout_ms, void *arch_info)
 {
        int retval;
@@ -293,7 +347,7 @@ int armv7m_run_algorithm(struct target *target,
 int armv7m_start_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
 int armv7m_start_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
-       uint32_t entry_point, uint32_t exit_point,
+       target_addr_t entry_point, target_addr_t exit_point,
        void *arch_info)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
        void *arch_info)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
@@ -316,7 +370,7 @@ int armv7m_start_algorithm(struct target *target,
 
        /* refresh core register cache
         * Not needed if core register cache is always consistent with target process state */
 
        /* refresh core register cache
         * Not needed if core register cache is always consistent with target process state */
-       for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) {
+       for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
 
                armv7m_algorithm_info->context[i] = buf_get_u32(
                                armv7m->arm.core_cache->reg_list[i].value,
 
                armv7m_algorithm_info->context[i] = buf_get_u32(
                                armv7m->arm.core_cache->reg_list[i].value,
@@ -334,6 +388,9 @@ int armv7m_start_algorithm(struct target *target,
        }
 
        for (int i = 0; i < num_reg_params; i++) {
        }
 
        for (int i = 0; i < num_reg_params; i++) {
+               if (reg_params[i].direction == PARAM_IN)
+                       continue;
+
                struct reg *reg =
                        register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
 /*             uint32_t regvalue; */
                struct reg *reg =
                        register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
 /*             uint32_t regvalue; */
@@ -353,6 +410,23 @@ int armv7m_start_algorithm(struct target *target,
                armv7m_set_core_reg(reg, reg_params[i].value);
        }
 
                armv7m_set_core_reg(reg, reg_params[i].value);
        }
 
+       {
+               /*
+                * Ensure xPSR.T is set to avoid trying to run things in arm
+                * (non-thumb) mode, which armv7m does not support.
+                *
+                * We do this by setting the entirety of xPSR, which should
+                * remove all the unknowns about xPSR state.
+                *
+                * Because xPSR.T is populated on reset from the vector table,
+                * it might be 0 if the vector table has "bad" data in it.
+                */
+               struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
+               buf_set_u32(reg->value, 0, 32, 0x01000000);
+               reg->valid = 1;
+               reg->dirty = 1;
+       }
+
        if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
                        armv7m_algorithm_info->core_mode != core_mode) {
 
        if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
                        armv7m_algorithm_info->core_mode != core_mode) {
 
@@ -381,7 +455,7 @@ int armv7m_start_algorithm(struct target *target,
 int armv7m_wait_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
 int armv7m_wait_algorithm(struct target *target,
        int num_mem_params, struct mem_param *mem_params,
        int num_reg_params, struct reg_param *reg_params,
-       uint32_t exit_point, int timeout_ms,
+       target_addr_t exit_point, int timeout_ms,
        void *arch_info)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
        void *arch_info)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
@@ -411,7 +485,7 @@ int armv7m_wait_algorithm(struct target *target,
 
        armv7m->load_core_reg_u32(target, 15, &pc);
        if (exit_point && (pc != exit_point)) {
 
        armv7m->load_core_reg_u32(target, 15, &pc);
        if (exit_point && (pc != exit_point)) {
-               LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32,
+               LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR,
                        pc,
                        exit_point);
                return ERROR_TARGET_TIMEOUT;
                        pc,
                        exit_point);
                return ERROR_TARGET_TIMEOUT;
@@ -451,7 +525,7 @@ int armv7m_wait_algorithm(struct target *target,
                }
        }
 
                }
        }
 
-       for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
+       for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
                uint32_t regvalue;
                regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
                if (regvalue != armv7m_algorithm_info->context[i]) {
                uint32_t regvalue;
                regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
                if (regvalue != armv7m_algorithm_info->context[i]) {
@@ -486,11 +560,15 @@ int armv7m_arch_state(struct target *target)
        struct arm *arm = &armv7m->arm;
        uint32_t ctrl, sp;
 
        struct arm *arm = &armv7m->arm;
        uint32_t ctrl, sp;
 
+       /* avoid filling log waiting for fileio reply */
+       if (target->semihosting && target->semihosting->hit_fileio)
+               return ERROR_OK;
+
        ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
        sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
 
        LOG_USER("target halted due to %s, current mode: %s %s\n"
        ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
        sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
 
        LOG_USER("target halted due to %s, current mode: %s %s\n"
-               "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
+               "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
                debug_reason_name(target),
                arm_mode_name(arm->core_mode),
                armv7m_exception_string(armv7m->exception_number),
                debug_reason_name(target),
                arm_mode_name(arm->core_mode),
                armv7m_exception_string(armv7m->exception_number),
@@ -498,7 +576,8 @@ int armv7m_arch_state(struct target *target)
                buf_get_u32(arm->pc->value, 0, 32),
                (ctrl & 0x02) ? 'p' : 'm',
                sp,
                buf_get_u32(arm->pc->value, 0, 32),
                (ctrl & 0x02) ? 'p' : 'm',
                sp,
-               arm->is_semihosting ? ", semihosting" : "");
+               (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+               (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
 
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
@@ -535,7 +614,10 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target)
 
                reg_list[i].name = armv7m_regs[i].name;
                reg_list[i].size = armv7m_regs[i].bits;
 
                reg_list[i].name = armv7m_regs[i].name;
                reg_list[i].size = armv7m_regs[i].bits;
-               reg_list[i].value = calloc(1, 4);
+               size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8);
+               if (storage_size < 4)
+                       storage_size = 4;
+               reg_list[i].value = calloc(1, storage_size);
                reg_list[i].dirty = 0;
                reg_list[i].valid = 0;
                reg_list[i].type = &armv7m_reg_type;
                reg_list[i].dirty = 0;
                reg_list[i].valid = 0;
                reg_list[i].type = &armv7m_reg_type;
@@ -567,6 +649,34 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target)
        return cache;
 }
 
        return cache;
 }
 
+void armv7m_free_reg_cache(struct target *target)
+{
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct arm *arm = &armv7m->arm;
+       struct reg_cache *cache;
+       struct reg *reg;
+       unsigned int i;
+
+       cache = arm->core_cache;
+
+       if (!cache)
+               return;
+
+       for (i = 0; i < cache->num_regs; i++) {
+               reg = &cache->reg_list[i];
+
+               free(reg->feature);
+               free(reg->reg_data_type);
+               free(reg->value);
+       }
+
+       free(cache->reg_list[0].arch_info);
+       free(cache->reg_list);
+       free(cache);
+
+       arm->core_cache = NULL;
+}
+
 static int armv7m_setup_semihosting(struct target *target, int enable)
 {
        /* nothing todo for armv7m */
 static int armv7m_setup_semihosting(struct target *target, int enable)
 {
        /* nothing todo for armv7m */
@@ -580,6 +690,9 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
 
        armv7m->common_magic = ARMV7M_COMMON_MAGIC;
        armv7m->fp_feature = FP_NONE;
 
        armv7m->common_magic = ARMV7M_COMMON_MAGIC;
        armv7m->fp_feature = FP_NONE;
+       armv7m->trace_config.trace_bus_id = 1;
+       /* Enable stimulus port #0 by default */
+       armv7m->trace_config.itm_ter[0] = 1;
 
        arm->core_type = ARM_MODE_THREAD;
        arm->arch_info = armv7m;
 
        arm->core_type = ARM_MODE_THREAD;
        arm->arch_info = armv7m;
@@ -593,47 +706,15 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m)
 
 /** Generates a CRC32 checksum of a memory region. */
 int armv7m_checksum_memory(struct target *target,
 
 /** Generates a CRC32 checksum of a memory region. */
 int armv7m_checksum_memory(struct target *target,
-       uint32_t address, uint32_t count, uint32_t *checksum)
+       target_addr_t address, uint32_t count, uint32_t *checksum)
 {
        struct working_area *crc_algorithm;
        struct armv7m_algorithm armv7m_info;
        struct reg_param reg_params[2];
        int retval;
 
 {
        struct working_area *crc_algorithm;
        struct armv7m_algorithm armv7m_info;
        struct reg_param reg_params[2];
        int retval;
 
-       /* see contrib/loaders/checksum/armv7m_crc.s for src */
-
        static const uint8_t cortex_m_crc_code[] = {
        static const uint8_t cortex_m_crc_code[] = {
-               /* main: */
-               0x02, 0x46,                     /* mov          r2, r0 */
-               0x00, 0x20,                     /* movs         r0, #0 */
-               0xC0, 0x43,                     /* mvns         r0, r0 */
-               0x0A, 0x4E,                     /* ldr          r6, CRC32XOR */
-               0x0B, 0x46,                     /* mov          r3, r1 */
-               0x00, 0x24,                     /* movs         r4, #0 */
-               0x0D, 0xE0,                     /* b            ncomp */
-               /* nbyte: */
-               0x11, 0x5D,                     /* ldrb         r1, [r2, r4] */
-               0x09, 0x06,                     /* lsls         r1, r1, #24 */
-               0x48, 0x40,                     /* eors         r0, r0, r1 */
-               0x00, 0x25,                     /* movs         r5, #0 */
-               /* loop: */
-               0x00, 0x28,                     /* cmp          r0, #0 */
-               0x02, 0xDA,                     /* bge          notset */
-               0x40, 0x00,                     /* lsls         r0, r0, #1 */
-               0x70, 0x40,                     /* eors         r0, r0, r6 */
-               0x00, 0xE0,                     /* b            cont */
-               /* notset: */
-               0x40, 0x00,                     /* lsls         r0, r0, #1 */
-               /* cont: */
-               0x01, 0x35,                     /* adds         r5, r5, #1 */
-               0x08, 0x2D,                     /* cmp          r5, #8 */
-               0xF6, 0xD1,                     /* bne          loop */
-               0x01, 0x34,                     /* adds         r4, r4, #1 */
-               /* ncomp: */
-               0x9C, 0x42,                     /* cmp          r4, r3 */
-               0xEF, 0xD1,                     /* bne          nbyte */
-               0x00, 0xBE,                     /* bkpt         #0 */
-               0xB7, 0x1D, 0xC1, 0x04  /* CRC32XOR:    .word   0x04c11db7 */
+#include "../../contrib/loaders/checksum/armv7m_crc.inc"
        };
 
        retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
        };
 
        retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm);
@@ -674,66 +755,134 @@ cleanup:
        return retval;
 }
 
        return retval;
 }
 
-/** Checks whether a memory region is zeroed. */
+/** Checks an array of memory regions whether they are erased. */
 int armv7m_blank_check_memory(struct target *target,
 int armv7m_blank_check_memory(struct target *target,
-       uint32_t address, uint32_t count, uint32_t *blank)
+       struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
 {
        struct working_area *erase_check_algorithm;
 {
        struct working_area *erase_check_algorithm;
-       struct reg_param reg_params[3];
+       struct working_area *erase_check_params;
+       struct reg_param reg_params[2];
        struct armv7m_algorithm armv7m_info;
        int retval;
 
        struct armv7m_algorithm armv7m_info;
        int retval;
 
-       /* see contrib/loaders/erase_check/armv7m_erase_check.s for src */
+       static bool timed_out;
 
        static const uint8_t erase_check_code[] = {
 
        static const uint8_t erase_check_code[] = {
-               /* loop: */
-               0x03, 0x78,             /* ldrb r3, [r0] */
-               0x01, 0x30,             /* adds r0, #1 */
-               0x1A, 0x40,             /* ands r2, r2, r3 */
-               0x01, 0x39,             /* subs r1, r1, #1 */
-               0xFA, 0xD1,             /* bne  loop */
-               0x00, 0xBE              /* bkpt #0 */
+#include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
        };
 
        };
 
+       const uint32_t code_size = sizeof(erase_check_code);
+
        /* make sure we have a working area */
        /* make sure we have a working area */
-       if (target_alloc_working_area(target, sizeof(erase_check_code),
+       if (target_alloc_working_area(target, code_size,
                &erase_check_algorithm) != ERROR_OK)
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 
        retval = target_write_buffer(target, erase_check_algorithm->address,
                &erase_check_algorithm) != ERROR_OK)
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 
        retval = target_write_buffer(target, erase_check_algorithm->address,
-                       sizeof(erase_check_code), (uint8_t *)erase_check_code);
+                       code_size, erase_check_code);
        if (retval != ERROR_OK)
        if (retval != ERROR_OK)
-               return retval;
+               goto cleanup1;
+
+       /* prepare blocks array for algo */
+       struct algo_block {
+               union {
+                       uint32_t size;
+                       uint32_t result;
+               };
+               uint32_t address;
+       };
+
+       uint32_t avail = target_get_working_area_avail(target);
+       int blocks_to_check = avail / sizeof(struct algo_block) - 1;
+       if (num_blocks < blocks_to_check)
+               blocks_to_check = num_blocks;
+
+       struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block));
+       if (params == NULL) {
+               retval = ERROR_FAIL;
+               goto cleanup1;
+       }
+
+       int i;
+       uint32_t total_size = 0;
+       for (i = 0; i < blocks_to_check; i++) {
+               total_size += blocks[i].size;
+               target_buffer_set_u32(target, (uint8_t *)&(params[i].size),
+                                               blocks[i].size / sizeof(uint32_t));
+               target_buffer_set_u32(target, (uint8_t *)&(params[i].address),
+                                               blocks[i].address);
+       }
+       target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0);
+
+       uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block);
+       if (target_alloc_working_area(target, param_size,
+                       &erase_check_params) != ERROR_OK) {
+               retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto cleanup2;
+       }
+
+       retval = target_write_buffer(target, erase_check_params->address,
+                               param_size, (uint8_t *)params);
+       if (retval != ERROR_OK)
+               goto cleanup3;
+
+       uint32_t erased_word = erased_value | (erased_value << 8)
+                              | (erased_value << 16) | (erased_value << 24);
+
+       LOG_DEBUG("Starting erase check of %d blocks, parameters@"
+                TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address);
 
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARM_MODE_THREAD;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
 
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARM_MODE_THREAD;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       buf_set_u32(reg_params[0].value, 0, 32, address);
+       buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address);
 
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
 
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, erased_word);
 
 
-       init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
-       buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+       /* assume CPU clk at least 1 MHz */
+       int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
 
        retval = target_run_algorithm(target,
 
        retval = target_run_algorithm(target,
-                       0,
-                       NULL,
-                       3,
-                       reg_params,
-                       erase_check_algorithm->address,
-                       erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
-                       10000,
-                       &armv7m_info);
+                               0, NULL,
+                               ARRAY_SIZE(reg_params), reg_params,
+                               erase_check_algorithm->address,
+                               erase_check_algorithm->address + (code_size - 2),
+                               timeout,
+                               &armv7m_info);
+
+       timed_out = retval == ERROR_TARGET_TIMEOUT;
+       if (retval != ERROR_OK && !timed_out)
+               goto cleanup4;
+
+       retval = target_read_buffer(target, erase_check_params->address,
+                               param_size, (uint8_t *)params);
+       if (retval != ERROR_OK)
+               goto cleanup4;
 
 
-       if (retval == ERROR_OK)
-               *blank = buf_get_u32(reg_params[2].value, 0, 32);
+       for (i = 0; i < blocks_to_check; i++) {
+               uint32_t result = target_buffer_get_u32(target,
+                                       (uint8_t *)&(params[i].result));
+               if (result != 0 && result != 1)
+                       break;
+
+               blocks[i].result = result;
+       }
+       if (i && timed_out)
+               LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i);
 
 
+       retval = i;             /* return number of blocks really checked */
+
+cleanup4:
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
-       destroy_reg_param(&reg_params[2]);
 
 
+cleanup3:
+       target_free_working_area(target, erase_check_params);
+cleanup2:
+       free(params);
+cleanup1:
        target_free_working_area(target, erase_check_algorithm);
 
        return retval;
        target_free_working_area(target, erase_check_algorithm);
 
        return retval;
@@ -777,8 +926,5 @@ const struct command_registration armv7m_command_handlers[] = {
        {
                .chain = arm_command_handlers,
        },
        {
                .chain = arm_command_handlers,
        },
-       {
-               .chain = dap_command_handlers,
-       },
        COMMAND_REGISTRATION_DONE
 };
        COMMAND_REGISTRATION_DONE
 };

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)