.. index:: 4K page layout, module;layout
.. _sec-module-layout:

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:

.. literalinclude:: page.s
   :language: ca65

.. index:: XROM;number

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. [#xrom]_

.. index:: function address table

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.

.. index:: poll vectors

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.

.. index:: ROM revision

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".

.. index:: checksum

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.


.. index:: FAT, order
.. _sec-fat-order:

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:

.. code-block:: ca65

                  .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.



.. rubric:: Footnotes
.. [#xrom] Unfortunately, the number range is not all that wide and
           the number of modules on the market severely outnumbers it.
