aboutsummaryrefslogtreecommitdiff
path: root/src/cortexm3.c
diff options
context:
space:
mode:
authorMike Smith2011-11-25 17:07:46 -0800
committerMike Smith2011-11-25 17:07:46 -0800
commitffda30f393cd72b6cfec21673abdee25aeaf2ee3 (patch)
treece6815b84780256e26cfbe932d4bdb415ea897b4 /src/cortexm3.c
parent8babb37472a70d8f3f4e4f8325f4ecc0af5a587a (diff)
Add support for a more comprehensive target description, including the additional v7m registers.
This doesn't work with vanilla gdb, as for reasons unknown said vanilla gdb doesn't support XML target descriptions queried from the remote. Add code to the fault unwinder to deal with the stack alignment fixup and FP registers. Avoid saving/restoring registers that don't get trashed.
Diffstat (limited to 'src/cortexm3.c')
-rw-r--r--src/cortexm3.c113
1 files changed, 91 insertions, 22 deletions
diff --git a/src/cortexm3.c b/src/cortexm3.c
index 645fe3e..0dbb722 100644
--- a/src/cortexm3.c
+++ b/src/cortexm3.c
@@ -46,6 +46,7 @@ static char cm3_driver_str[] = "ARM Cortex-M3";
#define CM3_SCS_BASE (CM3_PPB_BASE + 0xE000)
#define CM3_AIRCR (CM3_SCS_BASE + 0xD0C)
+#define CM3_CFSR (CM3_SCS_BASE + 0xD28)
#define CM3_HFSR (CM3_SCS_BASE + 0xD2C)
#define CM3_DFSR (CM3_SCS_BASE + 0xD30)
#define CM3_DHCSR (CM3_SCS_BASE + 0xDF0)
@@ -190,6 +191,54 @@ static struct wp_unit_s {
/* Breakpoint unit status */
static uint32_t hw_breakpoint[6];
+/* Register number tables */
+static uint32_t regnum_v7m[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* standard r0-r15 */
+ 0x10, /* xpsr */
+ 0x11, /* msp */
+ 0x12, /* psp */
+ 0x14 /* special */
+};
+#if 0
+/* XXX: need some way for a specific CPU to indicate it has FP registers */
+static uint32_t regnum_v7mf[] = {
+ 0x21, /* fpscr */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* s0-s7 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* s8-s15 */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* s16-s23 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* s24-s31 */
+};
+#endif
+
+static const char tdesc_armv7m[] =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<target>"
+ " <architecture>arm</architecture>"
+ " <feature name=\"org.gnu.gdb.arm.m-profile\">"
+ " <reg name=\"r0\" bitsize=\"32\"/>"
+ " <reg name=\"r1\" bitsize=\"32\"/>"
+ " <reg name=\"r2\" bitsize=\"32\"/>"
+ " <reg name=\"r3\" bitsize=\"32\"/>"
+ " <reg name=\"r4\" bitsize=\"32\"/>"
+ " <reg name=\"r5\" bitsize=\"32\"/>"
+ " <reg name=\"r6\" bitsize=\"32\"/>"
+ " <reg name=\"r7\" bitsize=\"32\"/>"
+ " <reg name=\"r8\" bitsize=\"32\"/>"
+ " <reg name=\"r9\" bitsize=\"32\"/>"
+ " <reg name=\"r10\" bitsize=\"32\"/>"
+ " <reg name=\"r11\" bitsize=\"32\"/>"
+ " <reg name=\"r12\" bitsize=\"32\"/>"
+ " <reg name=\"sp\" bitsize=\"32\" type=\"data_ptr\"/>"
+ " <reg name=\"lr\" bitsize=\"32\" type=\"code_ptr\"/>"
+ " <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\"/>"
+ " <reg name=\"xpsr\" bitsize=\"32\"/>"
+ " <reg name=\"msp\" bitsize=\"32\" save-restore=\"no\" type=\"data_ptr\"/>"
+ " <reg name=\"psp\" bitsize=\"32\" save-restore=\"no\" type=\"data_ptr\"/>"
+ " <reg name=\"special\" bitsize=\"32\" save-restore=\"no\"/>"
+ " </feature>"
+ "</target>";
+
int
cm3_probe(struct target_s *target)
{
@@ -199,6 +248,7 @@ cm3_probe(struct target_s *target)
target->detach = cm3_detach;
/* Should probe here to make sure it's Cortex-M3 */
+ target->tdesc = tdesc_armv7m;
target->regs_read = cm3_regs_read;
target->regs_write = cm3_regs_write;
target->pc_write = cm3_pc_write;
@@ -208,7 +258,7 @@ cm3_probe(struct target_s *target)
target->halt_wait = cm3_halt_wait;
target->halt_resume = cm3_halt_resume;
target->fault_unwind = cm3_fault_unwind;
- target->regs_size = 16<<2;
+ target->regs_size = sizeof(regnum_v7m); /* XXX: detect FP extension */
if(stm32_probe(target) == 0) return 0;
if(stm32f4_probe(target) == 0) return 0;
@@ -282,15 +332,21 @@ cm3_regs_read(struct target_s *target, void *data)
{
struct target_ap_s *t = (void *)target;
uint32_t *regs = data;
- int i;
+ unsigned i;
/* FIXME: Describe what's really going on here */
adiv5_ap_write(t->ap, 0x00, 0xA2000052);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, 0xE000EDF0);
- adiv5_ap_write(t->ap, 0x14, 0); /* Required to switch banks */
+
+ /* Map the banked data registers (0x10-0x1c) to the
+ * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, CM3_DHCSR);
+
+ /* Walk the regnum_v7m array, reading the registers it
+ * calls out. */
+ adiv5_ap_write(t->ap, 0x14, regnum_v7m[0]); /* Required to switch banks */
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
- for(i = 1; i < 16; i++) {
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, i);
+ for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, regnum_v7m[i]);
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
}
@@ -306,12 +362,18 @@ cm3_regs_write(struct target_s *target, const void *data)
/* FIXME: Describe what's really going on here */
adiv5_ap_write(t->ap, 0x00, 0xA2000052);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, 0xE000EDF0);
+
+ /* Map the banked data registers (0x10-0x1c) to the
+ * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x04, CM3_DHCSR);
+
+ /* Walk the regnum_v7m array, writing the registers it
+ * calls out. */
adiv5_ap_write(t->ap, 0x18, *regs++); /* Required to switch banks */
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000);
- for(i = 1; i < 16; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_v7m[0]);
+ for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
adiv5_dp_low_access(t->ap->dp, 1, 0, 0x18, *regs++);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, i | 0x10000);
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_v7m[i]);
}
return 0;
@@ -395,27 +457,34 @@ static int cm3_fault_unwind(struct target_s *target)
struct target_ap_s *t = (void *)target;
uint32_t dfsr = adiv5_ap_mem_read(t->ap, CM3_DFSR);
uint32_t hfsr = adiv5_ap_mem_read(t->ap, CM3_HFSR);
+ uint32_t cfsr = adiv5_ap_mem_read(t->ap, CM3_CFSR);
adiv5_ap_mem_write(t->ap, CM3_DFSR, dfsr);/* write back to reset */
adiv5_ap_mem_write(t->ap, CM3_HFSR, hfsr);/* write back to reset */
- /* We check for FORCED in the HardFault Status Register to avoid
- * catching core resets */
- if((dfsr & CM3_DFSR_VCATCH) && (hfsr & CM3_HFSR_FORCED)) {
+ adiv5_ap_mem_write(t->ap, CM3_CFSR, cfsr);/* write back to reset */
+ /* We check for FORCED in the HardFault Status Register or
+ * for a configurable fault to avoid catching core resets */
+ if((dfsr & CM3_DFSR_VCATCH) && ((hfsr & CM3_HFSR_FORCED) || cfsr)) {
/* Unwind exception */
- uint32_t regs[16];
+ uint32_t regs[target->regs_size];
uint32_t stack[8];
+ uint32_t retcode, framesize;
/* Read registers for post-exception stack pointer */
target_regs_read(target, regs);
+ /* save retcode currently in lr */
+ retcode = regs[14];
/* Read stack for pre-exception registers */
target_mem_read_words(target, stack, regs[13], sizeof(stack));
- regs[13] += sizeof(stack); /* Adjust SP for pop */
- regs[0] = stack[0];
- regs[1] = stack[1];
- regs[2] = stack[2];
- regs[3] = stack[3];
- regs[12] = stack[4];
- regs[14] = stack[5];
- regs[15] = stack[6];
+ regs[14] = stack[5]; /* restore LR to pre-exception state */
+ regs[15] = stack[6]; /* restore PC to pre-exception state */
+
+ /* adjust stack to pop exception state */
+ framesize = (retcode & (1<<4)) ? 0x68 : 0x20; /* check for basic vs. extended frame */
+ if (stack[7] & (1<<9)) /* check for stack alignment fixup */
+ framesize += 4;
+ regs[13] += framesize;
+
/* FIXME: stack[7] contains xPSR when this is supported */
+ /* although, if we caught the exception it will be unchanged */
/* Reset exception state to allow resuming from restored
* state.