3. Console command line

The console interpreter is intended for interactive command line use. In this mode you have access to a powerful command line interpreter with command completion, command history and command line editing.

Your command line history is also saved between sessions in ~/.dbnut/dbnut.history. You will also find a file that preserves the state of your HP-41 calculator in the same directory.

3.1. Command structure

Commands are made up from one or more space separated words. If a given word is long enough to be a unique match, it does not need to spelled out in full.

After the command there may be an argument that is specific to the command, i.e. a string, file path or boolean value.

Command completion

Command completion is available using the TAB key. Pressing TAB directly at the prompt provides a list of all words that can be used to start a command:

(dbnut) <TAB>
b                 enable            n                 s
break             exec-file         next              set
c                 file              nexti             show
cd                frame             ni                si
clear             ignore            p                 source
complete          info              platform          step
condition         interpreter-exec  plug-in           stepi
continue          interrupt         print             thread
delete            kill              pwd               tty
directory         lua               quit
disable           maintenance       r
disassemble       module            run
(dbnut)

Pressing TAB will complete the command to the left of the cursor as far as possible. If the word can be partially completed the first TAB will fill in as far as possible:

(dbnut) int<TAB>

Results in:

(dbnut) inter

Pressing TAB a second time results in:

(dbnut) inter<TAB>
interpreter-exec  interrupt
(dbnut) inter

3.2. A simple session

To get a feeling for how to run a very simple debugging session here is how it can look.

$ dbnut --load-module 41cx.mod myimage
Calypsi debugger for Nut
listening for user interface connections on port 8080
(dbnut) b APX
breakpoint 1
(dbnut) info breakpoints
Num      Type            Disp  Enb  Lua/plug-in   Address     What
1        breakpoint      keep  y    no            0x82af      APX
(dbnut) r
running

Note

A command only need entered with enough characters to make it unique. For the command info breakpoints it is enough to type i b followed by return. This works because the command interpreter takes all words in account. The command line completer looks at what is to the left of the cursor, so if you type i<TAB> you will get all command alternatives that start i. To make it complete to info you need to type inf<TAB> followed by b<TAB>. However, if you type i b<TAB> it will expanded to i breakpoints.

Now switch to the user interface and turn the calculator on. If this is the first time you start it, you will be greeted with the well known MEMORY LOST message indicating that the calculator firmware has initialized the calculator properly for the first time.

Enter the number 48 in the HP-41 user interface. Now execute the APX command, which happens to be the name of the command as well as entry point label in the MCODE program.

Once you do XEQ ALPHA APX ALPHA the user interface freezes as the debugger takes control when the breakpoint is hit.

(dbnut) r
running
program hit breakpoint 1
   1 #include "mainframe.h"
   2
   3               .pubweak APX
   4               .name   "APX"
-> 5 APX:          c=0                   ; initialize REG.9 for DIGENT
   6               c=c-1
   7               c=0     xs
   8               pt=     13
   9               lc      10            ; initial D.P. position
0x82af at stack/apx.s:5
(dbnut)

The breakpoint is hit at address 0x82af in the source file stack/apx.s:5. Some source lines are shown as context with the current line indicated.

We can now perform a couple of single steps:

(dbnut) s
    2
    3               .pubweak APX
    4               .name   "APX"
    5 APX:          c=0                   ; initialize REG.9 for DIGENT
->  6               c=c-1
    7               c=0     xs
    8               pt=     13
    9               lc      10            ; initial D.P. position
   10               regn=c  9
0x82b0 at stack/apx.s:6
(dbnut)
    3               .pubweak APX
    4               .name   "APX"
    5 APX:          c=0                   ; initialize REG.9 for DIGENT
    6               c=c-1
->  7               c=0     xs
    8               pt=     13
    9               lc      10            ; initial D.P. position
   10               regn=c  9
   11               gosub   STBT10        ; copy status bits for DIGENT
0x82b1 at stack/apx.s:7
(dbnut)

We use the step command that can be entered as s. This steps one source line. The second step we simply press RETURN which repeats the previous command (s in this case).

Each step moves us one line further ahead and the source context shown moves along with it.

We can inspect registers with info registers.

(dbnut) info registers
pc                  82b1
cy                     1 yes
a         00000008000000 0.0000008000.000
b         0000000000e005 0.000000000e.005
c         ffffffffffffff f.ffffffffff.fff
m         900a38582afa80 9.00a38582af.a80
n         00000008000000 0.0000008000.000
g                     a3
f                     00
st                    00
sth                   02
p                      1
q                      d
pactive                1 yes
cycles  000000000000487c
(dbnut)

The first column shows the register name, the second is the hex value of it and the third column shows the same value in a more decorative way (for some registers).

Hint

The cycles register is the cycle counter as a 64-bit hex number. This is very useful for evaluating performance of sections of code. Simply stop at strategic places and read the cycles register, then compute the difference.

Hint

A good calculator which can work in different number bases and word sizes is very useful when debugging MCODE. The HP-16C calculator or the Ladybug module for the HP-41 are very powerful tools for this.

Looking at the source code, we realize that we want to stop next at a certain line a bit further down, this can be done as follows:

(dbnut) b apx.s:49
breakpoint 2
(dbnut) c
running
program hit breakpoint 2
   45               acex    s
   46               rcr     -1
   47               pt=     0
   48               g=c
-> 49               gosub   DIGENT
   50               gosub   NOREG9        ; normalize and move to X
   51               bcex    x             ; decrement exponent
   52               c=c-1   x
   53               ?c#0    xs            ; negative (hit fractional part?)
0x82dd at stack/apx.s:49
(dbnut)

The continue command (short form c) is used to resume execution (not run which runs the program from start).

Here we want to see what we are passing in to DIGENT. We could display the registers again, but we can also show that value by just displaying the G register. We can do this by printing an expression (using the print or p command). A register name need to be preceded by a dollar sign:

(dbnut) p $g
$1 = 16
(dbnut) p/x $g
$2 = 0x10
(dbnut)

We got 16 and realized it was in decimal. Passing the /x modifier to the print command gives the value in hexadecimal.

We can also display a part of a register using a field. In this case we have a counter in the X (exponent) field of the B register:

(dbnut) p/x $b.x
$3 = 0x1
(dbnut)

It is apparently 1 at this point. Now step over the gosub we are standing at. This can be done using the next command (or n for short).

(dbnut) n
   46               rcr     -1
   47               pt=     0
   48               g=c
   49               gosub   DIGENT
-> 50               gosub   NOREG9        ; normalize and move to X
   51               bcex    x             ; decrement exponent
   52               c=c-1   x
   53               ?c#0    xs            ; negative (hit fractional part?)
   54               goc     25$           ; yes
0x82df at stack/apx.s:50
(dbnut)

We realize that we do not need to use the first breakpoint anymore. It can be removed using delete, but we decide to to disable it using the disable command instead:

(dbnut) disable 1
(dbnut) info breakpoints
Num      Type            Disp  Enb  Lua/plug-in   Address     What
1        breakpoint      keep  n    no            0x82af      APX
         breakpoint already hit 1 time
2        breakpoint      keep  y    no            0x82dd      apx.s:49
         breakpoint already hit 1 time
(dbnut)

Here we can see that the first breakpoint still exists, but it is not enabled (n in the Enb column). We can also see that the debugger also keeps track of statistics about the breakpoints.