What is a macro ?
The LH5801 offers 128 macros that are described inside the vector table of the ROM at &FF00 to &FFFF. The assembly mnenomics to "call" a macro is SBR (z80-like) or VME and VEJ(lh5801 official). The ML code are from &C0 to &FE (even bytes) of &CD &nn (for &nn < &C0).
The macro SBR (&34) [ML code CD 34] will jump to address pointed by &FF34, that is &DF23. There are a lot of advantages to use macros instead of CALL:
- First, macros require 1 byte (if >= &C0) or 2 bytes when CALL requires 3 bytes,
- Next, the macros could be called with condition, like SBR NZ,(&nn) when CALL must be preceeded by a 'NOT' conditiionnal jump, ie, JR Z,+3 CALL &nnpp,
- Last and important: the macros are useful for portability; If the address of macro &nn differs between two ROMs, only the vector at &FFnn is updated, and all codes calling SBR (&nn) will work. That is not true with CALL &nnpp where the address &nnpp is hard-coded inside the code and so is dependant from the ROM.
This will be updated dring the coming days. Please correct me if I wrote something wrong because the macros are not really documented...
Here is a list of the macros and a short expalanation In the following n p are 8-bytes values; k is a 16 bits value if the first byte >=&E0 and a 8-bits value else; mn 16-bits value; +d is a positive displacement in bytes starting a the address that immediately follows.
- SBR (&00), n,p,d - Jump at +d if register L is not >=n and <p or if register H is not 0
- SBR (&02), n,p,d - Same as SBR (&00) but load register HL with the value pointed by register DE, (see macro &C0)
- SBR (&04), d - Jump at +d if the register L is not &0D or &3A (while running a program) &3A is the : BASIC separator. Carry is set if register L = &3A, else carry is cleared
- ...
- SBR (&34), n,p0,d0[,p1,d1,..] - Check for n+1 peers (pz,dz); jump at +dz if register A = pz (z from 0 to n). This is exactly a swicth... case. The register H is untouched by the macro and can be used to save the value of the register A.
- ...
- SBR (&C0) - Load register HL wiith the value pointed by register DE: if (DE) >=&E0 the HL=(DE)(DE+1) else HL=&00(DE); the register DE is incremented by 1 or 2 bytes (if >=&E0)
- SBR (&C2) k,d - Load register HL with value pointed by register (DE) and jump at +d if register HL != k.
- SBR (&C4) k,d - Jump at +d if register HL != k.
- SBR (&C6) - Decrement register DE according to the value in register HL: if H >=&E0, decrement by 2, else decrement by 1
- SBR (&C8) k,d - Load register HL with value pointed by register (DE) and jump at +d if register HL != &0D and != &3A (while running)
- SBR (&CA), n - Save register BC to address &78n; (&78n) = B, (&78n+1) = C
- SBR (&CC), n - Load register BC with the value at address &78n; B = (&78n), C = (&78n+1)
- ...
- SBR (&D0), n,d - Convert the content of arithmetic register X-REG to register HL according to the value n, and jump at +d if an error occurs. The value n defines the range for conversion: &00 : unsigned 16 bits value (0.65535), &01 : signed 16-bits value (-32768..32767), &08 : 8-bit value (0..255), &03 : BASIC line number (1..65279), &09 : Increment ?, &0A : a LCD column (0..155), &10 : cursor position 0..25, and others I don't know...
- ...
- SBR (&DC), - Load the string pointers from X-REG to register BC (address of the string) and register L (length)
- SBR (&DE), d - Evaluate the BASIC expression pointed by register DE and jump at +d if an error occurs during the evaluation. The result of the expression (string or number) is stored into the arithmetic register X-REG (&FA00); if it is a string, &FA04 = &D0 (see note about arithmetic registers at the end)
- ...
SBR (&E0) - Raise the error using the value of register H; if H=&1A, the macro raises the ERROR 26
SBR (&E2) - Exit to BASIC with the next address pointed by (DE); continue the execution if a BASIC program is currently running
SBR (&E4) - Raise the ERROR 1; this is exactly LD H,&01 SBR (&E0) - ...
SBR (&F2) - Clear the screen like the BASIC command CLS - SBR (&F4), mn - Load register HL with the value at address &mn; H = (&mn), L = (&mn+1)
- SBR (&F4), mn - Save register HL to address &mn; (&mn) = H, (&mn+1) = L
- ...
SBR (&F8) - Maskable interrupt vector
SBR (&FA) - Timer vector (used when blinking the cursor...)
SBR (&FC) - Non-Maskable interrupt vector
SBR (&FE) - RESET vector : This is the point where the CPU jumps at PowerON, but also when the RESET putton is pushed. This is the well known CALL &E000