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.