/* 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);
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);
}
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);
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);
/* 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;
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;
+ }
+
+ 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)
+int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
uint32_t value;
int retval;
LOG_WARNING("Jazelle PC adjustment unknown");
break;
default:
- LOG_WARNING("unknow core state");
+ 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
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);
+ 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) {
+ 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);
+ 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"
}
/**
- * Read basic registers of the the current context: R0 to R15, and CPSR;
+ * 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
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;
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;
- retval = dpm_read_reg(dpm, r, i);
+ retval = arm_dpm_read_reg(dpm, r, i);
if (retval != ERROR_OK)
goto fail;
}
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;
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;
/* 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;
}
* 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;
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;
+ /* 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;
+ }
/* (void) */ dpm->finish(dpm);
done:
/* 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) {
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);
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) {
return retval;
if (mode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
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);
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;
* 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;
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)
} 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;
/* ?? */
break;
}
- dpm->wp_pc = addr;
+ dpm->wp_addr = addr;
}
/*----------------------------------------------------------------------*/
target->type->remove_breakpoint = dpm_remove_breakpoint;
}
- /* watchpoint setup */
- target->type->add_watchpoint = dpm_add_watchpoint;
- target->type->remove_watchpoint = dpm_remove_watchpoint;
+ /* 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 */
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);
+ 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;