#include "target_type.h"
#include "arm_disassembler.h"
#include "register.h"
+#include "arm_opcodes.h"
/* NOTE: most of this should work fine for the Cortex-M1 and
* Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M.
+ * Some differences: M0/M1 doesn't have FBP remapping or the
+ * DWT tracing/profiling support. (So the cycle counter will
+ * not be usable; the other stuff isn't currently used here.)
+ *
+ * Although there are some workarounds for errata seen only in r0p0
+ * silicon, such old parts are hard to find and thus not much tested
+ * any longer.
*/
static int cortex_m3_store_core_reg_u32(struct target *target,
enum armv7m_regtype type, uint32_t num, uint32_t value);
-#ifdef ARMV7_GDB_HACKS
-extern uint8_t armv7m_gdb_dummy_cpsr_value[];
-extern struct reg armv7m_gdb_dummy_cpsr_reg;
-#endif
-
static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp,
uint32_t *value, int regnum)
{
dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
- retval = swjdp_transaction_endcheck(swjdp);
+ retval = jtagdp_transaction_endcheck(swjdp);
/* restore DCB_DCRDR - this needs to be in a seperate
* transaction otherwise the emulated DCC channel breaks */
dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR);
- retval = swjdp_transaction_endcheck(swjdp);
+ retval = jtagdp_transaction_endcheck(swjdp);
/* restore DCB_DCRDR - this needs to be in a seperate
* transaction otherwise the emulated DCC channel breaks */
/* Read Debug Fault Status Register */
mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
+
/* Clear Debug Fault Status */
mem_ap_write_atomic_u32(swjdp, NVIC_DFSR, cortex_m3->nvic_dfsr);
LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m3->nvic_dfsr);
/* backup dhcsr reg */
dhcsr_save = cortex_m3->dcb_dhcsr;
- /* mask interrupts if not done already */
+ /* Mask interrupts before clearing halt, if done already. This avoids
+ * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
+ * HALT can put the core into an unknown state.
+ */
if (!(cortex_m3->dcb_dhcsr & C_MASKINTS))
- mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN);
- mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN);
+ mem_ap_write_atomic_u32(swjdp, DCB_DHCSR,
+ DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN);
+ mem_ap_write_atomic_u32(swjdp, DCB_DHCSR,
+ DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN);
LOG_DEBUG(" ");
/* restore dhcsr reg */
int i;
uint32_t dcb_demcr;
struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
+ struct armv7m_common *armv7m = &cortex_m3->armv7m;
struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info;
struct cortex_m3_fp_comparator *fp_list = cortex_m3->fp_comparator_list;
struct cortex_m3_dwt_comparator *dwt_list = cortex_m3->dwt_comparator_list;
+ /* REVISIT The four debug monitor bits are currently ignored... */
mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &dcb_demcr);
LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "",dcb_demcr);
- /* this regsiter is used for emulated dcc channel */
+ /* this register is used for emulated dcc channel */
mem_ap_write_u32(swjdp, DCB_DCRDR, 0);
/* Enable debug requests */
/* clear any interrupt masking */
cortex_m3_write_debug_halt_mask(target, 0, C_MASKINTS);
- /* Enable trace and dwt */
- mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR);
- /* Monitor bus faults */
- mem_ap_write_u32(swjdp, NVIC_SHCSR, SHCSR_BUSFAULTENA);
+ /* Enable features controlled by ITM and DWT blocks, and catch only
+ * the vectors we were told to pay attention to.
+ *
+ * Target firmware is responsible for all fault handling policy
+ * choices *EXCEPT* explicitly scripted overrides like "vector_catch"
+ * or manual updates to the NVIC SHCSR and CCR registers.
+ */
+ mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | armv7m->demcr);
+
+ /* Paranoia: evidently some (early?) chips don't preserve all the
+ * debug state (including FBP, DWT, etc) across reset...
+ */
/* Enable FPB */
target_write_u32(target, FP_CTRL, 3);
target_write_u32(target, dwt_list[i].dwt_comparator_address + 8,
dwt_list[i].function);
}
- swjdp_transaction_endcheck(swjdp);
+ jtagdp_transaction_endcheck(swjdp);
- armv7m_invalidate_core_regs(target);
+ register_cache_invalidate(cortex_m3->armv7m.core_cache);
/* make sure we have latest dhcsr flags */
mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
except_sr = 0;
break;
}
- swjdp_transaction_endcheck(swjdp);
+ jtagdp_transaction_endcheck(swjdp);
LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32 "", armv7m_exception_string(armv7m->exception_number), \
shcsr, except_sr, cfsr, except_ar);
return ERROR_OK;
struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
struct armv7m_common *armv7m = &cortex_m3->armv7m;
struct swjdp_common *swjdp = &armv7m->swjdp_info;
+ struct reg *r;
LOG_DEBUG(" ");
armv7m->read_core_reg(target, i);
}
- xPSR = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32);
+ r = armv7m->core_cache->reg_list + ARMV7M_xPSR;
+ xPSR = buf_get_u32(r->value, 0, 32);
#ifdef ARMV7_GDB_HACKS
/* FIXME this breaks on scan chains with more than one Cortex-M3.
/* copy real xpsr reg for gdb, setting thumb bit */
buf_set_u32(armv7m_gdb_dummy_cpsr_value, 0, 32, xPSR);
buf_set_u32(armv7m_gdb_dummy_cpsr_value, 5, 1, 1);
- armv7m_gdb_dummy_cpsr_reg.valid = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid;
- armv7m_gdb_dummy_cpsr_reg.dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty;
+ armv7m_gdb_dummy_cpsr_reg.valid = r->valid;
+ armv7m_gdb_dummy_cpsr_reg.dirty = r->dirty;
#endif
/* For IT instructions xPSR must be reloaded on resume and clear on debug exec */
if (xPSR & 0xf00)
{
- armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid;
+ r->dirty = r->valid;
cortex_m3_store_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 16, xPSR &~ 0xff);
}
}
else
{
- armv7m->core_mode = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1);
+ armv7m->core_mode = buf_get_u32(armv7m->core_cache
+ ->reg_list[ARMV7M_CONTROL].value, 0, 1);
armv7m->exception_number = 0;
}
return retval;
}
+ /* Recover from lockup. See ARMv7-M architecture spec,
+ * section B1.5.15 "Unrecoverable exception cases".
+ *
+ * REVISIT Is there a better way to report and handle this?
+ */
+ if (cortex_m3->dcb_dhcsr & S_LOCKUP) {
+ LOG_WARNING("%s -- clearing lockup after double fault",
+ target_name(target));
+ cortex_m3_write_debug_halt_mask(target, C_HALT, 0);
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ /* refresh status bits */
+ mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
+ }
+
if (cortex_m3->dcb_dhcsr & S_RESET_ST)
{
/* check if still in reset */
if (target->state == TARGET_RESET)
{
- /* Cannot switch context while running so endreset is called with target->state == TARGET_RESET */
- LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32 "", cortex_m3->dcb_dhcsr);
+ /* Cannot switch context while running so endreset is
+ * called with target->state == TARGET_RESET
+ */
+ LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32,
+ cortex_m3->dcb_dhcsr);
cortex_m3_endreset_event(target);
target->state = TARGET_RUNNING;
prev_target_state = TARGET_RUNNING;
uint32_t dcb_dhcsr = 0;
int retval, timeout = 0;
- /* Enter debug state on reset, cf. end_reset_event() */
- mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
+ /* Enter debug state on reset; restore DEMCR in endreset_event() */
+ mem_ap_write_u32(swjdp, DCB_DEMCR,
+ TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
- /* Request a reset */
- mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET);
+ /* Request a core-only reset */
+ mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR,
+ AIRCR_VECTKEY | AIRCR_VECTRESET);
target->state = TARGET_RESET;
/* registers are now invalid */
- armv7m_invalidate_core_regs(target);
+ register_cache_invalidate(cortex_m3->armv7m.core_cache);
while (timeout < 100)
{
retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr);
if (retval == ERROR_OK)
{
- mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr);
- if ((dcb_dhcsr & S_HALT) && (cortex_m3->nvic_dfsr & DFSR_VCATCH))
+ mem_ap_read_atomic_u32(swjdp, NVIC_DFSR,
+ &cortex_m3->nvic_dfsr);
+ if ((dcb_dhcsr & S_HALT)
+ && (cortex_m3->nvic_dfsr & DFSR_VCATCH))
{
- LOG_DEBUG("system reset-halted, dcb_dhcsr 0x%" PRIx32 ", nvic_dfsr 0x%" PRIx32 "", dcb_dhcsr, cortex_m3->nvic_dfsr);
+ LOG_DEBUG("system reset-halted, DHCSR 0x%08x, "
+ "DFSR 0x%08x",
+ (unsigned) dcb_dhcsr,
+ (unsigned) cortex_m3->nvic_dfsr);
cortex_m3_poll(target);
+ /* FIXME restore user's vector catch config */
return ERROR_OK;
}
else
- LOG_DEBUG("waiting for system reset-halt, dcb_dhcsr 0x%" PRIx32 ", %i ms", dcb_dhcsr, timeout);
+ LOG_DEBUG("waiting for system reset-halt, "
+ "DHCSR 0x%08x, %d ms",
+ (unsigned) dcb_dhcsr, timeout);
}
timeout++;
alive_sleep(1);
/* set any pending breakpoints */
while (breakpoint)
{
- if (breakpoint->set == 0)
+ if (!breakpoint->set)
cortex_m3_set_breakpoint(target, breakpoint);
breakpoint = breakpoint->next;
}
struct armv7m_common *armv7m = target_to_armv7m(target);
struct breakpoint *breakpoint = NULL;
uint32_t resume_pc;
+ struct reg *r;
if (target->state != TARGET_HALTED)
{
if (debug_execution)
{
+ r = armv7m->core_cache->reg_list + ARMV7M_PRIMASK;
+
/* Disable interrupts */
- /* We disable interrupts in the PRIMASK register instead of masking with C_MASKINTS,
- * This is probably the same issue as Cortex-M3 Errata 377493:
- * C_MASKINTS in parallel with disabled interrupts can cause local faults to not be taken. */
- buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1);
- armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = 1;
- armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = 1;
+ /* We disable interrupts in the PRIMASK register instead of
+ * masking with C_MASKINTS. This is probably the same issue
+ * as Cortex-M3 Erratum 377493 (fixed in r1p0): C_MASKINTS
+ * in parallel with disabled interrupts can cause local faults
+ * to not be taken.
+ *
+ * REVISIT this clearly breaks non-debug execution, since the
+ * PRIMASK register state isn't saved/restored... workaround
+ * by never resuming app code after debug execution.
+ */
+ buf_set_u32(r->value, 0, 1, 1);
+ r->dirty = true;
+ r->valid = true;
/* Make sure we are in Thumb mode */
- buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32,
- buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32) | (1 << 24));
- armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1;
- armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1;
+ r = armv7m->core_cache->reg_list + ARMV7M_xPSR;
+ buf_set_u32(r->value, 24, 1, 1);
+ r->dirty = true;
+ r->valid = true;
}
/* current = 1: continue on current pc, otherwise continue at <address> */
+ r = armv7m->core_cache->reg_list + 15;
if (!current)
{
- buf_set_u32(armv7m->core_cache->reg_list[15].value, 0, 32, address);
- armv7m->core_cache->reg_list[15].dirty = 1;
- armv7m->core_cache->reg_list[15].valid = 1;
+ buf_set_u32(r->value, 0, 32, address);
+ r->dirty = true;
+ r->valid = true;
+ }
+
+ /* if we halted last time due to a bkpt instruction
+ * then we have to manually step over it, otherwise
+ * the core will break again */
+
+ if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32))
+ && !debug_execution)
+ {
+ armv7m_maybe_skip_bkpt_inst(target, NULL);
}
- resume_pc = buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32);
+ resume_pc = buf_get_u32(r->value, 0, 32);
armv7m_restore_context(target);
target->debug_reason = DBG_REASON_NOTHALTED;
/* registers are now invalid */
- armv7m_invalidate_core_regs(target);
+ register_cache_invalidate(armv7m->core_cache);
+
if (!debug_execution)
{
target->state = TARGET_RUNNING;
struct armv7m_common *armv7m = &cortex_m3->armv7m;
struct swjdp_common *swjdp = &armv7m->swjdp_info;
struct breakpoint *breakpoint = NULL;
+ struct reg *pc = armv7m->core_cache->reg_list + 15;
+ bool bkpt_inst_found = false;
if (target->state != TARGET_HALTED)
{
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current)
- buf_set_u32(cortex_m3->armv7m.core_cache->reg_list[15].value,
- 0, 32, address);
+ buf_set_u32(pc->value, 0, 32, address);
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
- breakpoint = breakpoint_find(target, buf_get_u32(armv7m
- ->core_cache->reg_list[15].value, 0, 32));
+ breakpoint = breakpoint_find(target,
+ buf_get_u32(pc->value, 0, 32));
if (breakpoint)
cortex_m3_unset_breakpoint(target, breakpoint);
}
+ armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
+
target->debug_reason = DBG_REASON_SINGLESTEP;
armv7m_restore_context(target);
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
- /* set step and clear halt */
- cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+ /* if no bkpt instruction is found at pc then we can perform
+ * a normal step, otherwise we have to manually step over the bkpt
+ * instruction - as such simulate a step */
+ if (bkpt_inst_found == false)
+ {
+ /* set step and clear halt */
+ cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+ }
+
mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr);
/* registers are now invalid */
- armv7m_invalidate_core_regs(target);
+ register_cache_invalidate(cortex_m3->armv7m.core_cache);
if (breakpoint)
cortex_m3_set_breakpoint(target, breakpoint);
- LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
+ LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32
+ " nvic_icsr = 0x%" PRIx32,
+ cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
cortex_m3_debug_entry(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
- LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
+ LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32
+ " nvic_icsr = 0x%" PRIx32,
+ cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr);
+
return ERROR_OK;
}
{
/* Set/Clear C_MASKINTS in a separate operation */
if (cortex_m3->dcb_dhcsr & C_MASKINTS)
- mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN | C_HALT);
+ mem_ap_write_atomic_u32(swjdp, DCB_DHCSR,
+ DBGKEY | C_DEBUGEN | C_HALT);
/* clear any debug flags before resuming */
cortex_m3_clear_halt(target);
/* clear C_HALT in dhcsr reg */
cortex_m3_write_debug_halt_mask(target, 0, C_HALT);
-
- /* Enter debug state on reset, cf. end_reset_event() */
- mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR);
}
else
{
- /* Enter debug state on reset, cf. end_reset_event() */
- mem_ap_write_atomic_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
+ /* Halt in debug on reset; endreset_event() restores DEMCR.
+ *
+ * REVISIT catching BUSERR presumably helps to defend against
+ * bad vector table entries. Should this include MMERR or
+ * other flags too?
+ */
+ mem_ap_write_atomic_u32(swjdp, DCB_DEMCR,
+ TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
}
/*
target->state = TARGET_RESET;
jtag_add_sleep(50000);
- armv7m_invalidate_core_regs(target);
+ register_cache_invalidate(cortex_m3->armv7m.core_cache);
if (target->reset_halt)
{
else if (breakpoint->type == BKPT_SOFT)
{
uint8_t code[4];
- buf_set_u32(code, 0, 32, ARMV7M_T_BKPT(0x11));
- if ((retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK)
- {
+
+ /* NOTE: on ARMv6-M and ARMv7-M, BKPT(0xab) is used for
+ * semihosting; don't use that. Otherwise the BKPT
+ * parameter is arbitrary.
+ */
+ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
+ retval = target_read_memory(target,
+ breakpoint->address & 0xFFFFFFFE,
+ breakpoint->length, 1,
+ breakpoint->orig_instr);
+ if (retval != ERROR_OK)
return retval;
- }
- if ((retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code)) != ERROR_OK)
- {
+ retval = target_write_memory(target,
+ breakpoint->address & 0xFFFFFFFE,
+ breakpoint->length, 1,
+ code);
+ if (retval != ERROR_OK)
return retval;
- }
- breakpoint->set = 0x11; /* Any nice value but 0 */
+ breakpoint->set = true;
}
LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
}
}
}
- breakpoint->set = 0;
+ breakpoint->set = false;
return ERROR_OK;
}
target_write_u32(target, comparator->dwt_comparator_address + 8,
comparator->function);
- watchpoint->set = 0;
+ watchpoint->set = false;
return ERROR_OK;
}
{
struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
- /* REVISIT why check? DWT can be updated with core running ... */
- if (target->state != TARGET_HALTED)
- {
- LOG_WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
if (cortex_m3->dwt_comp_available < 1)
{
LOG_DEBUG("no comparators?");
/* set any pending watchpoints */
while (watchpoint)
{
- if (watchpoint->set == 0)
+ if (!watchpoint->set)
cortex_m3_set_watchpoint(target, watchpoint);
watchpoint = watchpoint->next;
}
retval = cortexm3_dap_write_coreregister_u32(swjdp, value, num);
if (retval != ERROR_OK)
{
+ struct reg *r;
+
LOG_ERROR("JTAG failure %i", retval);
- armv7m->core_cache->reg_list[num].dirty = armv7m->core_cache->reg_list[num].valid;
+ r = armv7m->core_cache->reg_list + num;
+ r->dirty = r->valid;
return ERROR_JTAG_DEVICE_ERROR;
}
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
static struct dwt_reg dwt_base_regs[] = {
{ DWT_CTRL, "dwt_ctrl", 32, },
+ /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly
+ * increments while the core is asleep.
+ */
{ DWT_CYCCNT, "dwt_cyccnt", 32, },
/* plus some 8 bit counters, useful for profiling with TPIU */
};
return retval;
if (((cpuid >> 4) & 0xc3f) == 0xc23)
- LOG_DEBUG("CORTEX-M3 processor detected");
+ LOG_DEBUG("Cortex-M3 r%" PRId8 "p%" PRId8 " processor detected",
+ (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf));
LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
/* NOTE: FPB and DWT are both optional. */
/* Setup DWT */
cortex_m3_dwt_setup(cortex_m3, target);
+
+ /* These hardware breakpoints only work for code in flash! */
+ LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
+ target_name(target),
+ cortex_m3->fp_num_code,
+ cortex_m3->dwt_num_comp);
}
return ERROR_OK;
}
}
write:
+ /* For now, armv7m->demcr only stores vector catch flags. */
+ armv7m->demcr = catch;
+
demcr &= ~0xffff;
demcr |= catch;
- /* write, but don't assume it stuck */
+ /* write, but don't assume it stuck (why not??) */
mem_ap_write_u32(swjdp, DCB_DEMCR, demcr);
mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr);
+
+ /* FIXME be sure to clear DEMCR on clean server shutdown.
+ * Otherwise the vector catch hardware could fire when there's
+ * no debugger hooked up, causing much confusion...
+ */
}
for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++)
if (CMD_ARGC > 0)
{
- if (!strcmp(CMD_ARGV[0], "on"))
- {
- cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
- }
- else if (!strcmp(CMD_ARGV[0], "off"))
- {
- cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
- }
- else
- {
- command_print(CMD_CTX, "usage: cortex_m3 maskisr ['on'|'off']");
- }
+ bool enable;
+ COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
+ uint32_t mask_on = C_HALT | (enable ? C_MASKINTS : 0);
+ uint32_t mask_off = enable ? 0 : C_MASKINTS;
+ cortex_m3_write_debug_halt_mask(target, mask_on, mask_off);
}
command_print(CMD_CTX, "cortex_m3 interrupt mask %s",
return ERROR_OK;
}
-static int cortex_m3_register_commands(struct command_context *cmd_ctx)
-{
- int retval;
- struct command *cortex_m3_cmd;
-
- retval = armv7m_register_commands(cmd_ctx);
-
- cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3",
- NULL, COMMAND_ANY, "cortex_m3 specific commands");
-
- register_command(cmd_ctx, cortex_m3_cmd, "disassemble",
- handle_cortex_m3_disassemble_command, COMMAND_EXEC,
- "disassemble Thumb2 instructions <address> [<count>]");
- register_command(cmd_ctx, cortex_m3_cmd, "maskisr",
- handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC,
- "mask cortex_m3 interrupts ['on'|'off']");
- register_command(cmd_ctx, cortex_m3_cmd, "vector_catch",
- handle_cortex_m3_vector_catch_command, COMMAND_EXEC,
- "catch hardware vectors ['all'|'none'|<list>]");
-
- return retval;
-}
+static const struct command_registration cortex_m3_exec_command_handlers[] = {
+ {
+ .name = "disassemble",
+ .handler = handle_cortex_m3_disassemble_command,
+ .mode = COMMAND_EXEC,
+ .help = "disassemble Thumb2 instructions",
+ .usage = "address [count]",
+ },
+ {
+ .name = "maskisr",
+ .handler = handle_cortex_m3_mask_interrupts_command,
+ .mode = COMMAND_EXEC,
+ .help = "mask cortex_m3 interrupts",
+ .usage = "['on'|'off']",
+ },
+ {
+ .name = "vector_catch",
+ .handler = handle_cortex_m3_vector_catch_command,
+ .mode = COMMAND_EXEC,
+ .help = "configure hardware vectors to trigger debug entry",
+ .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+static const struct command_registration cortex_m3_command_handlers[] = {
+ {
+ .chain = armv7m_command_handlers,
+ },
+ {
+ .name = "cortex_m3",
+ .mode = COMMAND_EXEC,
+ .help = "Cortex-M3 command group",
+ .chain = cortex_m3_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
struct target_type cortexm3_target =
{
.add_watchpoint = cortex_m3_add_watchpoint,
.remove_watchpoint = cortex_m3_remove_watchpoint,
- .register_commands = cortex_m3_register_commands,
+ .commands = cortex_m3_command_handlers,
.target_create = cortex_m3_target_create,
.init_target = cortex_m3_init_target,
.examine = cortex_m3_examine,