HP-41CX Emulator Tool - GLOBAL command
Table of Contents
When working on the Decoder/Encoder, the so-called GLOBAL commands were the most tricky to understand. There is plenty
of documentation, but none specifically for those who write an encoder (also known as a compiler).
Definition #
GLOBAL commands consist of a group comprising global LBL and the two END commands, as defined by documentation
describing the internal workings of an HP-41C.
Global LBL #
Alphanumeric labels are GLOBAL—with a few exceptions. The single-character variants LBL A to LBL J and LBL a to
LBL e are not actually global labels. This is probably for compatibility with the HP-67, the predecessor of the
HP-41C. Those single-character labels are also automatically assigned a key on the USER mode keyboard.
Every program should start with a global label. This is not enforced, but it is good practice, as sub-programmes without a global label can become orphaned, and accessing orphaned programmes is quite difficult.
END #
There are two types of END: the intermediate END that separates programmes, and the final .END.. There must always
be one final .END.. On the calculator itself, the FOCAL system ensures this. My encoder is not quite as
sophisticated. Forget the final .END., and you will run into problems later.
An intermediate END can be added by the user—for example, with [XEQ] [ALPHA] [E] [N] [D] [ALPHA] on the calculator
itself. An END should be followed by a global LBL, otherwise your programme might become orphaned.
There are also three more flags to further subdivide END commands: Packed, Compiled, and Private. Note that the
encoder always sets those flags to false. However, when the --with-hex command-line option is used, the decoder shows
them as comments.
How GLOBAL Commands Are Encoded #
All GLOBAL commands consist of 24 bits (3 bytes). Global LBL commands are then followed by the key assignment and
label text. The data is bit-packed.
| Bits | Content |
|---|---|
| 1 … 4 | Always C16—marks the beginning of a GLOBAL command |
| 5 … 7 | Byte count for the linked list. Range is 0 … 6 |
| 8 … 16 | Register count for the linked list |
| 17 … 20 | LBL: Start ALPHA; END: Stop & Private flag |
| 21 … 24 | LBL: ALPHA length; END: Packed and Compiled flag |
Note: Most HP-41C documentation uses one as the base index, and I follow that. This includes the programme itself, as you can freely choose the base index in Ada.
Linked List #
The GLOBAL commands all form a linked list from the last element to the first. For easy access by the FOCAL
interpreter, the last object must be right-justified in the last used register. If necessary, the final .END. is
moved into a register of its own. The space between is padded with 0016.
Without proper placement of the final .END., the linked list cannot be traversed. The programme can still be loaded
and executed, but CAT 1 and key assignments will not work.
The links of the list are relative and count the steps from the beginning of the current entry to the beginning of the previous entry. They are stored as 12 packed bits. Links are split into bytes and registers (7 bytes, 14 digits). The first three bits are the byte offset; the remaining 9 bits are the register offset.
Trivia: With just 9 bits for the register offset (capping offsets at 511 registers), the HP-41C could never fully exploit its theoretical 1024-register main memory. This elegant limitation birthed the extended memory “kludge” in the HP-41CX—a workaround that a simple 10-bit offset might have rendered obsolete.
LBL #
For LBL, the two bytes at bit positions 17 … 24 contain a standard string header consisting of the F16
marking the beginning of the string and the length byte. LBL commands are restricted to a maximum of 7 characters.
One additional byte is added to the length for the optional key assignment byte, making the total range of valid
values for the second byte 2 … 8.
END #
For END and .END., the two bytes at bit positions 17 … 24 contain four flags that describe the type of END. These
flags are structured such that bits 17 and 20 are always 0 (ensuring bits 17 … 20 never form the hexadecimal F value used
to mark the start of an Alpha string in LBL commands), while bits 21 and 24 are always 1 (ensuring bits 21 … 24 fall
outside the valid length range of 2 … 8 for LBL strings). This distinct bit pattern occupies a different numerical
range from the Alpha string header, allowing the FOCAL interpreter to reliably distinguish between END and LBL
commands.
| Bits | Meaning | Decoder |
|---|---|---|
| 17 | Always 02 | |
| 18 | Private | P |
| 19 | Final .END. | S |
| 20 | Always 02 | |
| 21 | Always 12 | |
| 22 | Packed | Z |
| 23 | Compiled | C |
| 24 | Always 12 |
Note: Bits 21 … 24 can also be all 02.
Final .END. #
As mentioned placement of the final .END. is crucial. Most program step are byte packed. While editing programs the
calculator add null operations 0016. These are completely ignored executed by the FOCAL interpreter. This is
unlike the zero character 00F0 NOP which has side effects. You can pack the code with `GTO.." which remove
the 0016 bytes.
However, the final .END. is always placed in the least significant 3 bytes of the final program fregister pointed to be
’.END. ABS.ADR.’ (3 least signifcant nibble of regiser 00D16). This way the interpreter can find the
final .END. without time consuming scan operations.
The most signifcant bytes can contain other programm steps or be padded with 0016. You can see this in the DF41 memory dump of the GRAVITY game:
DM41
08 4b000000000000 00000000000000 00000000000000 00000000000000
0c 0000000000019c 1a70016919c175 0000002c048000 00000000000000
174 00000000000000 00000000c8262d 93021036ba0000 402143668e2142
178 225140668e5222 8e042126421242 0010362266ba00 452e2e2e2163b4
17c 45502053504143 06ba0003fd4445 12437120424092 40ce0220512442
180 aa001330244222 00431371457502 40542467b200a9 a80066b2005222
184 42124222517141 42134321413426 2345759303207a 2e2e7e897f3061
188 77f75a45524f2e 4e452e2e2e7e89 2e2e2e7e89f64f 2e7e89f654574f
18c 54485245452e2e 7e892367b300f8 3d9b06f37f2046 537e894585f241
190 9b71f57f20462f 45f27f46f27f3d 226e261a15f156 454c3d9b037e89
194 899c000af54655 9c02a91d9b017e 10322533f2473d 101010361c1510
198 10104035cf6615 61181010421112 56495459a81b31 c000f800475241
A: c000f800475241 B: 0000002c0480fd C: 0000002c0480fd
S: 00001100000000
M: 00011cd5ff73cb N: 000000000000c0 G: 00
The final .END. (c8262d16) is in memory location 17516. The most significant bytes of 17516 as well as the two least significant bytes of 17516 are padded with 0016.
On the HP41C and it’s emulators this is done automatically.
Example #
The following example is taken from the PX-41CX and decoded with --with-hex, which adds flags, the offsets for the
linked list, and the hex code as comments to the output. This programme has no useful function. It only shows the use
of LBL and END.
; STACK = 1.000000000E+00 1.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
; ALPHA = ⊤END⊤
; SIZE = 100
; ΣREG = 11
; FLAGS = 0000 0000 0000 0000 0000 0000 0010 1100 0000 0100 1000 0000 0000 0000
; A: 09999999999000 B: 0000002c0480fd C: 000000002c00fd
; S: 00100010000000
; M: 000018a5ff83d3 N: 000000000c14c0 G: 00
LBL ⊤GLOBAL1⊤ ; Begin 000: c000f800474c4f42414c31
123 ; 016: 111213
ENTER↑ ; 01c: 83
STO 01 ; 01e: 31
RTN ; 020: 85
LBL ⊤LOCAL1⊤ ; (R:-2,S:-3) 022: c602f7004c4f43414c31
1 ; 036: 11
ENTER↑ ; 038: 83
2 ; 03a: 12
ENTER↑ ; 03c: 83
3 ; 03e: 13
* ; 040: 42
+ ; 042: 40
RTN ; 044: 85
END ; –––– (R:-2,S:-4) 046: c80209
LBL ⊤GLOBAL2⊤ ; (R: 0,S:-3) 04c: c600f800474c4f42414c32
1 ; 062: 11
ENTER↑ ; 064: 83
LBL 01 ; 066: 02
2 ; 068: 12
ENTER↑ ; 06a: 83
LBL A ; 06c: cf66
5 ; 070: 15
ENTER↑ ; 072: 83
GTO 01 ; 074: b200
XEQ A ; 078: e00066
8 ; 07e: 18
ENTER↑ ; 080: 83
LBL ⊤LOCAL2⊤ ; (R:-3,S:-6) 082: cc03f7004c4f43414c32
⊤ABCDE⊤ ; 096: f54142434445
GTO 01 ; 0a2: b200
RTN ; 0a6: 85
END ; –––– (R:-2,S:-5) 0a8: ca0209
.END. ; S––– (R: 0,S:-4) 0b0: c80020
Note: The double END at the end appeared after packing the programme with GTO... You should not actually type
them in, and if you recompile the programme with the encoder, I suggest deleting the extra END.
Terms #
| Term | Description |
|---|---|
| Bit | Single binary digit containing 02 or 12 |
| Nibble | String of 4 bits. Same as a decimal or hex digit. |
| Byte | String of 8 bits. |
| Digits | A single number. Size depends on the number base. If base is not specified on the HP-41, it is 4-bit decimal (BCD). |
| BCD | Binary coded decimal. A way to encode a decimal number in a nibble. |
| Binary digit | Same as Bit. |
| Hex digit | Same as Nibble. |
| Step | A physical programme step consists of 8 bits / 1 byte. |