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);
+ /* 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;
+ }
+
+ 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 */
static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
break;
}
break;
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+ return dpm_read_reg_u64(dpm, r, regnum);
+ break;
+ 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
return retval;
}
+/* Write 64bit VFP registers */
+static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+{
+ 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 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);
+ /* 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) {
+ r->dirty = false;
+ LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name,
+ (unsigned) value_r0, (unsigned) value_r1);
+ }
+
+ 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)
{
* 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);
+ break;
+ 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"
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 = dpm_read_reg(dpm, r, i);
+ if (retval != ERROR_OK)
+ goto fail;
+ }
+ r->dirty = true;
}
- r->dirty = true;
retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
if (retval != ERROR_OK)
arm_set_cpsr(arm, cpsr);
/* REVISIT we can probably avoid reading R1..R14, saving time... */
- for (unsigned i = 1; i < 16; i++) {
+ for (unsigned i = 2; i < 16; i++) {
r = arm_reg_current(arm, i);
if (r->valid)
continue;
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;
/* 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);
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) {
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) {
};
+static const struct {
+ unsigned int id;
+ const char *name;
+ uint32_t bits;
+ enum arm_mode mode;
+ enum reg_type type;
+ const char *group;
+ const char *feature;
+} arm_vfp_v3_regs[] = {
+ { ARM_VFP_V3_D0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D1, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D2, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D3, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D4, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D5, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D6, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D7, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D8, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D9, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D10, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D11, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D12, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D13, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D14, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D15, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D16, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D17, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D18, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D19, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D20, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D21, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D22, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D23, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D24, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D25, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D26, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D27, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D28, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D29, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D30, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_D31, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"},
+ { ARM_VFP_V3_FPSCR, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp"},
+};
+
/* map core mode (USR, FIQ, ...) and register number to
* indices into the register cache
*/
}
} else {
buf_set_u32(reg->value, 0, 32, value);
+ if (reg->size == 64) {
+ value = buf_get_u32(buf + 4, 0, 32);
+ buf_set_u32(reg->value + 4, 0, 32, value);
+ }
reg->valid = 1;
}
reg->dirty = 1;
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
{
int num_regs = ARRAY_SIZE(arm_core_regs);
+ int num_core_regs = num_regs;
+ if (arm->arm_vfp_version == ARM_VFP_V3)
+ num_regs += ARRAY_SIZE(arm_vfp_v3_regs);
+
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg));
cache->reg_list = reg_list;
cache->num_regs = 0;
- for (i = 0; i < num_regs; i++) {
+ for (i = 0; i < num_core_regs; i++) {
/* Skip registers this core doesn't expose */
if (arm_core_regs[i].mode == ARM_MODE_MON
&& arm->core_type != ARM_MODE_MON)
cache->num_regs++;
}
+ int j;
+ for (i = num_core_regs, j = 0; i < num_regs; i++, j++) {
+ reg_arch_info[i].num = arm_vfp_v3_regs[j].id;
+ reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode;
+ reg_arch_info[i].target = target;
+ reg_arch_info[i].arm = arm;
+
+ reg_list[i].name = arm_vfp_v3_regs[j].name;
+ reg_list[i].number = arm_vfp_v3_regs[j].id;
+ reg_list[i].size = arm_vfp_v3_regs[j].bits;
+ reg_list[i].value = reg_arch_info[i].value;
+ reg_list[i].type = &arm_reg_type;
+ reg_list[i].arch_info = ®_arch_info[i];
+ reg_list[i].exist = true;
+
+ reg_list[i].caller_save = false;
+
+ reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
+ reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type;
+
+ reg_list[i].feature = malloc(sizeof(struct reg_feature));
+ reg_list[i].feature->name = arm_vfp_v3_regs[j].feature;
+
+ reg_list[i].group = arm_vfp_v3_regs[j].group;
+
+ cache->num_regs++;
+ }
+
arm->pc = reg_list + 15;
arm->cpsr = reg_list + ARMV4_5_CPSR;
arm->core_cache = cache;
+
return cache;
}
case REG_CLASS_ALL:
*reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51);
+ unsigned int list_size_core = *reg_list_size;
+ if (arm->arm_vfp_version == ARM_VFP_V3)
+ *reg_list_size += 33;
+
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
for (i = 0; i < 16; i++)
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
(*reg_list)[24]->size = 0;
+ if (arm->arm_vfp_version == ARM_VFP_V3) {
+ unsigned int num_core_regs = ARRAY_SIZE(arm_core_regs);
+ for (i = 0; i < 33; i++)
+ (*reg_list)[list_size_core + i] = &(arm->core_cache->reg_list[num_core_regs + i]);
+ }
+
return ERROR_OK;
break;