TRS-80 DOS - NEWDOS/80 v2.0 for the Model I - SYS20/SYS Disassembled

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS20/SYS Disassembly - BASIC CMD, FN, INSTR, MID$=, &H, OPEN and LINE INPUT (Model I)

SYS20/SYS holds the BASIC statements and functions that are not needed often enough to stay in BASIC/CMD: CMD with a DOS command, CMD"S=" and CMD"F=" (with POPS, POPR and POPN), user functions (FN), INSTR, MID$ on the left side of an assignment, &H and &O constants, OPEN, the reading of INPUT# and READ items from a file, and LINE INPUT. It is one of the three BASIC overlays that load at 5200H, here 5200H-56E7H (1,256 bytes, transfer address 5200H); 56AEH-56E7H are unused zero bytes. BASIC loads it with RST 28H code 36H (function 1 of directory slot 16H) through its overlay loader at 576CH.

The page shows every byte of the file once, in address order. Calls into BASIC/CMD are linked only where the BASIC page has a row with the right bytes at that address.

Entry Points

AddressFrom BASICStatement
5202H57A5HCMD"command", CMD"S=command", CMD"F=function" (5202H).
534AH577FHFN (vector 4155H) (534AH).
53F2H5786HINSTR (vector 419DH) (53F2H).
5462H578BHMID$(...)= (link 41D9H) (5462H).
54C5H5790H&H and &O constants (vector 4194H) (54C5H).
5504H5798HOPEN (vector 4179H) (5504H).
55D4H579AHINPUT# and READ items (link 41DCH) (55D4H).
55E8H579FHLINE INPUT (vector 41A3H) (55E8H).

Variables

Locations inside SYS20 whose contents change while it runs, or that are read as data:

Address RangePurpose
5272H-5273H
2 bytes
Start of the saved copy of 5200H-70FFH below BASIC's stack (operand of 5271H). 0000H in the file; written at 5236H; used by the copy-back code running in the copy.
5275H-5276H
2 bytes
5200H, the start of the memory saved (operand of 5274H); also read as data at 5245H.
5278H-5279H
2 bytes
1F00H, the length of 5200H-70FFH (operand of 5277H); also read as data at 522FH.
5290H-5291H
2 bytes
BASIC's Stack Pointer while a full DOS command runs (operand of 528FH). 0000H in the file; written at 5224H.
52C9H-52CAH
2 bytes
Address of the 64-byte checksum window, 192 bytes below BASIC's stack (operand of 52C8H). 0000H in the file; written at 522CH; read at 529AH and 52A7H.
5386H-5387H
2 bytes
FN: the DEF's text pointer while the parameters are assigned (written at 5366H), then the call's text pointer after the arguments (written at 53AAH, read at 53E9H). Operand of 5385H; 0000H in the file.

Locations outside SYS20 that it reads or writes:

Address RangePurpose
40A0H-40A1H
2 bytes
The ROM's pointer to the start of the string space; BASIC's stack lies just below it. POPS (531BH) and MID$ (546FH).
40A7H-40A8H
2 bytes
The ROM's pointer to the input buffer, where file items are collected (5622H).
40AFH
1 byte
The ROM's type flag of the current value (02H integer, 03H string, 04H single, 08H double), tested by RST 20H.
40B1H-40B2H
2 bytes
The ROM's pointer to the top of BASIC's memory, where the checksum ends (52B5H).
40B3H-40B4H
2 bytes
The ROM's pointer to the next free entry of the string temporary pool (53B0H, 53C8H).
40D3H-40D5H
3 bytes
DSCTMP, the ROM's string descriptor work area (53C2H).
40FDH-40FEH
2 bytes
The ROM's pointer to the end of the array table: the saved copy must lie above it (523AH).
4121H-4122H
2 bytes
REG 1; for a string result it holds the address of the descriptor (53B4H, 5408H).
4200H-42FFH
256 bytes
DOS sector buffer area; its top (42FCH) is a temporary stack at 527FH.
4318H-4367H
80 bytes
SYS0's command buffer, holding the CMD string copied there by BASIC 57FFH.
436AH
1 byte
SYS0's DOS state byte; bit 7 = MINI-DOS mode, set around the first try of a CMD command (520FH-5217H).
5700H-5703H
4 bytes
BASIC's file work area: mode byte, open flags and record length stored by OPEN (55C9H-55CDH).
5711H
1 byte
High byte of the buffer address in the FCB at 570DH, raised by 1 for records shorter than 256 (5570H).
5716H
1 byte
LRL (record length) byte of the FCB at 570DH, set to 1 to give back one character (5691H).
5952H
table
BASIC's CMD"F=" function table: name length, name, address; ends with 00H (52EDH).
64C6H
1 byte
BASIC's file area size, 2 when BASIC was started with the V option (5573H).

Running a Full DOS Command

A DOS command from CMD"command" is first run as a MINI-DOS command, which leaves BASIC in memory. If the DOS answers ILLEGAL MINI DOS FUNCTION (38H), SYS20 copies BASIC's memory 5200H-70FFH to just below the stack, together with a short routine (5271H) that copies it back, and records a checksum of everything from 7100H to the top of memory in a 64-byte window below the stack (529AH). The command then runs as a full DOS command in 5200H-70FFH. When it returns, the memory is copied back and the checksum is made again; if any byte from 7100H up has changed, BASIC reports MEMORY FAULT (23H).

Disassembly

5200H - Load Entry

BASIC/CMD loads SYS20 through its overlay loader at 576CH with RST 28H code 36H (function 1 of directory slot 16H) into 5200H-56E7H. After loading, the SYS0 dispatcher calls 5200H, which must return with the Z FLAG set (no error); BASIC/CMD then jumps to the entry address it put in Register Pair BC (5202H, 534AH, 53F2H, 5462H, 54C5H, 5504H, 55D4H or 55E8H).

5200
CP A BF
Compare Register A with itself. The result is always equal, so the Z FLAG is set: the load succeeded with no error.
5201
RET C9
RETURN to the SYS0 dispatcher with the Z FLAG set, which tells BASIC/CMD's loader the overlay is in place.

5202H - CMD"command": Run a DOS Command from BASIC

Entered from BASIC 57A5H when the CMD string is longer than one character and does not end in $. BASIC 57FFH has evaluated the string, pushed its text pointer, copied the string in upper case to SYS0's command buffer at 4318H (ending with 0DH) and pushed its length count at 57A4H; Register Pair HL holds 4318H. CMD"S=command" leaves BASIC and runs the DOS command; CMD"F=name" runs one of BASIC's functions POPS, POPR, POPN, ERASE, KEEP, SASZ, SWAP or SS (table at BASIC 5952H); any other string is a DOS command, first run as a MINI-DOS command (BASIC stays in memory). If the DOS answers 38H (ILLEGAL MINI DOS FUNCTION), BASIC's memory 5200H-70FFH is copied below the stack, the command runs as a full DOS command, the memory is copied back, and a checksum of everything from 7100H to the top of memory must be unchanged, or the result is error 23H MEMORY FAULT.

