This is a genuine bug in the interaction between Debug Unit and CPU. When hardware single step is used, the pipeline can become confused, leading to multiple executions of the same instruction, and eventually to the same instruction being executed forever.
Hardware single-step is always used in two places. First when
restarting after a breakpoint to execute the instruction that was
replaced by l.trap
. GDB single steps the
instruction, then replaces it with l.trap
, so the
breakpoint can be used again.
Secondly GDB uses single step for the stepi command.
A sequence of stepi commands illustrates the problem:
(gdb) si 0x00001224 in simputs (str=0x0) at utils.c:102 102 { (gdb) si 0x00001228 102 { (gdb) si 0x00001228 102 { (gdb) si 0x0000122c 102 { (gdb) si 0x00001230 102 { (gdb) si 0x00001230 102 { (gdb) si 0x00001230 102 { (gdb) si 0x00001230 102 {
The VCD trace in Figure 4.16 shows the pipeline failing to fill correctly after some of the single steps
From around 140ms, the pipeline refill starts to go wrong. The ticks
on the dbg_stall
line are the individual single
steps. By 180ms the pipeline is completely filled with the
instruction at address 0x1230 (0xd7e21ffc,
l.sw -4(r2),r3
).
Unfortunately single stepping is sometimes used by GDB in other circumstances. For example a step (high level instruction step) or nextcommand> may use multiple steps rather than setting and running to a temporary breakpoint. Under these circumstances the GDB client will hang, because the target does not seem to reach its target.
There is a workaround, which is to use ctrl-C (twice) to break the connection and then reconnect. The OpenRISC 1000 is stalled at the time, so on reconnection will be at the same location. Using continue allows the pipeline to refill correctly.
(gdb) s ^C^CInterrupted while waiting for the program. Give up (and stop debugging it)? (y or n) y (gdb) target remote :51000 Remote debugging using :51000 0x00001230 in simputs (str=0x1350 "Hello World!\n") at utils.c:102 102 { (gdb) c Continuing. Breakpoint 4, simputs (str=0x1350 "Hello World!\n") at utils.c:105 105 for( i = 0; str[i] != '\0' ; i++ ) { (gdb)
The solution is to modify the handling of the RSP step (s)
packet, so that two consecutive hardware single-step operations
are never used. A second step is implemented using
l.trap
.
This is not completely trivial, since the case where the second step would have occurred on a branch delay slot must be handled. Fortunately under this circumstance the single step bug does not seem to occur, so it is sufficient to permit a second single step in the case where that step occurs on a delay slot.
The example code distributed with this application note does not have this solution implemented. It is left as an exercise for the reader.