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

Page Customization

Introduction/Summary

NEWDOS/80 v2.0 SYS14/SYS Disassembly - ROUTE, CLEAR, CREATE, ERROR, LIST and PRINT (Model III)

SYS14/SYS holds six library commands: ROUTE (device routing), CLEAR (routes, timer and named routine queues, HIMEM and memory), CREATE (make a file and pre-allocate its records), ERROR (show a DOS error message), and LIST and PRINT (show a text file on the display or the printer). Its five load records fill 4D00H-51E7H of the overlay area (1,256 bytes) and its transfer address is 4D00H; 5187H-51E7H are 00H.

The page shows every byte of the file once, in address order.

Commands

SYS1/SYS's command table gives every one of these commands the RST 28H code F0H (function 7 of directory slot 10H) with a sub-function in Register C.

Sub-FunctionCommand
1ROUTE, 4D4DH
2CREATE (SYS1/SYS parses the filespec into 4480H), 4F8EH
3Not a command: the return to SYS14/SYS after a DOS routine or another overlay was called through 4D27H, 4D37H
4CLEAR, 5071H
5 and 6LIST 50EAH and PRINT 50E5H (SYS1/SYS opens the file in 4480H and leaves the command line pointer on the stack)
7ERROR, shown through SYS4/SYS code 66H, 4D39H

Any other code or sub-function gives error 2AH. CREATE opens its file through SYS2/SYS and writes its last sector through SYS0/SYS 4439H, both of which may load another overlay over SYS14/SYS; 4D27H pushes the word F003H and the SYS0/SYS return point 4978H first, so that SYS14/SYS is loaded again at sub-function 3 and returns to the caller.

Numbers (ERROR's message number, MM=, LRL=, REC=, START=, END=, MEM= and LIST's line numbers) are read by 4EEFH: decimal, or hexadecimal ended by H. Every bad value is error 2FH (BAD PARAMETER(S)), and an unknown word or a bad separator error 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).

Routes

A route entry is 7 bytes: +0 the routed device's DCB, +2 that DCB's own type byte, +3 the link to the next entry (0000H after the last, FFFFH for a free entry), +5 the target DCB. The chain starts at 4A81H, the operand SYS0/SYS's device code reads, and every routed DCB has the type byte C0H. Named targets take one of SYS0/SYS's six entries at 42D6H-42FFH (when all six are in use the error is 3BH, Insufficient Memory). An MM=addr target is a block of the user's at 5200H or above: SYS14/SYS puts the route entry at addr, a DCB at addr + 08H with the driver address addr + 10H at addr + 09H, and the user's routine starts at addr + 10H.

NameDCBUse
KB4015HKeyboard; input; routed or target
DO401DHDisplay; output; routed or target
PR4025HPrinter; output; routed or target
RI41E5HRS-232 input; input; routed or target
RO41EDHRS-232 output; output; routed or target
RC41F5HRS-232 initialization; output; routed or target
NL4CA1HNothing in, nothing out; input and output; target only
MM=addraddr + 08HThe user's routine at addr + 10H; input and output; target only

An input device takes only input targets and an output device only output targets (error 2FH). ROUTE,dev first ends dev's routes; each target then gets a new entry at the end of the chain. ROUTE alone lists the entries, one line each (4E32H always skips the code that would put several targets of one device on one line).

CREATE

