
You have written RST 8 / DEFB 158 so often it is a reflex. But think about what it has to achieve. Your program runs with RAM switched in, so the MOS's code is not visible at all (S4). Yet two bytes later a character is on the screen and your program carries on. This section follows those two bytes.
RSTRST 8 is a call to address 0008h that takes one byte instead of the three a CALL needs. Even with the call's number in the byte after it, a MOS call is two bytes against a CALL's three, so a program that makes a hundred calls saves a hundred bytes. On a machine with 8K of ROM and programs measured in kilobytes, that mattered.
The price is that there are only eight RST addresses, and they are fixed. So the MOS uses just one of them for all its calls and passes the call's number in the byte that follows. The processor knows nothing about that byte; it is the MOS's job to read it and to make sure your program does not try to execute it.
Your RST 8 pushes the address of the next byte - the number - and jumps to 0008h. RAM is in, so 0008h is the copy start-up put there (S6):
jp 0fc22h ; RAM 0008h
and that jumps to the code start-up copied into high RAM.
In the source this code sits in the ROM at 105Ah, under its original name; start-up copied it to FC22h, where it runs:
ZCALM1:
ld (0fb79h),hl ;105a (runs at fc22h)
pop hl ;105d (runs at fc25h)
push af ;105e (runs at fc26h)
ld a,(hl) ;105f (runs at fc27h)
inc hl ;1060 (runs at fc28h)
ex (sp),hl ;1061 (runs at fc29h)
ld (0fb7bh),sp ;1062 (runs at fc2ah)
push hl ;1066 (runs at fc2eh)
or a ;1067 (runs at fc2fh)
ld hl,0fb00h ;1068 (runs at fc30h)
sbc hl,sp ;106b (runs at fc33h)
pop hl ;106d (runs at fc35h)
jr c,l1073h ;106e (runs at fc36h)
ld sp,0fcffh ;1070 (runs at fc38h)
l1073h:
out (024h),a ;1073 (runs at fc3bh)
call FMC1 ;1075 (runs at fc3dh)
Read it in pieces:
POP HL takes the return address: the address of the number. LD A,(HL) reads the number. INC HL and EX (SP),HL put back a return address one byte further on, so that when the call finishes your program resumes after the number. Your A is kept safe on the stack.SBC HL,SP with HL = FB00h compares your stack pointer with FB00h. If your stack is below FB00h (in the bottom 32K, say), it is about to vanish when the ROM is switched in, so the code moves SP to the MOS's own stack at FCFFh first. Most programs' stacks are higher, and the move is skipped.OUT (24h),A - the ROM is in. This code is in the top half, so it is still there.CALL FMC1 - into the ROM.FMC1:
push hl ;0fca
bit 7,a ;0fcb
res 7,a ;0fcd
jr z,FMUSR ;0fcf
ld hl,(0fb3ah) ;0fd1
add a,a ;0fd4
add a,l ;0fd5
ld l,a ;0fd6
jr nc,l0fdah ;0fd7
inc h ;0fd9
l0fdah:
ld a,(hl) ;0fda
inc hl ;0fdb
ld h,(hl) ;0fdc
ld l,a ;0fdd
pop af ;0fde
push hl ;0fdf
ld hl,(0fb79h) ;0fe0
ret ;0fe3
The number's top bit is tested and removed. With it set - every call you have used, 128 and above - the number minus 128 is doubled and added to the address held at FB3Ah, which is 0282h, the start of a table of routine addresses. The word found there is the routine. POP AF gives back your A; PUSH HL and RET jump to the routine with HL restored. For 158 the word is at 02BEh and holds 0F1Ah: OUTC, the routine that prints. S8 is about that table.
Notice the trick at the end: PUSH HL / RET is a jump to an address held in a register, made without losing HL's value, because HL is reloaded in between.
When OUTC returns, it returns into the RAM code just after CALL FMC1:
out (024h),a ;1078 (runs at fc40h)
ld sp,(0fb7bh) ;107a (runs at fc42h)
ret ;107e (runs at fc46h)
RAM back in; your stack pointer back; return to the byte after the number.
A number with its top bit clear takes the other branch at JR Z,FMUSR:
FMUSR:
ld hl,(0fb3ch) ;0fe4
jp (hl) ;0fe7
No table: just a jump to the address held at FB3Ch. As start-up leaves it, that is 007Dh - INITM, from S6. So RST 8 / DEFB 1 does not return at all: it restarts the MOS, and the start-up screen is drawn again.
The MOS makes RST 8 calls too, with the ROM already in. Then 0008h is the ROM's own byte, and there it says:
l0008h:
jp FXMON ;0008
...
FXMON:
ld (0fb79h),hl ;0fc2
pop hl ;0fc5
push af ;0fc6
ld a,(hl) ;0fc7
inc hl ;0fc8
ex (sp),hl ;0fc9
FMC1:
The same steps without the switching, falling straight into FMC1. Two ways in, one lookup: the RAM copy at 0008h and the ROM's 0008h are the same call reached from either side of the switch.
ORG 256
LD A,'A'
RST 8
DEFB 158 ; OUTC: table entry 30, at 02BEh
RST 8
DEFB 181 ; KSCAN: table entry 53, at 02ECh
RET
Build and run
Press Run.
What you should see
>A
A BC DE HL PC SZ-H-PNC
00 00FF 07FF FB46 0FA5 01011100
The A from call 158. Then call 181 looked for a key, found none, and returned 0 in A - the register display's first column. Two calls, two different routines, one route in.
RST 8 is a one-byte call. The number after it is read through the return address, which is then stepped past it. With RAM in, the call reaches a jump start-up left at RAM 0008h, then code in high RAM that switches the ROM in and calls FMC1; with the ROM in, the ROM's own 0008h leads to the same place. FMC1 finds the routine in a table whose address is held at FB3Ah, and the RAM code switches back and returns past the number.
S8 opens the table: 85 addresses, and the reason the > prompt uses them too.
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.