]> git.sur5r.net Git - openocd/blobdiff - src/target/armv7m.c
armv7m: add FPU registers support
[openocd] / src / target / armv7m.c
index 130504c90b0f51987690fe02273f59bddbc7102b..ee96f0e2b36648bbeb9965652ead8f2da7117866 100644 (file)
@@ -44,7 +44,7 @@
 #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",
@@ -52,7 +52,7 @@ static char *armv7m_exception_strings[] = {
 };
 
 /* 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,
@@ -61,7 +61,7 @@ const int armv7m_psp_reg_map[17] = {
 };
 
 /* 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,
@@ -110,6 +110,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_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)
@@ -131,8 +150,8 @@ int armv7m_restore_context(struct target *target)
 
        for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--) {
                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 +167,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).
  */
-char *armv7m_exception_string(int number)
+const char *armv7m_exception_string(int number)
 {
        static char enamebuf[32];
 
@@ -179,12 +198,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;
-       uint32_t value = buf_get_u32(buf, 0, 32);
 
        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;
 
@@ -202,10 +220,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;
-       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;
 
@@ -213,7 +249,7 @@ static int armv7m_read_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;
        struct arm_reg *armv7m_core_reg;
@@ -222,20 +258,38 @@ static int armv7m_write_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;
-       retval = armv7m->store_core_reg_u32(target,
-                                           armv7m_core_reg->num,
-                                           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, value);
        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,7 +304,7 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
        if (reg_class == REG_CLASS_ALL)
                *reg_list_size = ARMV7M_NUM_REGS;
        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)
@@ -533,7 +587,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].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;