Debug Shell

A debugger is a tool to check data at runtime. For amforth there is no single tool for that purpose. There are a Tracer and a Profiler available. They modify the code generation to achieve their goals. The debugshell presented here is called at explicit breakpoints to stop the execution of the current word and gives an independent command prompt to execute arbitrary commands.

This debugshell core can be modified and expanded in many ways. One example is the Watcher Utility for memory access.

Core

The debug shell core is quite small. Only 3 lines of code:

82 buffer: debugbuf
: (?) cr ." debug> " debugbuf dup 80 accept ;
: ?? begin (?) dup while (evaluate) repeat 2drop ;

Technically it is an isolated command shell activated at any time. With this debugger you can place the command ?? anywhere in your code and you’ll get the debug> prompt whenever execution reaches it.

Extensions

The first extension is to have an on-off feature of the debugger. This can be achieved by an global flag or using deferred words:

0 value debug?
\ re-defines the ?? command and uses the old one
\ internally
: ?? debug? if ?? then ;

assigning a non-zero value to debug? (true to debug?) will activate the debug prompt. Note that the debug flag is stored in EEPROM und the settings survive a reset.

Another on-off implementation uses the deferred word technique.

Edefer breakpoint
' ?? is breakpoint
\ ' noop is breakpoint

Here you use the command breakpoint in your code instead of the basic ?? command.

: foo bar breakpoint baz ;

Note that the deferred vector is stored in EEPROM and the settings survive a reset.

The third extension uses interrupts. Since amforth executes them as ordinary forth code it is possible to assign any interrupt source to the ?? command (0 is an example interrupt number)

> ' ?? 0 int!
> 0 int-trap

debug> rp@ hex .
82D
debug>
 ok
>

When you use an external interrupt via a simple key you get the debug prompt whenever you press it. If you configure and enable the external interrupt of course. Note that in this case the debug prompt is executed in the interrupt mode of the controller, you have to use the polling implementation of the usart receive module.