18. 4K page layout

The HP-41 assumes a certain layout of 4K ROM pages in order to identify the functions it contains and how they are to be used. At the end of each 4K page there is also some poll vectors that allow the code to hook in and handle certain events. A stripped down 4K ROM page can look as follows:

              .con  4               ; XROM number
              .con  3               ; number of entries

              ;; Function address table
              .fat  entry_Header
              .fat  entry_Code
              .fat  entry_Decode
              .con  0,0             ; marks end of FAT

;;; Code goes here
              .name "DECODE"
entry_Decode: ;; code goes here

              .name "CODE"
entry_Code:   ;; code goes here

              .name "-EXAMPLE 1"    ; header
entry_Header: rtn

;;; Poll vectors
              .section PollVectors
              .con  0               ; Pause
              .con  0               ; Running
              .con  0               ; Wake w/o key
              .con  0               ; Powoff
              .con  0               ; I/O
              .con  0               ; Deep wake-up
              .con  0               ; Memory lost
              .text "A1XE"          ; Identifier EX-1A

;;; Checksum will go here, but it is filled in by the linker
;;; so we leave it out.

The first word is the XROM number which should range from 1–31. You can pick any number, but should avoid those that your plug-in module are expected to co-exist with. 1

The second word is the number of functions in the function address table. When looking up a given function, this number is consulted to see if the given instruction number exists in this module.

The function address table is easily populated using the .fat directive. In reality there are two words for each entry. The function address table must be ended with two 0 words.

After this header you enter the space where we can put our own code.

At offset FF4 at the end comes the poll vectors. If you do not use them, or do not know what they are good for, just fill them out with 0 to indicate that they are unimplemented.

A four word module identifier, in reverse order, gives an indication of which module this is. You typically pick two letters related to the name of your module and a 2 digit revision number. The identifier in the example code is EX-1A, for “Example revision 1A”.

The very final word of the 4K page is a checksum. This checksum can be calculated and filled in by the linker, so we should not specify it in the source file.

18.1. FAT order

The automatic generation of FAT contributions by the RPN compiler makes it easy to populate a complete FAT. However, its automatic nature also means that if you add or remove global alpha labels, the FAT entries may change which may result in that the same function is assigned a different XROM number.

As XROM functions in a module may be used in RPN programs, such programs will have a dependency not only on the module, but also on the order of the entries in the FAT. Thus, if you add or remove entries, you may want to take full control over the FAT entries in order to keep it consistent. This can only be done by defining it manually in an MCODE source file.

To define a FAT manually, disable generation of FAT section fragments from the RPN compiler using the --no-fat option. Then you will need a full FAT defined in MCODE, it may look something like:

              .section Header
              .extern readRom16, writeRom16
              .extern FUPDATE, HFUPDAT

              .public `FAT entry: RDROM16`

XROMno:       .equ    14

              .con    XROMno          ; XROM number
              .con    .fatsize FatEnd ; number of entry points
FatStart:
              .fat    Header          ; ROM header
`FAT entry: RDROM16`:
              .fat    readRom16
              .fat    writeRom16
              .fatrpn FUPDATE
              .fatrpn HFUPDAT

FatEnd:       .con    0,0

In this table there are three MCODE functions and two RPN programs. The entries that are internally used by RPN programs in the module need to have the special `FAT entry: XXXX` label defined at its FAT entry. In this case only the MCODE program RDROM16 is used internally.

The entries that exist in different source files must be imported using the .extern directive. In MCODE you are quite free to choose the name, but in RPN you get the name of the global alpha label, which is exported by the RPN compiler for this purpose.

Footnotes

1

Unfortunately, the number range is not all that wide and the number of modules on the market severely outnumbers it.