Support for Arm VFP v3 registers read/write
This patch adds support in openOCD to read/write Arm vector/floating point registers. This is compatible with Arm vfp v3 target xml in GDB. Please refer to binutils-gdb/gdb/features/arm/arm-vfpv3.xml Change-Id: Id4dd1bddef51c558f1a86300c1a876d159463f18 Signed-off-by: Omair Javaid <omair.javaid@linaro.org> Reviewed-on: http://openocd.zylin.com/4421 Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> Tested-by: jenkinsriscv-compliance-dev
parent
2830008be0
commit
f18ca510b3
|
@ -77,6 +77,43 @@ enum arm_mode {
|
||||||
ARM_MODE_ANY = -1
|
ARM_MODE_ANY = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* VFPv3 internal register numbers mapping to d0:31 */
|
||||||
|
enum {
|
||||||
|
ARM_VFP_V3_D0 = 51,
|
||||||
|
ARM_VFP_V3_D1,
|
||||||
|
ARM_VFP_V3_D2,
|
||||||
|
ARM_VFP_V3_D3,
|
||||||
|
ARM_VFP_V3_D4,
|
||||||
|
ARM_VFP_V3_D5,
|
||||||
|
ARM_VFP_V3_D6,
|
||||||
|
ARM_VFP_V3_D7,
|
||||||
|
ARM_VFP_V3_D8,
|
||||||
|
ARM_VFP_V3_D9,
|
||||||
|
ARM_VFP_V3_D10,
|
||||||
|
ARM_VFP_V3_D11,
|
||||||
|
ARM_VFP_V3_D12,
|
||||||
|
ARM_VFP_V3_D13,
|
||||||
|
ARM_VFP_V3_D14,
|
||||||
|
ARM_VFP_V3_D15,
|
||||||
|
ARM_VFP_V3_D16,
|
||||||
|
ARM_VFP_V3_D17,
|
||||||
|
ARM_VFP_V3_D18,
|
||||||
|
ARM_VFP_V3_D19,
|
||||||
|
ARM_VFP_V3_D20,
|
||||||
|
ARM_VFP_V3_D21,
|
||||||
|
ARM_VFP_V3_D22,
|
||||||
|
ARM_VFP_V3_D23,
|
||||||
|
ARM_VFP_V3_D24,
|
||||||
|
ARM_VFP_V3_D25,
|
||||||
|
ARM_VFP_V3_D26,
|
||||||
|
ARM_VFP_V3_D27,
|
||||||
|
ARM_VFP_V3_D28,
|
||||||
|
ARM_VFP_V3_D29,
|
||||||
|
ARM_VFP_V3_D30,
|
||||||
|
ARM_VFP_V3_D31,
|
||||||
|
ARM_VFP_V3_FPSCR,
|
||||||
|
};
|
||||||
|
|
||||||
const char *arm_mode_name(unsigned psr_mode);
|
const char *arm_mode_name(unsigned psr_mode);
|
||||||
bool is_arm_mode(unsigned psr_mode);
|
bool is_arm_mode(unsigned psr_mode);
|
||||||
|
|
||||||
|
@ -89,6 +126,14 @@ enum arm_state {
|
||||||
ARM_STATE_AARCH64,
|
ARM_STATE_AARCH64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** ARM vector floating point enabled, if yes which version. */
|
||||||
|
enum arm_vfp_version {
|
||||||
|
ARM_VFP_DISABLED,
|
||||||
|
ARM_VFP_V1,
|
||||||
|
ARM_VFP_V2,
|
||||||
|
ARM_VFP_V3,
|
||||||
|
};
|
||||||
|
|
||||||
#define ARM_COMMON_MAGIC 0x0A450A45
|
#define ARM_COMMON_MAGIC 0x0A450A45
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,6 +190,9 @@ struct arm {
|
||||||
/** Flag reporting whether semihosting fileio operation is active. */
|
/** Flag reporting whether semihosting fileio operation is active. */
|
||||||
bool semihosting_hit_fileio;
|
bool semihosting_hit_fileio;
|
||||||
|
|
||||||
|
/** Floating point or VFP version, 0 if disabled. */
|
||||||
|
int arm_vfp_version;
|
||||||
|
|
||||||
/** Current semihosting operation. */
|
/** Current semihosting operation. */
|
||||||
int semihosting_op;
|
int semihosting_op;
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,42 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
|
||||||
return retval;
|
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 */
|
/* 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)
|
static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
{
|
{
|
||||||
|
@ -171,6 +207,14 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
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:
|
default:
|
||||||
/* 16: "MRS r0, CPSR"; then return via DCC
|
/* 16: "MRS r0, CPSR"; then return via DCC
|
||||||
* 17: "MRS r0, SPSR"; then return via DCC
|
* 17: "MRS r0, SPSR"; then return via DCC
|
||||||
|
@ -191,6 +235,40 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
return retval;
|
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 */
|
/* 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)
|
static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
{
|
{
|
||||||
|
@ -208,6 +286,14 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
|
||||||
* read r0 from DCC; then "MOV pc, r0" */
|
* read r0 from DCC; then "MOV pc, r0" */
|
||||||
retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
|
retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
|
||||||
break;
|
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:
|
default:
|
||||||
/* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
|
/* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
|
||||||
* 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
|
* 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
|
||||||
|
@ -262,14 +348,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* read R0 first (it's used for scratch), then CPSR */
|
/* read R0 and R1 first (it's used for scratch), then CPSR */
|
||||||
r = arm->core_cache->reg_list + 0;
|
for (unsigned i = 0; i < 2; i++) {
|
||||||
|
r = arm->core_cache->reg_list + i;
|
||||||
if (!r->valid) {
|
if (!r->valid) {
|
||||||
retval = dpm_read_reg(dpm, r, 0);
|
retval = dpm_read_reg(dpm, r, i);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
r->dirty = true;
|
r->dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
|
retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -279,7 +367,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
|
||||||
arm_set_cpsr(arm, cpsr);
|
arm_set_cpsr(arm, cpsr);
|
||||||
|
|
||||||
/* REVISIT we can probably avoid reading R1..R14, saving time... */
|
/* 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);
|
r = arm_reg_current(arm, i);
|
||||||
if (r->valid)
|
if (r->valid)
|
||||||
continue;
|
continue;
|
||||||
|
@ -412,8 +500,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
|
||||||
|
|
||||||
did_write = false;
|
did_write = false;
|
||||||
|
|
||||||
/* check everything except our scratch register R0 */
|
/* check everything except our scratch registers R0 and R1 */
|
||||||
for (unsigned i = 1; i < cache->num_regs; i++) {
|
for (unsigned i = 2; i < cache->num_regs; i++) {
|
||||||
struct arm_reg *r;
|
struct arm_reg *r;
|
||||||
unsigned regnum;
|
unsigned regnum;
|
||||||
|
|
||||||
|
@ -540,6 +628,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm,
|
||||||
/* r13/sp, and r14/lr are always shadowed */
|
/* r13/sp, and r14/lr are always shadowed */
|
||||||
case 13:
|
case 13:
|
||||||
case 14:
|
case 14:
|
||||||
|
case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR:
|
||||||
return mode;
|
return mode;
|
||||||
default:
|
default:
|
||||||
LOG_WARNING("invalid register #%u", num);
|
LOG_WARNING("invalid register #%u", num);
|
||||||
|
@ -561,7 +650,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
|
||||||
struct arm_dpm *dpm = target_to_arm(target)->dpm;
|
struct arm_dpm *dpm = target_to_arm(target)->dpm;
|
||||||
int retval;
|
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;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
if (regnum == 16) {
|
if (regnum == 16) {
|
||||||
|
@ -604,7 +694,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
|
||||||
int retval;
|
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;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
if (regnum == 16) {
|
if (regnum == 16) {
|
||||||
|
|
|
@ -132,6 +132,30 @@
|
||||||
*/
|
*/
|
||||||
#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm))
|
#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm))
|
||||||
|
|
||||||
|
/* Copies two words from two ARM core registers
|
||||||
|
* into a doubleword extension register, or
|
||||||
|
* from a doubleword extension register to two ARM core registers.
|
||||||
|
* See Armv7-A arch reference manual section A8.8.345
|
||||||
|
* Rt: Arm core register 1
|
||||||
|
* Rt2: Arm core register 2
|
||||||
|
* Vm: The doubleword extension register
|
||||||
|
* M: m = UInt(M:Vm);
|
||||||
|
* op: to_arm_registers = (op == ‘1’);
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_VMOV(op, Rt2, Rt, M, Vm) \
|
||||||
|
(0xec400b10 | ((op) << 20) | ((Rt2) << 16) | \
|
||||||
|
((Rt) << 12) | ((M) << 5) | (Vm))
|
||||||
|
|
||||||
|
/* Moves the value of the FPSCR to an ARM core register
|
||||||
|
* Rt: Arm core register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_VMRS(Rt) (0xeef10a10 | ((Rt) << 12))
|
||||||
|
|
||||||
|
/* Moves the value of an ARM core register to the FPSCR.
|
||||||
|
* Rt: Arm core register
|
||||||
|
*/
|
||||||
|
#define ARMV4_5_VMSR(Rt) (0xeee10a10 | ((Rt) << 12))
|
||||||
|
|
||||||
/* Store data from coprocessor to consecutive memory
|
/* Store data from coprocessor to consecutive memory
|
||||||
* See Armv7-A arch doc section A8.6.187
|
* See Armv7-A arch doc section A8.6.187
|
||||||
* P: 1=index mode (offset from Rn)
|
* P: 1=index mode (offset from Rn)
|
||||||
|
|
|
@ -340,6 +340,50 @@ static const struct {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
/* map core mode (USR, FIQ, ...) and register number to
|
||||||
* indices into the register cache
|
* indices into the register cache
|
||||||
*/
|
*/
|
||||||
|
@ -567,6 +611,10 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf_set_u32(reg->value, 0, 32, value);
|
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->valid = 1;
|
||||||
}
|
}
|
||||||
reg->dirty = 1;
|
reg->dirty = 1;
|
||||||
|
@ -582,6 +630,10 @@ static const struct reg_arch_type arm_reg_type = {
|
||||||
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||||
{
|
{
|
||||||
int num_regs = ARRAY_SIZE(arm_core_regs);
|
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_cache *cache = malloc(sizeof(struct reg_cache));
|
||||||
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
|
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
|
||||||
struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg));
|
struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg));
|
||||||
|
@ -599,7 +651,7 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||||
cache->reg_list = reg_list;
|
cache->reg_list = reg_list;
|
||||||
cache->num_regs = 0;
|
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 */
|
/* Skip registers this core doesn't expose */
|
||||||
if (arm_core_regs[i].mode == ARM_MODE_MON
|
if (arm_core_regs[i].mode == ARM_MODE_MON
|
||||||
&& arm->core_type != ARM_MODE_MON)
|
&& arm->core_type != ARM_MODE_MON)
|
||||||
|
@ -651,9 +703,38 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)
|
||||||
cache->num_regs++;
|
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->pc = reg_list + 15;
|
||||||
arm->cpsr = reg_list + ARMV4_5_CPSR;
|
arm->cpsr = reg_list + ARMV4_5_CPSR;
|
||||||
arm->core_cache = cache;
|
arm->core_cache = cache;
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,6 +1310,10 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||||
|
|
||||||
case REG_CLASS_ALL:
|
case REG_CLASS_ALL:
|
||||||
*reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51);
|
*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));
|
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
|
@ -1249,6 +1334,12 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||||
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
||||||
(*reg_list)[24]->size = 0;
|
(*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;
|
return ERROR_OK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -3178,6 +3178,8 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp)
|
||||||
|
|
||||||
cortex_a->armv7a_common.is_armv7r = false;
|
cortex_a->armv7a_common.is_armv7r = false;
|
||||||
|
|
||||||
|
cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3;
|
||||||
|
|
||||||
return cortex_a_init_arch_info(target, cortex_a, target->tap);
|
return cortex_a_init_arch_info(target, cortex_a, target->tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue