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

Page Customization

Introduction/Summary

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

SYS14/SYS holds six DOS commands: ROUTE, CREATE, CLEAR, LIST, PRINT and ERROR. It loads into the overlay area at 4D00H-51E7H (1,256 bytes in five load records, transfer address 4D00H); 5175H-51E7H are unused zero bytes. SYS1's command table sends the commands here with RST 28H code F0H (function 7 of directory slot 10H) and the sub-function in Register C.

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

Sub-Functions of Code F0H

CCommandWhat it does (from the code)
1ROUTERoutes KB, DO or PR to KB, DO, PR, NL or a device in memory (MM=addr); ROUTE,CLEAR ends all routes; ROUTE alone lists them (4D4DH).
2CREATEMakes a file with LRL=, and with REC= pre-allocates and zero-fills REC x LRL bytes; ASE= and ASC= set the FPDE flags (4F7CH).
3-The way back after 4D27H has called another overlay (4D27H).
4CLEAREnds routes, the *name routine list and the timer chain except the clock, sets HIMEM, zeroes memory from START to END (505FH).
5LISTShows a text file, from a given line, for a given number of lines (50D3H).
6PRINTThe same on the printer.
7ERRORShows the DOS error message n, through SYS4 function 3 (4D39H).

Errors: 2AH (other codes), 2FH BAD PARAMETER(S), 34H ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR, 3BH INSUFFICIENT MEMORY (no free ROUTE entry), and any DOS error of the file work.

Variables

Locations inside SYS14 whose contents change while it runs:

