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

Page Customization

Introduction/Summary

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

SYS20/SYS carries out a set of Disk BASIC statements and functions. It loads 5200H-56E7H in five load records (transfer address 5200H); the code ends at 56ADH and 56AEH-56E7H are 58 bytes of 00H. It is one of the BASIC overlays that BASIC/CMD loads at 5200H through its loader at 576CH (RST 28H code 36H, from 5782H). 5200H itself only returns with the Z FLAG set; BASIC/CMD then jumps to the entry it put in Register Pair BC. The page shows every byte of the file once, in address order.

Entries

EntryFrom BASIC/CMD and what it does
5202H CMD"command"57A4H (from the CMD link 57ECH, a string of two or more characters not ending in $, copied to the command buffer 4225H). CMD"S=command" leaves BASIC through SYS0/SYS 4405H. CMD"F=name" runs a function from BASIC/CMD's table at 592BH (POPS, POPR, POPN here; ERASE, KEEP, SASZ, SWAP, SS in BASIC/CMD). Anything else runs through DOS-CALL 4419H, first under MINI-DOS (428AH bit 7); if the DOS answers error 38H, 5200H-70FFH is copied below the stack, the command runs as a full DOS command, the memory is copied back and a checksum of 7100H to the top of memory must be unchanged (else DOS error 23H Memory Fault).
5316H, 5324H, 5334HCMD"F=POPS" empties BASIC's stack; CMD"F=POPR" drops the latest GOSUB (RETURN WITHOUT GOSUB if there is none); CMD"F=POPN" [var] drops the latest FOR loop, or that of var (NEXT WITHOUT FOR if there is none). Each goes on with the next statement (ROM 1D25H).
534AH FN577FH (link 4155H). Saves each parameter variable, assigns the arguments, evaluates the DEF's expression and gives the parameters their old values back. The call's and the DEF's separators must match. UNDEFINED USER FUNCTION if no DEF FN has run.
53F2H INSTR5786H (link 419DH). INSTR([start,]string1,string2): the position of string2 in string1 from start (1 if left out; 0 is ILLEGAL FUNCTION CALL), or 0.
5462H MID$=578BH (link 41D9H). MID$(var$,position[,length])=string replaces characters of var$ in place; var$ keeps its length. A string whose text lies in the program is copied to the string space first (BASIC 5CC4H).
54C5H &H, &O5790H (link 4194H). &H hexadecimal, &O or & alone octal; an integer result up to 16 bits, OVERFLOW above.
5504H OPEN5795H (link 4179H). OPEN "mode",file,"name"[,type][,record length]. Modes I, O, E (sequential), R and D (random; D needs an existing file). Types MI, MU, MF, FI, FF; the I types have no record length (7FFFH), U and F take 1-4095 (4095 if left out), MF and FF must have one. A plain random file takes 1-256, below 256 only when the file areas have room for a record buffer (649FH = 02H).
55D4H INPUT# item579AH (link 41DCH, called by the ROM at 222DH for each item of INPUT and READ). Only during a file statement (BASIC 6382H): the item is read from the file at 5621H and assigned by the ROM at 2243H.
55E8H LINE INPUT579FH (link 41A3H, the LINE token). LINE INPUT ["prompt";]var$ reads a line from the keyboard (BREAK stops the program); LINE INPUT#file,var$ reads one from the file. Not as a direct command.

5621H reads an item from the file through BASIC 60F2H into the ROM's input buffer, at most 255 characters. Register D holds the rules: bit 0 skips leading spaces and line feeds and lets a comma end the item, bit 1 lets quotes enclose it, bit 2 lets a space end it; a string item uses 03H, a number 05H, LINE INPUT# 00H. A carriage return ends the item unless it follows a line feed, and a line feed after it is taken with it. A character read past the item is given back with SYS0/SYS 4445H. The end of the file before an item starts is INPUT PAST END; inside an item it ends the item.

Variables

ROM Addresses