The options (LRL=1-256, REC=n, ASE=Y/N, ASC=Y/N) are collected on the stack. The file is opened or made through SYS2/SYS code 44H; FPDE byte 1 gets bit 7 for ASE=N (no extension) and bit 6 for ASC=N (no deallocation by the close), with bits 5-7 cleared otherwise, and FPDE byte 4 gets the LRL. With REC, the byte count REC x LRL is worked out by SYS0/SYS 4C42H, the last sector is written with 428BH bit 1 set (SYS2/SYS then allocates every granule needed and no extra ones), every sector is then written with 00H from a buffer at 4D4DH-4E4CH (ROUTE's own code), and the end of file is set to the byte count. Without REC the end of file is set to 0. The close (SYS0/SYS 4428H) writes it to the directory.

Variables

Memory Outside SYS14/SYS

Address
Size
Contents
3840H
1 byte
Keyboard Row
Bit 0 ENTER, bit 3 up arrow, bit 6 right arrow: LIST and PRINT pause and stop (5127H, 512EH, 513AH).
4015H, 401DH, 4025H
24 bytes
Device Control Blocks
Keyboard, display and printer DCBs (8 bytes each); byte 0 is the type, set to C0H while routed (4DD7H) and put back by 4EB6H.
41E5H, 41EDH, 41F5H
24 bytes
RS-232 Device Control Blocks
RS-232 input, output and initialization DCBs (8 bytes each), the devices RI, RO and RC.
4058H-4059H
2 bytes
Named Routine Queue
Head of the queue of named routines; CLEAR stores 0000H (5091H).
428BH
1 byte
Overlay Flags
Bit 1 set around CREATE's allocation (5020H, 5025H): SYS2/SYS takes no extra granules.
4290H
1 byte
Option AX
The highest character code LIST and PRINT show as it is (514EH).
42C9H-42CAH
2 bytes
Top of Memory
Found at reset; CLEAR's highest HIMEM (509AH).
42D6H-42FFH
42 bytes
Route Entries
Six 7-byte entries for named targets (4DB3H), link FFFFH when free (4EBBH).
4300H-43FFH
256 bytes
DOS Sector Buffer
The directory sector with CREATE's FPDE (4FE2H, 4FFBH); LIST's file buffer (50FFH).
4411H-4412H
2 bytes
HIMEM
Set by CLEAR (50AAH).
4480H-449FH
32 bytes
DOS FCB
The CREATE, LIST or PRINT file: 4483H buffer (502AH, 5102H), 4488H end of file low byte (504AH), 448AH-448BH NEXT sector (5013H, 5037H), 448CH-448DH end of file sector (5047H).
4584H-4585H
2 bytes
Timer Chain
Head of SYS0/SYS's timer chain; CLEAR stores 0000H (5097H).
4A81H-4A82H
2 bytes
Route Chain Head
The operand in SYS0/SYS that holds the first route entry (4E0AH, 4DE7H, 4E94H).

SYS14/SYS Buffers

Address
Size
Contents
4D4DH-4E4CH
256 bytes
CREATE Buffer
SYS14/SYS's own ROUTE code, zeroed and used as the sector buffer of CREATE (5027H-5031H).
4F48H-4F4DH
6 bytes
Hexadecimal Text
"0000H" and 03H: an MM block's address is written here by SYS0/SYS 44D2H (4E8DH).

Operands Changed at Run Time

Address
Size
Contents
4D34H-4D35H
2 bytes
Routine Called by 4D27H
The operand of JP Z at 4D33H: 0000H in the file, 4439H after 501AH.
4DA5H
1 byte
Routed Device's Attribute
The operand of AND at 4DA4H, stored at 4D61H.
4DCEH-4DCFH
2 bytes
Routed DCB
The operand of LD DE at 4DCDH, stored at 4D64H.
4DD9H
1 byte
Routed DCB's Type Byte
The operand of LD A at 4DD8H, stored at 4D6DH.
4DE2H-4DE3H
2 bytes
Target DCB
The operand of LD DE at 4DE1H, stored at 4DABH.
509EH-509FH
2 bytes
MEM
The operand of LD DE at 509DH: FFFFH in the file, MEM= stored at 5081H.
50AEH-50AFH
2 bytes
END
The operand of LD DE at 50ADH: FFFFH in the file, END= stored at 5081H.
50B5H-50B6H
2 bytes
START
The operand of LD HL at 50B4H: 5200H in the file, START= stored at 5081H.
5182H
1 byte
Output Routine
The low byte of the CALL at 5181H: 33H (display) in the file, 3BH (printer) after PRINT's 50E7H.

Outside Routines and Addresses

AddressContents
0013H, 0033H, 003BHROM: read a byte from a control block (5145H), display a character (4E44H, 4E4BH, 4E79H, 5181H), print a character (5181H after PRINT).
RST 18HROM: compare Register Pair HL with Register Pair DE (4D44H, 50A6H, 50B0H, 50BEH, 50C5H).
4409HSYS0/SYS: the DOS error exit (4EECH, 4F0FH).
4428H, 4439HSYS0/SYS: close (504DH), write the sector at NEXT (5017H, 503BH).
44D2H, 4467HSYS0/SYS: a word as four hexadecimal digits (4E8DH), display a message (4E1CH, 4E91H).
48C4H, 48F0HSYS0/SYS: write the directory sector (4FFBH), read the FPDE of an open FCB (4FE2H).
4978HSYS0/SYS: the function chain return that brings SYS14/SYS back (4D2CH).
4BC5HSYS0/SYS: the dispatcher's return address, dropped at 4D37H and 50EAH.
4C42HSYS0/SYS: multiply Register Pair HL by Register A (5009H).
4C6AH, 4C7AHSYS0/SYS: compare a word (4ED7H), test for the end of the line or a separator (4D3CH, 4D71H, 4DFCH, 4F93H, 5085H, 50ECH, 5177H).
4CA1HSYS0/SYS: the NL device control block (4F7AH).
44H, 66HRST 28H codes used: SYS2/SYS open new or existing (4FD3H), SYS4/SYS display an error message (4D49H).

Disassembly

4D00H - Function Dispatcher

SYS14/SYS (directory slot 10H) is loaded by the SYS0/SYS RST 28H dispatcher (4B67H) into 4D00H-51E7H and entered at 4D00H by the CALL at 4BC2H, with Register A = the RST 28H code, Register C = the sub-function, and the return address 4BC5H (the dispatcher's tail) on top of the stack. The only code it accepts is F0H (function 7 of slot 10H), which SYS1/SYS's command table gives to ROUTE (sub-function 1), CREATE (2), CLEAR (4), LIST (5), PRINT (6) and ERROR (7). Sub-function 3 is never in the command table: it is the word F003H that 4D27H pushes so that SYS0/SYS 4978H brings SYS14/SYS back after a DOS routine or another overlay has run. Register Pair HL points at the command line after the command word.

4D00
LD IY,4280H FD 21 80 42
Load Index Register IY with 4280H, the base address the DOS keeps its drive variables at (4280H-4287H, the current drive's PDRIVE bytes). No instruction of SYS14/SYS uses Index Register IY after this.
4D04
CP F0H FE F0
Compare Register A, the RST 28H code, against F0H, function 7 of directory slot 10H (SYS14/SYS). The Z FLAG is set if Register A = F0H.
4D06
If the NZ FLAG is set (Register A holds another code), JUMP to 4D22H to return error 2AH (ILLEGAL DOS FUNCTION).
4D08
DEC C 0D
DECrement Register C, the sub-function from SYS1/SYS's command table. The Z FLAG is set if Register C was 1 (ROUTE).
4D09
If the Z FLAG is set (sub-function 1, the ROUTE command), JUMP to 4D4DH.
4D0C
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 2 (CREATE).
4D0D
If the Z FLAG is set (sub-function 2, the CREATE command), JUMP to 4F8EH.
4D10
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 3, the return after a call made through 4D27H or 4D28H.
4D11
If the Z FLAG is set (sub-function 3, SYS14/SYS reloaded by SYS0/SYS 4978H), JUMP to 4D37H to return to the code that made the call.
4D13
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 4 (CLEAR).
4D14
If the Z FLAG is set (sub-function 4, the CLEAR command), JUMP to 5071H.
4D17
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 5 (LIST).
4D18
If the Z FLAG is set (sub-function 5, the LIST command), JUMP to 50EAH.
4D1B
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 6 (PRINT).
4D1C
If the Z FLAG is set (sub-function 6, the PRINT command), JUMP to 50E5H.
4D1F
DEC C 0D
DECrement Register C, the sub-function. The Z FLAG is set if Register C was 7 (ERROR).
4D20
If the Z FLAG is set (sub-function 7, the ERROR command), JUMP to 4D39H.
4D22
LD A,2AH 3E 2A
Load Register A with 2AH, the DOS error code ILLEGAL DOS FUNCTION, for a code other than F0H or a sub-function of 0 or above 7. 4D06H comes here.
4D24
JUMP to 4EEBH, which enables interrupts and leaves through the SYS0/SYS error exit 4409H with the error code in Register A.

4D27H - Call a DOS Routine or Another Overlay and Come Back

Either call may load another overlay into 4D00H-51FFH over SYS14/SYS, so the word F003H (code F0H, sub-function 3) and the SYS0/SYS return point 4978H are pushed first. When the routine or the overlay returns to 4978H with the Z FLAG, SYS0/SYS pops F003H into Register A and Register C and issues RST 28H, which reloads SYS14/SYS if it was overwritten and enters it at sub-function 3 (4D37H); that drops the dispatcher's return address and returns to the caller of 4D27H or 4D28H with Register Pairs DE and HL as the routine left them. With the NZ FLAG, 4978H goes to the DOS error exit 4409H instead. 4D27H calls the SYS0/SYS routine whose address is in the operand 4D34H (only 4439H, stored at 501AH); 4D28H runs RST 28H with the code in Register A (only 44H, SYS2/SYS's open, from 4FD8H).

4D27
XOR A AF
Load Register A with 00H (XOR A with itself): the call is to the SYS0/SYS routine whose address is in the operand 4D34H, not to an overlay. 5022H calls here.
4D28
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set (EXX), keeping the caller's BC, DE and HL for the call while the alternate Register Pairs build the return words. 4FD8H calls here with Register A = 44H.
4D29
LD BC,F003H 01 03 F0
Load the alternate Register Pair BC with F003H: Register B = F0H, SYS14/SYS's RST 28H code, and Register C = 03H, the sub-function that returns to the caller.
4D2C
LD DE,4978H 11 78 49
Load the alternate Register Pair DE with 4978H, the SYS0/SYS return point that tests the result and then runs the RST 28H named by the word below it.
4D2F
PUSH BC C5
Save the alternate Register Pair BC (F003H) onto the stack, the word SYS0/SYS 4978H takes the code and sub-function from.
4D30
PUSH DE D5
Save the alternate Register Pair DE (4978H) onto the stack, the address the routine or the overlay returns to.
4D31
EXX D9
Exchange back from the alternate set (EXX): Register Pairs BC, DE and HL hold the caller's values again for the routine or the overlay.
4D32
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if Register A is 00H (a SYS0/SYS routine, from 4D27H).
4D33
JP Z,0000H CA 00 00
Self-Modifying Code
If the Z FLAG is set (Register A = 00H), JUMP to the SYS0/SYS routine whose address is the operand 4D34H-4D35H: 0000H in the file, 4439H (write the sector at NEXT) after 501AH stores it. The routine returns to 4978H.
4D36
RST 28H EF
RST 28H with Register A = the code (44H from 4FD8H): SYS0/SYS's dispatcher loads and runs the overlay function, which returns to 4978H.
4D37
POP AF F1
Sub-function 3 (from 4D11H): restore Register Pair AF from the stack, which discards 4BC5H, the dispatcher's return address pushed by the CALL that entered SYS14/SYS again.
4D38
RET C9
RETURN to the caller of 4D27H or 4D28H (5025H or 4FDBH), with Register Pairs DE and HL as the routine or the overlay returned them.

4D39H - ERROR Command

ERROR,n displays the message of DOS error n (0-63) and returns to DOS READY. Register Pair HL points at n in the command line. The message is shown by SYS4/SYS function 3 (code 66H), which displays it whatever the DOS state and, since bit 7 of n is clear, leaves through 402DH to DOS READY.

4D39
GOSUB to 4EEFH, which reads the decimal (or hexadecimal, ended by H) number at Register Pair HL into Register Pair DE; no number gives error 2FH.
4D3C
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return that ends the line; otherwise the NZ FLAG with Register A = 34H.
4D3F
RET NZ C0
If the NZ FLAG is set (something follows the number), RETURN to the dispatcher's tail 4BC5H with Register A = 34H, the error ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.
4D40
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the error number read at 4D39H.
4D41
LD DE,0040H 11 40 00
Load Register Pair DE with 0040H (64), one more than the highest message number.
4D44
RST 18H DF
RST 18H: the ROM compares Register Pair HL (the error number) with Register Pair DE (0040H). The CARRY FLAG is set if HL is below DE; the NO CARRY FLAG for 64 or more.
4D45
If the NO CARRY FLAG is set (the number is 64 or more), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).
4D48
LD H,L 65
Load Register H with Register L: Register H = the error number (0-63), the high byte of the error word that SYS4/SYS takes from the stack.
4D49
LD A,66H 3E 66
Load Register A with 66H, the RST 28H code of SYS4/SYS (slot 06H) function 3: display the error message whatever the state of the DOS.
4D4B
PUSH HL E5
Save Register Pair HL onto the stack: Register H = the error number, read by SYS4/SYS (its 4D13H) below the dispatcher's return address.
4D4C
RST 28H EF
RST 28H with Register A = 66H: SYS4/SYS is loaded over SYS14/SYS, displays the message of the error in Register H and, with bit 7 of the number clear, jumps to 402DH (DOS READY). It does not come back.

4D4DH - ROUTE Command

ROUTE alone lists the routes. ROUTE,CLEAR ends every route. ROUTE,dev[,dev2][,dev3]... first ends the routes of dev, then routes dev to (an output device) or from (an input device) each device after it. The names are those of the table at 4F53H: KB (4015H), DO (401DH), PR (4025H), RI (41E5H), RO (41EDH) and RC (41F5H) may be routed; KB, DO, PR, RI, RO, RC, NL (4CA1H) and MM=addr may be targets; an input device may only use an input target and an output device only an output target (NL and MM= serve both). A route is a 7-byte entry: +0 the routed DCB, +2 its own type byte, +3 the link to the next entry (0000H ends the chain, FFFFH marks a free entry), +5 the target DCB. Entries for named targets come from SYS0/SYS's six entries at 42D6H-42FFH; an MM=addr target keeps its entry in the first bytes of its own block. The chain starts at the operand 4A81H in SYS0/SYS, and a routed DCB's type byte is set to C0H, which makes SYS0/SYS's device code (4A80H) follow the chain. Interrupts are disabled while the chain changes. This code area 4D4DH-4E4CH is also the zeroed sector buffer of CREATE (5027H).

4D4D
DI F3
Disable interrupts, so that no device driver walks the route chain while it is being changed. Every exit through 4E54H or 4EEBH enables them again.
4D4E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first character of the command line after ROUTE.
4D4F
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return that ends the command line. The Z FLAG is set for ROUTE alone.
4D51
If the Z FLAG is set (ROUTE with nothing after it), JUMP to 4E0AH to list the routes.
4D54
GOSUB to 4EC6H, which looks up the device name at Register Pair HL in the table at 4F53H: Register A returns its attribute byte, Register Pair DE its DCB address, Register Pair HL the command line past the name; an unknown name is error 34H.
4D57
BIT 7,A CB 7F
Test bit 7 of Register A, the attribute byte: set for a device that may be routed (KB, DO, PR, RI, RO, RC) and for the word CLEAR.
4D59
If the Z FLAG is set (bit 7 clear: NL or MM=, which cannot be routed), JUMP to 4EE9H for error 34H.
4D5C
BIT 4,A CB 67
Test bit 4 of Register A, the attribute byte: set only for the word CLEAR (attribute 90H).
4D5E
If the NZ FLAG is set (ROUTE,CLEAR), JUMP to 4DFCH to end every route.
4D61
LD (4DA5H),A 32 A5 4D
Self-Modifying Code
Store Register A (the routed device's attribute byte: C1H for an input device, C2H for an output device) at 4DA5H, the operand of the AND 00H at 4DA4H that checks each target's direction.
4D64
LD (4DCEH),DE ED 53 CE 4D
Self-Modifying Code
Store Register Pair DE (the routed device's DCB address) at 4DCEH-4DCFH, the operand of the LD DE,0000H at 4DCDH that writes it into each new route entry.
4D68
PUSH HL E5
Save Register Pair HL (the command line past the device name) onto the stack; 4D70H takes it back.
4D69
GOSUB to 4E94H with Register Pair DE = the routed DCB, which ends every route the DCB already has and puts its own type byte back.
4D6C
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the routed DCB's type byte as it is now that its old routes have ended.
4D6D
LD (4DD9H),A 32 D9 4D
Self-Modifying Code
Store Register A (the DCB's own type byte) at 4DD9H, the operand of the LD A,00H at 4DD8H, so that each new route entry keeps it at +2 for 4E94H to put back.

Target Loop
The command line pointer is on top of the stack; each pass takes one target device.

4D70
POP HL E1
Restore Register Pair HL from the stack: the command line at the separator after the last device read. 4DF9H comes back here after each target.
4D71
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return; a comma or spaces give the NZ FLAG with Register Pair HL past them; anything else gives the CARRY FLAG. Register A returns 34H except at the carriage return.
4D74
RET C D8
If the CARRY FLAG is set (a character that is not a separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H, error ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR. Interrupts are still disabled on this return.
4D75
If the Z FLAG is set (the end of the command line), JUMP to 4E54H, which enables interrupts and returns with the Z FLAG (no error).
4D78
GOSUB to 4EC6H, which looks up the target's name at Register Pair HL in the table at 4F53H: Register A = its attribute byte, Register Pair DE = its DCB address (0000H for MM=), Register Pair HL past the name.
4D7B
BIT 6,A CB 77
Test bit 6 of Register A, the attribute byte: set for a device that may be a target (every name except CLEAR).
4D7D
If the Z FLAG is set (CLEAR used as a target), JUMP to 4EE9H for error 34H.
4D80
BIT 5,A CB 6F
Test bit 5 of Register A, the attribute byte: set only for MM= (attribute 60H), which is followed by the address of a block of the user's own.
4D82
If the Z FLAG is set (a named target), JUMP to 4DA0H to check its direction and take a free entry from 42D6H-42FFH.
4D84
MM=addr: GOSUB to 4EEFH, which reads the address at Register Pair HL (after MM=) into Register Pair DE.
4D87
LD A,D 7A
Load Register A with Register D, the high byte of the MM block's address.
4D88
CP 52H FE 52
Compare Register A against 52H. The CARRY FLAG is set for an address below 5200H, memory the DOS uses itself.
4D8A
If the CARRY FLAG is set (below 5200H), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)). Interrupts stay disabled until the RST 28H dispatcher run by 4409H enables them (4B7CH).
4D8D
PUSH HL E5
Save Register Pair HL (the command line past the address) onto the stack; 4D70H takes it back.
4D8E
PUSH DE D5
Save Register Pair DE (the MM block's address) onto the stack; 4D9DH takes it back as the address of the route entry.
4D8F
LD HL,0010H 21 10 00
Load Register Pair HL with 0010H (16), the offset of the user's routine in the MM block: the first 16 bytes belong to the DOS.
4D92
ADD HL,DE 19
ADD Register Pair DE (the block's address) to Register Pair HL (0010H): Register Pair HL = block + 10H, the address of the user's routine.
4D93
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = block + 10H, the routine's address; Register Pair HL = the block's address.
4D94
LD HL,FFFAH 21 FA FF
Load Register Pair HL with FFFAH, which is minus 6.
4D97
ADD HL,DE 19
ADD Register Pair DE (block + 10H) to Register Pair HL (minus 6): Register Pair HL = block + 0AH, the high byte of the driver address of the DCB the DOS keeps at block + 08H.
4D98
LD (HL),D 72
Store Register D (the high byte of the routine's address, block + 10H) at Register Pair HL, block + 0AH.
4D99
DEC HL 2B
DECrement Register Pair HL to block + 09H, the low byte of the DCB's driver address.
4D9A
LD (HL),E 73
Store Register E (the low byte of the routine's address) at Register Pair HL, block + 09H: the DCB at block + 08H now names the user's routine as its driver.
4D9B
DEC HL 2B
DECrement Register Pair HL to block + 08H, the DCB of the MM device.
4D9C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = block + 08H, the target DCB; Register Pair HL = block + 10H.
4D9D
POP HL E1
Restore Register Pair HL from the stack: the MM block's address (pushed at 4D8EH), where the route entry is built. The command line pointer stays on the stack.
4D9E
JUMP to 4DABH with Register Pair DE = the target DCB and Register Pair HL = the entry's address (not 0000H). The direction test is skipped: an MM routine serves input and output.
4DA0
PUSH HL E5
A named target: save Register Pair HL (the command line past the name) onto the stack; 4D70H takes it back.
4DA1
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H: no entry address yet, so 4DB1H takes a free entry from 42D6H-42FFH.
4DA4
AND 00H E6 00
Self-Modifying Code
AND Register A (the target's attribute byte) with the operand at 4DA5H: 00H in the file, the routed device's attribute byte after 4D61H stores it. The bits both devices share remain.
4DA6
AND 03H E6 03
AND Register A with 03H, keeping the direction bits: bit 0 input (KB, RI, NL), bit 1 output (DO, PR, RO, RC, NL). The Z FLAG is set if the two devices have no direction in common.
4DA8
If the Z FLAG is set (an input device with an output target, or the reverse), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).
4DAB
LD (4DE2H),DE ED 53 E2 4D
Self-Modifying Code
Store Register Pair DE (the target DCB) at 4DE2H-4DE3H, the operand of the LD DE,0000H at 4DE1H that writes it into the entry. 4D9EH comes here for MM=.
4DAF
LD A,H 7C
Load Register A with Register H, the high byte of the entry address (0000H for a named target, the block for MM=).
4DB0
OR L B5
OR Register A with Register L: the NZ FLAG is set if Register Pair HL holds an entry address (MM=).
4DB1
If the NZ FLAG is set (MM=), JUMP to 4DCDH to build the entry at the start of the MM block.
4DB3
LD HL,42D3H 21 D3 42
Load Register Pair HL with 42D3H, three bytes before 42D6H, the first of SYS0/SYS's six route entries.

Find a Free Entry
Register Pair HL steps 7 bytes at a time through the entries at 42D6H, 42DDH, 42E4H, 42EBH, 42F2H and 42F9H; a free one has the link FFFFH at +3.

4DB6
LD A,L 7D
Load Register A with Register L, the low byte of the pointer (D3H, DAH, E1H, E8H, EFH, F6H for the six entries in turn, FDH after the last). 4DCAH comes back here.
4DB7
CP FDH FE FD
Compare Register A against FDH. The NO CARRY FLAG is set when Register L has reached FDH: all six entries have been looked at.
4DB9
LD A,3BH 3E 3B
Load Register A with 3BH, the DOS error code INSUFFICIENT MEMORY, given when every entry is in use. LD does not change the flags of the CP.
4DBB
If the NO CARRY FLAG is set (no entry is free), JUMP to 4EEBH to enable interrupts and leave with error 3BH in Register A.
4DBE
INC HL 23
INCrement Register Pair HL, the first of three steps to the next entry.
4DBF
INC HL 23
INCrement Register Pair HL, the second of three steps to the next entry.
4DC0
INC HL 23
INCrement Register Pair HL, the third step: Register Pair HL = the start of the entry to look at.
4DC1
LD D,H 54
Load Register D with Register H, the high byte of the entry's address.
4DC2
LD E,L 5D
Load Register E with Register L: Register Pair DE = the entry's address, kept in case it is free.
4DC3
INC HL 23
INCrement Register Pair HL to entry +1, the first of three steps to the entry's link.
4DC4
INC HL 23
INCrement Register Pair HL to entry +2, the second step to the link.
4DC5
INC HL 23
INCrement Register Pair HL to entry +3, the low byte of the entry's link.
4DC6
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the link.
4DC7
INC HL 23
INCrement Register Pair HL to entry +4, the high byte of the link.
4DC8
AND (HL) A6
AND Register A (the link's low byte) with the byte at Register Pair HL (its high byte): Register A = FFH only if both bytes are FFH.
4DC9
INC A 3C
INCrement Register A: the Z FLAG is set if it was FFH, so the link was FFFFH, a free entry.
4DCA
If the NZ FLAG is set (the entry is in use), LOOP BACK to 4DB6H with Register Pair HL at entry +4; three more steps reach the next entry.
4DCC
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the free entry's address.
4DCD
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the routed device's DCB address: the operand 4DCEH-4DCFH (0000H in the file) was stored at 4D64H. 4DB1H comes here for MM= with Register Pair HL = the block.
4DD0
PUSH HL E5
Save Register Pair HL (the entry's address) onto the stack; 4DF5H takes it back to link the entry in.
4DD1
LD (HL),E 73
Store Register E (the low byte of the routed DCB) at Register Pair HL, entry +0.
4DD2
INC HL 23
INCrement Register Pair HL to entry +1 of the new route entry.
4DD3
LD (HL),D 72
Store Register D (the high byte of the routed DCB) at Register Pair HL, entry +1.
4DD4
INC HL 23
INCrement Register Pair HL to entry +2 of the new route entry.
4DD5
LD A,C0H 3E C0
Load Register A with C0H, the type byte that makes SYS0/SYS's device code (4A80H) follow the route chain for a DCB.
4DD7
LD (DE),A 12
Store Register A (C0H) at Register Pair DE, the type byte of the routed DCB: from now on the DOS sends this device's input or output through the route chain.
4DD8
LD A,00H 3E 00
Self-Modifying Code
Load Register A with the routed DCB's own type byte: the operand 4DD9H (00H in the file) was stored at 4D6DH.
4DDA
LD (HL),A 77
Store Register A (the DCB's own type byte) at Register Pair HL, entry +2, so that 4E94H can put it back when the route ends.
4DDB
INC HL 23
INCrement Register Pair HL to entry +3, the low byte of the link.
4DDC
XOR A AF
Load Register A with 00H (XOR A with itself), for the link 0000H of the last entry in the chain.
4DDD
LD (HL),A 77
Store Register A (00H) at Register Pair HL, entry +3, the low byte of the link.
4DDE
INC HL 23
INCrement Register Pair HL to entry +4, the high byte of the link.
4DDF
LD (HL),A 77
Store Register A (00H) at Register Pair HL, entry +4: the link is 0000H, the end of the chain.
4DE0
INC HL 23
INCrement Register Pair HL to entry +5, the low byte of the target DCB.
4DE1
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the target DCB: the operand 4DE2H-4DE3H (0000H in the file) was stored at 4DABH.
4DE4
LD (HL),E 73
Store Register E (the low byte of the target DCB) at Register Pair HL, entry +5.
4DE5
INC HL 23
INCrement Register Pair HL to entry +6, the high byte of the target DCB.
4DE6
LD (HL),D 72
Store Register D (the high byte of the target DCB) at Register Pair HL, entry +6. The entry is complete.
4DE7
LD DE,4A7EH 11 7E 4A
Load Register Pair DE with 4A7EH, three bytes before 4A81H, the operand in SYS0/SYS that holds the first entry of the chain: the loop below then treats the head like the link of an entry.

Find the End of the Chain
Register Pair DE = the entry whose link (at +3) is looked at; 4A7EH stands for the chain head 4A81H.

4DEA
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the entry whose link is looked at. 4DF3H comes back here.
4DEB
INC HL 23
INCrement Register Pair HL to entry +1, the first of three steps to the link.
4DEC
INC HL 23
INCrement Register Pair HL to entry +2, the second step to the link.
4DED
INC HL 23
INCrement Register Pair HL to entry +3, the low byte of the link (4A81H for the chain head).
4DEE
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the link.
4DEF
INC HL 23
INCrement Register Pair HL to the high byte of the link.
4DF0
LD D,(HL) 56
Load Register D with the byte at Register Pair HL: Register Pair DE = the link, the next entry of the chain (0000H after the last).
4DF1
LD A,D 7A
Load Register A with Register D, the high byte of the link.
4DF2
OR E B3
OR Register A with Register E: the Z FLAG is set if the link is 0000H, the end of the chain.
4DF3
If the NZ FLAG is set (another entry follows), LOOP BACK to 4DEAH with Register Pair DE = that entry.
4DF5
POP BC C1
Restore Register Pair BC from the stack: the new entry's address, saved at 4DD0H.
4DF6
LD (HL),B 70
Store Register B (the high byte of the new entry) at Register Pair HL, the high byte of the last link (the entry's +4, or 4A82H when the chain was empty).
4DF7
DEC HL 2B
DECrement Register Pair HL to the low byte of that link.
4DF8
LD (HL),C 71
Store Register C (the low byte of the new entry) at Register Pair HL: the new entry is now the last one of the chain.
4DF9
JUMP to 4D70H for the next target in the command line, whose pointer is on top of the stack.

4DFCH - ROUTE,CLEAR

ROUTE,CLEAR must end the command line; every route of every device then ends. CLEAR's command code calls 4E01H for the same work.

4DFC
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL (after CLEAR): the Z FLAG at the carriage return; otherwise the NZ FLAG with Register A = 34H.
4DFF
If the NZ FLAG is set (something follows ROUTE,CLEAR), JUMP to 4E54H, which enables interrupts and returns with Register A = 34H and the NZ FLAG: error 34H, and no route has been changed.
4E01
DI F3
Disable interrupts, so that no device driver uses the route chain while it is taken apart. CLEAR enters here from 508BH.
4E02
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, which tells 4E94H to end the routes of every DCB.
4E05
GOSUB to 4E94H with Register Pair DE = 0000H: every entry is unlinked and freed, and each routed DCB gets its own type byte back.
4E08
JUMP to 4E53H to return with Register A = 00H and the Z FLAG (no error), interrupts enabled.

4E0AH - List the Routes

ROUTE alone shows one line per route entry, in chain order from the head at 4A81H: the routed device's name, the word TO and the target's name. A named device's name comes from the table at 4F53H; any other DCB is shown as MM= and the address of its block in hexadecimal.

4E0A
LD HL,(4A81H) 2A 81 4A
Load Register Pair HL with the word at 4A81H, the operand in SYS0/SYS that holds the first entry of the route chain (0000H when there are no routes).
4E0D
JUMP to 4E4FH to test Register Pair HL for the end of the chain before showing anything.

Entry Loop
Register Pair HL = the route entry to show.

4E0F
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, entry +0: the low byte of the routed DCB. 4E51H comes back here.
4E10
INC HL 23
INCrement Register Pair HL to entry +1, the high byte of the routed DCB.
4E11
LD D,(HL) 56
Load Register D with the byte at Register Pair HL: Register Pair DE = the routed DCB.
4E12
INC HL 23
INCrement Register Pair HL to entry +2, the routed DCB's own type byte.
4E13
INC HL 23
INCrement Register Pair HL to entry +3, the low byte of the link to the next entry.
4E14
PUSH DE D5
Save Register Pair DE (the routed DCB) onto the stack; 4E2AH takes it back.
4E15
PUSH HL E5
Save Register Pair HL (entry +3) onto the stack; 4E1FH takes it back.
4E16
GOSUB to 4E56H with Register Pair DE = the routed DCB, which displays its device name.
4E19
LD HL,4F4EH 21 4E 4F
Point Register Pair HL to 4F4EH, the text " TO " ended by 03H.
4E1C
GOSUB to SYS0/SYS 4467H, which displays the text at Register Pair HL (4F4EH) up to the 03H.
4E1F
POP HL E1
Restore Register Pair HL from the stack: entry +3. The JR at 4E47H, in code that is never executed, also leads here.
4E20
PUSH HL E5
Save Register Pair HL (entry +3) onto the stack again; 4E29H takes it back.
4E21
INC HL 23
INCrement Register Pair HL to entry +4, the high byte of the link.
4E22
INC HL 23
INCrement Register Pair HL to entry +5, the low byte of the target DCB.
4E23
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the target DCB.
4E24
INC HL 23
INCrement Register Pair HL to entry +6, the high byte of the target DCB.
4E25
LD D,(HL) 56
Load Register D with the byte at Register Pair HL: Register Pair DE = the target DCB.
4E26
GOSUB to 4E56H with Register Pair DE = the target DCB, which displays the target's device name.
4E29
POP HL E1
Restore Register Pair HL from the stack: entry +3, the link.
4E2A
POP DE D1
Restore Register Pair DE from the stack: the routed DCB, saved at 4E14H.
4E2B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the link to the next entry.
4E2C
INC HL 23
INCrement Register Pair HL to entry +4, the high byte of the link.
4E2D
LD H,(HL) 66
Load Register H with the byte at Register Pair HL, the high byte of the link.
4E2E
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the next entry (0000H after the last).
4E2F
PUSH HL E5
Save Register Pair HL (the next entry) onto the stack; 4E4EH takes it back.
4E30
LD A,H 7C
Load Register A with Register H, the high byte of the next entry.
4E31
OR L B5
OR Register A with Register L: the Z FLAG is set if the next entry is 0000H. The flags are not used, since 4E32H always jumps.
4E32
JUMP to 4E49H to end the line. This JR is taken every time, so the code at 4E34H-4E48H, which would show further targets of the same device on the same line, is never executed.
4E34
LD A,(HL) 7E
Never executed (4E32H jumps over it): load Register A with the byte at Register Pair HL, the low byte of the next entry's routed DCB.
4E35
CP E BB
Never executed: compare Register A (the next entry's DCB low byte) against Register E, the low byte of the routed DCB.
4E36
INC HL 23
Never executed: INCrement Register Pair HL to the next entry's +1, the high byte of its DCB.
4E37
Never executed: if the NZ FLAG is set (the low bytes differ), JUMP to 4E3BH.
4E39
LD A,(HL) 7E
Never executed: load Register A with the byte at Register Pair HL, the high byte of the next entry's routed DCB.
4E3A
CP D BA
Never executed: compare Register A against Register D, the high byte of the routed DCB.
4E3B
INC HL 23
Never executed: INCrement Register Pair HL to the next entry's +2.
4E3C
INC HL 23
Never executed: INCrement Register Pair HL to the next entry's +3, its link.
4E3D
Never executed: if the NZ FLAG is set (the next entry is for another device), JUMP to 4E49H to end the line.
4E3F
POP AF F1
Never executed: restore Register Pair AF from the stack, dropping the next entry's address saved at 4E2FH.
4E40
LD A,2CH 3E 2C
Never executed: load Register A with 2CH, a comma to separate two targets of the same device.
4E42
PUSH HL E5
Never executed: save Register Pair HL (the next entry's +3) onto the stack.
4E43
PUSH DE D5
Never executed: save Register Pair DE (the routed DCB) onto the stack.
4E44
Never executed: GOSUB to the ROM routine at 0033H, which displays the comma in Register A.
4E47
Never executed: JUMP to 4E1FH to show the next entry's target on the same line.
4E49
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return that ends the line of this route. 4E32H comes here.
4E4B
GOSUB to the ROM routine at 0033H, which displays the character in Register A (the carriage return) on the screen.
4E4E
POP HL E1
Restore Register Pair HL from the stack: the next entry, saved at 4E2FH.
4E4F
LD A,H 7C
Load Register A with Register H, the high byte of the entry. 4E0DH comes here first.
4E50
OR L B5
OR Register A with Register L: the Z FLAG is set if Register Pair HL is 0000H, the end of the chain.
4E51
If the NZ FLAG is set (another entry), LOOP BACK to 4E0FH to show it.
4E53
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error. 4E08H comes here.
4E54
EI FB
Enable interrupts again (disabled at 4D4DH or 4E01H). 4D75H and 4DFFH come here with Register A and the flags already set.
4E55
RET C9
RETURN with Register A and the flags as the result: to the dispatcher's tail 4BC5H, or to 508EH when CLEAR called 4E01H.

4E56H - Display a Device Name

Register Pair DE = a DCB address. The device table at 4F53H is searched for an entry whose word is that DCB; its name is displayed. A DCB that is not in the table belongs to an MM= block (its DCB is at block + 08H), so MM= is displayed followed by the block's address as four hexadecimal digits and H.

4E56
LD HL,4F53H 21 53 4F
Point Register Pair HL to 4F53H, the first entry of the device table (name, 00H, attribute byte, DCB word). 4E16H and 4E26H call here.

Table Search Loop
Register Pair HL = the start of the entry, which is also saved on the stack.

4E59
PUSH HL E5
Save Register Pair HL (the start of the entry, its name) onto the stack; 4E74H takes it back if this entry matches. 4E6DH comes back here.
4E5A
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, a character of the entry's name (00H at its end). 4E5DH comes back here.
4E5B
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H after the name.
4E5C
INC HL 23
INCrement Register Pair HL to the next byte of the entry. INC HL does not change the flags.
4E5D
If the NZ FLAG is set (still inside the name), LOOP BACK to 4E5AH.
4E5F
INC HL 23
INCrement Register Pair HL over the attribute byte to the low byte of the entry's DCB word.
4E60
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the entry's DCB address.
4E61
CP E BB
Compare Register A against Register E, the low byte of the DCB being looked for. The Z FLAG is set if they are equal.
4E62
INC HL 23
INCrement Register Pair HL to the high byte of the entry's DCB word. INC HL does not change the flags.
4E63
If the NZ FLAG is set (the low bytes differ), JUMP to 4E67H, where the NZ FLAG carries on the search.
4E65
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the high byte of the entry's DCB address.
4E66
SUB D 92
SUBtract Register D (the high byte of the DCB looked for) from Register A: Register A = 00H with the Z FLAG if the high bytes match too.
4E67
If the Z FLAG is set (this entry's DCB is the one in Register Pair DE), JUMP to 4E74H with Register A = 00H to display the entry's name.
4E69
INC HL 23
INCrement Register Pair HL to the first byte of the next entry.
4E6A
POP AF F1
Restore Register Pair AF from the stack, dropping the start of the entry that did not match.
4E6B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first byte of the next entry (00H at 4F8DH, the end of the table).
4E6C
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the end of the table.
4E6D
If the NZ FLAG is set (another entry), LOOP BACK to 4E59H to compare it.
4E6F
LD HL,4F86H 21 86 4F
No entry has this DCB: point Register Pair HL to 4F86H, the name MM= in the table.
4E72
INC A 3C
INCrement Register A from 00H to 01H, the mark that the block's address follows the name.
4E73
PUSH HL E5
Save Register Pair HL (4F86H, the name MM=) onto the stack for the POP at 4E74H.
4E74
POP HL E1
Restore Register Pair HL from the stack: the name to display (the matching entry's name, or MM= at 4F86H). 4E67H comes here.
4E75
PUSH AF F5
Save Register Pair AF onto the stack: Register A = 00H for a device in the table, 01H for an MM= block.
4E76
PUSH DE D5
Save Register Pair DE (the DCB address) onto the stack; the ROM display routine changes Register Pair DE.

Display the Name
Register Pair HL = the name, which ends with 00H.

4E77
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the name. 4E7EH comes back here.
4E78
INC HL 23
INCrement Register Pair HL to the following character of the name.
4E79
GOSUB to the ROM routine at 0033H, which displays the character in Register A.
4E7C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the following character of the name.
4E7D
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the name.
4E7E
If the NZ FLAG is set (more of the name), LOOP BACK to 4E77H.
4E80
POP DE D1
Restore Register Pair DE from the stack: the DCB address saved at 4E76H.
4E81
POP AF F1
Restore Register Pair AF from the stack: Register A = 00H (a device in the table) or 01H (an MM= block).
4E82
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for a device in the table.
4E83
RET Z C8
If the Z FLAG is set (the name was all there is to show), RETURN to the listing code.
4E84
LD HL,FFF8H 21 F8 FF
Load Register Pair HL with FFF8H, which is minus 8.
4E87
ADD HL,DE 19
ADD Register Pair DE (the DCB, at block + 08H) to Register Pair HL (minus 8): Register Pair HL = the MM block's address.
4E88
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the MM block's address, to be shown in hexadecimal.
4E89
LD HL,4F48H 21 48 4F
Point Register Pair HL to 4F48H, the text buffer "0000H" ended by 03H.
4E8C
PUSH HL E5
Save Register Pair HL (4F48H) onto the stack; 4E90H takes it back.
4E8D
GOSUB to SYS0/SYS 44D2H, which writes Register Pair DE (the block's address) as four hexadecimal digits at Register Pair HL (4F48H-4F4BH).
4E90
POP HL E1
Restore Register Pair HL from the stack: 4F48H, the four digits followed by H and 03H.
4E91
JUMP to SYS0/SYS 4467H, which displays the text at Register Pair HL up to the 03H and returns to the listing code.

4E94H - End the Routes of a Device

Register Pair DE = the DCB whose routes end, or 0000H to end every route. The chain is walked from the head at 4A81H; each matching entry is unlinked, marked free (link FFFFH) and its routed DCB gets its own type byte back (entry +2). Register Pair BC always holds the address of the link that points at the entry being looked at. Interrupts are disabled by the callers (4D4DH, 4E01H).

4E94
LD HL,4A7FH 21 7F 4A
Point Register Pair HL to 4A7FH, two bytes before the chain head 4A81H in SYS0/SYS, so that the next two steps reach the head the same way they reach an entry's link (+3 from entry +1). 4D69H and 4E05H call here.

Chain Loop
Register Pair HL = two bytes before a link (an entry's +1, or 4A7FH for the head).

4E97
INC HL 23
INCrement Register Pair HL, the first of two steps to the link. 4EADH comes back here with Register Pair HL at entry +1.
4E98
INC HL 23
INCrement Register Pair HL, the second step: Register Pair HL = the address of the link (4A81H, or an entry's +3).
4E99
LD B,H 44
Load Register B with Register H, the high byte of the link's address. 4EC4H comes back here after unlinking an entry.
4E9A
LD C,L 4D
Load Register C with Register L: Register Pair BC = the address of the link that points at the next entry.
4E9B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the link.
4E9C
INC HL 23
INCrement Register Pair HL to the high byte of the link.
4E9D
LD H,(HL) 66
Load Register H with the byte at Register Pair HL, the high byte of the link.
4E9E
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the entry the link points at.
4E9F
LD A,H 7C
Load Register A with Register H, the high byte of that entry's address.
4EA0
OR L B5
OR Register A with Register L: the Z FLAG is set if the link is 0000H, the end of the chain.
4EA1
RET Z C8
If the Z FLAG is set (no more entries), RETURN to the caller.
4EA2
LD A,D 7A
Load Register A with Register D, the high byte of the DCB whose routes end.
4EA3
OR E B3
OR Register A with Register E: the Z FLAG is set if Register Pair DE is 0000H, every route ends.
4EA4
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, entry +0: the low byte of the entry's routed DCB. LD does not change the flags.
4EA5
INC HL 23
INCrement Register Pair HL to entry +1, the high byte of the routed DCB. INC HL does not change the flags.
4EA6
If the Z FLAG is set (Register Pair DE = 0000H, every route ends), JUMP to 4EAFH to end this one.
4EA8
CP E BB
Compare Register A (the entry's DCB low byte) against Register E, the low byte of the DCB whose routes end.
4EA9
If the NZ FLAG is set (the low bytes differ), JUMP to 4EADH, where the NZ FLAG moves on to the next entry.
4EAB
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, entry +1: the high byte of the entry's routed DCB.
4EAC
CP D BA
Compare Register A against Register D, the high byte of the DCB whose routes end. The Z FLAG is set if the entry is for that DCB.
4EAD
If the NZ FLAG is set (the entry is for another device), LOOP BACK to 4E97H with Register Pair HL at entry +1; two steps reach its link.
4EAF
PUSH BC C5
Save Register Pair BC (the address of the link that points at this entry) onto the stack; 4EBFH takes it back. 4EA6H comes here.
4EB0
DEC HL 2B
DECrement Register Pair HL back to entry +0, the low byte of the routed DCB.
4EB1
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the low byte of the routed DCB.
4EB2
INC HL 23
INCrement Register Pair HL to entry +1, the high byte of the routed DCB.
4EB3
LD B,(HL) 46
Load Register B with the byte at Register Pair HL: Register Pair BC = the routed DCB.
4EB4
INC HL 23
INCrement Register Pair HL to entry +2, the DCB's own type byte saved when the route was made (4DDAH).
4EB5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the routed DCB's own type byte.
4EB6
LD (BC),A 02
Store Register A at Register Pair BC, the routed DCB's type byte: the C0H is replaced and the device is no longer routed.
4EB7
INC HL 23
INCrement Register Pair HL to entry +3, the low byte of the link.
4EB8
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the low byte of the link to the next entry.
4EB9
LD A,FFH 3E FF
Load Register A with FFH, the link value that marks an entry as free.
4EBB
LD (HL),A 77
Store Register A (FFH) at Register Pair HL, entry +3, the low byte of the link.
4EBC
INC HL 23
INCrement Register Pair HL to entry +4, the high byte of the link.
4EBD
LD B,(HL) 46
Load Register B with the byte at Register Pair HL: Register Pair BC = the next entry of the chain (0000H after the last).
4EBE
LD (HL),A 77
Store Register A (FFH) at Register Pair HL, entry +4: the link is FFFFH and the entry is free for 4DB6H.
4EBF
POP HL E1
Restore Register Pair HL from the stack: the address of the link that pointed at this entry (4A81H or another entry's +3).
4EC0
LD (HL),C 71
Store Register C (the low byte of the next entry) at Register Pair HL, the low byte of that link.
4EC1
INC HL 23
INCrement Register Pair HL to the high byte of that link.
4EC2
LD (HL),B 70
Store Register B (the high byte of the next entry) at Register Pair HL: the freed entry is out of the chain.
4EC3
DEC HL 2B
DECrement Register Pair HL back to the low byte of that link.
4EC4
JUMP to 4E99H with Register Pair HL = the same link, which now points at the entry after the freed one.

4EC6H - Look Up a Word in a Table

4EC6H looks up the name at Register Pair HL in the device table at 4F53H; 4EC9H takes the table in Register Pair BC (CREATE's 5050H, CLEAR's 50CAH). Each table entry is a word ended by 00H followed by three bytes (an attribute or flag byte and a 16-bit value); a 00H ends the table. On a match it returns Register A = the byte after the 00H, Register Pair DE = the 16-bit value and Register Pair HL past the word in the command line. A word not in the table leaves through 4EE9H with error 34H.

4EC6
LD BC,4F53H 01 53 4F
Load Register Pair BC with 4F53H, the device table used by ROUTE. 4D54H and 4D78H call here.
4EC9
LD D,03H 16 03
Load Register D with 03H, the number of bytes after the 00H of each word (the attribute byte and the 16-bit value). 4F9EH and 5079H call here with their own table in Register Pair BC.
4ECB
GOSUB to 4ED7H, which finds the entry whose word matches the text at Register Pair HL; it returns with Register Pair BC at the byte after that word's 00H and Register Pair HL past the text.
4ECE
PUSH BC C5
Save Register Pair BC (the address of the entry's attribute byte) onto the stack.
4ECF
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (at the Stack Pointer): Register Pair HL = the address of the attribute byte, and the command line pointer is kept on the stack.
4ED0
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the entry's attribute or flag byte.
4ED1
INC HL 23
INCrement Register Pair HL to the low byte of the entry's 16-bit value.
4ED2
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the low byte of the value.
4ED3
INC HL 23
INCrement Register Pair HL to the high byte of the entry's value.
4ED4
LD D,(HL) 56
Load Register D with the byte at Register Pair HL: Register Pair DE = the entry's value (a DCB, a handler's address or the address of an operand).
4ED5
POP HL E1
Restore Register Pair HL from the stack: the command line past the word.
4ED6
RET C9
RETURN with Register A = the attribute byte, Register Pair DE = the value and Register Pair HL past the word.

Search Loop
Register Pair BC = the table entry, Register Pair HL = the word in the command line, Register D = the bytes after each 00H.

4ED7
GOSUB to SYS0/SYS 4C6AH, which compares the 00H-ended word at Register Pair BC with the text at Register Pair HL: on a match the Z FLAG, Register Pair BC past the 00H and Register Pair HL past the text; otherwise the NZ FLAG with Register Pair HL unchanged and Register Pair BC inside the word. 4EE7H comes back here.
4EDA
RET Z C8
If the Z FLAG is set (the word matches), RETURN to 4ECEH with Register Pair BC at the attribute byte.
4EDB
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, a character of the table word (00H at its end). 4EDEH comes back here.
4EDC
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H that ends the table word.
4EDD
INC BC 03
INCrement Register Pair BC to the next byte of the table. INC BC does not change the flags.
4EDE
If the NZ FLAG is set (still inside the word), LOOP BACK to 4EDBH.
4EE0
LD E,D 5A
Load Register E with Register D, the number of bytes to step over after the 00H (03H).
4EE1
INC BC 03
INCrement Register Pair BC over one byte after the word's 00H. 4EE3H comes back here.
4EE2
DEC E 1D
DECrement Register E, the bytes still to step over. The Z FLAG is set when none are left.
4EE3
If the NZ FLAG is set (bytes left), LOOP BACK to 4EE1H.
4EE5
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, the first byte of the next entry (00H at the end of the table).
4EE6
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the end of the table.
4EE7
If the NZ FLAG is set (another entry), LOOP BACK to 4ED7H to compare it.

4EE9H - Error Exits

4EE9H gives error 34H; 4EEBH leaves with the error code already in Register A. Both enable interrupts, since ROUTE may have disabled them, and go to the SYS0/SYS error exit 4409H, which shows the message (or hands the error to SYS1/SYS under DOS-CALL or a chain file).

4EE9
LD A,34H 3E 34
Load Register A with 34H, the DOS error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR. 4D59H, 4D7DH and 516FH come here, and the table search falls into it when no word matches.
4EEB
EI FB
Enable interrupts (ROUTE disables them at 4D4DH). 4D24H, 4DBBH, 4F96H, 4FE5H, 4FFEH, 503EH and 5166H come here with the error code in Register A.
4EEC
JUMP to SYS0/SYS 4409H, the DOS error exit, with the error code in Register A.

4EEFH - Read a Number

Reads a number at Register Pair HL into Register Pair DE: decimal digits, or hexadecimal digits ended by H. The digits are first read as decimal; if a letter A-H follows them, the number is read again from its start as hexadecimal, and must then end with H. No digit, a missing H or a value above FFFFH is error 2FH. Register Pair HL returns past the number. Used by ERROR (4D39H), ROUTE's MM= (4D84H), CREATE's LRL= and REC= (4FBAH, 4FC8H), CLEAR's options (507DH) and LIST's parameters (5172H).

4EEF
PUSH HL E5
Save Register Pair HL (the start of the number) onto the stack, in case it has to be read again as hexadecimal.
4EF0
LD B,00H 06 00
Load Register B with 00H: bit 0 clear (decimal digits) and bit 1 clear (no digit read yet).
4EF2
GOSUB to 4F12H, which reads the digits at Register Pair HL into Register Pair DE; Register Pair HL stops at the first character that is not a digit.
4EF5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the decimal digits.
4EF6
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A: the letters A-H become 00H-07H.
4EF8
CP 08H FE 08
Compare Register A against 08H. The CARRY FLAG is set for a letter A-H: a hexadecimal digit or the closing H follows.
4EFA
If the NO CARRY FLAG is set (no letter A-H), JUMP to 4F09H: the number is decimal.
4EFC
POP HL E1
Restore Register Pair HL from the stack: the start of the number, to read it again.
4EFD
LD B,01H 06 01
Load Register B with 01H: bit 0 set, read hexadecimal digits; bit 1 clear, no digit read yet.
4EFF
PUSH HL E5
Save Register Pair HL (the start of the number) onto the stack again, to be dropped at 4F0BH.
4F00
GOSUB to 4F12H, which reads the hexadecimal digits at Register Pair HL into Register Pair DE.
4F03
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the hexadecimal digits.
4F04
CP 48H FE 48
Compare Register A against 48H (ASCII H). The Z FLAG is set for the closing H.
4F06
INC HL 23
INCrement Register Pair HL past the H. INC HL does not change the flags.
4F07
If the NZ FLAG is set (no closing H), JUMP to 4F0DH for error 2FH.
4F09
BIT 1,B CB 48
Test bit 1 of Register B: set by 4F2BH once a digit has been read. 4EFAH comes here.
4F0B
POP BC C1
Restore Register Pair BC from the stack, dropping the saved start of the number. POP does not change the flags.
4F0C
RET NZ C0
If the NZ FLAG is set (at least one digit), RETURN with the number in Register Pair DE and Register Pair HL past it.
4F0D
LD A,2FH 3E 2F
Load Register A with 2FH, the DOS error code BAD PARAMETER(S). Every check of a value in SYS14/SYS comes here.
4F0F
JUMP to SYS0/SYS 4409H, the DOS error exit, with the error code in Register A. Interrupts are not enabled here; the RST 28H dispatcher run by 4409H enables them (4B7CH).

4F12H - Read Digits

Register Pair HL = the text, Register B bit 0 = hexadecimal. The digits are added up in Register Pair DE (times 10, or times 16, plus the digit); Register A collects every carry out of bit 15, and any carry is error 2FH. Bit 1 of Register B is set when a digit is read. Returns at the first character that is not a digit, with Register Pair HL pointing at it.

4F12
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value before the first digit. 4EF2H and 4F00H call here.

Digit Loop
Register Pair HL = the next character, Register Pair DE = the value so far.

4F15
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the number. 4F46H comes back here.
4F16
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A: the digits 0-9 become 00H-09H.
4F18
CP 0AH FE 0A
Compare Register A against 0AH. The CARRY FLAG is set for a decimal digit.
4F1A
If the CARRY FLAG is set (0-9), JUMP to 4F26H with the digit's value in Register A.
4F1C
BIT 0,B CB 40
Test bit 0 of Register B: set when hexadecimal digits are being read.
4F1E
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends at this character.
4F1F
SUB 11H D6 11
SUBtract 11H more from Register A: the letters A-F (41H-46H, now 11H-16H) become 00H-05H.
4F21
CP 06H FE 06
Compare Register A against 06H. The NO CARRY FLAG is set for a character that is not A-F.
4F23
RET NC D0
If the NO CARRY FLAG is set (not A-F), RETURN: the number ends at this character.
4F24
ADD A,0AH C6 0A
ADD 0AH to Register A: the letters A-F become their values 0AH-0FH.
4F26
PUSH HL E5
Save Register Pair HL (the position of the digit) onto the stack. 4F1AH comes here with a decimal digit.
4F27
LD H,D 62
Load Register H with Register D, the high byte of the value so far.
4F28
LD L,E 6B
Load Register L with Register E: Register Pair HL = the value so far, and Register Pair DE keeps a copy for the times 5 of a decimal number.
4F29
LD C,A 4F
Load Register C with Register A, the value of the new digit.
4F2A
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects the carries out of Register Pair HL for this digit.
4F2B
SET 1,B CB C8
Set bit 1 of Register B: a digit has been read.
4F2D
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 2. A carry out of bit 15 sets the CARRY FLAG.
4F2E
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC): a carry makes Register A non-zero.
4F2F
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 4.
4F30
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
4F31
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal digits.
4F33
If the Z FLAG is set (decimal), JUMP to 4F38H to make times 5.
4F35
ADD HL,HL 29
Hexadecimal: ADD Register Pair HL to itself, the value times 8.
4F36
JUMP to 4F39H with Register Pair HL = the value times 8.
4F38
ADD HL,DE 19
Decimal: ADD Register Pair DE (the value) to Register Pair HL (the value times 4): the value times 5.
4F39
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry. 4F36H comes here.
4F3A
ADD HL,HL 29
ADD Register Pair HL to itself: the value times 16 (hexadecimal) or times 10 (decimal).
4F3B
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC), collecting the carry.
4F3C
LD E,C 59
Load Register E with Register C, the new digit's value.
4F3D
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the new digit.
4F3F
ADD HL,DE 19
ADD Register Pair DE (the digit) to Register Pair HL.
4F40
ADC A,A 8F
ADD Register A to itself with the CARRY FLAG (ADC): Register A is not 00H, and the NZ FLAG is set, if the value passed FFFFH at any step of this digit.
4F41
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the new value.
4F42
POP HL E1
Restore Register Pair HL from the stack: the position of the digit. POP does not change the flags.
4F43
If the NZ FLAG is set (the value passed FFFFH), JUMP to 4F0DH for error 2FH.
4F45
INC HL 23
INCrement Register Pair HL to the next character.
4F46
LOOP BACK to 4F15H for the next digit at Register Pair HL.

4F48H - Texts and the Device Table (Data)

The hexadecimal text buffer of 4E89H, the text shown between two device names, and the device table of ROUTE. Each device entry is the name, 00H, an attribute byte and the DCB address. Attribute bits: 7 may be routed, 6 may be a target, 5 an address follows (MM=), 4 the word CLEAR, 1 output, 0 input.

4F48-4F4D
DEFM "0000H" / DEFB 03H 30 30 30 30 48 03
The text buffer of 4E89H: SYS0/SYS 44D2H writes an MM block's address over the four 0 characters (4F48H-4F4BH), and 4467H displays it with the H, stopping at the 03H.
4F4E-4F52
DEFM " TO " / DEFB 03H 20 54 4F 20 03
The text shown between the routed device and its target by 4E19H, ended by 03H so the line goes on.
4F53-4F58
DEFM "KB" / DEFB 00H, C1H / DEFW 4015H 4B 42 00 C1 15 40
Device KB: attribute C1H (may be routed, may be a target, input), DCB 4015H, the keyboard control block.
4F59-4F5E
DEFM "DO" / DEFB 00H, C2H / DEFW 401DH 44 4F 00 C2 1D 40
Device DO: attribute C2H (may be routed, may be a target, output), DCB 401DH, the display control block.
4F5F-4F64
DEFM "PR" / DEFB 00H, C2H / DEFW 4025H 50 52 00 C2 25 40
Device PR: attribute C2H (may be routed, may be a target, output), DCB 4025H, the printer control block.
4F65-4F6A
DEFM "RI" / DEFB 00H, C1H / DEFW 41E5H 52 49 00 C1 E5 41
Device RI: attribute C1H (may be routed, may be a target, input), DCB 41E5H, the RS-232 input control block.
4F6B-4F70
DEFM "RO" / DEFB 00H, C2H / DEFW 41EDH 52 4F 00 C2 ED 41
Device RO: attribute C2H (may be routed, may be a target, output), DCB 41EDH, the RS-232 output control block.
4F71-4F76
DEFM "RC" / DEFB 00H, C2H / DEFW 41F5H 52 43 00 C2 F5 41
Device RC: attribute C2H (may be routed, may be a target, output), DCB 41F5H, the RS-232 initialization control block.
4F77-4F7C
DEFM "NL" / DEFB 00H, 43H / DEFW 4CA1H 4E 4C 00 43 A1 4C
Device NL: attribute 43H (a target only, input and output), DCB 4CA1H in SYS0/SYS, whose driver gives 00H and takes nothing.
4F7D-4F85
DEFM "CLEAR" / DEFB 00H, 90H / DEFW 0000H 43 4C 45 41 52 00 90 00 00
The word CLEAR: attribute 90H (bit 7 so that it passes 4D57H, bit 4 for ROUTE,CLEAR at 4D5CH); no DCB.
4F86-4F8C
DEFM "MM=" / DEFB 00H, 60H / DEFW 0000H 4D 4D 3D 00 60 00 00
MM=addr: attribute 60H (a target, followed by an address); no DCB, 4D84H builds one in the block. 4E6FH also displays this name for a DCB not in the table.
4F8D
DEFB 00H 00
The 00H that ends the device table (4E6BH, 4EE5H).

4F8EH - CREATE Command

CREATE,filespec[,LRL=n][,REC=n][,ASE=Y/N][,ASC=Y/N]. SYS1/SYS has parsed the filespec into the FCB at 4480H without opening it; Register Pair HL points at the command line after it. The options are collected on the stack: a word with the ASE/ASC flags (Register C: bit 7 ASE=N, bit 6 ASC=N) and the LRL (Register B, 00H for 256), and below it the number of records (0000H when REC is not given). The file is then opened, made if it does not exist, through SYS2/SYS; its FPDE gets the LRL and the ASE/ASC bits; with REC the whole file is allocated by writing its last sector, every sector is then written with zeros, and the end of file is set to REC times LRL bytes. Without REC the end of file is set to 0. The file is closed through SYS0/SYS 4428H.

4F8E
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H, the starting value of both words: no records, no flags and an LRL of 00H (256).
4F91
PUSH BC C5
Save Register Pair BC (0000H) onto the stack: the number of records, changed only by REC= (4FCDH).
4F92
PUSH BC C5
Save Register Pair BC (0000H) onto the stack again: the option word, Register C = the ASE/ASC flags and Register B = the LRL.

Option Loop
Register Pair HL = the command line; the option word is on top of the stack, the number of records below it.

4F93
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return; a comma or spaces give the NZ FLAG with Register Pair HL past them; anything else gives the CARRY FLAG with Register A = 34H. 4FCFH comes back here.
4F96
If the CARRY FLAG is set (a character that is not a separator), JUMP to 4EEBH to leave with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
4F99
If the Z FLAG is set (no more options), JUMP to 4FD1H to create the file.
4F9B
LD BC,5050H 01 50 50
Load Register Pair BC with 5050H, CREATE's option table: LRL=, REC=, ASE= and ASC=.
4F9E
GOSUB to 4EC9H, which looks the option at Register Pair HL up in the table at Register Pair BC: Register A = its flag byte, Register Pair DE = the address of its handler, Register Pair HL past the option's name. An unknown option is error 34H.
4FA1
PUSH DE D5
Save Register Pair DE (the handler's address: 4FBAH, 4FC8H or 4FA4H) onto the stack, for the RET at 4FA3H.
4FA2
LD D,A 57
Load Register D with Register A, the option's flag byte: 80H for ASE=, 40H for ASC=, 00H for LRL= and REC=.
4FA3
RET C9
RETURN to the address just pushed: a jump to the option's handler with Register D = its flag byte.
4FA4
LD E,00H 1E 00
ASE= or ASC=: load Register E with 00H, the mask for Y (the flag stays clear).
4FA6
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the letter after the = sign.
4FA7
CP 59H FE 59
Compare Register A against 59H (ASCII Y). The Z FLAG is set for Y.
4FA9
INC HL 23
INCrement Register Pair HL past the letter. INC HL does not change the flags.
4FAA
If the Z FLAG is set (Y), JUMP to 4FB2H with Register E = 00H.
4FAC
DEC E 1D
DECrement Register E from 00H to FFH, the mask for N (the flag is set).
4FAD
CP 4EH FE 4E
Compare Register A (the letter) against 4EH (ASCII N). The Z FLAG is set for N.
4FAF
If the NZ FLAG is set (neither Y nor N, or from 4FC0H an LRL out of range), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).
4FB2
LD A,D 7A
Load Register A with Register D, the option's flag: 80H for ASE=, 40H for ASC=. 4FAAH comes here for Y.
4FB3
AND E A3
AND Register A with Register E (00H for Y, FFH for N): the flag is kept only for N.
4FB4
POP BC C1
Restore Register Pair BC from the stack: the option word, Register C = the flags so far and Register B = the LRL.
4FB5
OR C B1
OR Register A with Register C, adding the new flag to the flags so far (a Y does not clear an earlier N).
4FB6
LD C,A 4F
Load Register C with Register A, the flags with this option's bit added.
4FB7
PUSH BC C5
Save Register Pair BC (the flags and the LRL) back onto the stack.
4FB8
JUMP to 4FCFH, which goes back to the option loop.
4FBA
LRL=: GOSUB to 4EEFH, which reads the record length at Register Pair HL into Register Pair DE.
4FBD
DEC DE 1B
DECrement Register Pair DE: a record length of 1-256 becomes 0000H-00FFH.
4FBE
LD A,D 7A
Load Register A with Register D, the high byte of the record length minus 1.
4FBF
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set only if the record length was 1-256.
4FC0
If the NZ FLAG is set (0, or more than 256), JUMP to 4FAFH, whose JP NZ then leaves with error 2FH.
4FC2
POP BC C1
Restore Register Pair BC from the stack: the option word, Register C = the flags and Register B = the old LRL.
4FC3
INC E 1C
INCrement Register E, the low byte of the record length minus 1: Register E = the record length, with 256 giving 00H.
4FC4
LD B,E 43
Load Register B with Register E, the new LRL (00H for 256).
4FC5
PUSH BC C5
Save Register Pair BC (the flags and the new LRL) back onto the stack.
4FC6
JUMP to 4FCFH, which goes back to the option loop.
4FC8
REC=: GOSUB to 4EEFH, which reads the number of records at Register Pair HL into Register Pair DE.
4FCB
POP BC C1
Restore Register Pair BC from the stack: the option word (flags and LRL).
4FCC
POP AF F1
Restore Register Pair AF from the stack, dropping the old number of records.
4FCD
PUSH DE D5
Save Register Pair DE (the new number of records) onto the stack.
4FCE
PUSH BC C5
Save Register Pair BC (the option word) back on top of it.
4FCF
JUMP to 4F93H for the next option at Register Pair HL. 4FB8H and 4FC6H come here.
4FD1
POP BC C1
Restore Register Pair BC from the stack: Register C = the ASE/ASC flags, Register B = the LRL. 4F99H comes here.
4FD2
PUSH BC C5
Save Register Pair BC back onto the stack, keeping it for 4FE8H; Register B stays the LRL for the open.
4FD3
LD A,44H 3E 44
Load Register A with 44H, the RST 28H code of SYS2/SYS function 2: open a new or existing file.
4FD5
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the FCB holding the filespec parsed by SYS1/SYS.
4FD8
GOSUB to 4D28H, which runs RST 28H with Register A = 44H: SYS2/SYS opens the file in the FCB at Register Pair DE (4480H) with the record length in Register B and the buffer at Register Pair HL (the command line pointer), making it if it does not exist; then SYS14/SYS is reloaded and returns here. An open error leaves through 4409H.
4FDB
PUSH DE D5
Save Register Pair DE (4480H, the FCB, as SYS2/SYS returned it) onto the stack.
4FDC
POP IX DD E1
Restore Index Register IX from the stack: Index Register IX = 4480H, the file's FCB, for the SYS0/SYS directory routines.
4FDE
RES 7,(IX+01H) DD CB 01 BE
Reset bit 7 of the byte at Index Register IX+01H, FCB+1: the open set it for a record length other than 256; cleared, the writes at 5022H and 503BH write whole sectors.
4FE2
GOSUB to SYS0/SYS 48F0H, which selects the FCB's drive and reads the directory sector holding the file's FPDE (FCB+7) into 4300H: Register Pair HL = the FPDE, or the NZ FLAG with an error code in Register A.
4FE5
If the NZ FLAG is set (an error), JUMP to 4EEBH to leave with it in Register A.
4FE8
POP BC C1
Restore Register Pair BC from the stack: Register C = the ASE/ASC flags, Register B = the LRL.
4FE9
LD A,C 79
Load Register A with Register C, the flags collected from ASE= and ASC=.
4FEA
AND C0H E6 C0
AND Register A with C0H, keeping bit 7 (ASE=N) and bit 6 (ASC=N).
4FEC
LD C,A 4F
Load Register C with Register A, the two flag bits.
4FED
INC HL 23
INCrement Register Pair HL to FPDE byte 1, the file's flags: bit 7 no extend, bit 6 no deallocate, bit 5 updated.
4FEE
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, FPDE byte 1.
4FEF
AND 1FH E6 1F
AND Register A with 1FH, clearing bits 7, 6 and 5 and keeping bits 0-4.
4FF1
OR C B1
OR Register A with Register C, putting in the ASE=N and ASC=N bits that were given.
4FF2
LD (HL),A 77
Store Register A at Register Pair HL, the new FPDE byte 1.
4FF3
INC HL 23
INCrement Register Pair HL to FPDE byte 2 of the file's entry.
4FF4
INC HL 23
INCrement Register Pair HL to FPDE byte 3, the end of file's low byte.
4FF5
INC HL 23
INCrement Register Pair HL to FPDE byte 4, the record length.
4FF6
LD (HL),B 70
Store Register B (the LRL, 00H for 256) at Register Pair HL, FPDE byte 4.
4FF7
LD (IX+02H),00H DD 36 02 00
Store 00H at Index Register IX+02H, FCB+2, which the open copied from FPDE byte 1: with bit 7 (no extend) clear in the FCB, the allocation for REC below is allowed even when ASE=N was given.
4FFB
GOSUB to SYS0/SYS 48C4H, which writes the directory sector in 4300H (with the changed FPDE) back to the diskette with the directory mark and a verify; the NZ FLAG with an error code in Register A on failure.
4FFE
If the NZ FLAG is set (a write error), JUMP to 4EEBH to leave with it in Register A.
5001
POP HL E1
Restore Register Pair HL from the stack: the number of records from REC= (0000H if REC was not given).
5002
LD A,H 7C
Load Register A with Register H, the high byte of the number of records.
5003
OR L B5
OR Register A with Register L: the Z FLAG is set (and Register A = 00H) if no records are to be written.
5004
If the Z FLAG is set (no REC), JUMP to 5047H with Register Pair HL = 0000H and Register A = 00H: the end of file becomes 0.
5006
LD A,B 78
Load Register A with Register B, the LRL (00H for 256).
5007
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for an LRL of 256.
5008
LD C,A 4F
Load Register C with Register A, the LRL; for 256 this is the 00H that is the byte count of the last sector. LD does not change the flags.
5009
If the NZ FLAG is set (an LRL of 1-255), GOSUB to SYS0/SYS 4C42H, which multiplies Register Pair HL (the number of records) by Register A (the LRL): the 24-bit byte count returns in Registers H, L and C, so Register Pair HL = the full sectors and Register C = the bytes in the last, partly filled one. For an LRL of 256 Register Pair HL already is the number of sectors and Register C = 00H.
500C
LD A,C 79
Load Register A with Register C, the bytes in the last sector.
500D
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the file ends exactly at the end of a sector.
500E
PUSH AF F5
Save Register Pair AF onto the stack: Register A = the bytes in the last sector, the end of file's low byte (5046H).
500F
PUSH HL E5
Save Register Pair HL (the full sectors, the end of file's middle and high bytes) onto the stack (5045H).
5010
If the NZ FLAG is set (a partly filled sector at the end), JUMP to 5013H: Register Pair HL is already the number of that last sector.
5012
DEC HL 2B
DECrement Register Pair HL: the file ends at a sector boundary, so its last sector is one below the count of full sectors.
5013
LD (448AH),HL 22 8A 44
Store Register Pair HL (the number of the last sector) at 448AH-448BH, FCB+10 and +11, the middle and high bytes of NEXT: the next write goes to that sector.
5016
PUSH HL E5
Save Register Pair HL (the number of the last sector) onto the stack (5033H).
5017
LD HL,4439H 21 39 44
Load Register Pair HL with 4439H, the SYS0/SYS vector that writes the sector at NEXT of the FCB at Register Pair DE.
501A
LD (4D34H),HL 22 34 4D
Self-Modifying Code
Store Register Pair HL (4439H) at 4D34H-4D35H, the operand of the JP Z at 4D33H, so that 4D27H calls the sector write.
501D
LD HL,428BH 21 8B 42
Point Register Pair HL to 428BH, the overlays' temporary flags in SYS0/SYS.
5020
SET 1,(HL) CB CE
Set bit 1 of the byte at Register Pair HL (428BH): SYS2/SYS's allocation takes no extra granules (it tests the bit at its 5018H).
5022
GOSUB to 4D27H, which calls SYS0/SYS 4439H with Register Pair DE = 4480H: writing the last sector allocates every granule up to it (SYS2/SYS function 64H is loaded for that); then SYS14/SYS is reloaded and returns here. The sector written comes from the buffer the open was given; 503BH writes it again with zeros. A write error leaves through 4409H.
5025
RES 1,(HL) CB 8E
Reset bit 1 of the byte at Register Pair HL (428BH, kept by the call): extra granules are allowed again.
5027
LD HL,4D4DH 21 4D 4D
Load Register Pair HL with 4D4DH, the start of SYS14/SYS's ROUTE code, which CREATE does not need.
502A
LD (4483H),HL 22 83 44
Store Register Pair HL (4D4DH) at 4483H-4484H, FCB+3 and +4, the buffer address: 4D4DH-4E4CH becomes the sector buffer.
502D
XOR A AF
Load Register A with 00H (XOR A with itself), the value every byte of the file gets.
502E
LD B,A 47
Load Register B with Register A (00H): the DJNZ loop runs 256 times.

Clear the Buffer
Register Pair HL = the buffer byte, Register B counts 256 bytes.

502F
LD (HL),A 77
Store Register A (00H) at Register Pair HL, a byte of the buffer 4D4DH-4E4CH. 5031H comes back here.
5030
INC HL 23
INCrement Register Pair HL to the next byte of the buffer.
5031
DECrement Register B and LOOP BACK to 502FH until all 256 bytes are 00H.
5033
POP BC C1
Restore Register Pair BC from the stack: the number of the last sector, saved at 5016H.
5034
INC BC 03
INCrement Register Pair BC: the number of sectors in the file.
5035
LD H,A 67
Load Register H with Register A (00H), the high byte of the first sector number.
5036
LD L,A 6F
Load Register L with Register A: Register Pair HL = 0000H.
5037
LD (448AH),HL 22 8A 44
Store Register Pair HL (0000H) at 448AH-448BH, the middle and high bytes of NEXT: the writes start at the first sector.

Write Loop
Register Pair BC = the sectors still to write; each write moves NEXT on by one sector. Every granule is already allocated, so these writes do not load another overlay.

503A
DEC BC 0B
DECrement Register Pair BC, the sectors still to write. 5043H comes back here.
503B
GOSUB to SYS0/SYS 4439H, which writes the zeroed buffer at FCB+3 (4D4DH) as the sector at NEXT of the FCB at Register Pair DE (4480H); the NZ FLAG with an error code in Register A on failure.
503E
If the NZ FLAG is set (a write error), JUMP to 4EEBH to leave with it in Register A.
5041
LD A,B 78
Load Register A with Register B, the high byte of the sectors still to write.
5042
OR C B1
OR Register A with Register C: the Z FLAG is set when no sector is left.
5043
If the NZ FLAG is set (sectors left), LOOP BACK to 503AH.
5045
POP HL E1
Restore Register Pair HL from the stack: the full sectors, saved at 500FH, the end of file's middle and high bytes.
5046
POP AF F1
Restore Register Pair AF from the stack: Register A = the bytes in the last sector, the end of file's low byte.
5047
LD (448CH),HL 22 8C 44
Store Register Pair HL at 448CH-448DH, FCB+12 and +13, the middle and high bytes of the end of file. 5004H comes here with 0000H.
504A
LD (4488H),A 32 88 44
Store Register A at 4488H, FCB+8, the low byte of the end of file: the end of file is now REC times LRL bytes (or 0).
504D
JUMP to SYS0/SYS 4428H, which closes the file in the FCB at Register Pair DE (4480H), writing its end of file into the FPDE, and returns to the dispatcher's tail 4BC5H with the result.

5050H - CREATE Option Table (Data)

Read by 4EC9H from 4F9BH. Each entry: the option word with its = sign, 00H, the flag byte (bit 7 ASE, bit 6 ASC) and the address of the handler 4FA3H jumps to.

5050-5057
DEFM "LRL=" / DEFB 00H, 00H / DEFW 4FBAH 4C 52 4C 3D 00 00 BA 4F
Option LRL=: flag 00H, handler 4FBAH, which reads the record length (1-256).
5058-505F
DEFM "REC=" / DEFB 00H, 00H / DEFW 4FC8H 52 45 43 3D 00 00 C8 4F
Option REC=: flag 00H, handler 4FC8H, which reads the number of records.
5060-5067
DEFM "ASE=" / DEFB 00H, 80H / DEFW 4FA4H 41 53 45 3D 00 80 A4 4F
Option ASE=: flag 80H (FPDE byte 1 bit 7, no extend, set for N), handler 4FA4H.
5068-506F
DEFM "ASC=" / DEFB 00H, 40H / DEFW 4FA4H 41 53 43 3D 00 40 A4 4F
Option ASC=: flag 40H (FPDE byte 1 bit 6, no deallocation by the close, set for N), handler 4FA4H.
5070
DEFB 00H 00
The 00H that ends CREATE's option table (4EE5H).

5071H - CLEAR Command

CLEAR[,START=a][,END=b][,MEM=c]. Every option stores its number straight into the operand it sets (509EH MEM, 50AEH END, 50B5H START). CLEAR then ends every route, empties the queue of named routines (4058H) and the timer chain (4584H), sets HIMEM (4411H) to MEM or to the top of memory found at reset (42C9H), whichever is lower (MEM below 7000H is error 2FH), and fills START (default 5200H, never lower) to the lower of END and HIMEM with 00H.

5071
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the first character of the command line after CLEAR.
5072
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return that ends the command line. The Z FLAG is set for CLEAR alone.
5074
If the Z FLAG is set (no options), JUMP to 508BH.

Option Loop
Register Pair HL = the command line at the next option.

5076
LD BC,50CAH 01 CA 50
Load Register Pair BC with 50CAH, CLEAR's option table: START=, END= and MEM=. 5089H comes back here.
5079
GOSUB to 4EC9H, which looks the option at Register Pair HL up in the table at Register Pair BC: Register Pair DE = the address of the operand it sets, Register Pair HL past the option's name. An unknown option is error 34H.
507C
PUSH DE D5
Save Register Pair DE (the operand's address: 50B5H, 50AEH or 509EH) onto the stack.
507D
GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE.
5080
EX (SP),HL E3
Exchange Register Pair HL with the word on top of the stack (at the Stack Pointer): Register Pair HL = the operand's address, and the command line pointer is kept on the stack.
5081
LD (HL),E 73
Self-Modifying Code
Store Register E (the low byte of the number) at Register Pair HL, the operand at 50B5H (START), 50AEH (END) or 509EH (MEM).
5082
INC HL 23
INCrement Register Pair HL to the high byte of that operand.
5083
LD (HL),D 72
Store Register D (the high byte of the number) at Register Pair HL: the operand now holds the option's value.
5084
POP HL E1
Restore Register Pair HL from the stack: the command line past the number.
5085
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return; a comma or spaces give the NZ FLAG with Register Pair HL past them; anything else gives the CARRY FLAG with Register A = 34H.
5088
RET C D8
If the CARRY FLAG is set (not a separator), RETURN to the dispatcher's tail 4BC5H with Register A = 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
5089
If the NZ FLAG is set (another option follows), LOOP BACK to 5076H.
508B
GOSUB to 4E01H, which ends every route (as ROUTE,CLEAR does) and returns with interrupts enabled. 5074H comes here.
508E
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the value of an empty queue or chain.
5091
LD (4058H),HL 22 58 40
Store Register Pair HL (0000H) at 4058H-4059H, the head of the queue of named routines (SYS9/SYS 5048H enqueues them): the queue is empty.
5094
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H again, the value of an empty timer chain.
5097
LD (4584H),HL 22 84 45
Store Register Pair HL (0000H) at 4584H-4585H, the head of SYS0/SYS's timer chain (the operand its clock routine 4551H walks): every timer routine is dequeued.
509A
LD HL,(42C9H) 2A C9 42
Load Register Pair HL with the word at 42C9H, the top of memory SYS0/SYS found at reset.
509D
LD DE,FFFFH 11 FF FF
Self-Modifying Code
Load Register Pair DE with MEM: the operand 509EH-509FH holds FFFFH in the file and the MEM= value after 5081H stores it.
50A0
LD A,D 7A
Load Register A with Register D, the high byte of MEM.
50A1
CP 70H FE 70
Compare Register A against 70H. The CARRY FLAG is set for a MEM below 7000H.
50A3
If the CARRY FLAG is set (MEM below 7000H), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).
50A6
RST 18H DF
RST 18H: the ROM compares Register Pair HL (the top of memory) with Register Pair DE (MEM). The CARRY FLAG is set if the top of memory is lower.
50A7
If the CARRY FLAG is set (the top of memory is lower), JUMP to 50AAH with Register Pair HL = the top of memory.
50A9
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = MEM, the lower of the two.
50AA
LD (4411H),HL 22 11 44
Store Register Pair HL (the new HIMEM, the lower of MEM and the top of memory) at 4411H-4412H, SYS0/SYS's HIMEM. 50A7H comes here.
50AD
LD DE,FFFFH 11 FF FF
Self-Modifying Code
Load Register Pair DE with END: the operand 50AEH-50AFH holds FFFFH in the file and the END= value after 5081H stores it.
50B0
RST 18H DF
RST 18H: the ROM compares Register Pair HL (HIMEM) with Register Pair DE (END). The NO CARRY FLAG is set if HIMEM is not below END.
50B1
If the NO CARRY FLAG is set (END is not above HIMEM), JUMP to 50B4H with Register Pair DE = END, the last byte to clear.
50B3
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = HIMEM, the last byte to clear.
50B4
LD HL,5200H 21 00 52
Self-Modifying Code
Load Register Pair HL with START: the operand 50B5H-50B6H holds 5200H in the file and the START= value after 5081H stores it. 50B1H comes here.
50B7
LD A,H 7C
Load Register A with Register H, the high byte of START.
50B8
CP 52H FE 52
Compare Register A against 52H. The CARRY FLAG is set for a START below 5200H, memory the DOS uses itself.
50BA
If the CARRY FLAG is set (START below 5200H), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).
50BD
DEC HL 2B
DECrement Register Pair HL: START minus 1, since the fill loop increments first.
50BE
RST 18H DF
RST 18H: the ROM compares Register Pair HL (START minus 1) with Register Pair DE (the last byte to clear). The NO CARRY FLAG is set if START lies beyond it.
50BF
If the NO CARRY FLAG is set (START is past the end), JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)).

Fill Loop
Register Pair HL = the byte cleared, Register Pair DE = the last byte to clear.

50C2
INC HL 23
INCrement Register Pair HL to the next byte to clear. 50C6H comes back here.
50C3
LD (HL),00H 36 00
Store 00H at Register Pair HL, clearing that byte of memory.
50C5
RST 18H DF
RST 18H: the ROM compares Register Pair HL (the byte just cleared) with Register Pair DE (the last byte). The CARRY FLAG is set while Register Pair HL is below it.
50C6
If the CARRY FLAG is set, LOOP BACK to 50C2H; the last byte itself is cleared on the final pass.
50C8
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
50C9
RET C9
RETURN to the dispatcher's tail 4BC5H with Register A = 00H and the Z FLAG: no error.

50CAH - CLEAR Option Table (Data)

Read by 4EC9H from 5076H. Each entry: the option word with its = sign, 00H, a flag byte of 00H and the address of the operand that the option's number is stored in (5081H).

50CA-50D3
DEFM "START=" / DEFB 00H, 00H / DEFW 50B5H 53 54 41 52 54 3D 00 00 B5 50
Option START=: its number goes to 50B5H, the operand of the LD HL at 50B4H (the first byte to clear).
50D4-50DB
DEFM "END=" / DEFB 00H, 00H / DEFW 50AEH 45 4E 44 3D 00 00 AE 50
Option END=: its number goes to 50AEH, the operand of the LD DE at 50ADH (the last byte to clear).
50DC-50E3
DEFM "MEM=" / DEFB 00H, 00H / DEFW 509EH 4D 45 4D 3D 00 00 9E 50
Option MEM=: its number goes to 509EH, the operand of the LD DE at 509DH (the new HIMEM).
50E4
DEFB 00H 00
The 00H that ends CLEAR's option table (4EE5H).

50E5H - LIST and PRINT Commands

LIST,filespec[,start-line[,line-count]] shows a text file on the display; PRINT does the same on the printer. SYS1/SYS has opened the file in the FCB at 4480H and left the command line pointer on the stack below the dispatcher's return address 4BC5H. A line ends with a carriage return (0DH). Bit 7 of each byte is cleared; a byte above option AX (4290H) or below 20H, other than the carriage return, is shown as a period. The keys are looked at after each line and after every 256 characters: the up arrow or the right arrow pauses, then ENTER goes on and the up arrow stops; the up arrow held while a byte is read stops at once. The end of the file ends the listing; another read error is reported.

50E5
LD A,3BH 3E 3B
PRINT: load Register A with 3BH, the low byte of 003BH, the ROM routine that sends a character to the printer.
50E7
LD (5182H),A 32 82 51
Self-Modifying Code
Store Register A (3BH) at 5182H, the low byte of the operand of the CALL 0033H at 5181H: every character now goes to the ROM printer routine 003BH instead of the display routine 0033H.
50EA
POP AF F1
LIST (and PRINT from 50E7H): restore Register Pair AF from the stack, dropping 4BC5H, the dispatcher's return address; the final RET then returns to the address SYS1/SYS left below the command line pointer.
50EB
POP HL E1
Restore Register Pair HL from the stack: the command line pointer SYS1/SYS left, after the filespec.
50EC
GOSUB to SYS0/SYS 4C7AH, which looks at the character at Register Pair HL: the Z FLAG at the carriage return; a comma or spaces give the NZ FLAG with Register Pair HL past them; anything else the CARRY FLAG and the NZ FLAG.
50EF
LD DE,0001H 11 01 00
Load Register Pair DE with 0001H, the first line shown when no start line is given. LD does not change the flags.
50F2
If the NZ FLAG is set (something follows the filespec), GOSUB to 516FH, which reads the start line into Register Pair DE (0 is error 2FH) and looks at the next separator, returning its flags.
50F5
PUSH DE D5
Save Register Pair DE (the start line) onto the stack.
50F6
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH, the line count when none is given: every line to the end of the file. LD does not change the flags.
50F9
If the NZ FLAG is set (a line count follows), GOSUB to 516FH, which reads it into Register Pair DE and looks at the next separator.
50FC
If the NZ FLAG is set (still more follows), JUMP to 517AH for error 2FH (BAD PARAMETER(S)).
50FE
POP BC C1
Restore Register Pair BC from the stack: the start line.
50FF
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, the DOS sector buffer.
5102
LD (4483H),HL 22 83 44
Store Register Pair HL (4300H) at 4483H-4484H, FCB+3 and +4, the buffer address of the FCB at 4480H.

Skip Lines
Register Pair BC = the start line; one line is skipped for each count above 1.

5105
DEC BC 0B
DECrement Register Pair BC, the lines still to skip plus one. 5111H comes back here.
5106
LD A,B 78
Load Register A with Register B, the high byte of the count.
5107
OR C B1
OR Register A with Register C: the Z FLAG is set when the start line has been reached.
5108
If the Z FLAG is set (no more lines to skip), JUMP to 5113H to start showing.
510A
GOSUB to 513AH, which reads the next byte of the file into Register A (a period for a byte that cannot be shown). 510FH comes back here.
510D
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return that ends a line.
510F
If the NZ FLAG is set (not the end of the line), LOOP BACK to 510AH.
5111
JUMP to 5105H: one more line has been skipped.

Show Loop
Register Pair DE = the lines still to show, Register C = the characters left before the next key check.

5113
GOSUB to 513AH, which reads the next byte of the file into Register A (a period for a byte that cannot be shown). 5108H, 511EH, 512CH and 5138H come here.
5116
GOSUB to 517FH, which sends the character in Register A to the display (or to the printer for PRINT).
5119
DEC C 0D
DECrement Register C, the characters left before the next key check. Register C is 00H when the skip loop ends, so the first check comes after 256 characters or at the first carriage return.
511A
If the Z FLAG is set (256 characters since the last check), JUMP to 5125H to look at the keys.
511C
CP 0DH FE 0D
Compare Register A (the character just sent) against 0DH, the carriage return.
511E
If the NZ FLAG is set (not the end of a line), LOOP BACK to 5113H.
5120
DEC DE 1B
DECrement Register Pair DE, the lines still to show.
5121
LD A,D 7A
Load Register A with Register D, the high byte of the lines still to show.
5122
OR E B3
OR Register A with Register E: the Z FLAG is set when the last line has been shown.
5123
If the Z FLAG is set (the line count is reached), JUMP to 516AH to end the listing.
5125
LD C,00H 0E 00
Load Register C with 00H, so that the next 256 characters pass before the next key check. 511AH comes here.
5127
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, the keyboard row with ENTER (bit 0), the up arrow (bit 3) and the right arrow (bit 6).
512A
AND 48H E6 48
AND Register A with 48H, keeping bit 6 (right arrow) and bit 3 (up arrow).
512C
If the Z FLAG is set (neither arrow is held), LOOP BACK to 5113H to go on.

Pause
Wait until ENTER or the up arrow is pressed.

512E
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, the keyboard row with ENTER (bit 0) and the up arrow (bit 3). 5133H comes back here.
5131
AND 09H E6 09
AND Register A with 09H, keeping bit 3 (up arrow) and bit 0 (ENTER).
5133
If the Z FLAG is set (neither key), LOOP BACK to 512EH: the listing stays paused.
5135
RRCA 0F
Rotate Register A right (RRCA): bit 0, ENTER, goes into the CARRY FLAG.
5136
If the NO CARRY FLAG is set (the up arrow without ENTER), JUMP to 516AH to stop the listing.
5138
ENTER: JUMP to 5113H to go on showing the file.

513AH - Read a Character of the File

Returns the next byte of the file in Register A, ready to show: bit 7 cleared, and a period for a byte above option AX (4290H) or a control character other than the carriage return. The up arrow, or the end of the file, ends the whole command from here (5169H drops this routine's return address). Another read error leaves through 4EEBH.

513A
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, the keyboard row with the up arrow (bit 3). 510AH and 5113H call here.
513D
AND 08H E6 08
AND Register A with 08H, keeping bit 3, the up arrow.
513F
If the NZ FLAG is set (the up arrow is held), JUMP to 5169H to stop the listing.
5141
PUSH DE D5
Save Register Pair DE (the lines still to show) onto the stack.
5142
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the FCB of the file being listed.
5145
GOSUB to the ROM routine at 0013H, which reads a byte from the control block at Register Pair DE into Register A; for an FCB it goes through 4033H to SYS0/SYS 4A80H, which reads the next byte of the file. The NZ FLAG with an error code in Register A on failure.
5148
POP DE D1
Restore Register Pair DE from the stack: the lines still to show. POP does not change the flags.
5149
If the NZ FLAG is set (an error or the end of the file), JUMP to 5160H.
514B
AND 7FH E6 7F
AND Register A with 7FH, clearing bit 7 of the byte read.
514D
PUSH HL E5
Save Register Pair HL onto the stack while Register Pair HL points at option AX.
514E
LD HL,4290H 21 90 42
Point Register Pair HL to 4290H, SYSTEM option AX: the highest character code shown as it is.
5151
CP (HL) BE
Compare Register A (the byte) against the byte at Register Pair HL (option AX): the CARRY FLAG is set below AX, the Z FLAG if equal.
5152
POP HL E1
Restore Register Pair HL from the stack. POP does not change the flags.
5153
If the CARRY FLAG is set (below AX), JUMP to 5157H to check for a control character.
5155
If the NZ FLAG is set (above AX), JUMP to 515DH to show a period instead.
5157
CP 20H FE 20
Compare Register A against 20H, the space. The NO CARRY FLAG is set for a space or anything above it. 5153H comes here.
5159
RET NC D0
If the NO CARRY FLAG is set (a character that can be shown), RETURN with it in Register A.
515A
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return.
515C
RET Z C8
If the Z FLAG is set (a carriage return), RETURN with it in Register A.
515D
LD A,2EH 3E 2E
Load Register A with 2EH (ASCII period), shown in place of the byte. 5155H comes here.
515F
RET C9
RETURN with Register A = 2EH, the period that is shown instead of the byte.
5160
CP 1CH FE 1C
Compare Register A (the error code) against 1CH, END OF FILE ENCOUNTERED. 5149H comes here.
5162
If the Z FLAG is set (the end of the file), JUMP to 5169H to end the listing without an error.
5164
CP 1DH FE 1D
Compare Register A against 1DH, PAST END OF FILE.
5166
If the NZ FLAG is set (another error), JUMP to 4EEBH to leave with the error code in Register A.
5169
POP AF F1
Restore Register Pair AF from the stack, dropping the return address of the call to 513AH (from 510AH or 5113H). 513FH and 5162H come here.
516A
GOSUB to 517DH, which sends a carriage return to end the last line. 5123H and 5136H come here.
516D
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
516E
RET C9
RETURN with Register A = 00H and the Z FLAG (no error) to the address SYS1/SYS left on the stack below the command line pointer.

516FH - Read a LIST Parameter

Called with the flags of SYS0/SYS 4C7AH. Reads a start line or a line count into Register Pair DE (0 is error 2FH) and returns the flags of 4C7AH for the character after it.

516F
If the CARRY FLAG is set (the character after the last item is not a separator), JUMP to 4EE9H for error 34H. 50F2H and 50F9H call here.
5172
GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE.
5175
LD A,D 7A
Load Register A with Register D, the high byte of the number.
5176
OR E B3
OR Register A with Register E: the Z FLAG is set if the number is 0.
5177
If the NZ FLAG is set (not 0), JUMP to SYS0/SYS 4C7AH, which looks at the character after the number and returns its flags (Z at the carriage return, NZ for more, CARRY for a bad character) to the caller of 516FH.
517A
JUMP to 4F0DH for error 2FH (BAD PARAMETER(S)): a start line or line count of 0, or a third parameter (from 50FCH).

517DH - Output a Character

517DH sends a carriage return, 517FH the character in Register A, to the display through the ROM routine 0033H, or to the printer through 003BH once PRINT has changed the operand at 5182H. Register Pairs AF and DE are kept.

517D
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return that ends the last line. 516AH calls here.
517F
PUSH DE D5
Save Register Pair DE onto the stack; the ROM output routine changes it. 5116H calls here.
5180
PUSH AF F5
Save Register Pair AF (Register A = the character) onto the stack.
5181
Self-Modifying Code
GOSUB to the ROM routine at 0033H, which displays the character in Register A; the operand's low byte at 5182H is 33H in the file and 3BH after PRINT's 50E7H, which sends it to the printer through 003BH instead.
5184
POP AF F1
Restore Register Pair AF from the stack: Register A = the character sent.
5185
POP DE D1
Restore Register Pair DE from the stack, as it was before the ROM output call.
5186
RET C9
RETURN with Register A = the character and Register Pair DE unchanged.

5187H - End of the File

The rest of the last load record.

5187-51E7
DEFB 00H x 97 00 x 97
97 bytes of 00H at the end of the file (5187H-51E7H); no code of SYS14/SYS reads them.