cortex_m: Fix single stepping will not return to debug mode sometimes

This occurs when stepping past a breakpoint on a even address with
maskisr option set to auto

With -d3 the following log message appears in this case:

"Debug : Interrupt handlers didn't complete within time,
 leaving target running"

Cause : Given a breakpoint is set on the lower half word and the PC is on
the upper half word. When another breakpoint is now set on the current PC
then resuming the core will not result in a break on the newly set
breakpoint. This has been observed on a STM32F1x, STM32F2x (CM3) but not
on a STM32F0x (CM0). It's not clear if this is a STM32F1/F2 only or a
general CM3 problem.


Change-Id: I384813f3bfdf935373b5e23cdb2d7f243c70cc00
Signed-off-by: Peter Horn <peter.horn@bluewin.ch>
Reviewed-on: http://openocd.zylin.com/864
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
This commit is contained in:
Peter Horn 2012-10-08 22:06:07 +02:00 committed by Spencer Oliver
parent ed3632d9c7
commit 79fa75e199
1 changed files with 59 additions and 34 deletions

View File

@ -854,45 +854,70 @@ static int cortex_m3_step(struct target *target, int current,
*
*/
/* Set a temporary break point */
retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value));
bool tmp_bp_set = (retval == ERROR_OK);
/* No more breakpoints left, just do a step */
if (!tmp_bp_set)
/* 2012-09-29 ph
*
* If a break point is already set on the lower half word then a break point on
* the upper half word will not break again when the core is restarted. So we
* just step over the instruction with interrupts disabled.
*
* The documentation has no information about this, it was found by observation
* on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 dosen't seem to
* suffer from this problem.
*
* To add some confusion: pc_value has bit 0 always set, while the breakpoint
* address has it always cleared. The former is done to indicate thumb mode
* to gdb.
*
*/
if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) {
LOG_DEBUG("Stepping over next instruction with interrupts disabled");
cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
/* Re-enable interrupts */
cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
}
else {
/* Start the core */
LOG_DEBUG("Starting core to serve pending interrupts");
int64_t t_start = timeval_ms();
cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP);
/* Wait for pending handlers to complete or timeout */
do {
retval = mem_ap_read_atomic_u32(swjdp,
DCB_DHCSR,
&cortex_m3->dcb_dhcsr);
if (retval != ERROR_OK) {
target->state = TARGET_UNKNOWN;
return retval;
}
isr_timed_out = ((timeval_ms() - t_start) > 500);
} while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out));
/* Set a temporary break point */
retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value));
bool tmp_bp_set = (retval == ERROR_OK);
/* Remove the temporary breakpoint */
breakpoint_remove(target, pc_value);
if (isr_timed_out) {
LOG_DEBUG("Interrupt handlers didn't complete within time, "
"leaving target running");
} else {
/* Step over next instruction with interrupts disabled */
cortex_m3_write_debug_halt_mask(target,
C_HALT | C_MASKINTS,
0);
/* No more breakpoints left, just do a step */
if (!tmp_bp_set)
cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
/* Re-enable interrupts */
cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
else {
/* Start the core */
LOG_DEBUG("Starting core to serve pending interrupts");
int64_t t_start = timeval_ms();
cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP);
/* Wait for pending handlers to complete or timeout */
do {
retval = mem_ap_read_atomic_u32(swjdp,
DCB_DHCSR,
&cortex_m3->dcb_dhcsr);
if (retval != ERROR_OK) {
target->state = TARGET_UNKNOWN;
return retval;
}
isr_timed_out = ((timeval_ms() - t_start) > 500);
} while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out));
/* Remove the temporary breakpoint */
breakpoint_remove(target, pc_value);
if (isr_timed_out) {
LOG_DEBUG("Interrupt handlers didn't complete within time, "
"leaving target running");
} else {
/* Step over next instruction with interrupts disabled */
cortex_m3_write_debug_halt_mask(target,
C_HALT | C_MASKINTS,
0);
cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
/* Re-enable interrupts */
cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
}
}
}
}