Address
Size
Contents
40A0H-40A1H
2 bytes
String Space Start
BASIC's stack lies just below it (531BH); compared with a string's text at 546FH.
40A7H-40A8H
2 bytes
Input Buffer
Where an item from a file is collected (5622H).
40AFH
1 byte
Value Type
02H integer, 03H string, 04H single, 08H double; tested with RST 20H.
40B1H-40B2H
2 bytes
Top of Memory
The end of the checksum (52B5H).
40B3H-40B4H
2 bytes
Temporary Pointer
The next free string temporary descriptor (53B0H, 53C8H).
40D3H-40D5H
3 bytes
DSCTMP
The descriptor work area (53C2H).
40FDH-40FEH
2 bytes
STREND
The end of the arrays (523AH).
4121H-4122H
2 bytes
REG 1
A string result's descriptor address (53B4H, 5408H).

DOS Addresses

Address
Size
Contents
4225H-4274H
80 bytes
Command Buffer
The CMD string (up to 79 characters), ended by 0DH (526BH; 4226H is the second character).
428AH
1 byte
Overlay Flags
Bit 7 MINI-DOS, set at 520FH and cleared at 5217H.
4300H-43FFH
256 bytes
Sector Buffer
43FCH is the temporary stack at 527FH.

BASIC/CMD Addresses

Address
Size
Contents
5700H-5701H
2 bytes
Mode and Flags
Of the file area's header copy, stored at 55CDH.
5702H-5703H
2 bytes
Record Length
Stored at 55C9H.
5711H
1 byte
FCB Buffer High Byte
FCB + 4; incremented at 5570H for a record buffer.
5716H
1 byte
FCB Record Length
FCB + 9; set to 01H at 5691H to give back one character.
649FH
1 byte
File Area Size
High byte of 012DH or 022DH: 02H gives room for a record buffer (5573H).

Operands Changed at Run Time

Address
Size
Contents
5272H-5273H
2 bytes
Copy Start
Operand of 5271H, stored at 5236H.
5275H-5276H
2 bytes
Saved Area Start
Operand of 5274H (5200H), read at 5245H.
5278H-5279H
2 bytes
Saved Area Length
Operand of 5277H (1F00H), read at 522FH.
5290H-5291H
2 bytes
BASIC Stack
Operand of 528FH, stored at 5224H.
52C9H-52CAH
2 bytes
Checksum Window
Operand of 52C8H, stored at 522CH, read at 529AH and 52A7H.
5386H-5387H
2 bytes
Text Pointer
Operand of 5385H: the DEF's text (5366H) or the call's (53AAH, read at 53E9H).

Outside Routines and Tables

WhereAddresses
ROM0361H (INLIN), 07B2H (OVERR), 0A7FH (CINT), 0A9AH, 0AF4H, 0E6CH (FIN), 1936H (FNDFOR), 197AH (OMERR), 1997H (SNERR), 199DH (NFERR), 1D25H (NEWSTT), 1DBEH, 1E4AH (FCERR), 1EEAH, 1F2BH and 1F33H (LET), 2169H (FINPRT), 21CDH, 2243H, 2335H (FRMPRN), 2337H (FRMEVL), 260DH (PTRGET), 27F8H, 2819H, 2828H (ERRDIR), 2843H, 2868H (STRLIT), 2888H, 29C2H, 29D7H (FRESTR), 29DDH, 29F5H (FRETMS), 2B1CH (GETBYT), 2B1FH (CONINT); RST 08H, RST 10H, RST 18H, RST 20H.
SYS0/SYS4405H (enter DOS), 4409H (error exit), 4416H (keep the drives turning), 4419H (DOS-CALL), 4445H (back one record).
BASIC/CMD5824H and 5831H (function names), 5CB7H (copy), 5CC4H, 5DA0H, 5DA9H, 5DAFH, 5DC7H, 5DCAH, 5DD6H (errors), 5DEFH (DOS error), 5E7BH (string variable), 5F36H, 6087H (open), 60F2H (read a byte), 6190H, 621EH, 62C0H, 6368H, 6382H.
BASIC/CMD table592BH, the CMD"F=" table: length, name and address per entry, 00H at the end (52EDH).

Disassembly

5200H - Load Entry

