aboutsummaryrefslogtreecommitdiff
path: root/src/cortexm3.c
diff options
context:
space:
mode:
authorMike Smith2011-12-26 02:34:45 -0800
committerMike Smith2011-12-26 02:34:45 -0800
commitbc4c87e45b5b9cc72c46993b1b416017fe4b39a6 (patch)
tree7175c098f06891843c21e5d0462e958b9e8620b8 /src/cortexm3.c
parent2653222d08f31ccac9d0e6c3d129ae20b5440eb7 (diff)
Add support for Cortex-M0, and specifically for the NXP LPC11xx devices.
Diffstat (limited to 'src/cortexm3.c')
-rw-r--r--src/cortexm3.c125
1 files changed, 72 insertions, 53 deletions
diff --git a/src/cortexm3.c b/src/cortexm3.c
index 0dbb722..0c6e151 100644
--- a/src/cortexm3.c
+++ b/src/cortexm3.c
@@ -23,6 +23,8 @@
* implemented according to the "ARMv7-M Architectue Reference Manual",
* ARM doc DDI0403C.
*
+ * Also supports Cortex-M0 / ARMv6-M
+ *
* Issues:
* There are way too many magic numbers used here.
*/
@@ -37,6 +39,7 @@
#include "cortexm3.h"
#include "lmi.h"
#include "stm32_tgt.h"
+#include "nxp_tgt.h"
static char cm3_driver_str[] = "ARM Cortex-M3";
@@ -107,7 +110,7 @@ static char cm3_driver_str[] = "ARM Cortex-M3";
#define CM3_DHCSR_S_HALT (1 << 17)
#define CM3_DHCSR_S_REGRDY (1 << 16)
/* Bits 15:6 - Reserved */
-#define CM3_DHCSR_C_SNAPSTALL (1 << 5)
+#define CM3_DHCSR_C_SNAPSTALL (1 << 5) /* v7m only */
/* Bit 4 - Reserved */
#define CM3_DHCSR_C_MASKINTS (1 << 3)
#define CM3_DHCSR_C_STEP (1 << 2)
@@ -124,25 +127,25 @@ static char cm3_driver_str[] = "ARM Cortex-M3";
/* Bits 31:25 - Reserved */
#define CM3_DEMCR_TRCENA (1 << 24)
/* Bits 23:20 - Reserved */
-#define CM3_DEMCR_MON_REQ (1 << 19)
-#define CM3_DEMCR_MON_STEP (1 << 18)
-#define CM3_DEMCR_VC_MON_PEND (1 << 17)
-#define CM3_DEMCR_VC_MON_EN (1 << 16)
+#define CM3_DEMCR_MON_REQ (1 << 19) /* v7m only */
+#define CM3_DEMCR_MON_STEP (1 << 18) /* v7m only */
+#define CM3_DEMCR_VC_MON_PEND (1 << 17) /* v7m only */
+#define CM3_DEMCR_VC_MON_EN (1 << 16) /* v7m only */
/* Bits 15:11 - Reserved */
#define CM3_DEMCR_VC_HARDERR (1 << 10)
-#define CM3_DEMCR_VC_INTERR (1 << 9)
-#define CM3_DEMCR_VC_BUSERR (1 << 8)
-#define CM3_DEMCR_VC_STATERR (1 << 7)
-#define CM3_DEMCR_VC_CHKERR (1 << 6)
-#define CM3_DEMCR_VC_NOCPERR (1 << 5)
-#define CM3_DEMCR_VC_MMERR (1 << 4)
+#define CM3_DEMCR_VC_INTERR (1 << 9) /* v7m only */
+#define CM3_DEMCR_VC_BUSERR (1 << 8) /* v7m only */
+#define CM3_DEMCR_VC_STATERR (1 << 7) /* v7m only */
+#define CM3_DEMCR_VC_CHKERR (1 << 6) /* v7m only */
+#define CM3_DEMCR_VC_NOCPERR (1 << 5) /* v7m only */
+#define CM3_DEMCR_VC_MMERR (1 << 4) /* v7m only */
/* Bits 3:1 - Reserved */
#define CM3_DEMCR_VC_CORERESET (1 << 0)
/* Flash Patch and Breakpoint Control Register (FP_CTRL) */
/* Bits 32:15 - Reserved */
-/* Bits 14:12 - NUM_CODE2 */
-/* Bits 11:8 - NUM_LIT */
+/* Bits 14:12 - NUM_CODE2 */ /* v7m only */
+/* Bits 11:8 - NUM_LIT */ /* v7m only */
/* Bits 7:4 - NUM_CODE1 */
/* Bits 3:2 - Unspecified */
#define CM3_FPB_CTRL_KEY (1 << 1)
@@ -155,7 +158,7 @@ static char cm3_driver_str[] = "ARM Cortex-M3";
/* Data Watchpoint and Trace Function Register (DWT_FUNCTIONx) */
#define CM3_DWT_FUNC_MATCHED (1 << 24)
-#define CM3_DWT_FUNC_DATAVSIZE_WORD (2 << 10)
+#define CM3_DWT_FUNC_DATAVSIZE_WORD (2 << 10) /* v7m only */
#define CM3_DWT_FUNC_FUNC_READ (5 << 0)
#define CM3_DWT_FUNC_FUNC_WRITE (6 << 0)
#define CM3_DWT_FUNC_FUNC_ACCESS (7 << 0)
@@ -182,17 +185,21 @@ static int cm3_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr,
static int cm3_check_hw_wp(struct target_s *target, uint32_t *addr);
/* Watchpoint unit status */
+#define CM3_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
static struct wp_unit_s {
uint32_t addr;
uint8_t type;
uint8_t size;
-} hw_watchpoint[4];
+} hw_watchpoint[CM3_MAX_WATCHPOINTS];
+static unsigned hw_watchpoint_max;
/* Breakpoint unit status */
-static uint32_t hw_breakpoint[6];
+#define CM3_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */
+static uint32_t hw_breakpoint[CM3_MAX_BREAKPOINTS];
+static unsigned hw_breakpoint_max;
/* Register number tables */
-static uint32_t regnum_v7m[] = {
+static uint32_t regnum_cortex_m[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* standard r0-r15 */
0x10, /* xpsr */
0x11, /* msp */
@@ -201,7 +208,7 @@ static uint32_t regnum_v7m[] = {
};
#if 0
/* XXX: need some way for a specific CPU to indicate it has FP registers */
-static uint32_t regnum_v7mf[] = {
+static uint32_t regnum_cortex_mf[] = {
0x21, /* fpscr */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* s0-s7 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* s8-s15 */
@@ -210,7 +217,7 @@ static uint32_t regnum_v7mf[] = {
};
#endif
-static const char tdesc_armv7m[] =
+static const char tdesc_cortex_m[] =
"<?xml version=\"1.0\"?>"
"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
"<target>"
@@ -248,7 +255,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->tdesc = tdesc_cortex_m;
target->regs_read = cm3_regs_read;
target->regs_write = cm3_regs_write;
target->pc_write = cm3_pc_write;
@@ -258,10 +265,11 @@ 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 = sizeof(regnum_v7m); /* XXX: detect FP extension */
+ target->regs_size = sizeof(regnum_cortex_m); /* XXX: detect FP extension */
if(stm32_probe(target) == 0) return 0;
if(stm32f4_probe(target) == 0) return 0;
+ if(lpc11xx_probe(target) == 0) return 0;
/* if not STM32 try LMI which I don't know how to detect reliably */
lmi_probe(target);
@@ -272,7 +280,8 @@ static void
cm3_attach(struct target_s *target)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
+ uint32_t r;
target_halt_request(target);
while(!target_halt_wait(target));
@@ -285,14 +294,24 @@ cm3_attach(struct target_s *target)
/* Reset DFSR flags */
adiv5_ap_mem_write(t->ap, CM3_DFSR, CM3_DFSR_RESETALL);
+ /* size the break/watchpoint units */
+ hw_breakpoint_max = CM3_MAX_BREAKPOINTS;
+ r = adiv5_ap_mem_read(t->ap, CM3_FPB_CTRL);
+ if (((r >> 4) & 0xf) < hw_breakpoint_max) /* only look at NUM_COMP1 */
+ hw_breakpoint_max = (r >> 4) & 0xf;
+ hw_watchpoint_max = CM3_MAX_WATCHPOINTS;
+ r = adiv5_ap_mem_read(t->ap, CM3_DWT_CTRL);
+ if ((r >> 28) > hw_watchpoint_max)
+ hw_watchpoint_max = r >> 28;
+
/* Clear any stale breakpoints */
- for(i = 0; i < 6; i++) {
+ for(i = 0; i < hw_breakpoint_max; i++) {
adiv5_ap_mem_write(t->ap, CM3_FPB_COMP(i), 0);
hw_breakpoint[i] = 0;
}
/* Clear any stale watchpoints */
- for(i = 0; i < 4; i++) {
+ for(i = 0; i < hw_watchpoint_max; i++) {
adiv5_ap_mem_write(t->ap, CM3_DWT_FUNC(i), 0);
hw_watchpoint[i].type = 0;
}
@@ -313,14 +332,14 @@ static void
cm3_detach(struct target_s *target)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
/* Clear any stale breakpoints */
- for(i = 0; i < 6; i++)
+ for(i = 0; i < hw_breakpoint_max; i++)
adiv5_ap_mem_write(t->ap, CM3_FPB_COMP(i), 0);
/* Clear any stale watchpoints */
- for(i = 0; i < 4; i++)
+ for(i = 0; i < hw_watchpoint_max; i++)
adiv5_ap_mem_write(t->ap, CM3_DWT_FUNC(i), 0);
/* Disable debug */
@@ -341,12 +360,12 @@ cm3_regs_read(struct target_s *target, void *data)
* 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
+ /* Walk the regnum_cortex_m array, reading the registers it
* calls out. */
- adiv5_ap_write(t->ap, 0x14, regnum_v7m[0]); /* Required to switch banks */
+ adiv5_ap_write(t->ap, 0x14, regnum_cortex_m[0]); /* Required to switch banks */
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
- for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, regnum_v7m[i]);
+ for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, regnum_cortex_m[i]);
*regs++ = adiv5_dp_read_ap(t->ap->dp, 0x18);
}
@@ -358,7 +377,7 @@ cm3_regs_write(struct target_s *target, const void *data)
{
struct target_ap_s *t = (void *)target;
const uint32_t *regs = data;
- int i;
+ unsigned i;
/* FIXME: Describe what's really going on here */
adiv5_ap_write(t->ap, 0x00, 0xA2000052);
@@ -367,13 +386,13 @@ cm3_regs_write(struct target_s *target, const void *data)
* 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
+ /* Walk the regnum_cortex_m 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 | regnum_v7m[0]);
- for(i = 1; i < sizeof(regnum_v7m) / 4; i++) {
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_cortex_m[0]);
+ for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) {
adiv5_dp_low_access(t->ap->dp, 1, 0, 0x18, *regs++);
- adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_v7m[i]);
+ adiv5_dp_low_access(t->ap->dp, 1, 0, 0x14, 0x10000 | regnum_cortex_m[i]);
}
return 0;
@@ -508,15 +527,15 @@ cm3_set_hw_bp(struct target_s *target, uint32_t addr)
{
struct target_ap_s *t = (void *)target;
uint32_t val = addr & 0x1FFFFFFC;
- int i;
+ unsigned i;
val |= (addr & 2)?0x80000000:0x40000000;
val |= 1;
- for(i = 0; i < 6; i++)
+ for(i = 0; i < hw_breakpoint_max; i++)
if((hw_breakpoint[i] & 1) == 0) break;
- if(i == 6) return -1;
+ if(i == hw_breakpoint_max) return -1;
hw_breakpoint[i] = addr | 1;
@@ -529,12 +548,12 @@ static int
cm3_clear_hw_bp(struct target_s *target, uint32_t addr)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
- for(i = 0; i < 6; i++)
+ for(i = 0; i < hw_breakpoint_max; i++)
if((hw_breakpoint[i] & ~1) == addr) break;
- if(i == 6) return -1;
+ if(i == hw_breakpoint_max) return -1;
hw_breakpoint[i] = 0;
@@ -551,7 +570,7 @@ static int
cm3_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
switch(len) { /* Convert bytes size to mask size */
case 1: len = CM3_DWT_MASK_BYTE; break;
@@ -569,10 +588,10 @@ cm3_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
return -1;
}
- for(i = 0; i < 4; i++)
+ for(i = 0; i < hw_watchpoint_max; i++)
if((hw_watchpoint[i].type) == 0) break;
- if(i == 4) return -2;
+ if(i == hw_watchpoint_max) return -2;
hw_watchpoint[i].type = type;
hw_watchpoint[i].addr = addr;
@@ -580,8 +599,8 @@ cm3_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
adiv5_ap_mem_write(t->ap, CM3_DWT_COMP(i), addr);
adiv5_ap_mem_write(t->ap, CM3_DWT_MASK(i), len);
- adiv5_ap_mem_write(t->ap, CM3_DWT_FUNC(i),
- CM3_DWT_FUNC_DATAVSIZE_WORD | type);
+ adiv5_ap_mem_write(t->ap, CM3_DWT_FUNC(i), type |
+ ((target->target_options & TOPT_FLAVOUR_V6M) ? 0: CM3_DWT_FUNC_DATAVSIZE_WORD));
return 0;
}
@@ -590,7 +609,7 @@ static int
cm3_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
switch(len) {
case 1: len = CM3_DWT_MASK_BYTE; break;
@@ -608,12 +627,12 @@ cm3_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t le
return -1;
}
- for(i = 0; i < 4; i++)
+ for(i = 0; i < hw_watchpoint_max; i++)
if((hw_watchpoint[i].addr == addr) &&
(hw_watchpoint[i].type == type) &&
(hw_watchpoint[i].size == len)) break;
- if(i == 4) return -2;
+ if(i == hw_watchpoint_max) return -2;
hw_watchpoint[i].type = 0;
@@ -626,16 +645,16 @@ static int
cm3_check_hw_wp(struct target_s *target, uint32_t *addr)
{
struct target_ap_s *t = (void *)target;
- int i;
+ unsigned i;
- for(i = 0; i < 4; i++)
+ for(i = 0; i < hw_watchpoint_max; i++)
/* if SET and MATCHED then break */
if(hw_watchpoint[i].type &&
(adiv5_ap_mem_read(t->ap, CM3_DWT_FUNC(i)) &
CM3_DWT_FUNC_MATCHED))
break;
- if(i == 4) return 0;
+ if(i == hw_watchpoint_max) return 0;
*addr = hw_watchpoint[i].addr;
return 1;