5202
POP BC C1
Restore Register Pair BC from the stack: the count BASIC pushed at 57A4H, with Register B = 00H and Register C = the length of the CMD string minus 1. (Register Pair BC held 5202H, the entry address the loader jumped to.)
5203
LD D,H 54
Load Register D with Register H, the high byte of 4318H, the address of the command in SYS0's command buffer.
5204
LD E,L 5D
Load Register E with Register L. Register Pair DE now holds 4318H, the first character of the command.
5205
INC HL 23
Increment Register Pair HL to 4319H, the command's second character.
5206
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the command's second character.
5207
CP 3DH FE 3D
Compare Register A (the second character) against 3DH, an equals sign: CMD"S=..." and CMD"F=..." have = in second place.
5209
If the Z FLAG is set (the second character is =), JUMP to 52E2H to handle S= or F=.
520C
LD HL,436AH 21 6A 43
Load Register Pair HL with 436AH, SYS0's DOS state byte (bit 7 = MINI-DOS mode, only commands that leave user memory alone are allowed).
520F
SET 7,(HL) CB FE
Set bit 7 of the byte at Register Pair HL (436AH): the command is run in MINI-DOS mode, so BASIC stays in memory.
5211
PUSH HL E5
Save Register Pair HL (436AH) on the stack so the bit can be cleared afterwards.
5212
EX DE,HL EB
Exchange Register Pairs DE and HL: HL now holds 4318H, the command, as DOS-CALL wants it.
5213
GOSUB to SYS0 4419H, DOS-CALL, which runs the command at Register Pair HL as a DOS command and returns: the Z FLAG set for no error; otherwise Register A holds the DOS error code, and the CARRY FLAG is set if the DOS has already displayed the error.
5216
POP HL E1
Restore Register Pair HL from the stack: 436AH, SYS0's DOS state byte.
5217
RES 7,(HL) CB BE
Reset bit 7 of the byte at Register Pair HL (436AH): MINI-DOS mode is over. RES does not change the flags.
5219
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer after the CMD string (pushed by BASIC at 5802H).
521A
JP C,5DEEH DA EE 5D
If the CARRY FLAG is set (the DOS displayed its error itself), JUMP to BASIC 5DEEH, which raises BASIC error 94H PREVIOUSLY DISPLAYED ERROR.
521D
RET Z C8
If the Z FLAG is set (the command ran without error), RETURN to BASIC with Register Pair HL = the text pointer.
521E
CP 38H FE 38
Compare Register A (the DOS error code) against 38H, ILLEGAL MINI DOS FUNCTION: the command needs the full DOS.
5220
JP NZ,5E16H C2 16 5E
If the NZ FLAG is set (some other DOS error), JUMP to BASIC 5E16H, which turns the DOS error code in Register A into a BASIC error.
5223
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack; it is the word just above the saved Stack Pointer.
5224
LD (5290H),SP ED 73 90 52
Self-Modifying Code
Store the Stack Pointer SP (BASIC's stack, with the text pointer on top) at 5290H, the operand of the LD SP,0000H at 528FH, which puts it back after the command.
5228
LD HL,FF40H 21 40 FF
Load Register Pair HL with FF40H, which is -192.
522B
ADD HL,SP 39
Add the Stack Pointer SP to Register Pair HL: HL = SP - 192, the start of a 64-byte checksum window below BASIC's stack.
522C
LD (52C9H),HL 22 C9 52
Self-Modifying Code
Store Register Pair HL (the checksum window's address) at 52C9H, the operand of the LD HL,0000H at 52C8H; the checksum routine also reads it at 529AH and 52A7H.
522F
LD BC,(5278H) ED 4B 78 52
Load Register Pair BC with the 16-bit value at 5278H, the operand of the LD BC,1F00H at 5277H: 1F00H, the length of BASIC's memory to save (5200H-70FFH).
5233
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
5234
SBC HL,BC ED 42
Subtract Register Pair BC (1F00H) from Register Pair HL (the checksum window): HL = where the saved copy of 5200H-70FFH starts, just below the window.
5236
LD (5272H),HL 22 72 52
Self-Modifying Code
Store Register Pair HL (the copy's start) at 5272H, the operand of the LD HL,0000H at 5271H, so the copy code knows where to copy back from.
5239
PUSH HL E5
Save Register Pair HL (the copy's start) on the stack.
523A
LD DE,(40FDH) ED 5B FD 40
Load Register Pair DE with the 16-bit value at 40FDH, the ROM's pointer to the end of BASIC's array table (the first free byte above the program and its variables).
523E
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
523F
SBC HL,DE ED 52
Subtract Register Pair DE (the end of the arrays) from Register Pair HL (the copy's start): the CARRY FLAG is set if the copy would overwrite the program's variables.
5241
POP DE D1
Restore Register Pair DE from the stack: the copy's start.
5242
If the CARRY FLAG is set (not enough free memory), JUMP to the ROM's OMERR at 197AH to report OUT OF MEMORY.
5245
LD HL,(5275H) 2A 75 52
Load Register Pair HL with the 16-bit value at 5275H, the operand of the LD DE,5200H at 5274H: 5200H, the start of the memory to save.
5248
PUSH HL E5
Save Register Pair HL (5200H, the start of the memory to save) on the stack.
5249
ADD HL,BC 09
Add Register Pair BC (1F00H) to Register Pair HL: HL = 7100H.
524A
DEC HL 2B
Decrement Register Pair HL: HL = 70FFH, the last byte to save.
524B
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
524C
SBC HL,DE ED 52
Subtract Register Pair DE (the copy's start) from Register Pair HL (70FFH): the NO CARRY FLAG is set if the copy would start at or below 70FFH, overlapping the memory it saves.
524E
If the NO CARRY FLAG is set (the copy would overlap 5200H-70FFH), JUMP to the ROM's OMERR at 197AH to report OUT OF MEMORY.
5251
POP HL E1
Restore Register Pair HL from the stack: 5200H.
5252
PUSH HL E5
Save Register Pair HL (5200H) on the stack again; it becomes the source address of the copy.
5253
PUSH DE D5
Save Register Pair DE (the copy's start) on the stack.
5254
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the copy's start, DE = 5200H.
5255
OR A B7
OR Register A with itself to clear the CARRY FLAG for the subtraction.
5256
SBC HL,DE ED 52
Subtract Register Pair DE (5200H) from Register Pair HL (the copy's start): HL = the distance from 5200H to the copy.
5258
LD DE,5271H 11 71 52
Load Register Pair DE with 5271H, the address of the copy-back code in SYS20.
525B
ADD HL,DE 19
Add Register Pair DE (5271H) to Register Pair HL (the distance): HL = the address of the copy-back code inside the saved copy.
525C
POP DE D1
Restore Register Pair DE from the stack: the copy's start, the destination of the copy.
525D
GOSUB to SYS0 4416H, which keeps the disk drives turning, so they are not stopped during the copy.
5260
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = 5200H (pushed at 5252H), and the address of the copied 5271H is saved in its place.
5261
LDIR ED B0
LDIR: copy BC bytes (1F00H) from Register Pair HL (5200H) to Register Pair DE (the copy's start), saving BASIC's memory 5200H-70FFH, SYS20 included, below the stack.
5263
POP HL E1
Restore Register Pair HL from the stack: the address of the copy-back code in the saved copy.
5264
LD SP,70FCH 31 FC 70
Load the Stack Pointer SP with 70FCH, inside the region just saved, so the full DOS command may use the memory below the old stack.
5267
PUSH HL E5
Push Register Pair HL (the copied 5271H) on the new stack: when the DOS command returns, it returns into the copy-back code in the saved copy.
5268
GOSUB to 529AH, which fills the checksum window with A5H and XORs every byte from 7100H to the top of memory into it.
526B
LD HL,4318H 21 18 43
Load Register Pair HL with 4318H, the command in SYS0's command buffer.
526E
JUMP to SYS0 4419H, DOS-CALL, to run the command at Register Pair HL, now as a full DOS command (bit 7 of 436AH is clear). It returns to the copied 5271H.

5271H - Back from the Command: Restore BASIC's Memory

5271H-527EH is executed in the saved copy below the stack (the DOS command has used 5200H-70FFH): it copies 5200H-70FFH back and jumps to 527FH in the restored SYS20. The operand at 5272H was set at 5236H; 5275H (5200H) and 5278H (1F00H) are also read as data at 5245H and 522FH.

5271
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the copy's start; the operand 5272H (0000H in the file) was stored at 5236H. This instruction runs in the saved copy.
5274
LD DE,5200H 11 00 52
Load Register Pair DE with 5200H, where BASIC's memory goes back.
5277
LD BC,1F00H 01 00 1F
Load Register Pair BC with 1F00H, the length of 5200H-70FFH.
527A
LDIR ED B0
LDIR: copy BC bytes (1F00H) from Register Pair HL (the saved copy) to Register Pair DE (5200H), restoring BASIC/CMD's memory, SYS20 included.
527C
JUMP to 527FH, now in the restored SYS20 at its own address.
527F
LD SP,42FCH 31 FC 42
Load the Stack Pointer SP with 42FCH, a temporary stack at the top of the DOS sector buffer area 4200H-42FFH, while the checksum runs over the memory where BASIC's stack lies.
5282
PUSH AF F5
Push Register Pair AF on the stack: Register A (the DOS error code) and the flags (Z = no error, CARRY = error already displayed) returned by the DOS command.
5283
GOSUB to 52A4H, which XORs 7100H to the top of memory into the checksum window again: the Z FLAG is set if every byte from 7100H up is unchanged.
5286
LD A,23H 3E 23
Load Register A with 23H, the DOS error code MEMORY FAULT. LD does not change the flags.
5288
If the NZ FLAG is set (the DOS command changed memory above 7100H), JUMP to SYS0 4409H, the DOS error exit, with Register A = 23H.
528B
GOSUB to SYS0 4416H, which keeps the disk drives turning.
528E
POP AF F1
Restore Register Pair AF from the stack: Register A and the flags returned by the DOS command.
528F
LD SP,0000H 31 00 00
Self-Modifying Code
Load the Stack Pointer SP with BASIC's stack; the operand 5290H (0000H in the file) was stored at 5224H.
5292
POP HL E1
Restore Register Pair HL from BASIC's stack: the text pointer after the CMD string (pushed at 5223H).
5293
JP C,5DEEH DA EE 5D
If the CARRY FLAG is set (the DOS displayed its error), JUMP to BASIC 5DEEH, which raises BASIC error 94H PREVIOUSLY DISPLAYED ERROR.
5296
JP NZ,5E16H C2 16 5E
If the NZ FLAG is set (the command ended with a DOS error in Register A), JUMP to BASIC 5E16H to turn it into a BASIC error.
5299
RET C9
RETURN to BASIC with Register Pair HL = the text pointer: the command ran.

529AH - The Memory Checksum

The 64-byte window (its address in the operand 52C9H) is filled with A5H, then every byte from 7100H to the top of memory (40B1H), except the window itself, is XORed into it, byte 0 of the window with byte 0, 64, 128 ... of memory, and so on. The second run (entry 52A4H, after the DOS command) XORs the same bytes into the window again; if memory is unchanged each byte cancels out and the window holds A5H in every byte again: the Z FLAG is set.

529A
LD HL,(52C9H) 2A C9 52
Load Register Pair HL with the 16-bit value at 52C9H, the operand of the LD HL,0000H at 52C8H: the address of the 64-byte checksum window, stored at 522CH.
529D
LD B,40H 06 40
Load Register B with 40H (64), the size of the window.
529F
LD (HL),A5H 36 A5
Store A5H at Register Pair HL, the next byte of the window.
52A1
INC HL 23
Increment Register Pair HL to the next byte of the window.
52A2
Decrement Register B (the window bytes left) and LOOP back to 529FH until all 64 hold A5H.
52A4
LD DE,7100H 11 00 71
Load Register Pair DE with 7100H, the first byte of memory checked (just above the 5200H-70FFH area that is saved and restored).
52A7
LD BC,(52C9H) ED 4B C9 52
Load Register Pair BC with the 16-bit value at 52C9H: the checksum window's address, where the first part of the check ends.
52AB
PUSH BC C5
Save Register Pair BC (the window's address) on the stack.
52AC
GOSUB to 52C8H, which XORs the memory from Register Pair DE (7100H) up to Register Pair BC (the window) into the window; it returns with DE at the window.
52AF
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the window's address.
52B0
LD BC,0040H 01 40 00
Load Register Pair BC with 0040H (64), the size of the window.
52B3
ADD HL,BC 09
Add Register Pair BC to Register Pair HL: HL = the first byte after the window.
52B4
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the first byte after the window, where the check continues.
52B5
LD BC,(40B1H) ED 4B B1 40
Load Register Pair BC with the 16-bit value at 40B1H, the ROM's pointer to the top of BASIC's memory (the highest usable address).
52B9
INC BC 03
Increment Register Pair BC: BC = one past the top of memory, where the check ends.
52BA
GOSUB to 52D7H, which goes on XORing from Register Pair DE (after the window) up to Register Pair BC (the top of memory), continuing the window position where the first part left off.
52BD
POP HL E1
Restore Register Pair HL from the stack: the window's address.
52BE
LD B,40H 06 40
Load Register B with 40H (64), the window bytes to test.
52C0
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, a byte of the window.
52C1
XOR A5H EE A5
XOR Register A with A5H: the Z FLAG is set if the byte is A5H again.
52C3
INC HL 23
Increment Register Pair HL to the next window byte (the flags are not changed).
52C4
RET NZ C0
If the NZ FLAG is set (this byte is not A5H, so memory differs from the first run), RETURN with NZ.
52C5
Decrement Register B (the bytes left) and LOOP back to 52C0H.
52C7
RET C9
RETURN with the Z FLAG set: every window byte is A5H (on the first run, the values are simply left in the window).
52C8
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the checksum window's address; the operand 52C9H (0000H in the file) was stored at 522CH. The window restarts here after every 64 bytes.
52CB
LD A,40H 3E 40
Load Register A with 40H (64), the window bytes before it wraps round.
52CD
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': the window count goes into the alternate Register A and the XOR work is done in the main one.
52CE
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next byte of memory being checked.
52CF
XOR (HL) AE
XOR Register A with the byte at Register Pair HL, the current window byte.
52D0
LD (HL),A 77
Store Register A at Register Pair HL: the window byte now includes this memory byte.
52D1
INC DE 13
Increment Register Pair DE to the next memory byte.
52D2
INC HL 23
Increment Register Pair HL to the next window byte.
52D3
LD A,D 7A
Load Register A with Register D, the high byte of the memory pointer.
52D4
CP B B8
Compare Register A with Register B, the high byte of the end address in Register Pair BC.
52D5
If the Z FLAG is set (the high bytes match), JUMP to 52DDH to compare the low bytes.
52D7
EX AF,AF' 08
Exchange Register Pair AF with the alternate AF': Register A holds the window count again. (The second part of the check at 52BAH enters here with the count left by the first part.)
52D8
DEC A 3D
Decrement Register A, the window bytes left before it wraps.
52D9
If the NZ FLAG is set (the window is not used up), LOOP back to 52CDH for the next memory byte.
52DB
JUMP to 52C8H to start again at the first byte of the window.
52DD
LD A,E 7B
Load Register A with Register E, the low byte of the memory pointer.
52DE
CP C B9
Compare Register A with Register C, the low byte of the end address.
52DF
If the NZ FLAG is set (the end is not reached), JUMP to 52D7H to go on.
52E1
RET C9
RETURN: the memory from Register Pair DE's start up to Register Pair BC has been XORed into the window.

52E2H - CMD"S=" and CMD"F="

Register Pair DE points at the command's first character (4318H) and Register Pair HL at the = (4319H); Register C holds the length of the CMD string minus 1. S= leaves BASIC for the DOS; F= looks the name up in BASIC's function table at 5952H, whose entries are a length byte, the name and a 2-byte address, ending with a 00H length.

52E2
INC HL 23
Increment Register Pair HL past the = to 431AH, the first character after S= or F=.
52E3
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the command's first character (the letter before the =).
52E4
CP 53H FE 53
Compare Register A against 53H, the letter S.
52E6
If the Z FLAG is set (CMD"S=command"), JUMP to SYS0 4405H, which enters the DOS and runs the command at Register Pair HL; it does not return, so BASIC is left.
52E9
CP 46H FE 46
Compare Register A against 46H, the letter F.
52EB
If the NZ FLAG is set (neither S nor F), JUMP to 5302H to report ILLEGAL FUNCTION CALL.
52ED
LD DE,5952H 11 52 59
Load Register Pair DE with 5952H, the start of BASIC/CMD's function table.
52F0
DEC C 0D
Decrement Register C: Register C (the string length minus 1) now holds the length of the name after F=.

TABLE SEARCH LOOP
Register Pair DE walks through the function table; Register Pair HL is saved and points at the name after F=.

52F1
PUSH HL E5
Save Register Pair HL (the name after F=) on the stack.
52F2
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the length of this table entry's name.
52F3
CP C B9
Compare Register A (the entry's length) with Register C (the length of the name given).
52F4
LD B,A 47
Load Register B with Register A, the entry's name length, as a count for skipping or comparing it.
52F5
INC DE 13
Increment Register Pair DE to the entry's first name character (the flags are not changed).
52F6
If the Z FLAG is set (the lengths match), JUMP to 5305H to compare the characters.
52F8
POP HL E1
Restore Register Pair HL from the stack: the name after F=.
52F9
INC DE 13
Increment Register Pair DE over one character of the entry's name.
52FA
Decrement Register B and LOOP back to 52F9H until Register Pair DE is past the entry's name.
52FC
INC DE 13
Increment Register Pair DE over the low byte of the entry's address.
52FD
INC DE 13
Increment Register Pair DE over the high byte: DE now points at the next entry's length byte.
52FE
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next entry's name length.
52FF
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the table.
5300
If the NZ FLAG is set (another entry follows), LOOP back to 52F1H.
5302
The name is not in the table: JUMP to the ROM's FCERR at 1E4AH to report ILLEGAL FUNCTION CALL.
5305
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, a character of the entry's name.
5306
CP (HL) BE
Compare Register A with the byte at Register Pair HL, the same character of the name given.
5307
LD (DE),A 12
Store Register A back at Register Pair DE; the table byte is unchanged and the flags are kept.
5308
INC HL 23
Increment Register Pair HL to the next character of the name given.
5309
If the NZ FLAG is set (the characters differ), JUMP to 52F8H to skip the rest of this entry.
530B
INC DE 13
Increment Register Pair DE to the entry's next character.
530C
Decrement Register B (the characters left) and LOOP back to 5305H.
530E
EX DE,HL EB
The name matches: exchange Register Pairs DE and HL, so HL points at the entry's 2-byte address.
530F
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the function's address.
5310
INC HL 23
Increment Register Pair HL to the high byte of the function's address.
5311
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds the function's address.
5312
POP HL E1
Restore Register Pair HL from the stack, discarding the pointer to the name pushed at 52F1H.
5313
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer after the CMD string (pushed by BASIC at 5802H).
5314
PUSH DE D5
Push Register Pair DE (the function's address) on the stack.
5315
RET C9
RETURN, which jumps to the function's address with Register Pair HL = BASIC's text pointer.

5316H - CMD"F=POPS", "F=POPR" and "F=POPN"

Three of the functions in the table at BASIC 5952H are here. POPS empties BASIC's stack of every GOSUB and FOR. POPR drops the latest GOSUB (and any FOR loops opened after it) without returning. POPN [var] drops a FOR loop (the latest, or the one of var) and any opened after it. Each continues with the next statement. On entry Register Pair HL holds BASIC's text pointer.

5316
EX DE,HL EB
POPS: exchange Register Pairs DE and HL, so DE holds BASIC's text pointer.
5317
LD HL,5346H 21 46 53
Load Register Pair HL with 5346H, the code that continues with the next statement.
531A
PUSH HL E5
Push Register Pair HL (5346H, the continue-with-next-statement code) on the stack.
531B
LD HL,(40A0H) 2A A0 40
Load Register Pair HL with the 16-bit value at 40A0H, the ROM's pointer to the start of the string space; BASIC's stack starts just below it.
531E
DEC HL 2B
Decrement Register Pair HL (one byte below the string space).
531F
DEC HL 2B
Decrement Register Pair HL again: HL = the empty-stack position of BASIC's stack.
5320
POP AF F1
Restore Register Pair AF from the stack: Register Pair AF takes 5346H, the continuation address pushed at 531AH.
5321
LD SP,HL F9
Load the Stack Pointer SP with Register Pair HL: BASIC's stack is empty, every GOSUB and FOR frame is gone.
5322
PUSH AF F5
Push Register Pair AF (5346H) on the empty stack.
5323
RET C9
RETURN to 5346H, which continues with the next statement.
5324
EX (SP),HL E3
POPR: exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): the text pointer goes onto the stack and HL holds the return address that was there.
5325
LD D,FFH 16 FF
Load Register D with FFH, which tells FNDFOR to stop at the first frame that is not a FOR frame.
5327
CALL 1936H CD 36 19
GOSUB to the ROM's FNDFOR at 1936H, which skips the FOR frames on BASIC's stack; Register Pair HL returns at the frame found and Register A holds its token.
532A
CP 91H FE 91
Compare Register A (the frame's token) against 91H, the GOSUB token that marks a GOSUB frame.
532C
JP NZ,1EEAH C2 EA 1E
If the NZ FLAG is set (no subroutine call is active), JUMP to 1EEAH in the ROM's RETURN code, which reports RETURN WITHOUT GOSUB.
532F
LD BC,0004H 01 04 00
Load Register Pair BC with 0004H, the part of the subroutine frame that 5343H adds to Register Pair HL to step past it.
5332
JUMP to 5343H to drop the frame at Register Pair HL and everything above it.
5334
LD DE,0000H 11 00 00
POPN: load Register Pair DE with 0000H: no variable given, any FOR frame will do.
5337
DEC HL 2B
Decrement Register Pair HL (the text pointer) so the RST 10H that follows fetches the current character again.
5338
RST 10H D7
RST 10H: increment Register Pair HL and load Register A with the next character. The Z FLAG is set at the end of the statement (no variable given).
5339
If the NZ FLAG is set (a variable follows), GOSUB to the ROM's PTRGET at 260DH: Register Pair DE = the address of the variable, the FOR loop wanted.
533C
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): the text pointer goes onto the stack and HL holds the return address that was there.
533D
CALL 1936H CD 36 19
GOSUB to the ROM's FNDFOR at 1936H with Register Pair DE (the variable, or 0 for any): Register Pair HL returns at the FOR frame, the Z FLAG set if one was found, and Register Pair BC holds the frame's size.
5340
JP NZ,199DH C2 9D 19
If the NZ FLAG is set (no matching FOR frame), JUMP to the ROM's NFERR at 199DH to report NEXT WITHOUT FOR.
5343
ADD HL,BC 09
Add Register Pair BC (the size of the frame's part to step over) to Register Pair HL: HL = the stack position after the frame.
5344
POP DE D1
Restore Register Pair DE from the stack: BASIC's text pointer.
5345
LD SP,HL F9
Load the Stack Pointer SP with Register Pair HL: the frame and every frame above it are dropped.
5346
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = BASIC's text pointer.
5347
JP 1D25H C3 25 1D
JUMP to 1D25H in the ROM's NEWSTT, which continues the program with the next statement at Register Pair HL.

534AH - FN: Calling a User Function

Entered from BASIC 577FH through the ROM vector 4155H when an expression holds FN name(arguments). The function's variable entry (found by BASIC 5837H) holds a pointer to the DEF FN statement's text. For each parameter named in the DEF, the parameter variable's current value is saved on the stack, the matching argument of the call is evaluated and assigned to it (the separators of the call and the DEF must match), then the expression after = in the DEF is evaluated, the parameters get their old values back, and the result is converted to the function's type. Register Pair HL is BASIC's text pointer at the function's name on entry.

534A
CALL 5837H CD 37 58
GOSUB to BASIC 5837H, which reads the function name at Register Pair HL and finds its variable entry: Register Pair DE returns pointing at the entry's value (the DEF pointer), Register Pair HL at the character after the name, and the Z FLAG is set for a string function.
534D
PUSH AF F5
Save Register Pair AF (Register A and the flags: the function's type) on the stack for the conversion at the end.
534E
XOR A AF
Load Register A with 00H (XOR A with itself).
534F
PUSH AF F5
Push Register Pair AF with Register A = 00H: a zero type word that marks the bottom of the saved parameters for the loop at 53E1H.
5350
EX DE,HL EB
Exchange Register Pairs DE and HL: HL points at the function entry's value, DE holds the call's text pointer (after the name).
5351
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the pointer to the DEF FN statement.
5352
INC HL 23
Increment Register Pair HL to the high byte of the DEF pointer.
5353
LD H,(HL) 66
Load Register H with the byte at Register Pair HL, the high byte of the DEF pointer.
5354
LD L,A 6F
Load Register L with Register A. Register Pair HL now holds the DEF pointer: the text of the DEF FN statement after the name.
5355
LD A,H 7C
Load Register A with Register H, the high byte of the DEF pointer.
5356
OR L B5
OR Register A with Register L: the Z FLAG is set if the pointer is 0000H, meaning no DEF FN for this name has been executed.
5357
JP Z,5DC7H CA C7 5D
If the Z FLAG is set (the function was never defined), JUMP to BASIC 5DC7H, which raises error 2EH UNDEFINED USER FUNCTION.
535A
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the character of the call after the function's name.
535B
CP 28H FE 28
Compare Register A against 28H, an opening parenthesis: the call has arguments.
535D
If the NZ FLAG is set (no arguments), JUMP to 539EH, where the DEF must go straight on with =.
535F
RST 08H CF
RST 08H: the character at Register Pair HL (the DEF's text) must be the byte that follows (an opening parenthesis), else SYNTAX ERROR; then RST 10H moves HL on and loads Register A.
5360
DEFB 28H 28
Data byte 28H (an opening parenthesis), the character the RST 08H at 535FH requires in the DEF. RST 08H returns past this byte, to 5361H.

PARAMETER LOOP
Register Pair HL = the DEF's text at the next parameter, Register Pair DE = the call's text at the next argument.

5361
PUSH DE D5
Save Register Pair DE (the call's text pointer) on the stack.
5362
GOSUB to BASIC 5844H, which reads the next parameter name in the DEF at Register Pair HL and finds (or creates) its variable: Register Pair DE returns with the variable's address, Register Pair HL past the name, Register A holds the value's length and the Z FLAG is set if it is a string.
5365
POP BC C1
Restore Register Pair BC from the stack: the call's text pointer.
5366
LD (5386H),HL 22 86 53
Self-Modifying Code
Store Register Pair HL (the DEF's text pointer, after this parameter) at 5386H, the operand of the LD HL,0000H at 5385H.
5369
If the NZ FLAG is set (a numeric parameter), JUMP to 5374H to save its value on the stack.
536B
PUSH DE D5
A string parameter: push Register Pair DE (the variable's address) for the restore loop.
536C
PUSH AF F5
Push Register Pair AF (Register A = 03H, the string type) for the restore loop.
536D
PUSH BC C5
Push Register Pair BC (the call's text pointer).
536E
PUSH DE D5
Push Register Pair DE (the variable's address) again, the argument for PUTNEW.
536F
CALL 2888H CD 88 28
GOSUB to 2888H in the ROM's PUTNEW, which makes a temporary copy of the string variable's descriptor so its old value can be put back later.
5372
JUMP to 5384H, past the numeric-parameter code, with Register Pair DE on the stack.
5374
NEG ED 44
A numeric parameter: NEG Register A (the value's length, 2, 4 or 8), giving minus the length.
5376
LD L,A 6F
Load Register L with Register A (minus the length).
5377
LD H,FFH 26 FF
Load Register H with FFH: Register Pair HL = minus the value's length as a 16-bit number.
5379
ADD HL,SP 39
Add the Stack Pointer SP to Register Pair HL: HL = SP minus the length.
537A
LD SP,HL F9
Load the Stack Pointer SP with Register Pair HL, making room on the stack for the value.
537B
NEG ED 44
NEG Register A again: Register A holds the value's length (its type) once more.
537D
PUSH DE D5
Push Register Pair DE (the variable's address) for the restore loop.
537E
PUSH AF F5
Push Register Pair AF (Register A = the type) for the restore loop.
537F
PUSH BC C5
Push Register Pair BC (the call's text pointer).
5380
PUSH DE D5
Push Register Pair DE (the variable's address) again.
5381
GOSUB to BASIC 5CDEH, which copies Register A bytes (the value) from the variable to the room made on the stack (the ROM's VMOVEA at 09D6H).
5384
POP DE D1
Restore Register Pair DE from the stack: the parameter variable's address.
5385
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the DEF's text pointer; the operand 5386H (0000H in the file) was stored at 5366H.
5388
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the call's text pointer, and the DEF's pointer is saved.
5389
RST 10H D7
RST 10H: move Register Pair HL (the call's text pointer) to the first character of the argument; Register A holds it.
538A
CALL 1F2BH CD 2B 1F
GOSUB to 1F2BH in the ROM's LET, which evaluates the argument at Register Pair HL and assigns it to the parameter variable in Register Pair DE; HL returns after the argument.
538D
POP DE D1
Restore Register Pair DE from the stack: the DEF's text pointer.
538E
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the separator after this parameter in the DEF (a comma or a closing parenthesis).
538F
CP (HL) BE
Compare Register A with the byte at Register Pair HL, the separator after this argument in the call.
5390
If the NZ FLAG is set (the call and the DEF do not match), JUMP to the ROM's SNERR at 1997H to report SYNTAX ERROR.
5393
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the call's text pointer, HL = the DEF's.
5394
CP 29H FE 29
Compare Register A (the separator) against 29H, a closing parenthesis: the last parameter.
5396
If the Z FLAG is set (all parameters are done), JUMP to 539CH.
5398
RST 08H CF
RST 08H: the character at Register Pair HL (the DEF's text) must be the byte that follows (a comma), else SYNTAX ERROR; then RST 10H moves HL to the next parameter.
5399
DEFB 2CH 2C
Data byte 2CH (a comma), the character the RST 08H at 5398H requires between the DEF's parameters. RST 08H returns past this byte, to 539AH.
539A
LOOP back to 5361H for the next parameter at Register Pair HL.
539C
INC DE 13
Increment Register Pair DE (the call's text pointer) past the call's closing parenthesis.
539D
RST 10H D7
RST 10H: move Register Pair HL (the DEF's text) past its closing parenthesis; Register A holds the next character.
539E
RST 08H CF
RST 08H: the character at Register Pair HL (the DEF's text) must be the byte that follows (the = token), else SYNTAX ERROR; then RST 10H moves HL to the start of the function's expression.
539F
DEFB D5H D5
Data byte D5H, the BASIC token for =, which the RST 08H at 539EH requires after the DEF's parameters. RST 08H returns past this byte, to 53A0H.
53A0
PUSH DE D5
Save Register Pair DE (the call's text pointer, after the arguments) on the stack.
53A1
GOSUB to the ROM's FRMEVL at 2337H, which evaluates the function's expression at Register Pair HL, with the parameters holding the arguments: the result goes to REG 1 (4121H) and 40AFH holds its type.
53A4
DEC HL 2B
Decrement Register Pair HL (the DEF's text, after the expression) so the RST 10H that follows fetches that character again.
53A5
RST 10H D7
RST 10H: move Register Pair HL on and load Register A with the character after the expression. The Z FLAG is set at the end of the statement.
53A6
If the NZ FLAG is set (the DEF goes on after the expression), JUMP to the ROM's SNERR at 1997H to report SYNTAX ERROR.
53A9
POP HL E1
Restore Register Pair HL from the stack: the call's text pointer, after the arguments.
53AA
LD (5386H),HL 22 86 53
Self-Modifying Code
Store Register Pair HL (the call's text pointer) at 5386H, the operand of 5385H, which is read back as data at 53E9H.
53AD
RST 20H E7
RST 20H (the ROM's type test on 40AFH): the Z FLAG is set if the result is a string.
53AE
If the NZ FLAG is set (a numeric result), JUMP to 53E1H to put the parameters back.
53B0
LD DE,(40B3H) ED 5B B3 40
Load Register Pair DE with the 16-bit value at 40B3H, the ROM's pointer to the next free entry of the string temporary pool (3-byte descriptors from 40B5H up).
53B4
LD HL,(4121H) 2A 21 41
Load Register Pair HL with the 16-bit value at 4121H, REG 1, which for a string result holds the address of the result's descriptor.
53B7
DEC DE 1B
Decrement Register Pair DE (the pool pointer): 1 of 3 back.
53B8
DEC DE 1B
Decrement Register Pair DE (the pool pointer): 2 of 3.
53B9
DEC DE 1B
Decrement Register Pair DE: 3 of 3. DE now points at the last temporary descriptor in the pool.
53BA
RST 18H DF
RST 18H: compare Register Pair HL (the result's descriptor) with Register Pair DE (the last temporary). The Z FLAG is set if the result is that temporary.
53BB
If the Z FLAG is set (the result is the last temporary), JUMP to 53C2H to move it out of the pool.
53BD
GOSUB to 2843H in the ROM's STR$ code, which makes a new temporary for the string whose descriptor is at Register Pair HL.
53C0
JUMP to 53E1H to put the parameters back, the result now a temporary.
53C2
LD DE,40D3H 11 D3 40
Load Register Pair DE with 40D3H, DSCTMP, the ROM's 3-byte descriptor work area.
53C5
CALL 29F5H CD F5 29
GOSUB to the ROM's FRETMS at 29F5H, which loads Register Pair HL with the last descriptor in the string temporary pool (the value at 40B3H minus 3) and frees it if Register Pair DE is that same address. It returns with HL pointing at that last descriptor.
53C8
LD (40B3H),HL 22 B3 40
Store Register Pair HL (the last descriptor's address) at 40B3H, the ROM's pointer to the next free entry of the temporary pool: the last temporary is taken out of the pool.
53CB
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H, the size of a string descriptor.
53CE
LDIR ED B0
LDIR: copy BC bytes (3) from Register Pair HL (the last temporary descriptor) to Register Pair DE: DSCTMP at 40D3H for the function's result, or the string parameter's variable when coming from 53D5H.
53D0
JUMP to 53E1H to fetch the next saved parameter.

RESTORE THE PARAMETERS
Each saved parameter left its type (Register A) and its variable's address on the stack; a zero type (pushed at 534FH) ends the loop.

53D2
POP DE D1
Restore Register Pair DE from the stack: the saved parameter's variable address.
53D3
CP 03H FE 03
Compare Register A (the saved type) against 03H, a string.
53D5
If the Z FLAG is set (a string parameter), JUMP to 53C5H: the last temporary in the pool is the copy of the parameter's old descriptor that PUTNEW made at 536FH; it is taken out of the pool and copied back into the variable at Register Pair DE.
53D7
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, to be added to the Stack Pointer.
53DA
ADD HL,SP 39
Add the Stack Pointer SP to Register Pair HL: HL = the address of the saved value on the stack.
53DB
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the saved value, HL = the variable's address.
53DC
GOSUB to BASIC 5CDEH, which copies Register A bytes (the value's length) from Register Pair DE (the saved value) to Register Pair HL (the variable).
53DF
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the address just past the saved value on the stack.
53E0
LD SP,HL F9
Load the Stack Pointer SP with Register Pair HL, releasing the room the saved value took.
53E1
POP AF F1
Restore Register Pair AF from the stack: Register A = the next saved parameter's type (00H for the marker pushed at 534FH).
53E2
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the marker.
53E3
If the NZ FLAG is set (another parameter was saved), LOOP back to 53D2H.
53E5
RST 20H E7
RST 20H: the Z FLAG is set if the function's result (in REG 1, type at 40AFH) is a string.
53E6
CALL Z,29C2H CC C2 29
If the Z FLAG is set (a string result), GOSUB to 29C2H in the ROM's string concatenation code, which makes the result a proper string temporary.
53E9
LD HL,(5386H) 2A 86 53
Load Register Pair HL with the 16-bit value at 5386H, the call's text pointer stored at 53AAH.
53EC
DEC HL 2B
Decrement Register Pair HL so the RST 10H that follows fetches the character after the call again.
53ED
RST 10H D7
RST 10H: move Register Pair HL on and load Register A with the character after the FN call, as the ROM's expression code expects.
53EE
POP AF F1
Restore Register Pair AF from the stack: the function's type saved at 534DH.
53EF
JUMP to the ROM's DOCNVF at 2819H, which converts the result in REG 1 to the function's type in Register A and returns to the expression code.

53F2H - INSTR

Entered from BASIC 5786H through the ROM vector 419DH. INSTR([start,]string1,string2) returns the position of string2 in string1, searching from the position start (1 if left out), or 0 if it is not there. Register Pair HL is BASIC's text pointer at the INSTR token on entry.

53F2
RST 10H D7
RST 10H: move Register Pair HL past the INSTR token; Register A holds the next character.
53F3
CALL 2335H CD 35 23
GOSUB to the ROM's FRMPRN at 2335H, which requires an opening parenthesis at Register Pair HL and evaluates the first expression into REG 1 (type at 40AFH).
53F6
RST 20H E7
RST 20H (the ROM's type test on 40AFH): the Z FLAG is set if the first expression is a string (so no start was given).
53F7
LD A,01H 3E 01
Load Register A with 01H, the default start position. LD does not change the flags.
53F9
If the NZ FLAG is set (the first expression is a number, the start), GOSUB to the ROM's CONINT at 2B1FH, which converts REG 1 to a byte in Register A (ILLEGAL FUNCTION CALL if above 255).
53FC
OR A B7
OR Register A (the start position) with itself to set the flags: the Z FLAG is set if it is 0.
53FD
If the Z FLAG is set (a start of 0), JUMP to the ROM's FCERR at 1E4AH to report ILLEGAL FUNCTION CALL.
5400
PUSH AF F5
Save Register Pair AF (Register A = the start position) on the stack.
5401
RST 20H E7
RST 20H: the Z FLAG is set if the first expression was a string (the type at 40AFH is unchanged).
5402
If the NZ FLAG is set (a start was given), GOSUB to 545DH, which requires a comma and evaluates string1 into REG 1.
5405
GOSUB to the ROM's CHKSTR at 0AF4H, which reports TYPE MISMATCH unless REG 1 holds a string.
5408
LD BC,(4121H) ED 4B 21 41
Load Register Pair BC with the 16-bit value at 4121H, REG 1: the address of string1's descriptor.
540C
PUSH BC C5
Save Register Pair BC (string1's descriptor) on the stack.
540D
GOSUB to 545DH, which requires a comma and evaluates string2 into REG 1.
5410
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (a closing parenthesis), else SYNTAX ERROR; then RST 10H moves HL on.
5411
DEFB 29H 29
Data byte 29H (a closing parenthesis), the character the RST 08H at 5410H requires after string2. RST 08H returns past this byte, to 5412H.
5412
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = string1's descriptor, and the text pointer is saved.
5413
PUSH HL E5
Save Register Pair HL (string1's descriptor) on the stack.
5414
GOSUB to the ROM's FRESTR at 29D7H, which checks REG 1 is a string, releases it if it is a temporary, and returns Register Pair HL = string2's descriptor.
5417
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = string1's descriptor, and string2's is saved.
5418
CALL 29DDH CD DD 29
GOSUB to 29DDH in the ROM's FREFAC code, which releases string1's descriptor (Register Pair HL) if it is a temporary.
541B
POP DE D1
Restore Register Pair DE from the stack: string2's descriptor.
541C
POP BC C1
Restore Register Pair BC from the stack: BASIC's text pointer.
541D
POP AF F1
Restore Register Pair AF from the stack: Register A = the start position.
541E
PUSH BC C5
Push Register Pair BC (the text pointer) back on the stack for the end.
541F
PUSH AF F5
Push Register Pair AF (Register A = the start position), which becomes the position counter.
5420
PUSH DE D5
Push Register Pair DE (string2's descriptor).
5421
LD B,(HL) 46
Load Register B with the byte at Register Pair HL, the length of string1.
5422
INC HL 23
Increment Register Pair HL to the low byte of string1's text address.
5423
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of string1's text address.
5424
INC HL 23
Increment Register Pair HL to the high byte of string1's text address.
5425
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds string1's text address.
5426
DEC A 3D
Decrement Register A: the start position minus 1, an offset into string1.
5427
LD L,A 6F
Load Register L with Register A (the offset).
5428
LD H,00H 26 00
Load Register H with 00H, so Register Pair HL = the offset.
542A
ADD HL,DE 19
Add Register Pair DE (string1's text) to Register Pair HL: HL = where the search begins in string1.
542B
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = string2's descriptor, and the search pointer is saved.
542C
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the length of string2.
542D
INC HL 23
Increment Register Pair HL to the low byte of string2's text address.
542E
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of string2's text address.
542F
INC HL 23
Increment Register Pair HL to the high byte of string2's text address.
5430
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds string2's text address.
5431
POP HL E1
Restore Register Pair HL from the stack: the search pointer into string1.
5432
SUB B 90
Subtract Register B (string1's length) from Register A (the start minus 1): the NO CARRY FLAG is set if the start lies past the end of string1.
5433
If the NO CARRY FLAG is set (nothing to search), JUMP to 5454H to return 0.
5435
NEG ED 44
NEG Register A: Register A = the characters of string1 from the start to its end.
5437
SUB C 91
Subtract Register C (string2's length) from Register A: the places left over where string2 could start, minus 1.
5438
LD B,A 47
Load Register B with Register A, that count. LD does not change the flags.
5439
If the CARRY FLAG is set (string2 is longer than what is left of string1), JUMP to 5454H to return 0.
543B
INC B 04
Increment Register B: the number of places to try.

SEARCH LOOP
Register Pair HL = the place in string1 being tried, Register Pair DE = string2's text, Register C = string2's length, Register B = the places left to try; the position counter is on the stack.

543C
PUSH HL E5
Save Register Pair HL (the place in string1 being tried) on the stack.
543D
PUSH DE D5
Save Register Pair DE (string2's text address) on the stack.
543E
PUSH BC C5
Save Register Pair BC (Register B = the places left, Register C = string2's length) on the stack.
543F
INC C 0C
Increment Register C (string2's length), so the DEC that follows gives the length again with the flags set.
5440
DEC C 0D
Decrement Register C, the characters of string2 left to compare: the Z FLAG is set when none are left.
5441
If the Z FLAG is set (all characters matched, or string2 is empty), JUMP to 5449H with the Z FLAG set.
5443
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the next character of string2.
5444
CP (HL) BE
Compare Register A with the byte at Register Pair HL, the character of string1.
5445
INC DE 13
Increment Register Pair DE to string2's next character (the flags are not changed).
5446
INC HL 23
Increment Register Pair HL to string1's next character.
5447
If the Z FLAG is set (the characters match), LOOP back to 5440H.
5449
POP BC C1
Restore Register Pair BC from the stack: the places left and string2's length.
544A
POP DE D1
Restore Register Pair DE from the stack: string2's text address.
544B
POP HL E1
Restore Register Pair HL from the stack: the place in string1 just tried. POP does not change the flags.
544C
If the Z FLAG is set (string2 was found here), JUMP to 5457H with the position on the stack.
544E
POP AF F1
Restore Register Pair AF from the stack: Register A = the position just tried.
544F
INC A 3C
Increment Register A: the next position in string1 to try.
5450
INC HL 23
Increment Register Pair HL to the next place in string1.
5451
PUSH AF F5
Push Register Pair AF (Register A = the new position) on the stack.
5452
Decrement Register B (the places left to try) and LOOP back to 543CH.
5454
POP AF F1
Not found: restore Register Pair AF from the stack, discarding the position.
5455
XOR A AF
Load Register A with 00H (XOR A with itself), the result for "not found".
5456
PUSH AF F5
Push Register Pair AF (Register A = 0) as the result position.
5457
POP AF F1
Restore Register Pair AF from the stack: Register A = the position where string2 was found, or 0.
5458
CALL 27F8H CD F8 27
GOSUB to 27F8H in the ROM's POS code, which puts Register A into REG 1 as an integer result.
545B
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer after the closing parenthesis.
545C
RET C9
RETURN to the ROM's expression code with the result in REG 1.
545D
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (a comma), else SYNTAX ERROR; then RST 10H moves HL on.
545E
DEFB 2CH 2C
Data byte 2CH (a comma), the character the RST 08H at 545DH requires between INSTR's arguments. RST 08H returns past this byte, to 545FH.
545F
JUMP to the ROM's FRMEVL at 2337H, which evaluates the next expression at Register Pair HL into REG 1 and returns to the caller of 545DH.

5462H - MID$ on the Left Side of an Assignment

Entered from BASIC 578BH through the ROM link 41D9H. MID$(var$,position[,length])=string replaces characters of var$ in place: from the position, as many as the length (the rest of var$ if left out) and the new string allow; var$ keeps its length. A string whose text lies in the program (a literal assigned earlier) is first copied to the string space so the program is not changed. Register Pair HL is BASIC's text pointer at the MID$ token on entry.

5462
RST 10H D7
RST 10H: move Register Pair HL past the MID$ token; Register A holds the next character.
5463
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (an opening parenthesis), else SYNTAX ERROR; then RST 10H moves HL to the variable name.
5464
DEFB 28H 28
Data byte 28H (an opening parenthesis), the character the RST 08H at 5463H requires after MID$. RST 08H returns past this byte, to 5465H.
5465
CALL 5EA2H CD A2 5E
GOSUB to BASIC 5EA2H, which reads the variable at Register Pair HL and returns Register Pair DE = the address of its string descriptor (TYPE MISMATCH if it is not a string), with HL after the name.
5468
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack.
5469
PUSH DE D5
Save Register Pair DE (the variable's descriptor address) on the stack.
546A
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the variable's descriptor (byte 0 = length, bytes 1-2 = text address).
546B
INC HL 23
Increment Register Pair HL to the low byte of the text address.
546C
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the variable's text address.
546D
INC HL 23
Increment Register Pair HL to the high byte of the variable's text address.
546E
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds the address of the variable's text.
546F
LD HL,(40A0H) 2A A0 40
Load Register Pair HL with the 16-bit value at 40A0H, the ROM's pointer to the start of the string space.
5472
RST 18H DF
RST 18H: compare Register Pair HL (the start of the string space) with Register Pair DE (the text address). The NO CARRY FLAG is set if the text lies below the string space, that is in the program.
5473
POP HL E1
Restore Register Pair HL from the stack: the variable's descriptor address. POP does not change the flags.
5474
PUSH HL E5
Save Register Pair HL (the descriptor address) on the stack again.
5475
If the NO CARRY FLAG is set (the text is in the program), GOSUB to BASIC 5CEBH, which copies the string into the string space and points the descriptor at Register Pair HL to the copy.
5478
POP HL E1
Restore Register Pair HL from the stack: the variable's descriptor address.
5479
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = BASIC's text pointer, and the descriptor address is saved.
547A
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (a comma), else SYNTAX ERROR; then RST 10H moves HL to the position.
547B
DEFB 2CH 2C
Data byte 2CH (a comma), the character the RST 08H at 547AH requires after the variable. RST 08H returns past this byte, to 547CH.
547C
CALL 2B1CH CD 1C 2B
GOSUB to the ROM's GETBYT at 2B1CH, which evaluates the expression at Register Pair HL and returns it as a byte (0-255) in Register A: the character position where the replacement starts.
547F
OR A B7
OR Register A (the position) with itself to set the flags: the Z FLAG is set if it is 0.
5480
If the Z FLAG is set (a position of 0), JUMP to the ROM's FCERR at 1E4AH to report ILLEGAL FUNCTION CALL.
5483
PUSH AF F5
Save Register Pair AF (Register A = the position) on the stack.
5484
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the position.
5485
CP 2CH FE 2C
Compare Register A against 2CH, a comma: a length follows.
5487
LD A,FFH 3E FF
Load Register A with FFH (255), the length used when none is given. LD does not change the flags.
5489
If the NZ FLAG is set (no comma, no length), JUMP to 548FH with Register A = 255.
548B
RST 10H D7
RST 10H: move Register Pair HL past the comma; Register A holds the next character.
548C
CALL 2B1CH CD 1C 2B
GOSUB to the ROM's GETBYT at 2B1CH: Register A = the length, the most characters to replace.
548F
PUSH AF F5
Save Register Pair AF (Register A = the length) on the stack.
5490
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (a closing parenthesis), else SYNTAX ERROR; then RST 10H moves HL on.
5491
DEFB 29H 29
Data byte 29H (a closing parenthesis), the character the RST 08H at 5490H requires. RST 08H returns past this byte, to 5492H.
5492
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (the = token), else SYNTAX ERROR; then RST 10H moves HL to the new string.
5493
DEFB D5H D5
Data byte D5H, the BASIC token for =, which the RST 08H at 5492H requires. RST 08H returns past this byte, to 5494H.
5494
GOSUB to the ROM's FRMEVL at 2337H, which evaluates the new string at Register Pair HL into REG 1.
5497
PUSH HL E5
Save Register Pair HL (BASIC's text pointer, after the statement) on the stack.
5498
GOSUB to the ROM's FRESTR at 29D7H, which checks REG 1 holds a string, releases it if it is a temporary, and returns Register Pair HL = the new string's descriptor.
549B
POP DE D1
Restore Register Pair DE from the stack: BASIC's text pointer.
549C
POP BC C1
Restore Register Pair BC from the stack: Register B = the length (pushed at 548FH as Register A).
549D
POP AF F1
Restore Register Pair AF from the stack: Register A = the position.
549E
LD C,A 4F
Load Register C with Register A, the position.
549F
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = BASIC's text pointer, DE = the new string's descriptor.
54A0
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the variable's descriptor address, and the text pointer is saved.
54A1
PUSH DE D5
Save Register Pair DE (the new string's descriptor) on the stack.
54A2
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the length of var$.
54A3
INC HL 23
Increment Register Pair HL to the low byte of var$'s text address.
54A4
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of var$'s text address.
54A5
INC HL 23
Increment Register Pair HL to the high byte of var$'s text address.
54A6
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds var$'s text address.
54A7
LD L,C 69
Load Register L with Register C, the position.
54A8
LD H,00H 26 00
Load Register H with 00H, so Register Pair HL = the position.
54AA
ADD HL,DE 19
Add Register Pair DE (var$'s text) to Register Pair HL.
54AB
DEC HL 2B
Decrement Register Pair HL: HL = the address in var$ of the first character to replace (text + position - 1).
54AC
SUB C 91
Subtract Register C (the position) from Register A (var$'s length): the CARRY FLAG is set if the position lies past the end of var$.
54AD
If the CARRY FLAG is set, JUMP to the ROM's FCERR at 1E4AH to report ILLEGAL FUNCTION CALL.
54B0
INC A 3C
Increment Register A: the characters of var$ from the position to its end.
54B1
CP B B8
Compare Register A with Register B (the length given): the NO CARRY FLAG is set if at least that many characters are there.
54B2
If the NO CARRY FLAG is set, JUMP to 54B5H, keeping Register B.
54B4
LD B,A 47
Load Register B with Register A: no more than the characters up to var$'s end are replaced.
54B5
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the new string's descriptor, and the write address in var$ is saved.
54B6
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the length of the new string.
54B7
INC HL 23
Increment Register Pair HL to the low byte of the new string's text address.
54B8
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the new string's text address.
54B9
INC HL 23
Increment Register Pair HL to the high byte of the new string's text address.
54BA
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE now holds the new string's text address.
54BB
POP HL E1
Restore Register Pair HL from the stack: the write address in var$.
54BC
CP B B8
Compare Register A (the new string's length) with Register B (the characters that may be replaced): the CARRY FLAG is set if the new string is shorter.
54BD
If the CARRY FLAG is set, JUMP to 54C0H: only the new string's length is copied.
54BF
LD A,B 78
Load Register A with Register B: only Register B characters are copied.
54C0
GOSUB to BASIC 5CDEH, which copies Register A bytes from Register Pair DE (the new string's text) to Register Pair HL (var$'s text at the position), like the ROM's VMOVEA at 09D6H.
54C3
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer after the statement.
54C4
RET C9
RETURN to BASIC with Register Pair HL = the text pointer.

54C5H - &H and &O Constants

Entered from BASIC 5790H through the ROM vector 4194H when an expression holds &. &Hdigits is hexadecimal; &Odigits or &digits is octal. The value is built in Register Pair DE (16 bits, 0-65535) and returned as an integer in REG 1; more than 16 bits is OVERFLOW. Register Pair HL is BASIC's text pointer at the & on entry.

54C5
RST 10H D7
RST 10H: move Register Pair HL past the &; Register A holds the next character (H, O or the first octal digit).
54C6
LD C,A 4F
Load Register C with Register A, the character after the &.
54C7
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value built so far.
54CA
LD A,C 79
Load Register A with Register C, the character after the &.
54CB
CP 48H FE 48
Compare Register A against 48H, the letter H.
54CD
If the NZ FLAG is set (not hexadecimal), JUMP to 54F1H for octal.

HEXADECIMAL DIGIT LOOP
Register Pair DE (swapped into HL while working) = the value so far; Register Pair HL = the text pointer.

54CF
RST 10H D7
RST 10H: move Register Pair HL to the next character; Register A holds it.
54D0
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the value so far, DE = the text pointer.
54D1
SUB 30H D6 30
Subtract 30H (the character 0) from Register A: the digits 0-9 become 00H-09H.
54D3
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for 0-9.
54D5
If the CARRY FLAG is set (a digit 0-9), JUMP to 54DFH with Register A = its value.
54D7
SUB 11H D6 11
Subtract 11H more from Register A: the letters A-F become 00H-05H.
54D9
CP 06H FE 06
Compare Register A against 06H: the CARRY FLAG is set for A-F.
54DB
If the NO CARRY FLAG is set (not a hexadecimal digit), JUMP to 54FFH: the constant ends here.
54DD
ADD A,0AH C6 0A
Add 0AH to Register A: the letters A-F become their values 10-15.
54DF
ADD HL,HL 29
Add Register Pair HL (the value) to itself: times 2.
54E0
If the CARRY FLAG is set (more than 16 bits), JUMP to 54E9H to report the overflow.
54E2
ADD HL,HL 29
Add Register Pair HL to itself: times 4 (an octal digit enters here, for times 8 in all).
54E3
If the CARRY FLAG is set (more than 16 bits), JUMP to 54E9H.
54E5
ADD HL,HL 29
Add Register Pair HL to itself: times 8 (times 4 for octal).
54E6
If the CARRY FLAG is set (more than 16 bits), JUMP to 54E9H.
54E8
ADD HL,HL 29
Add Register Pair HL to itself: times 16 in all for hexadecimal, times 8 for octal.
54E9
JP C,07B2H DA B2 07
If the CARRY FLAG is set (the value no longer fits in 16 bits), JUMP to the ROM's OVERR at 07B2H to report OVERFLOW.
54EC
ADD A,L 85
Add Register L (the low byte of the shifted value) to Register A (the digit's value).
54ED
LD L,A 6F
Load Register L with Register A: HL = the value with the new digit added (its low 3 or 4 bits were 0).
54EE
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the value, HL = the text pointer.
54EF
LOOP back to 54CAH, where Register A = Register C (still H, or O for octal) sends it to the next digit of the right kind.
54F1
LD C,4FH 0E 4F
Load Register C with 4FH, the letter O, so later digits go the octal way at 54CAH.
54F3
CP C B9
Compare Register A (the character after the &) with Register C (O).
54F4
If the Z FLAG is set (&O), JUMP to 54F7H to step past the O.
54F6
DEC HL 2B
No letter (&digits): decrement Register Pair HL so the RST 10H that follows fetches the first digit again.

OCTAL DIGIT LOOP
Same as the hexadecimal loop, but only 0-7 are digits and each digit multiplies the value by 8.

54F7
RST 10H D7
RST 10H: move Register Pair HL to the next character; Register A holds it.
54F8
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the value so far, DE = the text pointer.
54F9
SUB 30H D6 30
Subtract 30H (the character 0) from Register A: 0-7 become 00H-07H.
54FB
CP 08H FE 08
Compare Register A against 08H: the CARRY FLAG is set for an octal digit.
54FD
If the CARRY FLAG is set (an octal digit), JUMP to 54E2H to multiply the value by 8 and add it.
54FF
The constant is complete: GOSUB to the ROM's MAKINT at 0A9AH, which puts Register Pair HL (the value) into REG 1 as an integer and sets 40AFH to 02H.
5502
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = BASIC's text pointer at the first character after the constant.
5503
RET C9
RETURN to the ROM's expression code with the value in REG 1.

5504H - OPEN

Entered from BASIC 5798H through the ROM vector 4179H. OPEN "mode",file,"name"[,type][,record length]. The mode letter (I, O, E, R or D) gives the mode byte for 5700H and the open flags for BASIC 60AEH: whether the file must exist, may be created, is emptied or is positioned at its end. The optional type is two letters: the first F or M, the second I, U or F (MI, MU, MF, FI, FF); the I types have no record length (7FFFH), the others take one up to 4095, and FF and MF need one. Without a type, a random file may have a record length of 1-256 (below 256 only when BASIC was started with the V option, 64C6H = 2). The SYS10 page explains what the bits of the mode byte mean. On entry Register Pair HL is BASIC's text pointer after OPEN.

5504
CALL 61B7H CD B7 61
GOSUB to BASIC 61B7H, which evaluates the mode expression at Register Pair HL: the Z FLAG is set for a string, Register B holds its length and HL points at its text; the text pointer is left on the stack.
5507
If the NZ FLAG is set (the mode is not a string), JUMP to 552EH, which reports error 6CH BAD FILE MODE.
5509
DEC B 05
Decrement Register B, the mode string's length: the Z FLAG is set if it was exactly 1.
550A
If the NZ FLAG is set (not one character), JUMP to 552EH for BAD FILE MODE.
550C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the mode letter.
550D
LD HL,0128H 21 28 01
Load Register Pair HL with 0128H, the mode byte and flags for I (sequential input; the file must exist).
5510
CP 49H FE 49
Compare Register A (the mode letter) against 49H, the letter I.
5512
If the Z FLAG is set (mode I), JUMP to 5531H with Register Pair HL = 0128H.
5514
LD HL,8448H 21 48 84
Load Register Pair HL with 8448H, the mode byte and flags for O (sequential output; the file is emptied).
5517
CP 4FH FE 4F
Compare Register A against 4FH, the letter O.
5519
If the Z FLAG is set (mode O), JUMP to 5531H with Register Pair HL = 8448H.
551B
LD HL,8248H 21 48 82
Load Register Pair HL with 8248H, the mode byte and flags for E (sequential output added at the end of the file).
551E
CP 45H FE 45
Compare Register A against 45H, the letter E.
5520
If the Z FLAG is set (mode E), JUMP to 5531H with Register Pair HL = 8248H.
5522
LD HL,80ECH 21 EC 80
Load Register Pair HL with 80ECH, the mode byte and flags for R (random; the file is created if needed).
5525
CP 52H FE 52
Compare Register A against 52H, the letter R.
5527
If the Z FLAG is set (mode R), JUMP to 5531H with Register Pair HL = 80ECH.
5529
LD HL,01ECH 21 EC 01
Load Register Pair HL with 01ECH, the mode byte and flags for D (random; the file must exist).
552C
CP 44H FE 44
Compare Register A against 44H, the letter D.
552E
JP NZ,5DD0H C2 D0 5D
If the NZ FLAG is set (none of I, O, E, R, D), JUMP to BASIC 5DD0H, which raises error 6CH BAD FILE MODE.
5531
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): the mode bytes are saved, and HL = BASIC's text pointer after the mode.
5532
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (a comma), else SYNTAX ERROR; then RST 10H moves HL to the file number.
5533
DEFB 2CH 2C
Data byte 2CH (a comma), the character the RST 08H at 5532H requires after the mode. RST 08H returns past this byte, to 5534H.
5534
CALL 62E7H CD E7 62
GOSUB to BASIC 62E7H, which evaluates the file number at Register Pair HL, copies that file's area into the work area at 5700H (Index Register IX = 5700H, its FCB at 570DH) and requires a comma after it.
5537
POP BC C1
Restore Register Pair BC from the stack: Register C = the mode byte, Register B = the open flags (from 550DH-5529H).
5538
CALL 60AEH CD AE 60
GOSUB to BASIC 60AEH, which evaluates the file name at Register Pair HL and opens the file as Register Pair BC says (must exist, create, empty, append).
553B
LD DE,0100H 11 00 01
Load Register Pair DE with 0100H (256), the record length used when none is given.
553E
CALL 638FH CD 8F 63
GOSUB to BASIC 638FH: the Z FLAG is set if the statement ends at Register Pair HL (no type or record length).
5541
If the Z FLAG is set (nothing follows), JUMP to 55C9H to store the mode and a record length of 256.
5544
PUSH BC C5
Save Register Pair BC (the mode byte and flags) on the stack.
5545
CALL 61B7H CD B7 61
GOSUB to BASIC 61B7H, which evaluates the next parameter at Register Pair HL: the Z FLAG is set for a string (a type), Register B holds its length and HL points at its text; the text pointer is left on the stack.
5548
If the NZ FLAG is set (a number, so it is a record length), JUMP to 555AH.
554A
LD A,(HL) 7E
A type: load Register A with the byte at Register Pair HL, the type's first letter.
554B
INC HL 23
Increment Register Pair HL to the type's second letter.
554C
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the type's second letter.
554D
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer after the type.
554E
LD D,B 50
Load Register D with Register B, the length of the type string.
554F
POP BC C1
Restore Register Pair BC from the stack: Register C = the mode byte, Register B = the flags.
5550
SET 7,C CB F9
Set bit 7 of Register C, the mode byte: the file has a type.
5552
CP 46H FE 46
Compare Register A (the type's first letter) against 46H, the letter F.
5554
If the NZ FLAG is set (not F), JUMP to 557DH to check for M.
5556
SET 1,C CB C9
Set bit 1 of Register C, the mode byte: the first type letter is F.
5558
JUMP to 5583H to check the type's length in Register D.
555A
POP HL E1
A record length without a type: restore Register Pair HL from the stack, BASIC's text pointer after it.
555B
POP BC C1
Restore Register Pair BC from the stack: Register C = the mode byte, Register B = the flags.
555C
BIT 7,C CB 79
Test bit 7 of Register C, the mode byte: set for the random modes R and D.
555E
If the Z FLAG is set (a sequential mode, which takes no record length), JUMP to the ROM's SNERR at 1997H to report SYNTAX ERROR.
5561
PUSH BC C5
Save Register Pair BC (the mode byte and flags) on the stack.
5562
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack.
5563
GOSUB to the ROM's FRCINT at 0A7FH, which converts REG 1 to an integer in Register Pair HL: the record length.
5566
DEC HL 2B
Decrement Register Pair HL: the record length minus 1 (0-255 for lengths 1-256).
5567
LD A,H 7C
Load Register A with Register H, the high byte of the record length minus 1.
5568
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the length is 1-256.
5569
If the NZ FLAG is set (0, or more than 256), JUMP to 557AH for error A2H BAD RECORD LENGTH.
556B
INC HL 23
Increment Register Pair HL back to the record length.
556C
LD A,L 7D
Load Register A with Register L, the low byte of the record length.
556D
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the low byte is 0, that is a length of 256.
556E
If the Z FLAG is set (256, the sector size), JUMP to 55BFH.
5570
INC (IX+11H) DD 34 11
A length of 1-255: increment the byte at Index Register IX + 11H (5711H), the high byte of the buffer address in the FCB at 570DH, so the sector buffer is 256 bytes higher and the record buffer comes before it.
5573
LD A,(64C6H) 3A C6 64
Load Register A with the byte at 64C6H, BASIC/CMD's file area size: 2 when BASIC was started with the V option (two sectors per file area).
5576
CP 02H FE 02
Compare Register A (the file area size) against 02H, two sectors per file area.
5578
If the Z FLAG is set (the file area has room for a separate record buffer), JUMP to 55BFH.
557A
JP 5DFDH C3 FD 5D
JUMP to BASIC 5DFDH, which raises error A2H BAD RECORD LENGTH.
557D
CP 4DH FE 4D
Compare Register A (the type's first letter) against 4DH, the letter M.
557F
If the NZ FLAG is set (neither F nor M), JUMP to 5585H with the NZ FLAG set, for BAD FILE TYPE.
5581
SET 0,C CB C1
Set bit 0 of Register C, the mode byte: the first type letter is M.
5583
DEC D 15
Decrement Register D, the length of the type string.
5584
DEC D 15
Decrement Register D again: the Z FLAG is set if the type is exactly 2 letters.
5585
JP NZ,5DF1H C2 F1 5D
If the NZ FLAG is set (the type is not 2 letters, or the first is not F or M), JUMP to BASIC 5DF1H, which raises error 98H BAD FILE TYPE.
5588
RES 3,C CB 99
Reset bit 3 of Register C, the mode byte (second type letter U or F) until known.
558A
RES 2,C CB 91
Reset bit 2 of Register C, the mode byte (second type letter F) until known.
558C
LD A,E 7B
Load Register A with Register E, the type's second letter.
558D
LD DE,7FFFH 11 FF 7F
Load Register Pair DE with 7FFFH, the record length stored for an I type.
5590
CP 49H FE 49
Compare Register A (the second letter) against 49H, the letter I.
5592
If the Z FLAG is set (MI or FI), JUMP to 55C9H with Register Pair DE = 7FFFH.
5594
LD DE,0FFFH 11 FF 0F
Load Register Pair DE with 0FFFH (4095), the longest record length for the other types.
5597
BIT 1,C CB 49
Test bit 1 of Register C, the mode byte: set if the first letter is F.
5599
If the NZ FLAG is set (F: only FF is left), JUMP to 559FH.
559B
CP 55H FE 55
Compare Register A (the second letter) against 55H, the letter U.
559D
If the Z FLAG is set (the type is MU), JUMP to 55A5H.
559F
CP 46H FE 46
Compare Register A (the second letter) against 46H, the letter F.
55A1
If the NZ FLAG is set (not a valid second letter), JUMP to 5585H with the NZ FLAG set, for BAD FILE TYPE.
55A3
SET 2,C CB D1
Set bit 2 of Register C, the mode byte: the second type letter is F (fixed-length records).
55A5
SET 3,C CB D9
Set bit 3 of Register C, the mode byte: the second type letter is U or F.
55A7
CALL 638FH CD 8F 63
GOSUB to BASIC 638FH: the Z FLAG is set if the statement ends at Register Pair HL (no record length).
55AA
If the Z FLAG is set (no record length), JUMP to 55C4H.
55AC
PUSH BC C5
Save Register Pair BC (the mode byte and flags) on the stack.
55AD
CALL 61B7H CD B7 61
GOSUB to BASIC 61B7H, which evaluates the record length at Register Pair HL (the Z FLAG is set for a string), leaving the text pointer on the stack.
55B0
JP Z,5DFDH CA FD 5D
If the Z FLAG is set (a string, or from 55BDH a length of 0), JUMP to BASIC 5DFDH, which raises error A2H BAD RECORD LENGTH.
55B3
GOSUB to the ROM's FRCINT at 0A7FH: Register Pair HL = the record length as an integer.
55B6
LD A,H 7C
Load Register A with Register H, the high byte of the record length.
55B7
CP 10H FE 10
Compare Register A against 10H: the NO CARRY FLAG is set for 4096 or more.
55B9
JP NC,5DFDH D2 FD 5D
If the NO CARRY FLAG is set (too long), JUMP to BASIC 5DFDH for error A2H BAD RECORD LENGTH.
55BC
OR L B5
OR Register A (the high byte) with Register L (the low byte): the Z FLAG is set if the length is 0.
55BD
If the Z FLAG is set (a length of 0), JUMP to 55B0H, where the Z FLAG leads to BAD RECORD LENGTH.
55BF
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the record length.
55C0
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer.
55C1
POP BC C1
Restore Register Pair BC from the stack: Register C = the mode byte, Register B = the flags.
55C2
JUMP to 55C9H to store the record length in Register Pair DE and the mode in Register Pair BC.
55C4
BIT 2,C CB 51
No record length was given: test bit 2 of Register C, the mode byte (set for fixed-length records, types FF and MF).
55C6
JP NZ,5DFDH C2 FD 5D
If the NZ FLAG is set (FF or MF, which need a record length), JUMP to BASIC 5DFDH for error A2H BAD RECORD LENGTH.
55C9
LD (5702H),DE ED 53 02 57
Store Register Pair DE (the record length: 256, 7FFFH, 4095 or the one given) at 5702H-5703H in the file work area.
55CD
LD (5700H),BC ED 43 00 57
Store Register Pair BC at 5700H-5701H in the file work area: Register C (the mode byte) at 5700H, Register B (the flags) at 5701H.
55D1
JUMP to the ROM's FINPRT at 2169H, which ends the statement.

55D4H - INPUT# and READ Items from a File

Entered from BASIC 579AH through the ROM link 41DCH, which the ROM's INPUT and READ code calls when it is about to assign an item. BASIC 63A9H returns straight to the ROM unless an INPUT# is reading a file; otherwise the next item is read from the file into BASIC's input buffer (5621H) and the ROM's READ code assigns it to the variable.

55D4
CALL 63A9H CD A9 63
GOSUB to BASIC 63A9H, which drops this return and goes back to the ROM unless INPUT# is reading a file.
55D7
POP AF F1
Restore Register Pair AF from the stack: the flags the ROM pushed for the variable being assigned (Z for a string variable).
55D8
LD D,03H 16 03
Load Register D with 03H, the item rules for a string (bit 0: skip leading spaces and end at a comma; bit 1: quotes allowed).
55DA
RST 20H E7
RST 20H (the ROM's type test on 40AFH): the Z FLAG is set if the variable is a string.
55DB
If the Z FLAG is set (a string variable), JUMP to 55DFH with Register D = 03H.
55DD
LD D,05H 16 05
Load Register D with 05H, the item rules for a number (bit 0: skip leading spaces and end at a comma; bit 2: a space ends it).
55DF
PUSH AF F5
Save Register Pair AF (the variable's type flags) on the stack.
55E0
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack.
55E1
GOSUB to 5621H, which reads the next item from the file with the rules in Register D and turns it into a string or number.
55E4
POP HL E1
Restore Register Pair HL from the stack: BASIC's text pointer.
55E5
JP 2243H C3 43 22
JUMP to 2243H in the ROM's READ code, which assigns the item to the variable.

55E8H - LINE INPUT

Entered from BASIC 579FH through the ROM vector 41A3H (the LINE token). LINE INPUT ["prompt";]var$ reads a whole line from the keyboard (BREAK stops the program); LINE INPUT#file,var$ reads a whole line from a file. Either way the line goes into var$ unchanged, commas and quotes included. On entry Register Pair HL is BASIC's text pointer after LINE.

55E8
RST 08H CF
RST 08H: the character at Register Pair HL must be the byte that follows (the INPUT token), else SYNTAX ERROR; then RST 10H moves HL on.
55E9
DEFB 89H 89
Data byte 89H, the BASIC token for INPUT, which the RST 08H at 55E8H requires after LINE. RST 08H returns past this byte, to 55EAH.
55EA
GOSUB to the ROM's ERRDIR at 2828H, which reports ILLEGAL DIRECT if the statement is typed as a direct command.
55ED
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after LINE INPUT.
55EE
CP 23H FE 23
Compare Register A against 23H, the character #.
55F0
If the Z FLAG is set (LINE INPUT#), JUMP to 560EH.
55F2
CALL 21CDH CD CD 21
GOSUB to 21CDH in the ROM's INPUT code, which shows the prompt string at Register Pair HL if there is one.
55F5
CALL 5EA2H CD A2 5E
GOSUB to BASIC 5EA2H: Register Pair DE = the address of the string variable at Register Pair HL (TYPE MISMATCH if it is not a string).
55F8
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack.
55F9
PUSH DE D5
Save Register Pair DE (the variable's address) on the stack.
55FA
GOSUB to the ROM's INLIN at 0361H, which reads a line from the keyboard into the input buffer; Register Pair HL returns one byte before the line, as STRLIT wants it, and the CARRY FLAG is set if BREAK was pressed.
55FD
If the CARRY FLAG is set (BREAK), JUMP to 5609H.
55FF
LD B,00H 06 00
Load Register B with 00H, the end character for STRLIT (the line ends with 00H).
5601
GOSUB to 2868H in the ROM's STRLIT, which makes the text at Register Pair HL into a string result in REG 1.
5604
POP HL E1
Restore Register Pair HL from the stack: the variable's address.
5605
XOR A AF
Load Register A with 00H (XOR A with itself).
5606
JUMP to 1F33H in the ROM's LET, which assigns the string in REG 1 to the variable at Register Pair HL.
5609
POP AF F1
BREAK: restore Register Pair AF from the stack, discarding the variable's address.
560A
POP AF F1
Restore Register Pair AF from the stack, discarding BASIC's text pointer.
560B
JUMP to 1DBEH in the ROM's END/STOP code: the program stops as it does for BREAK.
560E
CALL 5F5DH CD 5D 5F
LINE INPUT#: GOSUB to BASIC 5F5DH, which reads the file number at Register Pair HL and selects that file for input.
5611
CALL 5EA2H CD A2 5E
GOSUB to BASIC 5EA2H: Register Pair DE = the address of the string variable.
5614
LD BC,2169H 01 69 21
Load Register Pair BC with 2169H, the ROM's FINPRT, which ends the statement.
5617
PUSH BC C5
Push Register Pair BC (2169H): the assignment at 1F33H returns there.
5618
PUSH HL E5
Save Register Pair HL (BASIC's text pointer) on the stack.
5619
PUSH DE D5
Save Register Pair DE (the variable's address) on the stack.
561A
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: the item is a string.
561B
LD D,A 57
Load Register D with Register A (00H): no item rules, the whole line is read.
561C
GOSUB to 5621H, which reads the line from the file into a string in REG 1.
561F
JUMP to 5604H to assign the string in REG 1 to the variable.

5621H - Read an Item from a File

Reads characters through BASIC 6119H (from the file open for input) into the input buffer (its address at 40A7H), at most 255. Register D holds the rules: bit 0 = skip leading spaces, and a comma or a line feed ends the item; bit 1 = quotes allowed (a quoted string may hold commas); bit 2 = a space ends the item; bit 3 = inside quotes (set here). A carriage return ends the item; a line feed after it is taken with it. A character read one too far is given back (the FCB is moved back one byte with SYS0 4445H and an LRL of 1). The end of the file is error 7CH INPUT PAST END. The item is then made a string (the ROM's STRLIT at 2868H) or a number (the ROM's FIN at 0E6CH). Register Pair AF on entry holds the Z FLAG for a string item.

5621
PUSH AF F5
Save Register Pair AF (Register A and the flags; the Z FLAG is set for a string item) on the stack.
5622
LD HL,(40A7H) 2A A7 40
Load Register Pair HL with the 16-bit value at 40A7H, the ROM's pointer to the input buffer, where the item is collected.
5625
LD B,FFH 06 FF
Load Register B with FFH (255), the most characters the item may hold.
5627
LD C,B 48
Load Register C with Register B (FFH): Register C holds the previous character, and FFH means there is none yet.
5628
PUSH HL E5
Save Register Pair HL (the start of the input buffer) on the stack.

SKIP LEADING SPACES
Register D = the item rules; Register A = the character just read.

5629
CALL 6119H CD 19 61
GOSUB to BASIC 6119H, which reads the next character of the file into Register A; the NZ FLAG is set at the end of the file.
562C
JP NZ,5DD6H C2 D6 5D
If the NZ FLAG is set (the end of the file), JUMP to BASIC 5DD6H, which raises error 7CH INPUT PAST END.
562F
CP 20H FE 20
Compare Register A (the character) against 20H, a space.
5631
If the NZ FLAG is set (not a space), JUMP to 5637H.
5633
BIT 0,D CB 42
Test bit 0 of Register D, the rule "skip leading spaces".
5635
If the NZ FLAG is set (leading spaces are skipped), LOOP back to 5629H for the next character.
5637
CP 22H FE 22
Compare Register A (the character) against 22H, a quote.
5639
If the NZ FLAG is set (not a quote), JUMP to 5643H.
563B
BIT 1,D CB 4A
Test bit 1 of Register D, the rule "quotes allowed".
563D
If the Z FLAG is set (quotes are not special), JUMP to 5643H to treat it as an ordinary character.
563F
SET 3,D CB DA
Set bit 3 of Register D: inside quotes, where commas do not end the item.
5641
JUMP to 5667H to read on; the opening quote is not stored.

CHARACTER LOOP
Register Pair HL = where the next character goes in the input buffer, Register B = the room left, Register C = the previous character, Register D = the rules.

5643
CP 0DH FE 0D
Compare Register A (the character) against 0DH, a carriage return.
5645
If the Z FLAG is set (a carriage return), JUMP to 5683H, which ends the item.
5647
CP 20H FE 20
Compare Register A (the character) against 20H, a space.
5649
If the NZ FLAG is set (not a space), JUMP to 564FH.
564B
BIT 2,D CB 52
Test bit 2 of Register D, the rule "a space ends the item".
564D
If the NZ FLAG is set (a space ends a number), JUMP to 5673H to look at what follows.
564F
CP 2CH FE 2C
Compare Register A (the character) against 2CH, a comma.
5651
If the NZ FLAG is set (not a comma), JUMP to 5657H.
5653
BIT 0,D CB 42
Test bit 0 of Register D, the rule "a comma ends the item".
5655
If the NZ FLAG is set (it does), JUMP to 569AH to end the item.
5657
CP 0AH FE 0A
Compare Register A (the character) against 0AH, a line feed.
5659
If the NZ FLAG is set (not a line feed), JUMP to 565FH.
565B
BIT 0,D CB 42
Test bit 0 of Register D, the rule that also skips line feeds.
565D
If the NZ FLAG is set (line feeds are skipped), JUMP to 5667H without storing it.
565F
OR A B7
OR Register A (the character) with itself to set the flags: the Z FLAG is set for a 00H byte.
5660
If the Z FLAG is set (00H), JUMP to 5667H: 00H bytes are not stored.
5662
LD (HL),A 77
Store Register A (the character) at Register Pair HL in the input buffer.
5663
INC HL 23
Increment Register Pair HL to the next place in the input buffer.
5664
DEC B 05
Decrement Register B, the room left in the item.
5665
If the Z FLAG is set (255 characters stored), JUMP to 569AH to end the item.
5667
LD C,A 4F
Load Register C with Register A: the character just handled becomes the previous character.
5668
GOSUB to 56A7H, which reads the next character into Register A (and ends the item at the end of the file).
566B
BIT 3,D CB 5A
Test bit 3 of Register D: set while inside quotes.
566D
If the Z FLAG is set (not inside quotes), LOOP back to 5643H to check the character.
566F
CP 22H FE 22
Inside quotes: compare Register A against 22H, the closing quote.
5671
If the NZ FLAG is set (not the closing quote), JUMP to 565FH to store the character, whatever it is.

AFTER THE ITEM
After a closing quote, or a space ending a number, skip spaces and look for the separator.

5673
GOSUB to 56A7H: Register A = the next character.
5676
CP 20H FE 20
Compare Register A (the character after the item) against 20H, a space.
5678
LD C,A 4F
Load Register C with Register A, the previous character now. LD does not change the flags.
5679
If the Z FLAG is set (a space), LOOP back to 5673H.
567B
CP 2CH FE 2C
Compare Register A (the character after the item) against 2CH, a comma.
567D
If the Z FLAG is set (the comma after the item), JUMP to 569AH to end the item.
567F
CP 0DH FE 0D
Compare Register A against 0DH, a carriage return.
5681
If the NZ FLAG is set (another character, which belongs to the next item), JUMP to 568FH to give it back to the file.
5683
LD A,C 79
A carriage return: load Register A with Register C, the previous character.
5684
CP 0AH FE 0A
Compare Register A (the previous character) against 0AH, a line feed.
5686
If the Z FLAG is set (the carriage return came after a line feed), JUMP to 565BH, which skips it for items and stores it for LINE INPUT#.
5688
GOSUB to 56A7H: Register A = the character after the carriage return.
568B
CP 0AH FE 0A
Compare Register A (the character after the carriage return) against 0AH, a line feed.
568D
If the Z FLAG is set (a line feed follows), JUMP to 569AH: it is taken with the carriage return and the item ends.
568F
LD A,01H 3E 01
Load Register A with 01H, the record length for giving back one character.
5691
LD (5716H),A 32 16 57
Store Register A (01H) at 5716H, the LRL byte (logical record length) of the FCB at 570DH, so a record is one byte.
5694
LD DE,4445H 11 45 44
Load Register Pair DE with 4445H, SYS0's vector that moves an FCB back one record.
5697
GOSUB to BASIC 6245H, which calls the SYS0 routine in Register Pair DE (4445H) for the file, giving the character just read back to the file.
569A
LD B,00H 06 00
Load Register B with 00H, the byte that ends the item in the input buffer.
569C
LD (HL),B 70
Store Register B (00H) at Register Pair HL, ending the item in the input buffer.
569D
POP HL E1
Restore Register Pair HL from the stack: the start of the input buffer (pushed at 5628H).
569E
POP AF F1
Restore Register Pair AF from the stack: the Z FLAG is set for a string item (pushed at 5621H).
569F
DEC HL 2B
Decrement Register Pair HL, one before the item's first character.
56A0
If the Z FLAG is set (a string item), JUMP to 2868H in the ROM's STRLIT, which makes the text after Register Pair HL, ending at 00H (Register B), into a string in REG 1.
56A3
RST 10H D7
A number: RST 10H moves Register Pair HL to the item's first non-blank character, in Register A.
56A4
JUMP to the ROM's FIN at 0E6CH, which converts the digits at Register Pair HL into a number in REG 1.
56A7
CALL 6119H CD 19 61
GOSUB to BASIC 6119H, which reads the next character of the file into Register A; the NZ FLAG is set at the end of the file.
56AA
RET Z C8
If the Z FLAG is set (a character was read), RETURN with it in Register A.
56AB
POP AF F1
The end of the file: restore Register Pair AF from the stack, discarding this routine's return address.
56AC
JUMP to 569AH: the item ends at the end of the file.

56AEH - Unused Bytes

56AEH-56E7H fill the last load record; nothing reads or executes them.

56AE-56E7
NOP x 58 00 x 58
58 zero bytes that fill the end of the file (up to 56E7H). No code jumps, calls or reads here.