BASIC/CMD loads SYS20/SYS through its overlay loader at 576CH with RST 28H code 36H (function 1 of directory slot 16H) into 5200H-56E7H. After loading, the SYS0/SYS 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/SYS 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's CMD link 57ECH has evaluated the string, pushed its text pointer (57EFH), copied the string in upper case to SYS0/SYS's command buffer at 4225H (ending with 0DH) and pushed its length count at 57A4H; Register Pair HL holds 4225H. 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 592BH); 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 4225H, the address of the command in SYS0/SYS's command buffer.
5204
LD E,L 5D
Load Register E with Register L. Register Pair DE now holds 4225H, the first character of the command.
5205
INC HL 23
Increment Register Pair HL to 4226H, 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,428AH 21 8A 42
Load Register Pair HL with 428AH, the overlays' flag byte in SYS0/SYS (bit 7 MINI-DOS, bit 6 DOS-CALL): under MINI-DOS only commands that leave the memory of the program alone are allowed.
520F
SET 7,(HL) CB FE
Set bit 7 of the byte at Register Pair HL (428AH): the command is run in MINI-DOS mode, so BASIC stays in memory.
5211
PUSH HL E5
Save Register Pair HL (428AH) on the stack so the bit can be cleared afterwards.
5212
EX DE,HL EB
Exchange Register Pairs DE and HL: HL now holds 4225H, the command, as DOS-CALL wants it.
5213
GOSUB to SYS0/SYS 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: 428AH, SYS0/SYS's DOS state byte.
5217
RES 7,(HL) CB BE
Reset bit 7 of the byte at Register Pair HL (428AH): 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 57EFH).
521A
If the CARRY FLAG is set (the DOS displayed its error itself), JUMP to BASIC 5DC7H, 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
If the NZ FLAG is set (some other DOS error), JUMP to BASIC 5DEFH, 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/SYS.
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/SYS 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 Register Pair BC bytes (1F00H) from Register Pair HL (5200H) to Register Pair DE (the copy's start), saving BASIC's memory 5200H-70FFH, SYS20/SYS 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, near the top of 5200H-70FFH just saved: the DOS command's stack lies in memory that is copied back afterwards, not above 7100H where the checksum looks.
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,4225H 21 25 42
Load Register Pair HL with 4225H, the command in SYS0/SYS's command buffer.
526E
JUMP to SYS0/SYS 4419H, DOS-CALL, to run the command at Register Pair HL, now as a full DOS command (bit 7 of 428AH 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/SYS. 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 Register Pair BC bytes (1F00H) from Register Pair HL (the saved copy) to Register Pair DE (5200H), restoring BASIC/CMD's memory, SYS20/SYS included.
527C
JUMP to 527FH, now in the restored SYS20/SYS at its own address.
527F
LD SP,43FCH 31 FC 43
Load the Stack Pointer SP with 43FCH, a temporary stack in SYS0/SYS's sector buffer 4300H-43FFH, 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/SYS 4409H, the DOS error exit, with Register A = 23H.
528B
GOSUB to SYS0/SYS 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
If the CARRY FLAG is set (the DOS displayed its error), JUMP to BASIC 5DC7H, which raises BASIC error 94H PREVIOUSLY DISPLAYED ERROR.
5296
If the NZ FLAG is set (the command ended with a DOS error in Register A), JUMP to BASIC 5DEFH 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 (4225H) and Register Pair HL at the = (4226H); 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 592BH, 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 4227H, 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/SYS 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,592BH 11 2B 59
Load Register Pair DE with 592BH, 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 57EFH).
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 592BH 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: Register Pair DE is then not 0000H and matches no loop variable, so FNDFOR passes over every FOR frame and stops at the first frame that is not one.
5327
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
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
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
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 5824H) 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
GOSUB to BASIC 5824H, 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
If the Z FLAG is set (the function was never defined), JUMP to BASIC 5DA0H, 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 => 28H CF 28
RST 08H with the byte 28H: the character at Register Pair HL (the DEF's text after the name) must be an opening parenthesis, as in the call, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.

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 5831H, 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
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 5CB7H, 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
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 => 2CH CF 2C
RST 08H with the byte 2CH: the character at Register Pair HL (the DEF's text) must be a comma before the next parameter, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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 => D5H CF D5
RST 08H with the byte D5H: the character at Register Pair HL (the DEF's text) must be the = token D5H, so HL then reaches the function's expression, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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 the ROM at 2843H, which copies the string of the descriptor at Register Pair HL (the result) into new string space (GETSPA 28BFH) and builds the copy's descriptor at DSCTMP 40D3H.
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
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 Register Pair 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 5CB7H, 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 the ROM at 29C2H, which goes on at PUTNEW 2884H: the descriptor at DSCTMP 40D3H becomes the next string temporary (40B3H) and REG 1 (4121H) points at it, type 03H at 40AFH.
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
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 at 0AF4H, which gives TYPE MISMATCH unless REG 1 (4121H) holds a string (the type at 40AFH is 03H): string1 must be 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 => 29H CF 29
RST 08H with the byte 29H: the character at Register Pair HL (BASIC's text after string2) must be a closing parenthesis, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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
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
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 => 2CH CF 2C
RST 08H with the byte 2CH: the character at Register Pair HL (BASIC's text) must be a comma; 545FH then evaluates the expression after it, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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 => 28H CF 28
RST 08H with the byte 28H: the character at Register Pair HL (BASIC's text after MID$) must be an opening parenthesis, so HL then reaches the variable's name, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
5465
GOSUB to BASIC 5E7BH, 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 5CC4H, 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 => 2CH CF 2C
RST 08H with the byte 2CH: the character at Register Pair HL (BASIC's text after the variable) must be a comma before the position, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
547C
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
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 => 29H CF 29
RST 08H with the byte 29H: the character at Register Pair HL (BASIC's text after the position or length) must be a closing parenthesis, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
5492
RST 08H => D5H CF D5
RST 08H with the byte D5H: the character at Register Pair HL (BASIC's text) must be the = token D5H before the new string, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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 5CB7H, 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
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
Not a digit of the right kind: GOSUB to the ROM at 0A9AH, which stores Register Pair HL (the value) in REG 1 (4121H) as an integer and sets the type at 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 5795H 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 6087H: 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, 649FH = 2). The mode byte (5700H): bit 7 random, 6 writable, 5 readable, 3 set by the types U and F (and by every mode letter), 2 fixed-length records, 1 first letter F, 0 first letter M; the open flags (5701H after AND F8H): bit 7 the file may be extended, bit 2 it is emptied, bit 1 it starts at its end, bit 0 (open only) an existing file only. On entry Register Pair HL is BASIC's text pointer after OPEN.

5504
GOSUB to BASIC 6190H, 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 for I: Register H = 01H, the open flags (bit 0: an existing file only); Register L = 28H, the mode byte (bit 5 readable, and bit 3, the bit the types U and F set).
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 for O: Register H = 84H, the open flags (bit 7 the file may be extended, bit 2 it is emptied); Register L = 48H, the mode byte (bit 6 writable, and bit 3).
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 for E: Register H = 82H, the open flags (bit 7 the file may be extended, bit 1 it starts at its end); Register L = 48H, the mode byte (bit 6 writable, and bit 3).
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 for R: Register H = 80H, the open flags (bit 7 the file may be extended; a new or an existing file); Register L = ECH, the mode byte (bit 7 random, 6 writable, 5 readable, 3, and 2 fixed-length records).
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 for D: Register H = 01H, the open flags (bit 0: an existing file only); Register L = ECH, the mode byte (bit 7 random, 6 writable, 5 readable, 3, and 2 fixed-length records).
552C
CP 44H FE 44
Compare Register A against 44H, the letter D.
552E
If the NZ FLAG is set (none of I, O, E, R, D), JUMP to BASIC 5DA9H, 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 => 2CH CF 2C
RST 08H with the byte 2CH: the character at Register Pair HL (BASIC's text after the mode) must be a comma before the file number, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
5534
GOSUB to BASIC 62C0H, which reads the file number at Register Pair HL, sets up the file statement (6382H = C9H, STMT USES 2 FILE AREAS if one is running), copies that file area's 2DH-byte header to 5700H (Index Register IX = 5700H, the FCB at 570DH) and requires a comma after the number.
5537
POP BC C1
Restore Register Pair BC from the stack: Register C = the mode byte, Register B = the open flags (Register Pair HL loaded at 550DH-5529H).
5538
GOSUB to BASIC 6087H, 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
GOSUB to BASIC 6368H: 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
GOSUB to BASIC 6190H, 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's random bit: a file with a type is read and written with GET and PUT.
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 CINT at 0A7FH, which converts the record length in REG 1 (4121H) to an integer in Register Pair HL (OVERFLOW if it does not fit).
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,(649FH) 3A 9F 64
Load Register A with the byte at 649FH, 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
JUMP to BASIC 5DD6H, 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
If the NZ FLAG is set (the type is not 2 letters, or the first is not F or M), JUMP to BASIC 5DCAH, 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,FFFH 11 FF 0F
Load Register Pair DE with 0FFFH (4095), the record length of a U or F type when none is given (for MF and FF one must be given, 55C4H).
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
GOSUB to BASIC 6368H: 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
GOSUB to BASIC 6190H, 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
If the Z FLAG is set (a string, or from 55BDH a length of 0), JUMP to BASIC 5DD6H, which raises error A2H BAD RECORD LENGTH.
55B3
GOSUB to the ROM's CINT at 0A7FH, which converts the record length in REG 1 (4121H) to an integer in Register Pair HL (OVERFLOW if it does not fit).
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
If the NO CARRY FLAG is set (too long), JUMP to BASIC 5DD6H 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
If the NZ FLAG is set (FF or MF, which need a record length), JUMP to BASIC 5DD6H 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, with the type bits) at 5700H, Register B (the open flags AND F8H, as BASIC 60DEH left them) 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 at 222DH for each item it reads. BASIC 6382H 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
GOSUB to BASIC 6382H, 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, discarding the return address 2230H of the ROM's CALL 41DCH at 222DH: SYS20/SYS reads the item itself and goes on at ROM 2243H.
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 flags of the type test) on the stack, as the ROM's PUSH AF at 2231H does; ROM 2243H pops it.
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
JUMP to ROM 2243H in the READ code: POP AF, then the item in REG 1 (4121H) is assigned to the variable whose address the ROM pushed at 222CH, and the ROM goes on with the next item.

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 => 89H CF 89
RST 08H with the byte 89H: the character at Register Pair HL (BASIC's text after LINE) must be the INPUT token 89H, else the ROM gives SYNTAX ERROR; RST 08H then steps Register Pair HL to the next character and loads it into Register A.
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
GOSUB to 21CDH in the ROM's INPUT code, which shows the prompt string at Register Pair HL if there is one.
55F5
GOSUB to BASIC 5E7BH: 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 into the ROM's STOP code at 1DBEH (the bytes F6H FFH of its LD HL,FFF6H at 1DBDH, run as OR FFH): with the NZ FLAG it drops the return address on the stack, keeps the line for CONT and ends at 1A06H with BREAK IN line, as the ROM's INPUT does at 2221H.
560E
LINE INPUT#: GOSUB to BASIC 5F36H with Register A = #, which requires a file open for reading (Register C = 20H), reads the file number and the comma and sets up the file statement (Index Register IX = 5700H).
5611
GOSUB to BASIC 5E7BH: 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 60F2H (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 line feeds, and a comma 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 (one right after a line feed does not), and 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/SYS 4445H and an LRL of 1). The end of the file before the item starts is error 7CH INPUT PAST END; inside the item it ends the item (56ABH). 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
GOSUB to BASIC 60F2H, which reads the next character of the file into Register A; the NZ FLAG is set at the end of the file.
562C
If the NZ FLAG is set (the end of the file), JUMP to BASIC 5DAFH, 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 unless the previous character in Register C was a line feed.
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 right after a line feed), JUMP to 565BH with Register A = 0AH: the carriage return does not end the item; for items (bit 0) nothing is stored, for LINE INPUT# a second 0AH is stored, and reading goes on.
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/SYS's vector that moves an FCB back one record.
5697
GOSUB to BASIC 621EH, which calls the SYS0/SYS 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 text at Register Pair HL (the item) into a number in REG 1 (4121H) and returns to the ROM's READ code.
56A7
GOSUB to BASIC 60F2H, 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.
56AE-56E7
DEFB 00H x 58 00 x 58
58 bytes of 00H to the end of the file (56E7H). Nothing in SYS20/SYS reads or writes them.