Address RangePurpose
4D34H-4D35H
2 bytes
The routine 4D27H calls: 0000H in the file, 4439H (SYS0's sector write) stored by CREATE at 5008H.
4D4DH-4E4CH
256 bytes
ROUTE's own code, used by CREATE as a zeroed sector buffer after the file is allocated (5015H).
4DA5H
1 byte
ROUTE: the routed device's attribute (operand of 4DA4H; written at 4D61H).
4DCEH-4DCFH
2 bytes
ROUTE: the routed device's DCB (operand of 4DCDH; written at 4D64H).
4DD9H
1 byte
ROUTE: the routed DCB's own type byte (operand of 4DD8H; written at 4D6DH).
4DE2H-4DE3H
2 bytes
ROUTE: the target DCB (operand of 4DE1H; written at 4DABH).
4F48H-4F4DH
6 bytes
Hex buffer for an MM= address (written by SYS0 4063H at 4E8DH).
508CH-508DH
2 bytes
CLEAR: MEM (operand of 508BH; FFFFH in the file, written at 506FH).
509CH-509DH
2 bytes
CLEAR: END (operand of 509BH; FFFFH in the file, written at 506FH).
50A3H-50A4H
2 bytes
CLEAR: START (operand of 50A2H; 5200H in the file, written at 506FH).
5170H
1 byte
Low byte of the output routine called at 516FH: 33H (display) in the file, 3BH (printer) for PRINT (written at 50D5H).

Locations outside SYS14 that it reads or writes:

Address RangePurpose
3840H
1 byte
Keyboard row 6: ENTER (bit 0), up arrow (bit 3), right arrow (bit 6), read by LIST and PRINT.
4015H, 401DH, 4025H
DCBs
The KB, DO and PR device control blocks; a routed DCB's type byte is C0H.
4049H-404AH
2 bytes
SYS0's HIMEM, set by CLEAR (5098H).
4051H-4052H
2 bytes
Head of SYS0's *name routine list, emptied by CLEAR (507FH).
4370H
1 byte
SYS0's copy of the SYSTEM option AX: the highest character LIST shows as it is (513CH).
43A9H-43AAH
2 bytes
The top of memory found at reset (5088H).
43B2H-43CDH
28 bytes
The four 7-byte route entries (free when the link is FFFFH).
436BH
1 byte
SYS0 flags; bit 1 stops SYS2's extra granules while CREATE allocates (500EH).
4480H-449FH
32 bytes
The FCB of CREATE, LIST and PRINT: buffer 4483H, EOF byte 4488H, NEXT 448AH, EOF sector 448CH.
461DH-461EH
2 bytes
Head of SYS0's timer chain, set to the clock routine 44C9H by CLEAR (5085H).
4ADCH-4ADDH
2 bytes
Operand at SYS0 4ADBH: the head of the route chain.

ROUTE Entries

Each route is a 7-byte entry: +0 the routed DCB, +2 its own type byte, +3 the link to the next entry (0000H = the last, FFFFH = a free entry), +5 the target DCB. The four entries at SYS0 43B2H-43CDH are used unless the target is MM=addr, whose block holds its own entry at addr, a DCB at addr+8 and the driver at addr+10H. The chain starts at the operand at SYS0 4ADCH; a routed DCB gets the type byte C0H, so that SYS0 4ADBH passes its input and output along the chain (Part 5 section 3).

Disassembly

4D00H - Function Dispatcher

SYS14 is entered by the SYS0 RST 28H dispatcher (4BC2H) with Register A = the RST 28H code and Register C = the sub-function. SYS1's command table sends ROUTE (1), CREATE (2), CLEAR (4), LIST (5), PRINT (6) and ERROR (7) here with code F0H (function 7 of directory slot 10H); sub-function 3 is only reached through the SYS0 49D3H chain, to come back after another overlay has run (4D27H). For every command, Register Pair HL points at the command line after the command word (and, for CREATE, LIST and PRINT, the file named there is already in the FCB at 4480H, opened by SYS1 for LIST and PRINT).

4D00
LD IY,4380H FD 21 80 43
Load Index Register IY with 4380H, the base of SYS0's variables; SYS14 itself does not use IY afterwards.
4D04
CP F0H FE F0
Compare Register A (the RST 28H code) against F0H, function 7 of slot 10H.
4D06
If the NZ FLAG is set (another code), JUMP to 4D22H for error 2AH.
4D08
DEC C 0D
Decrement Register C (the sub-function): the Z FLAG is set if it was 1.
4D09
If the Z FLAG is set (Register C was 1, ROUTE), JUMP to 4D4DH.
4D0C
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 2.
4D0D
If the Z FLAG is set (Register C was 2, CREATE), JUMP to 4F7CH.
4D10
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 3.
4D11
If the Z FLAG is set (Register C was 3, back from another overlay), JUMP to 4D37H.
4D13
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 4.
4D14
If the Z FLAG is set (Register C was 4, CLEAR), JUMP to 505FH.
4D17
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 5.
4D18
If the Z FLAG is set (Register C was 5, LIST), JUMP to 50D8H.
4D1B
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 6.
4D1C
If the Z FLAG is set (Register C was 6, PRINT), JUMP to 50D3H.
4D1F
DEC C 0D
Decrement Register C: the Z FLAG is set if it was 7.
4D20
If the Z FLAG is set (Register C was 7, ERROR), JUMP to 4D39H.
4D22
LD A,2AH 3E 2A
Load Register A with 2AH, the DOS error code ILLEGAL DOS FUNCTION.
4D24
JUMP to 4EEBH, which enables interrupts and leaves through SYS0's error exit 4409H with Register A = the code.

4D27H - Call Another Overlay and Come Back

4D27H runs the DOS routine whose address is in the operand 4D34H (Register A = 0); 4D28H runs RST 28H with the code in Register A. Either may load another overlay into 4D00H-51FFH over SYS14, so the word F003H (code F0H, sub-function 3) and 49D3H are pushed first: SYS0 49D3H then reloads SYS14 at sub-function 3, which drops the dispatcher's return address and returns straight to the caller. An error goes to 4409H instead (Part 5, section 2).

4D27
XOR A AF
Load Register A with 00H (XOR A with itself): call the routine whose address is in 4D34H.
4D28
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set BC', DE', HL', keeping the caller's BC, DE and HL for the call.
4D29
LD BC,F003H 01 03 F0
Load Register Pair BC (alternate) with F003H: code F0H, sub-function 3, which brings SYS14 back.
4D2C
LD DE,49D3H 11 D3 49
Load Register Pair DE (alternate) with 49D3H, the SYS0 return that issues the next RST 28H.
4D2F
PUSH BC C5
Push Register Pair BC (F003H) on the stack, for SYS0 49D3H.
4D30
PUSH DE D5
Push Register Pair DE (49D3H) as the return address of the routine or overlay.
4D31
EXX D9
Exchange back from the alternate Register Pairs to the main Register Pairs BC, DE and HL, as the caller left them.
4D32
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if Register A is 0.
4D33
JP Z,0000H CA 00 00
Self-Modifying Code
If the Z FLAG is set, JUMP to the routine in the operand 4D34H (0000H in the file; 4439H, SYS0's sector write, stored at 5008H).
4D36
RST 28H EF
Otherwise RST 28H with the code in Register A, which may load another overlay.
4D37
POP AF F1
Sub-function 3: restore Register Pair AF from the stack, discarding the dispatcher's return address (4C20H).
4D38
RET C9
RETURN to the caller of 4D27H, with the result of the routine or overlay.

4D39H - ERROR

ERROR n shows the DOS error message n (0-63) through SYS4 function 3. Register Pair HL points at n.

4D39
GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE (error 2FH if there is none).
4D3C
GOSUB to SYS0 4CD5H, which checks what follows at Register Pair HL: the Z FLAG is set at the end of the command.
4D3F
RET NZ C0
If the NZ FLAG is set (something follows), RETURN with the error from 4CD5H (34H).
4D40
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the error number.
4D41
LD DE,0040H 11 40 00
Load Register Pair DE with 0040H (64), one past the highest message number.
4D44
RST 18H DF
RST 18H: compare Register Pair HL (the error number) with Register Pair DE (64). The NO CARRY FLAG is set for 64 or more.
4D45
If the NO CARRY FLAG is set, JUMP to 4F0DH for error 2FH.
4D48
LD H,L 65
Load Register H with Register L: H = the error number (0-63).
4D49
LD A,66H 3E 66
Load Register A with 66H, RST 28H code for SYS4 (slot 06H), function 3: display an error message.
4D4B
PUSH HL E5
Push Register Pair HL (Register H = the error number) on the stack, where SYS4 function 3 takes it.
4D4C
RST 28H EF
RST 28H with Register A = 66H: SYS4 displays the message and returns to the DOS.

4D4DH - ROUTE

ROUTE alone lists the routes. ROUTE,dev,dev2[,dev3...] sends a device's input or output to the others too: dev is KB, DO or PR; a target is KB, DO, PR, NL or MM=addr (a device of your own: a 16-byte block at addr, 5200H or above, whose route entry is at addr, DCB at addr+8 and driver at addr+10H). ROUTE,CLEAR ends all routes. Routes are 7-byte entries (DCB, saved type byte, link, target DCB) in the table at 43B2H (four of them) or in an MM block, chained from the operand at SYS0 4ADCH; the routed DCB's type byte becomes C0H, which makes SYS0 4ADBH follow the chain. 4D4DH-4E4CH is also the zeroed sector buffer of CREATE (5015H). Register Pair HL points at the command line after ROUTE.

4D4D
DI F3
Disable interrupts, so no device is used while the route chain is changed.
4D4E
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the command.
4D4F
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return that ends the command.
4D51
If the Z FLAG is set (ROUTE alone), JUMP to 4E0AH to list the routes.
4D54
GOSUB to 4EC6H, which looks the device name at Register Pair HL up in the table at 4F53H: Register A = its attribute byte, Register Pair DE = its DCB.
4D57
BIT 7,A CB 7F
Test bit 7 of Register A (the attribute): set for a device that may be routed.
4D59
If the Z FLAG is set (it may not), JUMP to 4EE9H for error 34H.
4D5C
BIT 4,A CB 67
Test bit 4 of Register A (the attribute): set only for the word CLEAR.
4D5E
If the NZ FLAG is set (ROUTE,CLEAR), JUMP to 4DFCH.
4D61
LD (4DA5H),A 32 A5 4D
Self-Modifying Code
Store Register A (the routed device's attribute) at 4DA5H, the operand of the AND 00H at 4DA4H.
4D64
LD (4DCEH),DE ED 53 CE 4D
Self-Modifying Code
Store Register Pair DE (the routed device's DCB) at 4DCEH, the operand of the LD DE,0000H at 4DCDH.
4D68
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4D69
GOSUB to 4E94H, which ends any route of the DCB in Register Pair DE, putting its own type byte back.
4D6C
LD A,(DE) 1A
Load Register A with the byte at Register Pair DE, the DCB's own type byte (restored by now).
4D6D
LD (4DD9H),A 32 D9 4D
Self-Modifying Code
Store Register A (the DCB's type byte) at 4DD9H, the operand of the LD A,00H at 4DD8H, to be kept in each route entry.

TARGET LOOP
Register Pair HL = the command line at the next target.

4D70
POP HL E1
Restore Register Pair HL from the stack: the command line.
4D71
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: the CARRY FLAG for a bad one, the Z FLAG at the end, otherwise HL moves to the next item.
4D74
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN with it (error 34H).
4D75
If the Z FLAG is set (the end), JUMP to 4E54H, which enables interrupts and returns.
4D78
GOSUB to 4EC6H, which looks the target's name up: Register A = its attribute, Register Pair DE = its DCB.
4D7B
BIT 6,A CB 77
Test bit 6 of Register A (the attribute): set for a device that may be a target.
4D7D
If the Z FLAG is set (it may not), JUMP to 4EE9H for error 34H.
4D80
BIT 5,A CB 6F
Test bit 5 of Register A: set for MM=, which is followed by an address.
4D82
If the Z FLAG is set (a named device), JUMP to 4DA0H.
4D84
GOSUB to 4EEFH, which reads the MM block's address at Register Pair HL into Register Pair DE.
4D87
LD A,D 7A
Load Register A with Register D, the high byte of the block's address.
4D88
CP 52H FE 52
Compare Register A against 52H: the CARRY FLAG is set below 5200H, the DOS's own memory.
4D8A
If the CARRY FLAG is set, JUMP to 4F0DH for error 2FH.
4D8D
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4D8E
PUSH DE D5
Save Register Pair DE (the block's address) on the stack.
4D8F
LD HL,0010H 21 10 00
Load Register Pair HL with 0010H (16), the driver's offset in the block.
4D92
ADD HL,DE 19
Add Register Pair DE (the block) to Register Pair HL: HL = the driver's address, block + 10H.
4D93
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the driver's address.
4D94
LD HL,FFFAH 21 FA FF
Load Register Pair HL with FFFAH, which is -6.
4D97
ADD HL,DE 19
Add Register Pair DE to Register Pair HL: HL = block + 0AH, the high byte of the DCB's driver address.
4D98
LD (HL),D 72
Store Register D (the high byte of the driver's address) at Register Pair HL, block + 0AH.
4D99
DEC HL 2B
Decrement Register Pair HL to block + 09H, the driver address's low byte.
4D9A
LD (HL),E 73
Store Register E (the low byte of the driver's address) at Register Pair HL, block + 09H.
4D9B
DEC HL 2B
Decrement Register Pair HL to block + 08H, the DCB.
4D9C
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the MM device's DCB (block + 8).
4D9D
POP HL E1
Restore Register Pair HL from the stack: the block's address, where its route entry goes.
4D9E
JUMP to 4DABH with Register Pair DE = the target DCB and Register Pair HL = the entry.
4DA0
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4DA1
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H: no entry given, one is taken from the table at 43B2H.
4DA4
AND 00H E6 00
Self-Modifying Code
AND Register A (the target's attribute) with the routed device's attribute, the operand 4DA5H (00H in the file, stored at 4D61H).
4DA6
AND 03H E6 03
AND Register A with 03H, keeping the direction bits (bit 0 input, bit 1 output) both devices share.
4DA8
If the Z FLAG is set (no direction in common), JUMP to 4F0DH for error 2FH.
4DAB
LD (4DE2H),DE ED 53 E2 4D
Self-Modifying Code
Store Register Pair DE (the target DCB) at 4DE2H, the operand of the LD DE,0000H at 4DE1H.
4DAF
LD A,H 7C
Load Register A with Register H, the high byte of the entry address.
4DB0
OR L B5
OR Register A with Register L: the NZ FLAG is set if an entry was given (MM=).
4DB1
If the NZ FLAG is set, JUMP to 4DCDH to fill the MM block's entry.
4DB3
LD HL,43AFH 21 AF 43
Load Register Pair HL with 43AFH, three bytes before the first entry of the route table at 43B2H.

FIND A FREE ENTRY
Register Pair HL steps through the four 7-byte entries at 43B2H; a free one has the link FFFFH.

4DB6
LD A,L 7D
Load Register A with Register L, the low byte of the pointer.
4DB7
CP CBH FE CB
Compare Register A against CBH: the NO CARRY FLAG is set once the pointer is past the fourth entry.
4DB9
LD A,3BH 3E 3B
Load Register A with 3BH, the DOS error code INSUFFICIENT MEMORY. LD does not change the flags.
4DBB
If the NO CARRY FLAG is set (no free entry), JUMP to 4EEBH to leave with the error.
4DBE
INC HL 23
Increment Register Pair HL: 1 of 3 to the next entry.
4DBF
INC HL 23
Increment Register Pair HL: 2 of 3 towards the next route entry.
4DC0
INC HL 23
Increment Register Pair HL: 3 of 3, HL = the entry's start.
4DC1
LD D,H 54
Load Register D with Register H, the high byte of the entry.
4DC2
LD E,L 5D
Load Register E with Register L. Register Pair DE = the entry.
4DC3
INC HL 23
Increment Register Pair HL: 1 of 3 to the entry's link (+3).
4DC4
INC HL 23
Increment Register Pair HL: 2 of 3 towards the entry's link at +3.
4DC5
INC HL 23
Increment Register Pair HL: 3 of 3, HL = the link's low byte.
4DC6
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the link's low byte.
4DC7
INC HL 23
Increment Register Pair HL to the link's high byte.
4DC8
AND (HL) A6
AND Register A with the byte at Register Pair HL: FFH only if both bytes are FFH.
4DC9
INC A 3C
Increment Register A: the Z FLAG is set for FFFFH, a free entry.
4DCA
If the NZ FLAG is set (the entry is in use), LOOP back to 4DB6H.
4DCC
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the free entry.
4DCD
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the routed device's DCB; the operand 4DCEH (0000H in the file) was stored at 4D64H.
4DD0
PUSH HL E5
Save Register Pair HL (the entry) on the stack.
4DD1
LD (HL),E 73
Store Register E (the DCB's low byte) 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 DCB's high byte) 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 follow the route chain.
4DD7
LD (DE),A 12
Store Register A (C0H) at Register Pair DE, the routed DCB's type byte: SYS0 now routes it.
4DD8
LD A,00H 3E 00
Self-Modifying Code
Load Register A with the DCB's own type byte; the operand 4DD9H (00H in the file) was stored at 4D6DH.
4DDA
LD (HL),A 77
Store Register A at Register Pair HL, entry +2: the DCB's type byte, put back when the route ends.
4DDB
INC HL 23
Increment Register Pair HL to entry +3 of the new route entry.
4DDC
XOR A AF
Load Register A with 00H (XOR A with itself).
4DDD
LD (HL),A 77
Store Register A (00H) at Register Pair HL, entry +3: the link's low byte, 0000H = the end of the chain.
4DDE
INC HL 23
Increment Register Pair HL to entry +4 of the new route entry.
4DDF
LD (HL),A 77
Store Register A (00H) at Register Pair HL, entry +4: the link's high byte.
4DE0
INC HL 23
Increment Register Pair HL to entry +5 of the new route entry.
4DE1
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the target DCB; the operand 4DE2H (0000H in the file) was stored at 4DABH.
4DE4
LD (HL),E 73
Store Register E (the target DCB's low byte) at Register Pair HL, entry +5.
4DE5
INC HL 23
Increment Register Pair HL to entry +6 of the new route entry.
4DE6
LD (HL),D 72
Store Register D (the target DCB's high byte) at Register Pair HL, entry +6.
4DE7
LD DE,4AD9H 11 D9 4A
Load Register Pair DE with 4AD9H: three bytes before SYS0's chain head at 4ADCH, so the loop below treats the head like an entry's link.

FIND THE END OF THE CHAIN
Register Pair DE = the entry whose link is looked at (4AD9H stands for the head).

4DEA
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the entry to look at.
4DEB
INC HL 23
Increment Register Pair HL: 1 of 3 to its link.
4DEC
INC HL 23
Increment Register Pair HL: 2 of 3 towards the entry's link at +3.
4DED
INC HL 23
Increment Register Pair HL: 3 of 3, HL = the link's low byte.
4DEE
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the link's low byte.
4DEF
INC HL 23
Increment Register Pair HL to the link's high byte.
4DF0
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE = the next entry.
4DF1
LD A,D 7A
Load Register A with Register D, the high byte of the next entry.
4DF2
OR E B3
OR Register A with Register E: the Z FLAG is set at the end of the chain (0000H).
4DF3
If the NZ FLAG is set (more entries), LOOP back to 4DEAH.
4DF5
POP BC C1
Restore Register Pair BC from the stack: the new entry (pushed at 4DD0H).
4DF6
LD (HL),B 70
Store Register B (the new entry's high byte) at Register Pair HL, the last link's high byte.
4DF7
DEC HL 2B
Decrement Register Pair HL to the link's low byte.
4DF8
LD (HL),C 71
Store Register C (the new entry's low byte) at Register Pair HL: the new entry is linked at the end.
4DF9
JUMP to 4D70H for the next target in the command line.
4DFC
ROUTE,CLEAR: GOSUB to SYS0 4CD5H, which checks what follows at Register Pair HL: the Z FLAG at the end.
4DFF
If the NZ FLAG is set (something follows CLEAR), JUMP to 4E54H, which enables interrupts and returns with Register A as 4CD5H left it; no route is changed.
4E01
DI F3
Disable interrupts (CLEAR also enters here from 505FH's 5079H).
4E02
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H: end the routes of every DCB.
4E05
GOSUB to 4E94H, which ends every route and puts back each DCB's type byte.
4E08
JUMP to 4E53H to enable interrupts and return with no error.

4E0AH - List the Routes

One line per routed device: its name, TO, and the target; the entry at SYS0's chain head (4ADCH) comes first.

4E0A
LD HL,(4ADCH) 2A DC 4A
Load Register Pair HL with the 16-bit value at 4ADCH, the operand at SYS0 4ADBH: the first entry of the route chain (0000H if none).
4E0D
JUMP to 4E4FH to test for the end of the chain.

ENTRY LOOP
Register Pair HL = the route entry being shown.

4E0F
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, entry +0: the routed DCB's low byte.
4E10
INC HL 23
Increment Register Pair HL to entry +1, the DCB's high byte.
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 saved type byte.
4E13
INC HL 23
Increment Register Pair HL to entry +3, the link.
4E14
PUSH DE D5
Save Register Pair DE (the routed DCB) on the stack.
4E15
PUSH HL E5
Save Register Pair HL (entry +3) on the stack.
4E16
GOSUB to 4E56H, which prints the name of the device whose DCB is in Register Pair DE.
4E19
LD HL,4F4EH 21 4E 4F
Load Register Pair HL with 4F4EH, the text " TO ".
4E1C
GOSUB to SYS0 4467H, which displays the text at Register Pair HL.
4E1F
POP HL E1
Restore Register Pair HL from the stack: entry +3.
4E20
PUSH HL E5
Save Register Pair HL (entry +3) on the stack again for 4E29H.
4E21
INC HL 23
Increment Register Pair HL to entry +4, the link's high byte.
4E22
INC HL 23
Increment Register Pair HL to entry +5, the target DCB.
4E23
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the target DCB's low byte.
4E24
INC HL 23
Increment Register Pair HL to entry +6, the target DCB's high byte.
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, which prints the target's 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.
4E2B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the link's low byte.
4E2C
INC HL 23
Increment Register Pair HL to the link's high byte.
4E2D
LD H,(HL) 66
Load Register H with the byte at Register Pair HL, the link's high byte.
4E2E
LD L,A 6F
Load Register L with Register A. Register Pair HL = the next entry.
4E2F
PUSH HL E5
Save Register Pair HL (the next entry) on the stack.
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 at the end of the chain.
4E32
JUMP to 4E49H whatever the flags (JR, 18H), so the same-device test at 4E34H-4E47H is never executed.
4E34
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next entry's DCB low byte. Never executed: 4E32H jumps past it.
4E35
CP E BB
Compare Register A with Register E, the routed DCB's low byte (never executed).
4E36
INC HL 23
Increment Register Pair HL to the next entry's DCB high byte (never executed).
4E37
If the NZ FLAG is set, JUMP to 4E3BH (never executed).
4E39
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next entry's DCB high byte (never executed).
4E3A
CP D BA
Compare Register A with Register D, the routed DCB's high byte (never executed).
4E3B
INC HL 23
Increment Register Pair HL to the next entry's +2 (never executed).
4E3C
INC HL 23
Increment Register Pair HL to the next entry's link (never executed).
4E3D
If the NZ FLAG is set (another device), JUMP to 4E49H (never executed).
4E3F
POP AF F1
Restore Register Pair AF from the stack, discarding the saved entry (never executed).
4E40
LD A,2CH 3E 2C
Load Register A with 2CH, a comma between targets of one device (never executed).
4E42
PUSH HL E5
Save Register Pair HL on the stack (never executed).
4E43
PUSH DE D5
Save Register Pair DE on the stack (never executed).
4E44
GOSUB to the ROM's display routine at 0033H to show the comma in Register A (never executed).
4E47
JUMP to 4E1FH to print the next target on the same line (never executed).
4E49
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return ending the line.
4E4B
GOSUB to the ROM's display routine at 0033H, which shows the character in Register A.
4E4E
POP HL E1
Restore Register Pair HL from the stack: the next entry.
4E4F
LD A,H 7C
Load Register A with Register H, the high byte of the entry.
4E50
OR L B5
OR Register A with Register L: the Z FLAG is set at the end of the chain (0000H).
4E51
If the NZ FLAG is set (another entry), LOOP back to 4E0FH.
4E53
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
4E54
EI FB
Enable interrupts again (ROUTE disabled them at 4D4DH or 4E01H).
4E55
RET C9
RETURN to the DOS with Register A = the result (00H for no error).

4E56H - Print a Device Name

Register Pair DE = a DCB. Prints its name from the table at 4F53H, or MM= and the block's address (the DCB minus 8) in hexadecimal for any other DCB.

4E56
LD HL,4F53H 21 53 4F
Load Register Pair HL with 4F53H, the device table (name, 00H, attribute, DCB address).

TABLE SEARCH LOOP
Register Pair HL walks the device table; the entry's start is saved on the stack.

4E59
PUSH HL E5
Save Register Pair HL (the entry's name) on the stack.
4E5A
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, a character of the name (00H at its end).
4E5B
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H.
4E5C
INC HL 23
Increment Register Pair HL (the flags are not changed).
4E5D
If the NZ FLAG is set (more of the name), LOOP back to 4E5AH.
4E5F
INC HL 23
Increment Register Pair HL over the attribute byte to the DCB address.
4E60
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the low byte of the entry's DCB.
4E61
CP E BB
Compare Register A with Register E, the low byte of the DCB wanted.
4E62
INC HL 23
Increment Register Pair HL to the high byte (the flags are not changed).
4E63
If the NZ FLAG is set (the low bytes differ), JUMP to 4E67H with NZ.
4E65
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the high byte of the entry's DCB.
4E66
SUB D 92
Subtract Register D from Register A: Register A = 00H and the Z FLAG set if the high bytes match too.
4E67
If the Z FLAG is set (this entry is the device), JUMP to 4E74H with Register A = 00H.
4E69
INC HL 23
Increment Register Pair HL to the next entry.
4E6A
POP AF F1
Restore Register Pair AF from the stack, discarding this entry's start.
4E6B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next entry's first byte (00H at 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.
4E6D
If the NZ FLAG is set (another entry), LOOP back to 4E59H.
4E6F
LD HL,4F74H 21 74 4F
Not in the table: load Register Pair HL with 4F74H, the name MM=.
4E72
INC A 3C
Increment Register A (00H) to 01H: the block's address is shown after the name.
4E73
PUSH HL E5
Push Register Pair HL (the text MM=) for the POP that follows.
4E74
POP HL E1
Restore Register Pair HL from the stack: the name to print (the entry's name, or MM=).
4E75
PUSH AF F5
Save Register Pair AF (Register A = 00H for a named device, 01H for MM=) on the stack.
4E76
PUSH DE D5
Save Register Pair DE (the DCB) on the stack.

PRINT THE NAME
Register Pair HL = the name, ended by 00H.

4E77
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, a character of the name.
4E78
INC HL 23
Increment Register Pair HL to the next character.
4E79
GOSUB to the ROM's display routine at 0033H, which shows the character in Register A.
4E7C
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4E7D
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H end.
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.
4E81
POP AF F1
Restore Register Pair AF from the stack: Register A = 00H (named) or 01H (MM=).
4E82
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for a named device.
4E83
RET Z C8
If the Z FLAG is set (a named device), RETURN.
4E84
LD HL,FFF8H 21 F8 FF
Load Register Pair HL with FFF8H, which is -8.
4E87
ADD HL,DE 19
Add Register Pair DE (the DCB) to Register Pair HL: HL = the MM block's address (the DCB is at block + 8).
4E88
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the block's address.
4E89
LD HL,4F48H 21 48 4F
Load Register Pair HL with 4F48H, the hex buffer (four digits, H and 03H).
4E8C
PUSH HL E5
Save Register Pair HL (4F48H, the hex buffer) on the stack.
4E8D
GOSUB to SYS0 4063H, which writes Register Pair DE as four hexadecimal digits at Register Pair HL.
4E90
POP HL E1
Restore Register Pair HL from the stack: 4F48H.
4E91
JUMP to SYS0 4467H, which displays the buffer at Register Pair HL (the digits and H, up to the 03H) and returns.

4E94H - End Routes

Register Pair DE = the DCB whose routes end (0000H = all of them). Each entry of the chain for it is unlinked, marked free (link FFFFH) and the DCB's own type byte is put back. Register Pair BC holds the address of the link that points at the entry being looked at.

4E94
LD HL,4ADAH 21 DA 4A
Load Register Pair HL with 4ADAH: two bytes before SYS0's chain head at 4ADCH, so the loop treats the head like an entry's link.

CHAIN LOOP
Register Pair HL = the entry before (its link at +3), Register Pair BC = the address of that link.

4E97
INC HL 23
Increment Register Pair HL: 1 of 2 to the link.
4E98
INC HL 23
Increment Register Pair HL: HL = the link's address.
4E99
LD B,H 44
Load Register B with Register H, the high byte of the link's address.
4E9A
LD C,L 4D
Load Register C with Register L. Register Pair BC = the address of the link.
4E9B
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the link's low byte.
4E9C
INC HL 23
Increment Register Pair HL to the link's high byte.
4E9D
LD H,(HL) 66
Load Register H with the byte at Register Pair HL, the link's high byte.
4E9E
LD L,A 6F
Load Register L with Register A. Register Pair HL = the entry the link points at.
4E9F
LD A,H 7C
Load Register A with Register H, the high byte of the entry.
4EA0
OR L B5
OR Register A with Register L: the Z FLAG is set at the end of the chain (0000H).
4EA1
RET Z C8
If the Z FLAG is set (no more entries), RETURN.
4EA2
LD A,D 7A
Load Register A with Register D, the high byte of the DCB wanted.
4EA3
OR E B3
OR Register A with Register E: the Z FLAG is set if Register Pair DE is 0000H, all routes end.
4EA4
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, entry +0: the entry's DCB low byte. LD does not change the flags.
4EA5
INC HL 23
Increment Register Pair HL to entry +1 (the flags are not changed).
4EA6
If the Z FLAG is set (all routes end), JUMP to 4EAFH to end this one.
4EA8
CP E BB
Compare Register A (the entry's DCB low byte) with Register E.
4EA9
If the NZ FLAG is set (another DCB), JUMP to 4EADH with NZ.
4EAB
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the entry's DCB high byte.
4EAC
CP D BA
Compare Register A with Register D: the Z FLAG is set if the entry is for this DCB.
4EAD
If the NZ FLAG is set (another DCB), LOOP back to 4E97H with Register Pair HL at entry +1, so HL + 2 is its link.
4EAF
PUSH BC C5
Save Register Pair BC (the address of the link pointing at this entry) on the stack.
4EB0
DEC HL 2B
Decrement Register Pair HL back to entry +0, the DCB's low byte.
4EB1
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the entry's DCB low byte.
4EB2
INC HL 23
Increment Register Pair HL to entry +1, the DCB's high byte.
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 saved type byte.
4EB5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, entry +2: the DCB's own type byte, saved when the route was made.
4EB6
LD (BC),A 02
Store Register A at Register Pair BC, the DCB's type byte: the device is no longer routed.
4EB7
INC HL 23
Increment Register Pair HL to entry +3, the link.
4EB8
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL, the link's low byte (the next entry).
4EB9
LD A,FFH 3E FF
Load Register A with FFH, the link value that marks a free entry.
4EBB
LD (HL),A 77
Store Register A (FFH) at Register Pair HL, the link's low byte: the entry is free.
4EBC
INC HL 23
Increment Register Pair HL to the link's high byte.
4EBD
LD B,(HL) 46
Load Register B with the byte at Register Pair HL. Register Pair BC = the next entry.
4EBE
LD (HL),A 77
Store Register A (FFH) at Register Pair HL, the link's high byte.
4EBF
POP HL E1
Restore Register Pair HL from the stack: the address of the link that pointed at this entry.
4EC0
LD (HL),C 71
Store Register C (the next entry's low byte) at Register Pair HL: the entry is unlinked.
4EC1
INC HL 23
Increment Register Pair HL to the link's high byte.
4EC2
LD (HL),B 70
Store Register B (the next entry's high byte) at Register Pair HL.
4EC3
DEC HL 2B
Decrement Register Pair HL back to the link's low byte.
4EC4
JUMP to 4E99H to look at the entry this link now points to.

4EC6H - Look Up a Word

4EC6H looks up a device name in the table at 4F53H; 4EC9H takes the table in Register Pair BC and the number of bytes after each name in Register D (3). A table entry is a name ended by 00H, an attribute byte and a word; 00H ends the table. Returns Register A = the attribute, Register Pair DE = the word and Register Pair HL past the name; a name not in the table is error 34H.

4EC6
LD BC,4F53H 01 53 4F
Load Register Pair BC with 4F53H, the device table.
4EC9
LD D,03H 16 03
Load Register D with 03H: an attribute byte and a 2-byte word follow each name.
4ECB
GOSUB to 4ED7H, which finds the entry for the word at Register Pair HL; Register Pair BC returns at its attribute byte.
4ECE
PUSH BC C5
Save Register Pair BC (the attribute's address) on the stack.
4ECF
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the attribute's address, and the command line pointer is saved.
4ED0
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the entry's attribute.
4ED1
INC HL 23
Increment Register Pair HL to the word's low byte.
4ED2
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL, the word's low byte.
4ED3
INC HL 23
Increment Register Pair HL to the high byte of the entry's word.
4ED4
LD D,(HL) 56
Load Register D with the byte at Register Pair HL. Register Pair DE = the entry's word (a DCB, handler or operand address).
4ED5
POP HL E1
Restore Register Pair HL from the stack: the command line past the name.
4ED6
RET C9
RETURN with Register A = the attribute and Register Pair DE = the word.

SEARCH LOOP
Register Pair BC = the table entry, Register Pair HL = the command line, Register D = the bytes after each name's 00H.

4ED7
GOSUB to SYS0 4CC5H, which compares the name at Register Pair BC with the text at Register Pair HL: the Z FLAG is set on a match, with BC at the attribute and HL past the name.
4EDA
RET Z C8
If the Z FLAG is set (found), RETURN with Register Pair BC at the attribute.
4EDB
LD A,(BC) 0A
Load Register A with the byte at Register Pair BC, a byte of the entry's name.
4EDC
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set at the 00H end of the name.
4EDD
INC BC 03
Increment Register Pair BC (the flags are not changed).
4EDE
If the NZ FLAG is set (more of the name), LOOP back to 4EDBH.
4EE0
LD E,D 5A
Load Register E with Register D, the bytes to skip after the name (3).
4EE1
INC BC 03
Increment Register Pair BC over one of the bytes after the name's 00H.
4EE2
DEC E 1D
Decrement Register E, the bytes left to skip.
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 next entry's first byte (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.
4EE7
If the NZ FLAG is set (another entry), LOOP back to 4ED7H.
4EE9
LD A,34H 3E 34
Load Register A with 34H, the DOS error code ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR.
4EEB
EI FB
Enable interrupts again, in case ROUTE disabled them.
4EEC
JUMP to SYS0 4409H, the DOS error exit, with the error code in Register A.

4EEFH - Read a Number

A decimal number, or a hexadecimal one ended by H (a letter A-H after the digits makes it start again as hexadecimal). Returns it in Register Pair DE; no digit, a missing H, or a number past FFFFH is error 2FH. Register Pair HL is the command line.

4EEF
PUSH HL E5
Save Register Pair HL (the start of the number) on the stack.
4EF0
LD B,00H 06 00
Load Register B with 00H: decimal digits, none read yet.
4EF2
GOSUB to 4F12H, which reads digits at Register Pair HL into Register Pair DE; HL stops at the first other character.
4EF5
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the character after the digits.
4EF6
SUB 41H D6 41
Subtract 41H (the letter A) from Register A, the character after the digits.
4EF8
CP 08H FE 08
Compare Register A against 08H: the CARRY FLAG is set for A to H, a hexadecimal digit or the closing H.
4EFA
If the NO CARRY FLAG is set (a decimal number), JUMP to 4F09H.
4EFC
POP HL E1
Restore Register Pair HL from the stack: back to the start of the number.
4EFD
LD B,01H 06 01
Load Register B with 01H: bit 0 set, read hexadecimal digits.
4EFF
PUSH HL E5
Save Register Pair HL on the stack again, to be discarded at 4F0BH.
4F00
GOSUB to 4F12H, which reads 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 digits.
4F04
CP 48H FE 48
Compare Register A against 48H, the letter H.
4F06
INC HL 23
Increment Register Pair HL past it (the flags are not changed).
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 once a digit has been read.
4F0B
POP BC C1
Restore Register Pair BC from the stack, discarding the saved start of the number.
4F0C
RET NZ C0
If the NZ FLAG is set (a digit was read), RETURN with the number in Register Pair DE.
4F0D
LD A,2FH 3E 2F
Load Register A with 2FH, the DOS error code BAD PARAMETER(S).
4F0F
JUMP to SYS0 4409H, the DOS error exit, with the error code in Register A.
4F12
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the number so far.

DIGIT LOOP
Register Pair HL = the command line, Register Pair DE = the number so far, Register B = the flags (bit 0 hexadecimal, bit 1 a digit read).

4F15
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character.
4F16
SUB 30H D6 30
Subtract 30H (the digit 0) from Register A: 0-9 become 00H-09H.
4F18
CP 0AH FE 0A
Compare Register A against 0AH: the CARRY FLAG is set for 0-9.
4F1A
If the CARRY FLAG is set (a digit 0-9), JUMP to 4F26H with its value in Register A.
4F1C
BIT 0,B CB 40
Test bit 0 of Register B: set when reading hexadecimal digits.
4F1E
RET Z C8
If the Z FLAG is set (decimal), RETURN: the number ends here.
4F1F
SUB 11H D6 11
Subtract 11H more from Register A: the letters A-F become 00H-05H.
4F21
CP 06H FE 06
Compare Register A against 06H: the NO CARRY FLAG is set if it is not A-F.
4F23
RET NC D0
If the NO CARRY FLAG is set, RETURN: the number ends here.
4F24
ADD A,0AH C6 0A
Add 0AH to Register A: the letters A-F become their values 10-15.
4F26
PUSH HL E5
Save Register Pair HL (the command line) on the stack.
4F27
LD H,D 62
Load Register H with Register D, the high byte of the number so far.
4F28
LD L,E 6B
Load Register L with Register E. Register Pair HL = the number so far (Register Pair DE keeps it too, for times 5).
4F29
LD C,A 4F
Load Register C with Register A, the new digit's value.
4F2A
XOR A AF
Load Register A with 00H (XOR A with itself): Register A collects any overflow.
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 number times 2.
4F2E
ADC A,A 8F
Add Register A to itself with the CARRY FLAG: an overflow makes Register A non-zero.
4F2F
ADD HL,HL 29
Add Register Pair HL to itself: the number times 4.
4F30
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
4F31
BIT 0,B CB 40
Test bit 0 of Register B: set for hexadecimal.
4F33
If the Z FLAG is set (decimal), JUMP to 4F38H.
4F35
ADD HL,HL 29
Hexadecimal: add Register Pair HL to itself, the number times 8.
4F36
JUMP to 4F39H with Register Pair HL = 8 times the number.
4F38
ADD HL,DE 19
Decimal: add Register Pair DE (the number) to Register Pair HL (4 times it): times 5.
4F39
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
4F3A
ADD HL,HL 29
Add Register Pair HL to itself: times 16 (hexadecimal) or 10 (decimal).
4F3B
ADC A,A 8F
Add Register A to itself with the CARRY FLAG, collecting any overflow.
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, so Register Pair DE = the 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: Register A is non-zero (NZ) if the number passed FFFFH at any step.
4F41
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = the new number.
4F42
POP HL E1
Restore Register Pair HL from the stack: the command line at the digit.
4F43
If the NZ FLAG is set (the number 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, not code.

4F48-4F4D
DEFM "0000H", 03H 30 30 30 30 48 03
The buffer for MM='s address: four hex digits written by SYS0 4063H at 4E8DH, then H and the 03H that ends the display.
4F4E-4F52
DEFM " TO ", 03H 20 54 4F 20 03
The text " TO " and 03H, shown between the two devices of a route (4E19H).
4F53-4F58
DEFM "KB", 00H, C1H, 15H, "@" 4B 42 00 C1 15 40
Device table entry KB: attribute C1H (may be routed, may be a target, input), DCB 4015H.
4F59-4F5E
DEFM "DO", 00H, C2H, 1DH, "@" 44 4F 00 C2 1D 40
Device table entry DO: attribute C2H (may be routed, may be a target, output), DCB 401DH.
4F5F-4F64
DEFM "PR", 00H, C2H, "%@" 50 52 00 C2 25 40
Device table entry PR: attribute C2H (may be routed, may be a target, output), DCB 4025H.
4F65-4F6A
DEFM "NL", 00H, "C", FCH, "L" 4E 4C 00 43 FC 4C
Device table entry NL: attribute 43H (only a target, input and output), DCB 4CFCH, SYS0's null device.
4F6B-4F73
DEFM "CLEAR", 00H, 90H, 00H, 00H 43 4C 45 41 52 00 90 00 00
Device table entry CLEAR: attribute 90H (may be routed, bit 4 = CLEAR), word 0000H.
4F74-4F7A
DEFM "MM=", 00H, "`", 00H, 00H 4D 4D 3D 00 60 00 00
Device table entry MM=: attribute 60H (a target, bit 5 = an address follows), word 0000H; also the name shown for a DCB not in the table (4E6FH).
4F7B
DEFB 00H 00
00H: the end of the device table, tested at 4E6CH and 4EE6H.

4F7CH - CREATE

CREATE filespec[,LRL=n][,REC=n][,ASE=Y/N][,ASC=Y/N]. The file is opened (made if it does not exist) through SYS2; its FPDE gets the LRL (1-256) and the ASE/ASC flags (FPDE byte 1 bits 7 and 6 set for N); and with REC the file is given REC times LRL bytes: all its granules are taken at once (SYS0 436BH bit 1 stops SYS2's three extra granules), every sector is written with zeros and the end of file is set. SYS1 has put the filespec into the FCB at 4480H; Register Pair HL points at the command line after it. The options are kept on the stack: the number of records, and a word with the flags (Register C) and the LRL (Register B).

4F7C
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: no records yet.
4F7F
PUSH BC C5
Push Register Pair BC (0000H): the number of records.
4F80
PUSH BC C5
Push Register Pair BC (0000H) again: the flags 00H (Register C) and the LRL 00H (Register B), where 0 means 256.

OPTION LOOP
Register Pair HL = the command line; the options word and the number of records are on the stack.

4F81
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: the CARRY FLAG for a bad one, the Z FLAG at the end, otherwise HL moves to the next option.
4F84
If the CARRY FLAG is set (a bad separator), JUMP to 4EEBH to leave with error 34H in Register A.
4F87
If the Z FLAG is set (no more options), JUMP to 4FBFH to create the file.
4F89
LD BC,503EH 01 3E 50
Load Register Pair BC with 503EH, CREATE's option table (LRL=, REC=, ASE=, ASC=).
4F8C
GOSUB to 4EC9H, which looks the option at Register Pair HL up: Register A = its flag byte, Register Pair DE = its handler.
4F8F
PUSH DE D5
Push Register Pair DE (the handler's address) on the stack.
4F90
LD D,A 57
Load Register D with Register A, the option's flag (80H for ASE, 40H for ASC, 00H otherwise).
4F91
RET C9
RETURN, which jumps to the handler just pushed.
4F92
LD E,00H 1E 00
ASE= or ASC=: load Register E with 00H, the mask for Y (the flag is not set).
4F94
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the value's letter.
4F95
CP 59H FE 59
Compare Register A against 59H, the letter Y.
4F97
INC HL 23
Increment Register Pair HL past the letter (the flags are not changed).
4F98
If the Z FLAG is set (Y), JUMP to 4FA0H with Register E = 00H.
4F9A
DEC E 1D
Decrement Register E to FFH, the mask for N (the flag is set).
4F9B
CP 4EH FE 4E
Compare Register A (the letter) against 4EH, the letter N.
4F9D
If the NZ FLAG is set (neither Y nor N), JUMP to 4F0DH for error 2FH.
4FA0
LD A,D 7A
Load Register A with Register D, the option's flag (80H ASE, 40H ASC).
4FA1
AND E A3
AND Register A with Register E: the flag is kept only for N.
4FA2
POP BC C1
Restore Register Pair BC from the stack: Register C = the flags so far, Register B = the LRL.
4FA3
OR C B1
OR Register A with Register C, adding the flag to the flags.
4FA4
LD C,A 4F
Load Register C with Register A, the new flags.
4FA5
PUSH BC C5
Push Register Pair BC (the flags and the LRL) back on the stack.
4FA6
JUMP to 4FBDH, which goes back to the option loop.
4FA8
LRL=: GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE.
4FAB
DEC DE 1B
Decrement Register Pair DE: 1-256 become 0-255.
4FAC
LD A,D 7A
Load Register A with Register D, the high byte of the LRL minus 1.
4FAD
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the LRL was 1-256.
4FAE
If the NZ FLAG is set (0 or above 256), JUMP to 4F9DH, where the NZ FLAG leads to error 2FH.
4FB0
POP BC C1
Restore Register Pair BC from the stack: the flags (Register C) and the LRL (Register B).
4FB1
INC E 1C
Increment Register E back to the LRL's low byte (256 becomes 00H).
4FB2
LD B,E 43
Load Register B with Register E, the new LRL (00H for 256).
4FB3
PUSH BC C5
Push Register Pair BC (the flags and the new LRL) back on the stack.
4FB4
JUMP to 4FBDH, which goes back to the option loop.
4FB6
REC=: GOSUB to 4EEFH, which reads the number of records at Register Pair HL into Register Pair DE.
4FB9
POP BC C1
Restore Register Pair BC from the stack: the flags and the LRL.
4FBA
POP AF F1
Restore Register Pair AF from the stack, discarding the old number of records.
4FBB
PUSH DE D5
Push Register Pair DE (the new number of records) on the stack.
4FBC
PUSH BC C5
Push Register Pair BC (the flags and the LRL) back on top.
4FBD
JUMP to 4F81H for the next option at Register Pair HL.
4FBF
POP BC C1
Restore Register Pair BC from the stack: Register C = the flags, Register B = the LRL.
4FC0
PUSH BC C5
Push Register Pair BC back, keeping it for after the open.
4FC1
LD A,44H 3E 44
Load Register A with 44H, the RST 28H code for SYS2: open a new or existing file.
4FC3
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the FCB holding the filespec.
4FC6
GOSUB to 4D28H, which runs RST 28H 44H (SYS2 opens the file) and comes back to SYS14.
4FC9
PUSH DE D5
Push Register Pair DE (4480H, the FCB) on the stack.
4FCA
POP IX DD E1
Pop Index Register IX from the stack: IX = 4480H, the file's FCB.
4FCC
RES 7,(IX+01H) DD CB 01 BE
Reset bit 7 of the byte at Index Register IX+01H, FCB byte 1: the file is not in record mode.
4FD0
GOSUB to SYS0 494BH, which reads the directory sector holding the file's FPDE and returns Register Pair HL = the FPDE; the NZ FLAG is set on an error.
4FD3
If the NZ FLAG is set (an error), JUMP to 4EEBH to leave with it.
4FD6
POP BC C1
Restore Register Pair BC from the stack: Register C = the flags, Register B = the LRL.
4FD7
LD A,C 79
Load Register A with Register C, the flags collected from ASE= and ASC=.
4FD8
AND C0H E6 C0
AND Register A with C0H, keeping bit 7 (ASE=N) and bit 6 (ASC=N).
4FDA
LD C,A 4F
Load Register C with Register A, those two flags.
4FDB
INC HL 23
Increment Register Pair HL to FPDE byte 1, the file's flag byte.
4FDC
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, FPDE byte 1.
4FDD
AND 1FH E6 1F
AND Register A with 1FH, keeping bits 0-4 and clearing the ASE, ASC and UDF bits 5-7.
4FDF
OR C B1
OR Register A with Register C, adding the ASE/ASC flags.
4FE0
LD (HL),A 77
Store Register A at Register Pair HL, the new FPDE byte 1.
4FE1
INC HL 23
Increment Register Pair HL to FPDE byte 2 of the file's entry.
4FE2
INC HL 23
Increment Register Pair HL to FPDE byte 3 of the file's entry.
4FE3
INC HL 23
Increment Register Pair HL to FPDE byte 4, the LRL.
4FE4
LD (HL),B 70
Store Register B (the LRL, 00H for 256) at Register Pair HL, FPDE byte 4.
4FE5
LD (IX+02H),00H DD 36 02 00
Store 00H in the byte at Index Register IX+02H, FCB byte 2.
4FE9
GOSUB to SYS0 491FH, which writes the directory sector (with the changed FPDE) back; the NZ FLAG is set on an error.
4FEC
If the NZ FLAG is set (a write error), JUMP to 4EEBH to leave with it.
4FEF
POP HL E1
Restore Register Pair HL from the stack: the number of records (REC=).
4FF0
LD A,H 7C
Load Register A with Register H, the high byte of the number of records.
4FF1
OR L B5
OR Register A with Register L: the Z FLAG is set if REC was not given (0).
4FF2
If the Z FLAG is set, JUMP to 5035H to set an end of file of 0 (Register A = 00H, Register Pair HL = 0000H).
4FF4
LD A,B 78
Load Register A with Register B, the LRL (00H stands for 256).
4FF5
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set for an LRL of 256 (00H).
4FF6
LD C,A 4F
Load Register C with Register A (00H for 256). LD does not change the flags.
4FF7
If the NZ FLAG is set (LRL 1-255), GOSUB to SYS0 4C9DH, which multiplies the records (Register Pair HL) by the LRL (Register A): Register Pair HL = the full sectors and Register C = the bytes in the last one. With LRL 256, HL is already the sectors and Register C = 0.
4FFA
LD A,C 79
Load Register A with Register C, the bytes in the last sector.
4FFB
OR A B7
OR Register A with itself to set the flags: the Z FLAG is set if the file ends on a sector boundary.
4FFC
PUSH AF F5
Save Register Pair AF (Register A = the bytes in the last sector) on the stack.
4FFD
PUSH HL E5
Save Register Pair HL (the full sectors) on the stack.
4FFE
If the NZ FLAG is set (a part sector at the end), JUMP to 5001H: its number is Register Pair HL.
5000
DEC HL 2B
Decrement Register Pair HL: the last sector is one lower.
5001
LD (448AH),HL 22 8A 44
Store Register Pair HL (the last sector's number) at 448AH, NEXT in the FCB (FCB + 10).
5004
PUSH HL E5
Save Register Pair HL (the last sector's number) on the stack.
5005
LD HL,4439H 21 39 44
Load Register Pair HL with 4439H, SYS0's routine that writes the sector at NEXT.
5008
LD (4D34H),HL 22 34 4D
Self-Modifying Code
Store Register Pair HL (4439H) at 4D34H, the operand of the JP Z at 4D33H, so 4D27H calls it.
500B
LD HL,436BH 21 6B 43
Load Register Pair HL with 436BH, a SYS0 flag byte.
500E
SET 1,(HL) CB CE
Set bit 1 of the byte at Register Pair HL (436BH): SYS2 takes no extra granules when the file grows.
5010
GOSUB to 4D27H, which calls 4439H to write the last sector: this allocates the whole file at once (SYS2 may be loaded to do it, and SYS14 is reloaded afterwards).
5013
RES 1,(HL) CB 8E
Reset bit 1 of the byte at Register Pair HL (436BH) again.
5015
LD HL,4D4DH 21 4D 4D
Load Register Pair HL with 4D4DH, the start of SYS14's ROUTE code, no longer needed.
5018
LD (4483H),HL 22 83 44
Store Register Pair HL (4D4DH) at 4483H, the FCB's buffer address (FCB + 3): 256 bytes of ROUTE code become the sector buffer.
501B
XOR A AF
Load Register A with 00H (XOR A with itself).
501C
LD B,A 47
Load Register B with Register A (00H): the loop runs 256 times.

CLEAR THE BUFFER
Register Pair HL = the buffer (4D4DH-4E4CH), Register B counts 256 bytes.

501D
LD (HL),A 77
Store Register A (00H) at Register Pair HL, a byte of the buffer.
501E
INC HL 23
Increment Register Pair HL to the next byte of the 256-byte buffer.
501F
Decrement Register B and LOOP back to 501DH for all 256 bytes.
5021
POP BC C1
Restore Register Pair BC from the stack: the last sector's number.
5022
INC BC 03
Increment Register Pair BC: the number of sectors in the file.
5023
LD H,A 67
Load Register H with Register A (00H), the high byte of sector 0.
5024
LD L,A 6F
Load Register L with Register A. Register Pair HL = 0000H.
5025
LD (448AH),HL 22 8A 44
Store Register Pair HL (0000H) at 448AH, NEXT: the writing starts at sector 0.

WRITE LOOP
Register Pair BC = the sectors left to write; SYS0 4439H moves NEXT on after each.

5028
DEC BC 0B
Decrement Register Pair BC, the sectors left.
5029
GOSUB to SYS0 4439H, which writes the zeroed buffer as the sector at NEXT; the NZ FLAG is set on an error.
502C
If the NZ FLAG is set (a write error), JUMP to 4EEBH to leave with it.
502F
LD A,B 78
Load Register A with Register B, the high byte of the sectors left.
5030
OR C B1
OR Register A with Register C: the Z FLAG is set when none are left.
5031
If the NZ FLAG is set (sectors left), LOOP back to 5028H.
5033
POP HL E1
Restore Register Pair HL from the stack: the full sectors, the middle and high bytes of the end of file.
5034
POP AF F1
Restore Register Pair AF from the stack: Register A = the bytes in the last sector, the low byte of the end of file.
5035
LD (448CH),HL 22 8C 44
Store Register Pair HL at 448CH, the EOF sector in the FCB (FCB + 12/13).
5038
LD (4488H),A 32 88 44
Store Register A at 4488H, the EOF byte in the FCB (FCB + 8).
503B
JUMP to SYS0 4428H, which closes the file, writing the end of file into its directory entry.

503EH - CREATE's Options

Data, not code. Each entry is the keyword, 00H, a flag byte (for ASE and ASC, the FPDE byte 1 bit set for N) and the handler's address.

503E-5042
DEFM "LRL=", 00H 4C 52 4C 3D 00
Keyword LRL= and its 00H end, for the option table at 503EH.
5043
DEFB 00H 00
Flag byte 00H for LRL=: it sets no bit in FPDE byte 1.
5044-5045
DEFW 4FA8H A8 4F
DEFW 4FA8H, the handler for LRL= (reads the record length).
5046-504A
DEFM "REC=", 00H 52 45 43 3D 00
Keyword REC= and its 00H end, the number of records.
504B
DEFB 00H 00
Flag byte 00H for REC=: it sets no bit in FPDE byte 1.
504C-504D
DEFW 4FB6H B6 4F
DEFW 4FB6H, the handler for REC= (reads the number of records).
504E-5052
DEFM "ASE=", 00H 41 53 45 3D 00
Keyword ASE= and its 00H end, allocate on extend (Y/N).
5053
DEFB 80H 80
Flag byte 80H for ASE=: FPDE byte 1 bit 7, set for N (the file may not extend).
5054-5055
DEFW 4F92H 92 4F
DEFW 4F92H, the handler for ASE= and ASC= (reads Y or N).
5056-505A
DEFM "ASC=", 00H 41 53 43 3D 00
Keyword ASC= and its 00H end, deallocate on close (Y/N).
505B
DEFB 40H 40
Flag byte 40H for ASC=: FPDE byte 1 bit 6, set for N (the space is kept at close).
505C-505D
DEFW 4F92H 92 4F
DEFW 4F92H, the handler for ASE= and ASC= (reads Y or N).
505E
DEFB 00H 00
00H: the end of CREATE's option table, tested at 4EE6H.

505FH - CLEAR

CLEAR[,START=a][,END=b][,MEM=c]. Ends all routes, empties the *name routine list (4051H) and the timer chain (only the clock routine 44C9H is left in 461DH), sets HIMEM (4049H) to MEM (at least 7000H) or the top of memory found at reset (43A9H), whichever is lower, and fills START (5200H or above, default 5200H) to END (default HIMEM) with zeros. Each option's number is stored straight into the operand it sets.

505F
LD A,(HL) 7E
Load Register A with the byte at Register Pair HL, the next character of the command.
5060
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return that ends the command.
5062
If the Z FLAG is set (no options), JUMP to 5079H.
5064
LD BC,50B8H 01 B8 50
Load Register Pair BC with 50B8H, CLEAR's option table (START=, END=, MEM=).
5067
GOSUB to 4EC9H, which looks the option at Register Pair HL up: Register Pair DE = the address of the operand it sets.
506A
PUSH DE D5
Save Register Pair DE (the operand's address) on the stack.
506B
GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE.
506E
EX (SP),HL E3
Exchange Register Pair HL with the word at the top of the stack (at the Stack Pointer SP): HL = the operand's address, and the command line is saved.
506F
LD (HL),E 73
Self-Modifying Code
Store Register E (the number's low byte) at Register Pair HL, the operand at 50A3H, 509CH or 508CH.
5070
INC HL 23
Increment Register Pair HL to the operand's high byte.
5071
LD (HL),D 72
Store Register D (the number's high byte) at Register Pair HL.
5072
POP HL E1
Restore Register Pair HL from the stack: the command line.
5073
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: CARRY for a bad one, Z at the end.
5076
RET C D8
If the CARRY FLAG is set (a bad separator), RETURN with it (error 34H).
5077
If the NZ FLAG is set (another option), LOOP back to 5064H.
5079
GOSUB to 4E01H, which ends all routes (ROUTE,CLEAR).
507C
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, the value of an empty list.
507F
LD (4051H),HL 22 51 40
Store Register Pair HL (0000H) at 4051H, the head of SYS0's *name routine list: the list is empty.
5082
LD HL,44C9H 21 C9 44
Load Register Pair HL with 44C9H, SYS0's clock routine.
5085
LD (461DH),HL 22 1D 46
Store Register Pair HL (44C9H) at 461DH, the head of SYS0's timer chain: only the clock routine is left.
5088
LD HL,(43A9H) 2A A9 43
Load Register Pair HL with the 16-bit value at 43A9H, the top of memory SYS0 found at reset.
508B
LD DE,FFFFH 11 FF FF
Self-Modifying Code
Load Register Pair DE with MEM; the operand 508CH holds FFFFH unless MEM= stored a value at 506FH.
508E
LD A,D 7A
Load Register A with Register D, the high byte of MEM.
508F
CP 70H FE 70
Compare Register A against 70H: the CARRY FLAG is set below 7000H.
5091
If the CARRY FLAG is set (MEM too low), JUMP to 4F0DH for error 2FH.
5094
RST 18H DF
RST 18H: compare Register Pair HL (the top of memory) with Register Pair DE (MEM). The CARRY FLAG is set if the top of memory is lower.
5095
If the CARRY FLAG is set, JUMP to 5098H with Register Pair HL = the top of memory.
5097
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = MEM, the lower of the two.
5098
LD (4049H),HL 22 49 40
Store Register Pair HL (the new HIMEM) at 4049H, SYS0's HIMEM.
509B
LD DE,FFFFH 11 FF FF
Self-Modifying Code
Load Register Pair DE with END; the operand 509CH holds FFFFH unless END= stored a value.
509E
RST 18H DF
RST 18H: compare Register Pair HL (HIMEM) with Register Pair DE (END). The NO CARRY FLAG is set if HIMEM is not lower.
509F
If the NO CARRY FLAG is set, JUMP to 50A2H with Register Pair DE = END.
50A1
EX DE,HL EB
Exchange Register Pairs DE and HL: DE = HIMEM, the end of the fill.
50A2
LD HL,5200H 21 00 52
Self-Modifying Code
Load Register Pair HL with START; the operand 50A3H holds 5200H unless START= stored a value.
50A5
LD A,H 7C
Load Register A with Register H, the high byte of START.
50A6
CP 52H FE 52
Compare Register A against 52H: the CARRY FLAG is set below 5200H, the DOS's own memory.
50A8
If the CARRY FLAG is set, JUMP to 4F0DH for error 2FH.
50AB
DEC HL 2B
Decrement Register Pair HL: START minus 1, since the loop increments first.
50AC
RST 18H DF
RST 18H: compare Register Pair HL (START - 1) with Register Pair DE (the end). The NO CARRY FLAG is set if START lies past the end.
50AD
If the NO CARRY FLAG is set, JUMP to 4F0DH for error 2FH.

FILL LOOP
Register Pair HL = the byte cleared, Register Pair DE = the end.

50B0
INC HL 23
Increment Register Pair HL to the next byte to clear.
50B1
LD (HL),00H 36 00
Store 00H at Register Pair HL, clearing the byte of memory.
50B3
RST 18H DF
RST 18H: compare Register Pair HL with Register Pair DE (the end). The CARRY FLAG is set while HL is below it.
50B4
If the CARRY FLAG is set, LOOP back to 50B0H; the byte at the end is cleared too.
50B6
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
50B7
RET C9
RETURN to the DOS with Register A = 00H, no error.
50B8-50BE
DEFM "START=", 00H 53 54 41 52 54 3D 00
Keyword START= and its 00H end, for CLEAR's option table at 50B8H.
50BF
DEFB 00H 00
Flag byte 00H for START= (not used by CLEAR).
50C0-50C1
DEFW 50A3H A3 50
DEFW 50A3H, the operand START= sets (the LD HL at 50A2H).
50C2-50C6
DEFM "END=", 00H 45 4E 44 3D 00
Keyword END= and its 00H end, the last address to clear.
50C7
DEFB 00H 00
Flag byte 00H for END=; CLEAR does not use the flag byte.
50C8-50C9
DEFW 509CH 9C 50
DEFW 509CH, the operand END= sets (the LD DE at 509BH).
50CA-50CE
DEFM "MEM=", 00H 4D 45 4D 3D 00
Keyword MEM= and its 00H end: the value for the new HIMEM.
50CF
DEFB 00H 00
Flag byte 00H for MEM=; CLEAR does not use the flag byte.
50D0-50D1
DEFW 508CH 8C 50
DEFW 508CH, the operand MEM= sets (the LD DE at 508BH).
50D2
DEFB 00H 00
00H: the end of CLEAR's option table, tested at 4EE6H.

50D3H - LIST and PRINT

LIST filespec[,first[,count]] shows a text file from line first (default 1) for count lines (default all); PRINT does the same on the printer. SYS1 has opened the file (FCB 4480H) and left the command line pointer on the stack. Characters above option AX (4370H) and control characters other than a carriage return are shown as a period. The up arrow key stops; the up or right arrow key held at the end of a line (or after 256 characters) pauses until ENTER (go on) or the up arrow (stop). The keyboard row 3840H holds ENTER in bit 0, the up arrow in bit 3, the right arrow in bit 6.

50D3
LD A,3BH 3E 3B
PRINT: load Register A with 3BH, the low byte of the ROM's printer routine 003BH.
50D5
LD (5170H),A 32 70 51
Self-Modifying Code
Store Register A (3BH) at 5170H, the operand of the CALL 0033H at 516FH: the characters go to the printer (003BH) instead of the display.
50D8
POP AF F1
Restore Register Pair AF from the stack, discarding the dispatcher's return address.
50D9
POP HL E1
Restore Register Pair HL from the stack: the command line pointer SYS1 left, after the file name.
50DA
GOSUB to SYS0 4CD5H, which checks the separator at Register Pair HL: CARRY for a bad one, Z at the end, NZ if a parameter follows.
50DD
LD DE,0001H 11 01 00
Load Register Pair DE with 0001H, the default first line. LD does not change the flags.
50E0
If the NZ FLAG is set (a parameter follows), GOSUB to 515DH, which reads it into Register Pair DE (not 0) and checks the next separator.
50E3
PUSH DE D5
Save Register Pair DE (the first line) on the stack.
50E4
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH, the default count: all lines.
50E7
If the NZ FLAG is set (another parameter follows), GOSUB to 515DH to read the count into Register Pair DE.
50EA
If the NZ FLAG is set (still more follows), JUMP to 5168H for error 2FH.
50EC
POP BC C1
Restore Register Pair BC from the stack: the first line.
50ED
LD HL,4200H 21 00 42
Load Register Pair HL with 4200H, the DOS sector buffer.
50F0
LD (4483H),HL 22 83 44
Store Register Pair HL (4200H) at 4483H, the buffer address of the FCB at 4480H.

SKIP LINES
Register Pair BC counts down the lines before the first one shown.

50F3
DEC BC 0B
Decrement Register Pair BC, the lines left to skip.
50F4
LD A,B 78
Load Register A with Register B, the high byte of the lines left.
50F5
OR C B1
OR Register A with Register C: the Z FLAG is set when none are left.
50F6
If the Z FLAG is set, JUMP to 5101H to start showing.
50F8
GOSUB to 5128H, which reads the next character of the file into Register A.
50FB
CP 0DH FE 0D
Compare Register A against 0DH, the carriage return at the end of a line.
50FD
If the NZ FLAG is set (not the end of the line), LOOP back to 50F8H.
50FF
JUMP to 50F3H: one more line skipped; Register Pair BC counts on.

SHOW LOOP
Register Pair DE = the lines left to show, Register C counts characters (a key check every 256).

5101
GOSUB to 5128H, which reads the next character into Register A (a period for one that cannot be shown).
5104
GOSUB to 516DH, which shows the character in Register A (display or printer).
5107
DEC C 0D
Decrement Register C, the characters shown since the last key check.
5108
If the Z FLAG is set (256 characters since the last check), JUMP to 5113H to look at the keys.
510A
CP 0DH FE 0D
Compare Register A (the character) against 0DH, the end of a line.
510C
If the NZ FLAG is set (not the end), LOOP back to 5101H.
510E
DEC DE 1B
Decrement Register Pair DE, the lines left to show.
510F
LD A,D 7A
Load Register A with Register D, the high byte of the lines left.
5110
OR E B3
OR Register A with Register E: the Z FLAG is set when none are left.
5111
If the Z FLAG is set (the last line), JUMP to 5158H to finish.
5113
LD C,00H 0E 00
Load Register C with 00H, restarting the character count.
5115
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, keyboard row 6 (ENTER, CLEAR, BREAK, arrows, space).
5118
AND 48H E6 48
AND Register A with 48H, keeping the up arrow (bit 3) and the right arrow (bit 6).
511A
If the Z FLAG is set (neither is held), LOOP back to 5101H.
511C
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, keyboard row 6 again.
511F
AND 09H E6 09
AND Register A with 09H, keeping ENTER (bit 0) and the up arrow (bit 3).
5121
If the Z FLAG is set (neither pressed), LOOP back to 511CH: the listing pauses.
5123
RRCA 0F
Rotate Register A right: bit 0 (ENTER) goes into the CARRY FLAG.
5124
If the NO CARRY FLAG is set (the up arrow), JUMP to 5158H to stop.
5126
ENTER: JUMP to 5101H to go on showing the file's lines.
5128
LD A,(3840H) 3A 40 38
Load Register A with the byte at 3840H, keyboard row 6.
512B
AND 08H E6 08
AND Register A with 08H, keeping the up arrow (bit 3).
512D
If the NZ FLAG is set (the up arrow is pressed), JUMP to 5157H to stop.
512F
PUSH DE D5
Save Register Pair DE (the lines left) on the stack.
5130
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, the file's FCB.
5133
GOSUB to the ROM's input routine at 0013H, which reads the next byte of the file at Register Pair DE into Register A (through SYS0 4ADBH); the NZ FLAG is set on an error.
5136
POP DE D1
Restore Register Pair DE from the stack: the lines left.
5137
If the NZ FLAG is set (a read error or the end of the file), JUMP to 514EH.
5139
AND 7FH E6 7F
AND Register A with 7FH, clearing bit 7 of the character.
513B
PUSH HL E5
Save Register Pair HL on the stack while 4370H is compared.
513C
LD HL,4370H 21 70 43
Load Register Pair HL with 4370H, SYS0's copy of the SYSTEM option AX: the highest character code shown as it is.
513F
CP (HL) BE
Compare Register A (the character) with the byte at Register Pair HL (AX): the CARRY FLAG is set below AX, the Z FLAG if equal.
5140
POP HL E1
Restore Register Pair HL from the stack. POP does not change the flags.
5141
If the CARRY FLAG is set (below AX), JUMP to 5145H.
5143
If the NZ FLAG is set (above AX), JUMP to 514BH to show a period.
5145
CP 20H FE 20
Compare Register A against 20H: the NO CARRY FLAG is set for a space or above.
5147
RET NC D0
If the NO CARRY FLAG is set (a printable character), RETURN with it in Register A.
5148
CP 0DH FE 0D
Compare Register A against 0DH, a carriage return.
514A
RET Z C8
If the Z FLAG is set (a carriage return), RETURN with it.
514B
LD A,2EH 3E 2E
Load Register A with 2EH, a period, shown in place of the character.
514D
RET C9
RETURN with Register A = 2EH, the period to show.
514E
CP 1CH FE 1C
Compare Register A (the DOS error code) against 1CH, END OF FILE ENCOUNTERED.
5150
If the Z FLAG is set, JUMP to 5157H to stop normally.
5152
CP 1DH FE 1D
Compare Register A against 1DH, PAST END OF FILE.
5154
If the NZ FLAG is set (another error), JUMP to 4EEBH to leave with the error in Register A.
5157
POP AF F1
Restore Register Pair AF from the stack, discarding the return address of the call to 5128H.
5158
GOSUB to 516BH, which shows a carriage return to end the last line.
515B
XOR A AF
Load Register A with 00H (XOR A with itself), which also sets the Z FLAG: no error.
515C
RET C9
RETURN to the DOS with Register A = 00H and the Z FLAG set: no error.
515D
If the CARRY FLAG is set (the separator from 4CD5H was bad), JUMP to 4EE9H for error 34H.
5160
GOSUB to 4EEFH, which reads the number at Register Pair HL into Register Pair DE.
5163
LD A,D 7A
Load Register A with Register D, the high byte of the number.
5164
OR E B3
OR Register A with Register E: the Z FLAG is set if the number is 0.
5165
If the NZ FLAG is set (not 0), JUMP to SYS0 4CD5H, which checks the next separator and returns to the caller with its flags.
5168
JUMP to 4F0DH for error 2FH: a line number or count of 0, or too many parameters.
516B
LD A,0DH 3E 0D
Load Register A with 0DH, a carriage return, to end the output line.
516D
PUSH DE D5
Save Register Pair DE on the stack; the ROM's output routine changes it.
516E
PUSH AF F5
Save Register Pair AF (Register A = the character) on the stack.
516F
Self-Modifying Code
GOSUB to the ROM's display routine at 0033H, or its printer routine at 003BH for PRINT; the operand's low byte 5170H is 33H in the file and 3BH after 50D5H.
5172
POP AF F1
Restore Register Pair AF from the stack: Register A = the character.
5173
POP DE D1
Restore Register Pair DE from the stack, as it was before the output call.
5174
RET C9
RETURN with Register Pairs AF and DE unchanged.

5175H - Unused Bytes

5175H-51E7H fill the last load record; nothing reads or executes them.

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