TRS-80 DOS - LDOS 5.3.1 for the Model I - SYS6/SYS Disassembled

Page Customization

Summary:

LDOS 5.3.1 SYS6/SYS Disassembly - Library A Command Overlay Set (Model I)

SYS6/SYS is the Library A transient command file of LDOS 5.3.1 for the TRS-80 Model I. It is not a single program: it is a partitioned overlay file holding fifteen independent command overlays. Every overlay is assembled to load and run at 5200H, directly above the resident operating system (SYS0/SYS occupies 4000H-4DFFH and the RST 28H dispatcher/overlay loader live inside it). Only one overlay is resident at any moment; the resident overlay loader reads the requested overlay into 5200H, transfers control to it, and the overlay runs to completion and returns to the caller.

SYS6 is reached through the resident supervisor call RST 28H with the request code 88H in register A and the command number in register B. The resident dispatcher at 4BCDH (see the SYS0 disassembly) recognises code 88H as "Library A", calls the overlay loader at 4BF5H to bring the B-th overlay of SYS6 into memory at 5200H, and enters it at its first byte. The companion file SYS7/SYS is Library B (request code 89H) and holds the remaining transient commands. The command-name to (library, number) mapping is performed earlier by the command interpreter SYS1/SYS, which classifies the typed command word and issues the appropriate RST 28H request.

Because all fifteen overlays share the load address 5200H, the addresses in this disassembly repeat from overlay to overlay. Each overlay is documented as its own numbered section below, in the order it appears in the SYS6 file (which is the order of its command number). The entire memory image of every overlay in this page has been verified byte-for-byte against the raw SYS6.SYS load module (the LDOS load records were parsed and each overlay's loaded bytes compared against the listing; 0 mismatches across all fifteen overlays).

SYS6 Overlay Structure Map

The fifteen overlays and their SYS6.SYS file offsets, load range, and function. Each overlay begins with a stack-pointer save (LD (nnnnH),SP) so that it can restore the caller's stack and return, then validates its command line through the resident parameter services before performing its work.

OverlayFile OffsetLoad RangeCommand / Function
100C7H5200H-5603H
1028 bytes
MEMORY
High-memory management and the high-memory module directory. Sets and reports HIGH$ (4049H), reserves or releases high memory, and walks the resident high-memory module chain printing each module name, start, end and length.
204E2H5200H-5BE0H
2529 bytes
DIR
Directory display. Reads directory records, formats the Filespec / Attrib / LRL / #Recs / EOF / DE / File Size / MOD Date Time columns, computes free space, and supports the invisible, system, date/modified and sort options.
30EEEH5200H-5370H
369 bytes
REMOVE
Deletes one or more files. Requires a file spec, displays "Deleting: " for each file, and calls the resident @KILL service.
4106AH5200H-52D2H
211 bytes
LIB
Displays the Library A command directory ("Library <A>"), the list of command words serviced by SYS6.
51144H5200H-5D00H
1737 bytes
DO
The Job Control Language processor. Reads a JCL source file, honours the IF / ELSE / END / SET / RESET / ASSIGN / INCLUDE / QUIT directives, expands parameters, and writes the compiled SYSTEM/JCL file that the resident keyboard driver then replays.
61838H5200H-59DAH
1925 bytes
SPOOL
The printer spooler. Allocates or reclaims the spool buffer, starts, pauses, resumes and clears despooling, and reports spooler status. Sub-options MEM, SDISK, N(o disk), PAUSE, RESUME and CLEAR.
71FE8H5200H-5A6DH
2003 bytes
COPY
File copy and append. Displays "Copying: " / "Appending: ", checks LRL compatibility, prompts for SOURCE and DESTINATION disk swaps on a single-drive system, and supports the CLONE, STRIP, ECHO and X options.
827E6H5200H-563BH
1084 bytes
LIST
Lists the contents of a file to the screen with ASCII, HEX, LINE, REC(ord), NUM(ber) and TAB-expansion options.
92C39H5200H-53A4H
421 bytes
RENAME
Renames a file. Requires a file spec, rejects a duplicate name ("Duplicate file name!"), and updates the directory entry.
102DE9H5200H-56DFH
1208 bytes
SYSTEM (status/drives)
Reports the system configuration: resident system modules, drive geometry (floppy/rigid, removable/fixed, cylinders, sides, density, step and settle timing, verify), and the BYTEIO / DRIVES / STATUS sub-options.
1132BCH5200H-53A1H
418 bytes
LINK
Links two character devices so that output to one is also sent to the other. Requires a device spec and refuses to link a routed device.
123469H5200H-54D5H
726 bytes
Command overlay 12
Accepts LRL and DATE parameters (keyword table SO / LRL / DATE) and manages a memory reset; it emits "Can't reset memory, background task(s) exist" when active background tasks block the operation. Valid only at LDOS command level.
13374EH5200H-53F3H
500 bytes
ROUTE
Routes a character device, including to NIL and with a REWIND option. Requires a device spec and is valid only at LDOS command level.
14394DH5A00H-5B43H
324 bytes
Command overlay 14 (device driver/filter)
Attaches a driver or filter to a character device (references "DVRFLT"). Requires a file spec and a device spec and is valid only at LDOS command level.
153A9CH5200H-536FH
368 bytes
Command overlay 15 (disk-swap operation)
Prompts "Insert SYSTEM disk" and "Insert SOURCE disk" and can report "Command aborted!"; drives a single-drive multi-disk operation and requires a file spec.

Resident SYS0 Services Used By SYS6

Every overlay reaches back into the resident SYS0 core for its parameter parsing, display, math and directory primitives. These are external references; each is linked to the SYS0 disassembly at its resident address.

AddressResident Service
402DH@EXIT
Normal return to the LDOS command level; an overlay jumps here after clearing itself out of high memory or when finished.
4030H@ABORT
Abnormal return to DOS on a fatal command error.
4049HHIGH$
Resident word holding the current top-of-user-memory address; the MEMORY command reads and rewrites it to reserve or release high memory.
4403HResident word holding the top of physical/available memory used as the ceiling when computing free high memory.
4467H@DSPLY
Display a message (HL points to the text) to the video device.
4476H@PARAM
Parse the command line against a parameter descriptor table (DE points to the table); returns NZ on a parameter error.
447BH@LOGOT
Display a carriage-return-terminated string (HL points to the text).
4D76HResident routine that stores register pair DE as four hexadecimal ASCII digits at (HL); used to format addresses such as X'nnnn'.

Cross-Reference Notes

SYS6 is entered from the resident RST 28H dispatcher at 4BCDH in SYS0/SYS in response to request code 88H, and returns to it (or to @EXIT 402DH / @ABORT 4030H). The command interpreter SYS1/SYS decides which SYS6 command number to request. SYS6 itself calls only into the resident SYS0 core (4000H-4DFFH); it does not call SYS7 or any other overlay. Companion command file SYS7/SYS is Library B (request code 89H).

Disassembly:

5200H - Overlay Entry and Command Parameter Parse

Entry point of the MEMORY command overlay. It saves the caller's stack pointer for a clean return, then hands its command tail to the resident @PARAM service to decode the CLEAR, ADD, WORD, BYTE, GO, PRINT and HIGH keywords. Each recognised keyword deposits its value directly into the operand field of an instruction inside this overlay, so the tests that follow read those self-modified operands.

5200
LD (546CH),SP ED 73 6C 54
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn instruction at 546BH so the overlay exit can restore the caller's stack exactly. Register SP holds the LDOS command-level stack on entry.
5204
LD DE,54E9H 11 E9 54
Point register pair DE at 54E9H, the @PARAM keyword descriptor table for this command (the CLEAR/ADD/WORD/BYTE/GO/CLEAR/PRINT/HIGH keywords and their abbreviations).
5207
GOSUB to the resident @PARAM service at 4476H to parse the command tail against the descriptor table in DE. @PARAM deposits each supplied keyword value into the operand cell named by its table entry and returns NZ if the line contained an unrecognised parameter.
520A
If @PARAM returned the NZ flag (a bad or unknown parameter was found), JUMP to the parameter error handler at 54A0H to report a syntax error and abort.

Command Dispatch
The overlay's behaviour is selected entirely by which @PARAM keyword was present. Each keyword deposited its argument into a self-modified operand cell (520EH CLEAR, 523CH ADD, 525FH WORD, 5266H BYTE, 5295H HIGH, 542EH PRINT, 5460H GO), and the tests below branch on those cells.

520D
LD DE,0000H 11 00 00
Self-Modifying Code
Load DE with the CLEAR keyword value. The operand at 520EH is 0000H as assembled but is overwritten by @PARAM with the CLEAR argument; DE therefore holds the CLEAR request (nonzero when CLEAR was given).
5210
LD A,D 7A
Copy the high byte of the CLEAR value (register D) into register A to begin testing whether CLEAR was supplied.
5211
OR E B3
OR register A with the low byte (register E); the Z flag is set only if the whole CLEAR value in DE is zero (CLEAR not given).
5212
If the Z flag is set (CLEAR was not requested), JUMP to 523BH to handle the ADD keyword and the directory display.
5214
CLEAR was requested. GOSUB to the command-level check at 547AH to confirm the command is legal in the current system state before wiping memory.
5217
LD HL,5224H 21 24 52
Point register pair HL at 5224H, the source of the 23-byte CLEAR routine template that must run from resident memory.
521A
LD DE,4200H 11 00 42
Point register pair DE at the resident scratch buffer 4200H (SBUFF$), the destination where the CLEAR routine will be copied and executed.
521D
PUSH DE D5
Save the destination address 4200H (register DE) on the stack; the RET at 5223H will pop it as the return address, transferring control into the copied routine.
521E
LD BC,0017H 01 17 00
Load register pair BC with 0017H (23), the length in bytes of the CLEAR routine template at 5224H.
5221
LDIR ED B0
Block-move BC (23) bytes from (HL)=5224H to (DE)=4200H, relocating the CLEAR routine into the resident scratch buffer.
5223
RET C9
RETurn, popping 4200H off the stack as the target address and thereby jumping into the relocated CLEAR routine now resident at 4200H.

5224H - CLEAR Routine Template (Relocated to 4200H)

This 23-byte block is not executed in place. The setup above copies it to the resident scratch buffer at 4200H and returns into it. Running there, it zero-fills memory from 5201H up to the current HIGH$ ceiling and exits to DOS, wiping the reserved high-memory region requested by the CLEAR keyword.

5224
LD HL,(4049H) 2A 49 40
Fetch the current HIGH$ ceiling from the resident word at 4049H into register pair HL (the top of reserved user memory).
5227
LD DE,5200H 11 00 52
Load register pair DE with 5200H, this overlay's load address, the bottom of the region to be cleared.
522A
PUSH DE D5
Save 5200H (register DE) on the stack for use as the block-move start pointer below.
522B
XOR A AF
Set register A to zero and clear the carry flag in preparation for the subtraction that follows.
522C
SBC HL,DE ED 52
Subtract DE (5200H) from HL (HIGH$) with the carry clear, leaving in HL the byte count from 5200H up to HIGH$.
522E
LD B,H 44
Copy the high byte of that count (register H) into register B, forming the high half of the block-move counter.
522F
LD C,L 4D
Copy the low byte of the count (register L) into register C, completing the 16-bit count in register pair BC.
5230
POP HL E1
Restore 5200H from the stack into register pair HL as the block-move source/fill pointer.
5231
LD DE,5201H 11 01 52
Load register pair DE with 5201H, one byte above HL; the classic fill pattern where HL supplies the seed and the LDIR propagates it upward.
5234
LD (HL),00H 36 00
Store 00H into (HL)=5200H, seeding the fill with a zero byte.
5236
LDIR ED B0
Block-move (fill) forward: propagate the zero byte from (HL) to (DE) for BC bytes, zeroing memory from 5200H up to the HIGH$ ceiling and releasing the reserved area.
5238
JUMP to the resident @EXIT vector at 402DH to return cleanly to the LDOS command level after clearing memory.

523BH - ADD Keyword: Hexadecimal and Decimal Value Display

Reached when CLEAR was not given. If the ADD keyword supplied a value it is echoed back to the operator both ways - as a 4-digit hexadecimal address and as a decimal number - in the form X'dddd' = ddddd ('dddd' => X'dddd'), using the resident hex-format and the local decimal-format helpers.

523B
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the ADD keyword value. The operand at 523CH is assembled as 0000H and patched by @PARAM with the ADD argument; HL therefore holds the number to be displayed (zero if ADD was not given).
523E
LD A,H 7C
Copy the high byte of the ADD value (register H) into register A to test whether a value was supplied.
523F
OR L B5
OR register A with the low byte (register L); the Z flag is set only when the whole ADD value in HL is zero (ADD not given).
5240
If the Z flag is set (no ADD value), JUMP to 5294H to handle the HIGH keyword and the directory.
5242
PUSH HL E5
Save the ADD value (register pair HL) on the stack; it will be reused for both the decimal and the parenthesised hexadecimal forms of the display.
5243
EX DE,HL EB
Exchange DE and HL so the ADD value is in register pair DE, the input expected by the resident hex formatter.
5244
LD HL,556DH 21 6D 55
Point register pair HL at 556DH, the position in the message template where the first X'dddd' hexadecimal field is to be written.
5247
GOSUB to the resident formatter at 4D76H to store DE (the ADD value) as four hexadecimal ASCII digits at (HL)=556DH.
524A
POP HL E1
Restore the ADD value from the stack into register pair HL.
524B
PUSH HL E5
Save the ADD value (register pair HL) on the stack again for the decimal conversion.
524C
LD DE,5575H 11 75 55
Point register pair DE at 5575H, the field in the template that receives the decimal form of the value.
524F
GOSUB to the local decimal formatter at 5411H to convert HL to a right-justified decimal string at (DE)=5575H.
5252
POP HL E1
Restore the ADD value from the stack into register pair HL.
5253
PUSH HL E5
Save the ADD value on the stack once more for the final swapped-nibble display.
5254
LD D,(HL) 56
Load register D with the byte at (HL), the high byte of the value at the ADD address, beginning a read of the little-endian word stored there.
5255
INC HL 23
INCrement HL to point at the next byte.
5256
LD E,(HL) 5E
Load register E with the byte at (HL), so DE now holds the reversed-order word read from the ADD location.
5257
LD HL,557EH 21 7E 55
Point register pair HL at 557EH, the second X'dddd' field in the template (the ('dddd' => X'dddd') part).
525A
GOSUB to 4D76H to store DE as four hexadecimal ASCII digits at (HL)=557EH.
525D
POP HL E1
Restore the ADD value from the stack into register pair HL.
525E
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the WORD keyword value. The operand at 525FH is patched by @PARAM; DE is nonzero if WORD was requested.
5261
LD A,D 7A
Copy the high byte of the WORD value (register D) into register A to test whether WORD was given.
5262
OR E B3
OR register A with the low byte (register E); the Z flag is set only if the WORD value is zero (WORD not given).
5263
If the NZ flag is set (WORD was given), JUMP to 5273H to format the value as a 16-bit word.
5265
LD DE,00FFH 11 FF 00
Self-Modifying Code
Load register pair DE with the BYTE keyword value. The operand at 5266H is assembled as 00FFH and patched by @PARAM; DE reflects whether BYTE was requested.
5268
LD A,D 7A
Copy the high byte of the BYTE value (register D) into register A.
5269
OR A B7
OR register A with itself to set the flags on the BYTE high byte.
526A
If the NZ flag is set (an out-of-range BYTE value), JUMP to the parameter error handler at 54A0H.
526D
INC E 1C
INCrement register E; combined with the following DECrement this tests whether the BYTE low byte was 0FFH (the assembled default, meaning BYTE not actually given).
526E
If the INCrement produced zero (E was 0FFH, so BYTE defaulted), JUMP to 5286H to select the byte display template.
5270
DEC E 1D
DECrement register E back to its true value now that the test is complete.
5271
JUMP forward to 5276H to store the resolved byte value.
5273
INC HL 23
WORD path. INCrement HL to address the high byte of the two-byte field being built.
5274
LD (HL),D 72
Store register D (the high byte of the value) at (HL).
5275
DEC HL 2B
DECrement HL back to the low-byte position.
5276
LD (HL),E 73
Store register E (the low byte of the value) at (HL), completing the value written into the display field.
5277
LD A,E 7B
Copy register E (the low byte) into register A while the two bytes are swapped for the reversed display.
5278
INC HL 23
INCrement HL to the next byte.
5279
LD E,(HL) 5E
Load register E from (HL), reading the neighbouring byte for the reversed-order presentation.
527A
LD D,A 57
Copy register A (the saved low byte) into register D, so DE now carries the byte value in the order needed for the template.
527B
LD HL,5589H 21 89 55
Point register pair HL at 5589H, the display field used for the word/byte value.
527E
GOSUB to 4D76H to store DE as hexadecimal ASCII digits at (HL)=5589H.
5281
LD HL,558EH 21 8E 55
Point register pair HL at 558EH, the terminator/format position for the word form of the message.
5284
JUMP to 5289H to apply the common message terminator.
5286
LD HL,5583H 21 83 55
Byte path. Point register pair HL at 5583H, the display field for the single-byte form of the message.
5289
LD (HL),29H 36 29
Store 29H (the ASCII right parenthesis) at (HL), closing the parenthesised part of the value display.
528B
INC HL 23
INCrement HL to the following byte.
528C
LD (HL),03H 36 03
Store 03H at (HL), the end-of-message marker for the @DSPLY call.
528E
LD HL,556BH 21 6B 55
Point register pair HL at 556BH, the start of the assembled X'dddd' = ddddd message line.
5291
GOSUB to the resident @DSPLY service at 4467H to display the value-conversion message on the video screen.

5294H - HIGH Keyword: Reserve or Release High Memory

If the HIGH keyword supplied a new HIGH$ value this section validates it against the overlay's own load address and the top of memory, plants a relocatable reserve stub just below the new ceiling, and rewrites the resident HIGH$ word (4049H). If HIGH was not given, control falls through to the high-memory directory display.

5294
LD BC,0000H 01 00 00
Self-Modifying Code
Load register pair BC with the HIGH keyword value. The operand at 5295H is patched by @PARAM; BC holds the requested new HIGH$ ceiling (zero if HIGH was not given).
5297
LD A,B 78
Copy the high byte of the HIGH value (register B) into register A to test whether HIGH was supplied.
5298
OR C B1
OR register A with the low byte (register C); the Z flag is set only if the HIGH value is zero (HIGH not given).
5299
If the Z flag is set (HIGH not requested), JUMP to 52CFH to display the high-memory directory instead.
529B
HIGH was requested. GOSUB to the command-level check at 547AH to confirm reserving memory is permitted now.
529E
LD HL,(5200H) 2A 00 52
Load register pair HL from the word at 5200H. At this moment 5200H holds this overlay's first bytes; the value is used as the lower bound against which the requested HIGH$ is validated.
52A1
XOR A AF
Set register A to zero and clear the carry flag before comparing.
52A2
SBC HL,BC ED 42
Subtract BC (the requested HIGH$) from HL; the carry/zero result tells whether the request lies at or below the overlay, which would be illegal.
52A4
If no borrow occurred (the request is not above the overlay - too low), JUMP to 5495H, the entry that displays the Range error message.

Range Check
A requested HIGH$ must lie above this overlay's load area yet not above the current ceiling; either violation jumps to the Range error entry at 5495H.

52A7
LD HL,(4049H) 2A 49 40
Fetch the current HIGH$ ceiling from the resident word at 4049H into register pair HL.
52AA
LD (54ABH),HL 22 AB 54
Store the current HIGH$ value (register pair HL) into 54ABH, saving the old ceiling so the reserved size can be reported.
52AD
XOR A AF
Set register A to zero and clear the carry flag before the next comparison.
52AE
SBC HL,BC ED 42
Subtract BC (the requested new ceiling) from HL (the current HIGH$); a borrow means the request is above the present ceiling, which is out of range.
52B0
If a borrow occurred (requested HIGH$ is above the current ceiling), JUMP to 5495H to display the Range error message.
52B3
LD D,B 50
Copy the high byte of the requested ceiling (register B) into register D.
52B4
LD E,C 59
Copy the low byte of the requested ceiling (register C) into register E, so register pair DE now mirrors the requested HIGH$ value.
52B5
INC DE 13
INCrement DE to form the size/address arithmetic value used in the reserve report.
52B6
LD HL,54AFH 21 AF 54
Point register pair HL at 54AFH, the hexadecimal field inside the relocatable reserve stub where the reserved address is recorded.
52B9
GOSUB to 4D76H to store DE as four hexadecimal ASCII digits at (HL)=54AFH within the reserve stub.
52BC
LD HL,0FFF6H 21 F6 FF
Load register pair HL with 0FFF6H (-10), the negative offset used to step the ceiling down by the size of the reserve stub.
52BF
ADD HL,BC 09
ADD BC (the requested ceiling) to HL, computing the new HIGH$ that sits just below the planted reserve stub.
52C0
LD (4049H),HL 22 49 40
Store the new ceiling (register pair HL) into the resident HIGH$ word at 4049H, reserving the high memory.
52C3
INC HL 23
INCrement HL to point one byte above the new ceiling, the address where the reserve stub is to be copied.
52C4
EX DE,HL EB
Exchange DE and HL so register pair DE addresses the reserve-stub destination in high memory.
52C5
LD HL,54A9H 21 A9 54
Point register pair HL at 54A9H, the 10-byte reserve-stub template within this overlay.
52C8
LD BC,000AH 01 0A 00
Load register pair BC with 000AH (10), the length of the reserve-stub template.
52CB
LDIR ED B0
Block-move BC (10) bytes from (HL)=54A9H to (DE), planting the reserve stub just above the new HIGH$ so the reserved block is recorded in the resident module chain.
52CD
JUMP to 52E7H to display the resulting high-memory directory.

52CFH - Confirm HIGH$ and Prepare Directory Display

Compares the resident HIGH$ ceiling (4049H) against the top-of-memory word (4403H). When they are equal (no high memory reserved) it shows the current High = X'xxxx' line; otherwise it proceeds to walk the reserved high-memory module chain.

52CF
LD DE,(4049H) ED 5B 49 40
Load register pair DE from the resident HIGH$ word at 4049H (the current ceiling).
52D3
LD HL,(4403H) 2A 03 44
Load register pair HL from the top-of-memory word at 4403H (the highest usable address).
52D6
OR A B7
Clear the carry flag before the comparison.
52D7
SBC HL,DE ED 52
Subtract DE (HIGH$) from HL (top of memory); the Z flag is set when they are equal, meaning no high memory is currently reserved.
52D9
If the NZ flag is set (some high memory is reserved), JUMP to 52E7H to list the reserved modules.
52DB
LD HL,5565H 21 65 55
No reservation exists. Point register pair HL at 5565H, the hexadecimal field in the High = X'xxxx' message.
52DE
GOSUB to 4D76H to store DE (the HIGH$ value) as four hexadecimal ASCII digits at (HL)=5565H.
52E1
LD HL,555AH 21 5A 55
Point register pair HL at 555AH, the start of the High = X'xxxx' message.
52E4
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated High = X'xxxx' line.

52E7H - High-Memory Directory: Header and Module Loop

Prints the High Memory Directory heading and then iterates over the resident high-memory module chain. For each linked module it copies the module's name and computes and formats its start address, end address and length into the display line.

52E7
GOSUB to the pause/key-wait helper at 543FH to honour paged output at the top of the directory.
52EA
LD DE,(4403H) ED 5B 03 44
Load register pair DE from the top-of-memory word at 4403H.
52EE
LD HL,(4049H) 2A 49 40
Load register pair HL from the resident HIGH$ word at 4049H.
52F1
SBC HL,DE ED 52
Subtract DE (top of memory) from HL (HIGH$); the Z flag is set when nothing is reserved so the directory is empty.
52F3
If the Z flag is set (no reserved modules), JUMP to the overlay exit at 545FH.
52F6
LD A,0DH 3E 0D
Load register A with 0DH (a carriage return) to terminate the work line being built.
52F8
LD (5200H),A 32 00 52
Store the carriage return (register A) at 5200H, marking the start of the work line.
52FB
GOSUB to the line-emit helper at 542AH to output the (currently blank) line and reset the work area.
52FE
GOSUB to 5357H to build the directory column-header line.
5301
GOSUB to the line-emit helper at 542AH to display the column-header line.
5304
LD HL,(4049H) 2A 49 40
Load register pair HL from the resident HIGH$ word at 4049H, the address of the first reserved module header.
5307
INC HL 23
INCrement HL to step over the module-header link byte to the marker field.
5308
LD (533CH),HL 22 3C 53
Store the current header pointer (register pair HL) into the self-modified cell at 533CH, preserving the walk position.
530B
LD A,(HL) 7E
Load register A with the byte at (HL), the module-header marker byte for the current module.
530C
CP 18H FE 18
Compare register A against 18H, the marker that identifies a valid high-memory module header.
530E
If register A is not 18H (not a module header), JUMP to 53A4H to scan for the next valid header.
5311
INC HL 23
INCrement HL past the marker byte.
5312
INC HL 23
INCrement HL again to reach the module's start-address field.
5313
LD E,(HL) 5E
Load register E with the low byte of the module start address from (HL).
5314
INC HL 23
INCrement HL to the high byte of the start address.
5315
LD D,(HL) 56
Load register D with the high byte of the module start address, so register pair DE holds the module's start address.
5316
LD (5330H),DE ED 53 30 53
Store the module start address (register pair DE) into the self-modified cell at 5330H for the length calculation.
531A
INC HL 23
INCrement HL to the module name-length field.
531B
LD B,(HL) 46
Load register B with the byte at (HL), the length of the module name in characters (the loop counter).
531C
INC HL 23
INCrement HL to the first character of the module name.
531D
LD DE,5200H 11 00 52
Point register pair DE at 5200H, the start of the work area that will receive the module name for display.
5320
LD A,(HL) 7E
Load register A with the name character at (HL).
5321
LD (DE),A 12
Store the character (register A) at (DE) in the work area.
5322
INC HL 23
INCrement HL to the next source name character.
5323
INC DE 13
INCrement DE to the next work-area position.
5324
DECrement register B and LOOP BACK to 5320H until all B name characters have been copied.
5326
LD HL,(533CH) 2A 3C 53
Reload register pair HL from the saved walk position at 533CH (the current module header).
5329
LD DE,5212H 11 12 52
Point register pair DE at 5212H, the Start Address field of the directory work line.
532C
GOSUB to the hex-field helper at 53FFH to format the module start address into the Start Address column.
532F
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the placeholder used when computing the module end address below.
5332
LD DE,5224H 11 24 52
Point register pair DE at 5224H, the End Address field of the work line.
5335
GOSUB to the hex-field helper at 53FFH to format the end address into the End Address column.
5338
LD HL,(5330H) 2A 30 53
Load register pair HL from the saved module start address at 5330H.
533B
LD DE,0000H 11 00 00
Load register pair DE with 0000H, the subtrahend base for the length computation.
533E
OR A B7
Clear the carry flag before subtracting.
533F
SBC HL,DE ED 52
Subtract DE from HL to begin forming the module length.
5341
INC HL 23
INCrement HL so the length is inclusive of the final byte.
5342
LD DE,5233H 11 33 52
Point register pair DE at 5233H, the Length field of the work line.
5345
GOSUB to the decimal helper at 5411H to write the module length as decimal digits into the Length column.
5348
GOSUB to the line-emit helper at 542AH to display this module's completed directory row.
534B
LD HL,(5330H) 2A 30 53
Load register pair HL from the saved module start address at 5330H to test for the end of the chain.
534E
INC HL 23
INCrement HL to test whether the address wrapped to zero (end of the reserved region).
534F
LD A,H 7C
Copy the high byte (register H) into register A.
5350
OR L B5
OR register A with the low byte (register L); the Z flag is set when the pointer has reached the top of memory.
5351
If the Z flag is set (chain exhausted), JUMP to the overlay exit at 545FH.
5354
JUMP back to 5308H to process the next module header in the chain.

5357H - Build the Directory Column-Header Line

Assembles the column-header line (Module / Start Address / End Address / Length) and the HIGH$ = value into the overlay's work area at 5200H, then emits it above the per-module rows.

5357
LD HL,558FH 21 8F 55
Point register pair HL at 558FH, the source text of the directory column headings.
535A
LD DE,5200H 11 00 52
Point register pair DE at the work area 5200H that will hold the header line.
535D
LD BC,0015H 01 15 00
Load register pair BC with 0015H (21), the length of the first header fragment.
5360
LDIR ED B0
Block-move BC (21) bytes from (HL)=558FH to the work area, laying down the leading header text.
5362
LD HL,55A4H 21 A4 55
Point register pair HL at 55A4H, the next header text fragment.
5365
LD DE,5219H 11 19 52
Point register pair DE at 5219H within the work line where that fragment belongs.
5368
LD C,07H 0E 07
Load register C with 07H (7), the length of this fragment (register B is already zero).
536A
LDIR ED B0
Block-move 7 bytes from (HL)=55A4H into the work line.
536C
LD HL,(4049H) 2A 49 40
Load register pair HL from the resident HIGH$ word at 4049H for display in the header.
536F
LD DE,5221H 11 21 52
Point register pair DE at 5221H, the header field that shows the HIGH$ value.
5372
GOSUB to the hex-field helper at 53FFH to format HIGH$ into the header line.
5375
LD HL,55B2H 21 B2 55
Point register pair HL at 55B2H, a further header text fragment.
5378
LD DE,522CH 11 2C 52
Point register pair DE at 522CH within the work line.
537B
LD BC,0008H 01 08 00
Load register pair BC with 0008H (8), the length of the fragment.
537E
LDIR ED B0
Block-move 8 bytes from (HL)=55B2H into the work line.
5380
LD HL,(4403H) 2A 03 44
Load register pair HL from the top-of-memory word at 4403H.
5383
LD DE,(4049H) ED 5B 49 40
Load register pair DE from the resident HIGH$ word at 4049H.
5387
OR A B7
Clear the carry flag before subtracting.
5388
SBC HL,DE ED 52
Subtract DE (HIGH$) from HL (top of memory), giving the total reserved high-memory size.
538A
LD DE,5234H 11 34 52
Point register pair DE at 5234H, the field for the reserved-size figure.
538D
GOSUB to the decimal helper at 5411H to write the reserved size as decimal digits into the header line.
5390
LD A,0DH 3E 0D
Load register A with 0DH (a carriage return) to terminate the header line.
5392
LD (5239H),A 32 39 52
Store the carriage return (register A) at 5239H, marking the end of the assembled header text.
5395
GOSUB to the line-emit helper at 542AH to display the finished header line.
5398
LD HL,55BAH 21 BA 55
Point register pair HL at 55BAH, the second column-heading text block (Module / Start Address / End Address / Length).
539B
LD DE,5200H 11 00 52
Point register pair DE at the work area 5200H.
539E
LD BC,003AH 01 3A 00
Load register pair BC with 003AH (58), the length of the column-heading block.
53A1
LDIR ED B0
Block-move BC (58) bytes from (HL)=55BAH into the work area.
53A3
RET C9
RETurn to the caller with the column-heading line assembled.

53A4H - Scan the Resident High-Memory Module Chain

Walks the chain of resident high-memory module headers. Each header is found by its 18H marker byte; the routine reads the forward link and the module name, validates the name characters, and formats each module's extent for display, looping until the chain reaches the top of memory.

53A4
PUSH HL E5
Save the current scan pointer (register pair HL) on the stack while searching for the next module header.
53A5
DEC HL 2B
DECrement HL to reposition before rescanning.
53A6
LD DE,(4403H) ED 5B 03 44
Load register pair DE from the top-of-memory word at 4403H, the upper limit of the scan.
53AA
EX DE,HL EB
Exchange DE and HL so HL holds the top of memory and DE the scan pointer.
53AB
OR A B7
Clear the carry flag before subtracting.
53AC
SBC HL,DE ED 52
Subtract DE (scan pointer) from HL (top of memory), forming in HL the number of bytes remaining to scan.
53AE
LD B,H 44
Copy the high byte of that count (register H) into register B.
53AF
LD C,L 4D
Copy the low byte of the count (register L) into register C, giving the CPIR search length in register pair BC.
53B0
POP HL E1
Restore the scan pointer from the stack into register pair HL.
53B1
If the count was zero (register pair BC is zero, nothing left to scan), JUMP to the overlay exit at 545FH.
53B4
LD A,18H 3E 18
Load register A with 18H, the module-header marker to search for.
53B6
CPIR ED B1
Search forward: CPIR compares A against successive bytes at (HL), incrementing HL and decrementing BC, until the 18H marker is found or BC reaches zero.

Loop End
CPIR either finds the 18H module marker or exhausts the byte count in BC.

53B8
If the marker was not found (NZ, BC exhausted), JUMP to 53F7H to finish at the top of memory.
53BA
DEC HL 2B
DECrement HL to step back to the marker byte position.
53BB
DEC HL 2B
DECrement HL again to reach the module-header link field preceding the marker.
53BC
LD (5330H),HL 22 30 53
Store the candidate header pointer (register pair HL) into the self-modified cell at 5330H.
53BF
INC HL 23
INCrement HL to advance through the candidate header for validation.
53C0
INC HL 23
INCrement HL again over the header fields.
53C1
INC HL 23
INCrement HL a third time to reach the module's end-of-extent word.
53C2
LD E,(HL) 5E
Load register E with the low byte of the module extent from (HL).
53C3
INC HL 23
INCrement HL to the high byte.
53C4
LD D,(HL) 56
Load register D with the high byte of the module extent, so register pair DE holds the extent value.
53C5
LD HL,(5330H) 2A 30 53
Reload the candidate header pointer from 5330H into register pair HL.
53C8
EX DE,HL EB
Exchange DE and HL so HL holds the extent and DE the header pointer for the range check.
53C9
OR A B7
Clear the carry flag before subtracting.
53CA
SBC HL,DE ED 52
Subtract DE from HL to test whether the extent lies within the reserved region.
53CC
If a borrow occurred (the candidate is not a valid module header), JUMP to 53F0H to advance past it.
53CE
LD HL,(5330H) 2A 30 53
Reload the candidate header pointer from 5330H into register pair HL.
53D1
INC HL 23
INCrement HL over the header link field.
53D2
INC HL 23
INCrement HL to the module name area.
53D3
INC HL 23
INCrement HL through the name fields.
53D4
INC HL 23
INCrement HL further into the name.
53D5
INC HL 23
INCrement HL to the module name-length byte.
53D6
LD A,(HL) 7E
Load register A with the name-length byte at (HL).
53D7
CP 10H FE 10
Compare register A against 10H (16); a length of 16 or more is invalid for a module name.
53D9
If register A is 16 or greater (NC), JUMP to 53F0H to reject this candidate.
53DB
LD B,A 47
Copy the valid name length (register A) into register B as the character-validation loop counter.
53DC
INC HL 23
INCrement HL to the next module name character.
53DD
LD A,(HL) 7E
Load register A with a name character at (HL).
53DE
CP 21H FE 21
Compare register A against 21H (the ASCII space+1); characters below this are non-printable and disqualify the header.
53E0
If register A is below 21H (C), JUMP to 53F0H to reject the candidate.
53E2
CP 7BH FE 7B
Compare register A against 7BH (just past lowercase z); characters at or above this are also invalid.
53E4
If register A is 7BH or greater (NC), JUMP to 53F0H to reject the candidate.
53E6
DECrement register B and LOOP BACK to 53DCH until all name characters have been validated.
53E8
LD HL,55F4H 21 F4 55
The candidate is a genuine module header. Point register pair HL at 55F4H, the <unknown> fallback name text used when a module has no printable name.
53EB
LD B,09H 06 09
Load register B with 09H (9), the length of the fallback name.
53ED
JUMP to 531DH to copy the (fallback) name into the work line and continue the directory display for this module.
53F0
LD HL,(5330H) 2A 30 53
Rejected candidate. Reload the candidate pointer from 5330H into register pair HL.
53F3
INC HL 23
INCrement HL past the rejected marker.
53F4
INC HL 23
INCrement HL again to resume scanning beyond it.
53F5
JUMP back to 53A4H to search for the next module header.
53F7
LD HL,(4403H) 2A 03 44
No further headers. Load register pair HL from the top-of-memory word at 4403H.
53FA
LD (5330H),HL 22 30 53
Store the top of memory (register pair HL) into 5330H as the terminating extent so the display loop ends.
53FD
JUMP to 53E8H to finish with the <unknown> entry for the trailing region.

53FFH - Helper: Format Register Pair as Hex Address Field

Utility used throughout the directory display. It converts the value in HL to four hexadecimal ASCII digits (via the resident 4D76H formatter) and drops them, wrapped in X'____', into the caller-supplied field.

53FF
PUSH DE D5
Save the caller's field pointer (register pair DE) on the stack.
5400
EX DE,HL EB
Exchange DE and HL so register pair DE holds the value to be formatted.
5401
LD HL,55FFH 21 FF 55
Point register pair HL at 55FFH, the X'____' hexadecimal template within this overlay.
5404
GOSUB to 4D76H to store DE as four hexadecimal ASCII digits into the X'____' template at (HL)=55FFH.
5407
POP DE D1
Restore the caller's field pointer from the stack into register pair DE.
5408
LD HL,55FDH 21 FD 55
Point register pair HL at 55FDH, the start of the formatted X'____' string (including the leading X').
540B
LD BC,0007H 01 07 00
Load register pair BC with 0007H (7), the length of the X'dddd' field.
540E
LDIR ED B0
Block-move BC (7) bytes from (HL)=55FDH to the caller's field at (DE), placing the formatted address.
5410
RET C9
RETurn to the caller with the hexadecimal field written.

5411H - Helper: Format Value as Right-Justified Decimal

Utility that converts the binary value in HL to a right-justified, space-padded decimal string of up to five digits at the buffer addressed by DE, using the resident divide-by-ten helper (44C4H).

5411
LD B,05H 06 05
Load register B with 05H (5), the number of leading spaces/decimal positions to prepare.
5413
LD A,20H 3E 20
Load register A with 20H (an ASCII space) to blank the decimal field.
5415
LD (DE),A 12
Store the space (register A) at (DE).
5416
INC DE 13
INCrement DE to the next field position.
5417
DECrement register B and LOOP BACK to 5415H until 5 spaces have been written, clearing the decimal field.
5419
PUSH DE D5
Save the field-end pointer (register pair DE) on the stack; digits are filled right to left from here.
541A
DEC DE 1B
DECrement DE to the least-significant digit position.
541B
LD A,0AH 3E 0A
Load register A with 0AH (10), the divisor for extracting the next decimal digit.
541D
GOSUB to the resident divide helper at 44C4H to divide HL by 10; it returns the quotient in HL and the remainder (the next digit 0-9) in register A.
5420
ADD A,30H C6 30
ADD 30H to register A to convert the remainder digit to its ASCII character.
5422
LD (DE),A 12
Store the ASCII digit (register A) at (DE).
5423
DEC DE 1B
DECrement DE to the next-higher digit position (moving left).
5424
LD A,H 7C
Copy the high byte of the quotient (register H) into register A to test for completion.
5425
OR L B5
OR register A with the low byte (register L); the Z flag is set when the quotient has reached zero.
5426
If the NZ flag is set (more digits remain), LOOP BACK to 541BH to extract the next decimal digit.
5428
POP DE D1
Restore the saved field-end pointer from the stack into register pair DE.
5429
RET C9
RETurn to the caller with the decimal number formatted.

542AH - Helper: Emit the Work Line and Blank It

Displays the assembled work line at 5200H to the video device (and to the printer when the PRINT keyword was given), then refills the 57-byte work area with spaces ready for the next line.

542A
LD HL,5200H 21 00 52
Point register pair HL at the work line at 5200H that is to be displayed.
542D
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the PRINT keyword value. The operand at 542EH is patched by @PARAM; DE is nonzero when PRINT was requested so output is echoed to the printer.
5430
INC E 1C
INCrement register E, then the following DECrement tests whether the PRINT value was present without altering it.
5431
DEC E 1D
DECrement register E to restore the PRINT flag value while the Z flag reflects whether PRINT was given.
5432
If the PRINT flag is nonzero (NZ), GOSUB to the resident @PRINT service at 446AH to send the work line to the printer.
5435
GOSUB to the resident @DSPLY service at 4467H to display the work line on the video screen.
5438
LD B,39H 06 39
Load register B with 39H (57), the width of the work area to be blanked for the next line.
543A
LD (HL),20H 36 20
Store 20H (an ASCII space) at (HL).
543C
INC HL 23
INCrement HL to the next work-area byte.
543D
DECrement register B and LOOP BACK to 543AH until all 57 bytes of the work area are spaces.

543FH - Helper: Optional Pause / Wait for a Key

Provides the paged-display pause. It tests a self-modified counter; when a screen is full it waits at the ROM keyboard scan for a key, honouring the BREAK key as an abort back to DOS.

543F
LD A,0FH 3E 0F
Self-Modifying Code
Load register A with 0FH (15), the count of lines per screen. The store below patches the counter cell at 5440H, so this value is decremented on each call.
5441
DEC A 3D
DECrement register A, counting down one displayed line.
5442
LD (5440H),A 32 40 54
Store the decremented count (register A) back into the counter operand at 5440H.
5445
RET NZ C0
If the count did not reach zero (NZ, screen not yet full), RETurn to the caller without pausing.
5446
The screen is full. GOSUB to the ROM keyboard routine at 0049H to wait for and read a key press.
5449
CP 01H FE 01
Compare the key (register A) against 01H, the BREAK key code.
544B
If register A equals 01H (BREAK was pressed), JUMP to 549BH to abort the display and exit.
544E
GOSUB to the ROM routine at 01C9H to clear the display line / advance for the next page.
5451
LD A,0FH 3E 0F
Reload register A with 0FH (15) to reset the lines-per-screen counter.
5453
LD (5440H),A 32 40 54
Store the reset count (register A) into the counter operand at 5440H.
5456
GOSUB to 5398H to redraw the column headings at the top of the new page.
5459
LD HL,5200H 21 00 52
Point register pair HL at the work line at 5200H.
545C
JUMP to 5435H to display the freshly-drawn heading line.

545FH - Overlay Exit and Caller Stack Restore

The common exit. It optionally jumps through a saved vector, restores the caller's stack pointer that was saved at entry, and returns to the LDOS command level, or aborts to DOS if the system flag demands it.

545F
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the sentinel that means no special exit vector is pending.
5462
LD A,H 7C
Copy the high byte (register H) into register A to test the sentinel.
5463
AND L A5
AND register A with the low byte (register L); the result is 0FFH only when HL is the 0FFFFH sentinel.
5464
INC A 3C
INCrement register A; if HL was 0FFFFH the result is zero (Z), meaning no vector jump is required.
5465
If the Z flag is set (no exit vector), JUMP over the vector jump to 5468H.
5467
JP (HL) E9
Otherwise JUMP to the address held in register pair HL, taking a pending exit vector.
5468
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the assembled placeholder for the caller's returned status.
546B
LD SP,0000H 31 00 00
Self-Modifying Code
Load register SP from the operand at 546CH, which was set at entry (5200H) to the caller's stack pointer, restoring the caller's stack for the return.
546E
LD A,H 7C
Copy the high byte of the returned status (register H) into register A.
546F
OR L B5
OR register A with the low byte (register L); the Z flag is set when the status is zero (success).
5470
RET Z C8
If the Z flag is set (success), RETurn to the LDOS command level.
5471
LD A,(430FH) 3A 0F 43
On a non-success status, load register A from the resident system flag byte at 430FH.
5474
BIT 5,A CB 6F
Test bit 5 of register A, the flag that requests an abort-to-DOS on error.
5476
RET Z C8
If bit 5 is zero (Z), RETurn normally to the caller.
5477
Otherwise JUMP to the resident @ABORT vector at 4030H to abort to DOS.

547AH - Command-Level and System-State Check

Verifies that the command was issued from the LDOS command level and not from within another running program or a background task, refusing the operation and displaying the Can't message otherwise.

547A
LD A,(430FH) 3A 0F 43
Load register A from the resident system flag byte at 430FH to check the current execution context.
547D
BIT 5,A CB 6F
Test bit 5 of register A, which indicates that a non-command-level (nested) execution context is active.
547F
LD A,(402DH) 3A 2D 40
Load register A from 402DH, the first byte of the resident @EXIT vector, used below to detect whether the normal return path is intact.
5482
If bit 5 was zero (Z, at command level), JUMP to 5487H to continue the check.
5484
LD A,(4065H) 3A 65 40
Otherwise load register A from 4065H (the saved register snapshot / A slot), reading the alternative context state.
5487
CP 0C3H FE C3
Compare register A against 0C3H (a Z80 JP opcode); this detects whether the sampled vector still holds a valid jump.
5489
If register A equals 0C3H (the vector is intact), JUMP to 5491H to reject the command as not allowed here.
548B
LD A,(4758H) 3A 58 47
Load register A from 4758H, the resident SYS1 status byte reflecting a busy/active condition.
548E
BIT 1,A CB 4F
Test bit 1 of register A, the flag marking an active operation that would forbid this command.
5490
RET Z C8
If bit 1 is zero (Z, clear to proceed), RETurn to the caller allowing the operation.
5491
LD HL,54B3H 21 B3 54
Point register pair HL at 54B3H, the Can't -- Only valid at LDOS command level message.
5494
LD IX,54DDH DD 21 DD 54
Overlapping Code
As assembled this is LD IX,54DDH (bytes DD 21 DD 54), loading register pair IX with the address of the Range error message so the caller-level rejection can show it. When control instead jumps to 5495H (skipping the DD prefix byte), the same bytes 21 DD 54 read as LD HL,54DDH, loading HL with the Range error message address for the out-of-range HIGH$ path.

Self-Modifying / Overlapping Code
This is the single deliberate overlap in the overlay: the byte at 5494H (DD) is an IX prefix on the fall-through path but is skipped when entered at 5495H, so the following three bytes serve as either LD IX,54DDH or LD HL,54DDH.

5498
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message addressed by HL.
549B
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the sentinel status meaning the command failed / no exit vector.
549E
JUMP back to 546BH to restore the caller's stack and return with the failure status.

54A0H - Parameter Error Handler

Entered when @PARAM rejected the command line. It raises the resident error service with the syntax-error code and returns to DOS.

54A0
LD A,2CH 3E 2C
Parameter error. Load register A with 2CH, the LDOS parameter/syntax error number.
54A2
OR 0C0H F6 C0
OR register A with 0C0H, setting the high option bits (message-only plus return-to-caller) expected by the resident @ERROR service.
54A4
GOSUB to the resident @ERROR service at 4409H to report the parameter error.
54A7
JUMP back to 549BH to exit with the failure status.

5200H - REMOVE Command: Entry and File Loop

Entry of the REMOVE command overlay. It saves the caller's stack pointer, polls the keyboard so a BREAK can interrupt a wildcard removal, and steps through the command line one file specification at a time, killing each matching file or device.

5200
LD (5220H),SP ED 73 20 52
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn instruction at 521FH so the overlay exit can restore the caller's stack. Register SP holds the LDOS command-level stack on entry.
5204
GOSUB to the keyboard-poll helper at 531FH so a pending pause or BREAK is honoured before starting.
5207
PUSH HL E5
Save register pair HL (the current command-line scan pointer) on the stack across the loop body.
5208
XOR A AF
Loop re-entry that forces a clean continue: set register A to zero (Z flag set) so the error test below is not taken. Reached from 52FFH after a file has been processed.

Main Loop
The removal loop re-enters here (from 52FFH) to process the next specification with a forced success status, and at 5209H (from 524CH/527BH) to carry a resident-service error into the error handler at 5341H.

5209
POP HL E1
Loop re-entry that preserves an error status: restore register pair HL from the stack. Reached from 524CH and 527BH with the NZ flag set when the resident service reported an error.
520A
If the NZ flag is set (a resident service reported an error), JUMP to the error handler at 5341H.
520D
GOSUB to the keyboard-poll helper at 531FH again to honour a pause or BREAK between files.
5210
If the poll returned NZ (BREAK was pressed), JUMP to 5346H to exit with a failure status.
5213
DEC HL 2B
DECrement HL to reposition before the space-skip scan.
5214
INC HL 23
INCrement HL to the next command-line character.
5215
LD A,(HL) 7E
Load register A with the command-line character at (HL).
5216
CP 20H FE 20
Compare register A against 20H (a space).
5218
If register A is a space (Z), LOOP BACK to 5214H to skip leading spaces.
521A
If register A is at or above a space (NC, a printable character begins the next spec), JUMP to 522EH to process it; otherwise fall through to the exit.

521CH - Overlay Exit and Caller Stack Restore

The common exit. It restores the caller's stack pointer saved at entry and returns to the LDOS command level, or aborts to DOS when the system flag requires it.

521C
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status returned to the caller.
521F
LD SP,0000H 31 00 00
Self-Modifying Code
Load register SP from the operand at 5220H, set at entry to the caller's stack pointer, restoring the caller's stack for the return.
5222
LD A,H 7C
Copy the high byte of the status (register H) into register A.
5223
OR L B5
OR register A with the low byte (register L); the Z flag is set when the status is zero (success).
5224
RET Z C8
If the Z flag is set (success), RETurn to the LDOS command level.
5225
LD A,(430FH) 3A 0F 43
On a non-success status, load register A from the resident system flag byte at 430FH.
5228
BIT 5,A CB 6F
Test bit 5 of register A, the flag that requests an abort-to-DOS on error.
522A
RET Z C8
If bit 5 is zero (Z), RETurn normally to the caller.
522B
Otherwise JUMP to the resident @ABORT vector at 4030H to abort to DOS.

522EH - Process One File Specification

Parses a single file or device specification with the resident @FSPEC service, builds the name for display, and removes it. A logical device (leading asterisk) is handled by the device path; a disk file is opened and then killed through the resident @KILL service, with the Deleting: name line shown for each file.

522E
LD DE,5380H 11 80 53
Point register pair DE at 5380H, the file control block work area that @FSPEC will fill from the specification.
5231
GOSUB to the resident @FSPEC service at 441CH to parse the file specification at (HL) into the FCB at (DE); it returns NZ on a malformed spec.
5234
If @FSPEC returned NZ (an invalid specification), JUMP to 534CH to report File spec required.
5237
PUSH HL E5
Save the command-line scan pointer (register pair HL) on the stack.
5238
PUSH DE D5
Save the FCB pointer (register pair DE) on the stack.
5239
EX DE,HL EB
Exchange DE and HL so register pair HL addresses the parsed FCB for the name copy.
523A
LD DE,5371H 11 71 53
Point register pair DE at 5371H, the buffer that receives the cleaned name for the Deleting: line.
523D
GOSUB to the name-copy helper at 530AH to copy the file name (skipping spaces and the drive colon) into the display buffer.
5240
LD A,0DH 3E 0D
Load register A with 0DH (a carriage return) to terminate the copied name.
5242
LD (DE),A 12
Store the carriage return (register A) at (DE), ending the display name.
5243
POP DE D1
Restore the FCB pointer from the stack into register pair DE.
5244
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (asterisk) marks a logical device specification.
5245
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
5247
If register A is an asterisk (Z), JUMP to 5286H to remove a logical device.
5249
GOSUB to the resident @OPEN service at 4424H to open the file named by the FCB; it returns NZ if the file cannot be opened.
524C
If @OPEN returned NZ (open failed / no such file), JUMP back to 5209H so the error status is carried into the error handler.
524E
LD A,(5381H) 3A 81 53
Load register A from 5381H, the FCB flag byte written by @OPEN, to check the file's access class.
5251
AND 07H E6 07
AND register A with 07H to isolate the low three access bits.
5253
CP 02H FE 02
Compare register A against 02H; an access level below the required protection permits removal.
5255
LD A,25H 3E 25
Load register A with 25H, the protection-violation error number, in case removal is refused.
5257
If the access level is at or above the protected threshold (NC), JUMP to the error handler at 5341H with error 25H.
525A
LD HL,5371H 21 71 53
Point register pair HL at 5371H, the copied display name, to append the drive indicator.
525D
LD A,(HL) 7E
Load register A with a name character at (HL).
525E
CP 0EH FE 0E
Compare register A against 0EH; a low value marks the end of the copied name.
5260
If register A is 0EH or greater (NC), JUMP to 5270H to continue scanning for the name terminator.
5262
LD (HL),3AH 36 3A
Store 3AH (an ASCII colon) at (HL), inserting the drive separator into the display name.
5264
INC HL 23
INCrement HL to the drive-digit position.
5265
LD A,(5386H) 3A 86 53
Load register A from 5386H, the FCB drive-number field.
5268
ADD A,30H C6 30
ADD 30H to register A to convert the drive number to its ASCII digit.
526A
LD (HL),A 77
Store the ASCII drive digit (register A) at (HL).
526B
INC HL 23
INCrement HL to the following position.
526C
LD (HL),0DH 36 0D
Store 0DH (a carriage return) at (HL), terminating the name with its drive suffix.
526E
JUMP to 5275H to display the line and kill the file.
5270
CP 3AH FE 3A
Compare the scanned character (register A) against 3AH (a colon); a colon means the name already carries a drive suffix.
5272
INC HL 23
INCrement HL to the next character.
5273
If register A was not a colon (NZ), LOOP BACK to 525DH to keep scanning the name.
5275
GOSUB to the display helper at 527DH to show the Deleting: name line.
5278
GOSUB to the resident @KILL service at 442CH to delete the opened file.
527B
JUMP back to 5209H to carry any error status forward and continue with the next specification.

527DH - Helper: Display the Deleting Line

Displays the Deleting: prefix followed by the name of the file being removed, preserving the caller's DE pointer.

527D
LD HL,5367H 21 67 53
Point register pair HL at 5367H, the Deleting: prefix text.
5280
PUSH DE D5
Save the caller's DE pointer on the stack.
5281
GOSUB to the resident @DSPLY service at 4467H to display the Deleting: name line.
5284
POP DE D1
Restore the caller's DE pointer from the stack.
5285
RET C9
RETurn to the caller.

5286H - Remove a Logical Device

Handles a specification that names a logical device rather than a disk file. It locates the matching device control block in the resident device chain, validates that it may be removed, and unlinks it.

5286
PUSH DE D5
Save the FCB pointer (register pair DE) on the stack.
5287
POP IX DD E1
Pop it into register pair IX so IX indexes the device-specification FCB.
5289
LD E,(IX+01H) DD 5E 01
Load register E with the byte at IX+01H, the low byte of the two-character device name.
528C
LD D,(IX+02H) DD 56 02
Load register D with the byte at IX+02H, the high byte of the device name, so register pair DE holds the requested device name.
528F
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the resident KIDCB$ device control block chain.
5292
PUSH HL E5
Save the current DCB pointer (register pair HL) on the stack while its name is compared.
5293
LD A,L 7D
Copy the low byte of the DCB address (register L) into register A to compute the name-field offset.
5294
ADD A,06H C6 06
ADD 06H to register A to index the device name inside the current control block.
5296
LD L,A 6F
Copy the result (register A) back into register L so HL addresses the DCB name field.
5297
LD A,(HL) 7E
Load register A with the first device-name character at (HL).
5298
INC L 2C
INCrement register L to the second name character.
5299
CP E BB
Compare register A against register E (the low byte of the requested name).
529A
If they differ (NZ), JUMP to 52A3H to advance to the next device control block.
529C
LD A,(HL) 7E
Load register A with the second device-name character at (HL).
529D
CP D BA
Compare register A against register D (the high byte of the requested name).
529E
If they differ (NZ), JUMP to 52A3H to advance to the next control block.
52A0
POP HL E1
The names match. Discard the saved DCB pointer from the stack into register pair HL.
52A1
JUMP to 52B6H to validate and remove the matched device.
52A3
POP AF F1
No match. Restore flags/discard the saved pointer by popping into AF.
52A4
INC L 2C
INCrement register L to step toward the next control block in the chain.
52A5
If the increment did not wrap the low byte to zero (NZ), JUMP to 52ACH to continue.
52A7
LD A,08H 3E 08
The chain end was reached without a match. Load register A with 08H, the device-not-found error number.
52A9
JUMP to the error handler at 5341H with error 08H.
52AC
LD A,L 7D
Copy the running DCB low address (register L) into register A to test for the end of the standard DCB block.
52AD
CP 2DH FE 2D
Compare register A against 2DH, the address at which the standard device blocks give way to the auxiliary chain.
52AF
If not at that boundary (NZ), JUMP back to 5292H to test the next control block.
52B1
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device control block chain (the JL/SI/SO devices), and continue the search there.
52B4
JUMP back to 5292H to search the auxiliary chain.
52B6
LD A,L 7D
Copy the matched DCB low address (register L) into register A for a range check.
52B7
CP 0C1H FE C1
Compare register A against 0C1H; addresses at or above this are outside the removable range.
52B9
If register A is 0C1H or greater (NC), JUMP to 52C0H to test the removability flag.
52BB
LD A,28H 3E 28
The device is a fixed system device. Load register A with 28H, the cannot-remove error number.
52BD
JUMP to the error handler at 5341H with error 28H.
52C0
BIT 3,(HL) CB 5E
Test bit 3 of the DCB flag byte at (HL); bit 3 marks a device that may be removed.
52C2
If bit 3 is set (NZ, removable), JUMP to 52C9H to unlink it.
52C4
LD A,27H 3E 27
The device is not removable. Load register A with 27H, the corresponding error number.
52C6
JUMP to the error handler at 5341H with error 27H.
52C9
GOSUB to the zero-field helper at 5302H to clear the device control block being removed.
52CC
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the KIDCB$ chain, to begin relinking around the removed device.
52CF
LD A,08H 3E 08
Load register A with 08H, the control-block stride used to walk the chain.
52D1
LD (52E9H),A 32 E9 52
Self-Modifying Code
Store the stride (register A) into the operand at 52E9H, setting the increment used by the chain-walk instruction below.
52D4
BIT 4,(HL) CB 66
Test bit 4 of the DCB flag byte at (HL); bit 4 marks a control block that carries a driver link to be cleared.
52D6
If bit 4 is clear (Z), JUMP to 52E7H to skip the driver-unlink step.
52D8
PUSH HL E5
Save the current DCB pointer (register pair HL) on the stack.
52D9
INC L 2C
INCrement register L to the DCB driver-address low byte.
52DA
LD A,(HL) 7E
Load register A with the driver-address low byte at (HL).
52DB
INC L 2C
INCrement register L to the driver-address high byte.
52DC
LD H,(HL) 66
Load register H with the driver-address high byte at (HL).
52DD
LD L,A 6F
Copy the low byte (register A) into register L so register pair HL now points at the linked driver block.
52DE
LD A,(HL) 7E
Load register A with the driver block's first byte at (HL) to test whether it is still in use.
52DF
POP HL E1
Restore the DCB pointer from the stack into register pair HL.
52E0
OR A B7
OR register A with itself to set the Z flag when the driver block is empty.
52E1
If the driver block is non-empty (NZ), JUMP to 52E7H leaving it intact.
52E3
LD (HL),08H 36 08
Store 08H at (HL), marking the control block slot free.
52E5
JUMP back to 52CCH to continue relinking the chain.
52E7
LD A,L 7D
Copy the DCB low address (register L) into register A to advance to the next block.
52E8
ADD A,08H C6 08
Self-Modifying Code
ADD the stride (operand at 52E9H, set to 08H above) to register A to index the next control block.
52EA
LD L,A 6F
Copy the result (register A) into register L so HL addresses the next control block.
52EB
If the address wrapped to zero (Z, end of the standard block), JUMP to 52F6H to finish.
52ED
CP 2DH FE 2D
Compare register A against 2DH, the boundary to the auxiliary chain.
52EF
If not at the boundary (NZ), JUMP back to 52D4H to process the next control block.
52F1
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device chain, to continue relinking there.
52F4
JUMP back to 52D4H to process the auxiliary chain.
52F6
PUSH IX DD E5
Restore the removed device's FCB pointer into register pair HL from IX for the final report.
52F8
POP HL E1
Pop IX into register pair HL so HL indexes the removed device block.
52F9
GOSUB to the zero-field helper at 5302H to finish clearing the removed device block.
52FC
GOSUB to the display helper at 527DH to show the Deleting: line for the removed device.
52FF
JUMP to 5208H to loop for the next specification with a clean continue status.

5302H - Helper: Zero an 8-Byte Field

Fills eight bytes at (HL) with zero, used to clear a device control block field before it is rebuilt.

5302
LD B,08H 06 08
Load register B with 08H, the number of bytes to clear.
5304
XOR A AF
Set register A to zero, the fill value.
5305
LD (HL),A 77
Store the zero byte (register A) at (HL).
5306
INC HL 23
INCrement HL to the next byte.
5307
DECrement register B and LOOP BACK to 5305H until 8 bytes have been cleared.
5309
RET C9
RETurn to the caller.

530AH - Helper: Copy a Name Skipping Spaces and the Drive Colon

Copies characters of a file specification into the display buffer, skipping embedded spaces and stopping the drive-suffix scan at the colon, so the reported name is clean.

530A
LD A,(HL) 7E
Load register A with the source character at (HL).
530B
CP 20H FE 20
Compare register A against 20H (a space); characters below a space end the name.
530D
RET C D8
If register A is below a space (C), RETurn to the caller (name complete).
530E
CP 2EH FE 2E
Compare register A against 2EH (a period), the extension separator.
5310
If register A is not a period (NZ), JUMP to 531BH to copy the character.
5312
INC HL 23
INCrement HL to scan past the extension for a drive colon.
5313
LD A,(HL) 7E
Load register A with the next character at (HL).
5314
CP 20H FE 20
Compare register A against 20H (a space).
5316
RET C D8
If register A is below a space (C), RETurn to the caller.
5317
CP 3AH FE 3A
Compare register A against 3AH (a colon), the drive separator.
5319
If register A is not a colon (NZ), LOOP BACK to 5312H to keep scanning.
531B
LDI ED A0
Copy one byte from (HL) to (DE) and increment both pointers (LDI), placing the character into the display buffer.
531D
JUMP back to 530AH to copy the next character.

531FH - Helper: Poll the Keyboard for Pause and BREAK

Polls the resident keyboard flag; when the pause key is active it waits, and it recognises BREAK so a long wildcard removal can be interrupted.

531F
PUSH HL E5
Save register pair HL on the stack while the keyboard flag is examined.
5320
LD HL,4423H 21 23 44
Point register pair HL at 4423H, the resident KFLAG$ keyboard status byte.
5323
BIT 0,(HL) CB 46
Test bit 0 of the KFLAG$ byte at (HL); bit 0 set indicates the pause/BREAK key is active.
5325
If bit 0 is clear (Z, no key held), JUMP to 533FH to return without pausing.
5327
PUSH AF F5
Save register AF on the stack before the pause loop.
5328
PUSH BC C5
Save register pair BC on the stack.
5329
PUSH DE D5
Save register pair DE on the stack.
532A
RES 0,(HL) CB 86
RESet bit 0 of the KFLAG$ byte at (HL), acknowledging the pause key.
532C
LD BC,0B00H 01 00 0B
Load register pair BC with 0B00H, the delay count for the pause.
532F
GOSUB to the ROM @PAUSE routine at 0060H to delay while the key is held.
5332
BIT 0,(HL) CB 46
Test bit 0 of the KFLAG$ byte at (HL) again to see whether the key is still active.
5334
If bit 0 is still set (NZ), LOOP BACK to 532AH to continue pausing.
5336
GOSUB to the ROM @KBD routine at 002BH to read the keyboard, draining any pending key.
5339
OR A B7
OR register A with itself to set the Z flag when no key is pending.
533A
If a key is still pending (NZ), LOOP BACK to 5336H to drain it.
533C
POP DE D1
Restore register pair DE from the stack.
533D
POP BC C1
Restore register pair BC from the stack.
533E
POP AF F1
Restore register AF from the stack.
533F
POP HL E1
Restore register pair HL from the stack.
5340
RET C9
RETurn to the caller.

5341H - Error Handler

Raises the resident @ERROR service with the error code in register A and exits with a failure status.

5341
OR 0C0H F6 C0
Error handler. OR register A (the error number) with 0C0H, setting the message-only and return-to-caller option bits expected by the resident @ERROR service.
5343
GOSUB to the resident @ERROR service at 4409H to report the error.
5346
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the failure status.
5349
JUMP to the exit at 521FH to restore the caller's stack and return the failure status.

534CH - File Spec Required Message

Displays the File spec required message when the command was entered with no file specification, then exits with a failure status.

534C
LD HL,5354H 21 54 53
Point register pair HL at 5354H, the File spec required message.
534F
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message.
5352
JUMP to 5346H to exit with a failure status.

5354H - REMOVE Data: Messages

The two message strings used by the REMOVE command: the missing-specification error and the per-file Deleting: prefix.

5354-5365
DEFM "File spec required" 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64
Message
The File spec required text, carriage-return terminated (0DH), displayed by 534FH when no specification was given.
5366
DEFB 0DH 0D
Continuation of the block described above.
5367-5370
DEFM "Deleting: " 44 65 6C 65 74 69 6E 67 3A 20
Message Prefix
The Deleting: prefix (with trailing space), displayed at 5281H ahead of each file or device name as it is removed.

5200H - LIB Command: Entry Vectors

Entry of the LIB command overlay. The first two words are jump vectors: the loader enters at 5200H and jumps to the directory display at 5222H. The short routine that follows homes and clears the screen (and optionally routes output) and returns the success status.

5200
Entry point. JUMP to the directory-display routine at 5222H (the loader always enters the overlay here).
5203
Secondary entry vector: JUMP to 5214H, the screen home-and-clear routine, used when only the display needs to be reset.
5206
LD DE,4025H 11 25 40
Point register pair DE at 4025H, the resident printer device control block PRDCB$, in case output is to be echoed.
5209
XOR A AF
Set register A to zero and clear the flags before issuing the control call.
520A
GOSUB to the ROM @CTL routine at 0023H to send the control byte in register A to the device addressed by DE.
520D
LD A,0CH 3E 0C
Load register A with 0CH, a form-feed/clear control code.
520F
If the previous control call reported ready (Z flag set), GOSUB to the ROM @PRT routine at 003BH to send the clear code to the printer.
5212
JUMP to 521EH to finish with the success status.
5214
LD A,1CH 3E 1C
Load register A with 1CH, the video home-cursor control code.
5216
GOSUB to the ROM @DSP routine at 0033H to home the cursor on the video display.
5219
LD A,1FH 3E 1F
Load register A with 1FH, the clear-to-end-of-frame control code.
521B
GOSUB to the ROM @DSP routine at 0033H to clear the screen.
521E
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status returned to the caller.
5221
RET C9
RETurn to the caller with a zero (success) status.

5222H - Display the Library A and Library B Command Directories

Prints the Library heading and lists the resident command-name table at 4EBDH in four columns. The table holds every transient command word; bit 6 of each entry's flag byte selects the library, so this routine lists the Library A names first, then relabels the heading to <B> and lists the Library B names.

5222
LD HL,52C7H 21 C7 52
Point register pair HL at 52C7H, the Library <A> heading text.
5225
GOSUB to the resident @DSPLY service at 4467H to display the Library heading line.
5228
LD HL,4EBDH 21 BD 4E
Point register pair HL at 4EBDH, the resident Library command-name table held by the SYS1 command interpreter (at 4EBDH).
522B
LD C,04H 0E 04
Load register C with 04H, the count of display columns for the command grid.
522D
LD B,02H 06 02
Load register B with 02H, the number of leading spaces before the first column.
522F
GOSUB to the space helper at 52BFH to emit the leading indent.
5232
LD B,05H 06 05
Load register B with 05H, the character width of one command name for the print loop.
5234
LD A,(HL) 7E
Load register A with the first byte of the current table entry at (HL); a zero byte marks the end of the entries in this row/table.
5235
OR A B7
OR register A with itself to set the Z flag when the entry byte is zero (end of table).
5236
If the Z flag is set (no more entries), JUMP to 5269H to finish the Library A pass.
5238
PUSH HL E5
Save the entry pointer (register pair HL) on the stack while the flag byte is inspected.
5239
LD DE,0007H 11 07 00
Load register pair DE with 0007H, the offset from the name to the entry's flag byte.
523C
ADD HL,DE 19
ADD DE to HL so HL addresses the flag byte at entry+7.
523D
BIT 6,(HL) CB 76
Test bit 6 of the flag byte at (HL); bit 6 set marks a Library B command, which is skipped on this Library A pass.
523F
If bit 6 is clear (Z, a Library A command), JUMP to 5245H to print this name.
5241
POP AF F1
Bit 6 was set (a Library B entry). Discard the saved pointer by popping it into AF.
5242
INC HL 23
INCrement HL to step to the next table entry.
5243
JUMP back to 5232H to examine the next entry.
5245
POP HL E1
Restore the entry pointer from the stack into register pair HL to print the Library A command name.
5246
LD A,(HL) 7E
Load register A with the first name character at (HL).
5247
GOSUB to the ROM @DSP routine at 0033H to display the character.
524A
INC HL 23
INCrement HL to the next name character.
524B
LD A,(HL) 7E
Load register A with the next name character at (HL).
524C
CP 20H FE 20
Compare register A against 20H (a space); a space is printed as-is, otherwise the case bit is normalised below.
524E
If register A is a space (Z), JUMP to 5252H to print it unchanged.
5250
XOR 20H EE 20
Exclusive-OR register A with 20H to toggle the letter case of the character before display (the table stores names with the case bit inverted).
5252
INC HL 23
INCrement HL to the following name character.
5253
GOSUB to the ROM @DSP routine at 0033H to display the character.
5256
DECrement register B and LOOP BACK to 524BH until all characters of the name after the first have been shown.
5258
LD B,08H 06 08
Load register B with 08H, the gap width to pad between command columns.
525A
GOSUB to the space helper at 52BFH to write the inter-column spacing.
525D
INC HL 23
INCrement HL to skip the flag byte area.
525E
INC HL 23
INCrement HL again to reach the next table entry.
525F
DEC C 0D
DECrement register C, counting down one filled column.
5260
If the column count did not reach zero (NZ), JUMP back to 5232H to print the next command name on the same row.
5262
LD A,0DH 3E 0D
A full row of columns was printed. Load register A with 0DH (a carriage return) to end the line.
5264
GOSUB to the ROM @DSP routine at 0033H to output the carriage return.
5267
JUMP back to 522BH to begin the next row of command names.
5269
LD A,0DH 3E 0D
End of the Library A pass. Load register A with 0DH (a carriage return) to close the listing.
526B
GOSUB to the ROM @DSP routine at 0033H to output the carriage return.
526E
LD HL,52D0H 21 D0 52
Point register pair HL at 52D0H, the letter in the Library <A> heading text.
5271
LD (HL),42H 36 42
Self-Modifying Code
Store 42H (ASCII B) at (HL)=52D0H, changing the heading from Library <A> to Library <B> for the second pass.
5273
LD HL,52C7H 21 C7 52
Point register pair HL at 52C7H, the (now relabelled) Library <B> heading text.

Library Selector
Both passes read the same resident table at 4EBDH; bit 6 of each entry's flag byte (entry+7) chooses the library, so the Library A pass prints the bit-6-clear entries and the Library B pass prints the bit-6-set entries.

5276
GOSUB to the resident @DSPLY service at 4467H to display the Library <B> heading.
5279
LD HL,4EBDH 21 BD 4E
Point register pair HL at 4EBDH, the resident command-name table, to list the Library B entries.
527C
LD C,04H 0E 04
Load register C with 04H, the display-column count.
527E
LD B,02H 06 02
Load register B with 02H, the leading indent width.
5280
GOSUB to the space helper at 52BFH to emit the leading indent.
5283
LD B,05H 06 05
Load register B with 05H, the character width of one command name.
5285
LD A,(HL) 7E
Load register A with the first byte of the current entry at (HL); zero marks the end.
5286
OR A B7
OR register A with itself to set the Z flag on a zero entry byte.
5287
If the Z flag is set (end of table), JUMP to 52BAH to finish the Library B pass.
5289
PUSH HL E5
Save the entry pointer (register pair HL) on the stack.
528A
LD DE,0007H 11 07 00
Load register pair DE with 0007H, the offset to the entry's flag byte.
528D
ADD HL,DE 19
ADD DE to HL so HL addresses the flag byte at entry+7.
528E
BIT 6,(HL) CB 76
Test bit 6 of the flag byte at (HL); bit 6 set marks a Library B command, which is what this pass prints.
5290
If bit 6 is set (NZ, a Library B command), JUMP to 5296H to print this name.
5292
POP AF F1
Bit 6 was clear (a Library A entry). Discard the saved pointer by popping it into AF.
5293
INC HL 23
INCrement HL to the next table entry.
5294
JUMP back to 5283H to examine the next entry.
5296
POP HL E1
Restore the entry pointer from the stack into register pair HL to print the Library B command name.
5297
LD A,(HL) 7E
Load register A with the first name character at (HL).
5298
GOSUB to the ROM @DSP routine at 0033H to display the character.
529B
INC HL 23
INCrement HL to the next name character.
529C
LD A,(HL) 7E
Load register A with the next name character at (HL).
529D
CP 20H FE 20
Compare register A against 20H (a space).
529F
If register A is a space (Z), JUMP to 52A3H to print it unchanged.
52A1
XOR 20H EE 20
Exclusive-OR register A with 20H to normalise the letter case before display.
52A3
INC HL 23
INCrement HL to the following name character.
52A4
GOSUB to the ROM @DSP routine at 0033H to display the character.
52A7
DECrement register B and LOOP BACK to 529CH until the whole name is displayed.
52A9
LD B,08H 06 08
Load register B with 08H, the inter-column gap width.
52AB
GOSUB to the space helper at 52BFH to write the inter-column spacing.
52AE
INC HL 23
INCrement HL past the flag byte.
52AF
INC HL 23
INCrement HL again to reach the next table entry.
52B0
DEC C 0D
DECrement register C, counting down one column.
52B1
If the column count did not reach zero (NZ), JUMP back to 5283H for the next name on the row.
52B3
LD A,0DH 3E 0D
Load register A with 0DH (a carriage return) to end the row.
52B5
GOSUB to the ROM @DSP routine at 0033H to output the carriage return.
52B8
JUMP back to 527CH to begin the next row of Library B names.
52BA
LD A,0DH 3E 0D
End of both passes. Load register A with 0DH (a carriage return) for a final blank line.
52BC
JUMP to 521BH to clear/finish through the common exit that returns the success status.

52BFH - Helper: Emit a Run of Spaces

Small utility that writes register B spaces to the display through the ROM character output, used to indent and align the command-name columns.

52BF
LD A,20H 3E 20
Load register A with 20H (an ASCII space) to be written to the display.
52C1
GOSUB to the ROM @DSP routine at 0033H to output one space.
52C4
DECrement register B and LOOP BACK to 52BFH until B spaces have been written.
52C6
RET C9
RETurn to the caller.

5200H - LINK Command: Entry, Command-Level Check and Device-Spec Parse

Entry of the LINK command overlay, which links two character devices so that output to the first is also passed to the second. It saves the caller's stack, confirms the command was issued at the LDOS command level, and parses the two device specifications (each must name a device, introduced by the asterisk character 2AH) with the resident @FSPEC service.

5200
LD (52B9H),SP ED 73 B9 52
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn instruction at 52B8H so the overlay exit can restore the caller's stack. Register SP holds the LDOS command-level stack on entry.
5204
LD A,(430FH) 3A 0F 43
Load register A from the resident system flag byte at 430FH to check the execution context.
5207
BIT 5,A CB 6F
Test bit 5 of register A, which is set when execution is not at the LDOS command level.
5209
LD A,(402DH) 3A 2D 40
Load register A from 402DH, the first byte of the resident @EXIT vector, used to detect whether the normal return path is intact.
520C
If bit 5 was clear (Z, at command level), JUMP to 5211H to continue the check.
520E
LD A,(4065H) 3A 65 40
Otherwise load register A from 4065H, the saved register-snapshot A slot, for the nested-context test.
5211
CP 0C3H FE C3
Compare register A against 0C3H (a Z80 JP opcode) to test whether the sampled vector still holds a valid jump.
5213
If register A equals 0C3H (a nested context is active), JUMP to 5335H to refuse the command with the command-level message.
5216
LD A,(4758H) 3A 58 47
Load register A from 4758H, the resident SYS1 status byte, to test for a busy condition.
5219
BIT 1,A CB 4F
Test bit 1 of register A, the flag marking an active operation that forbids this command.
521B
If bit 1 is set (NZ, busy), JUMP to 5335H to refuse the command.
521E
LD DE,53A2H 11 A2 53
Point register pair DE at 53A2H, the FCB work area for the first device specification.
5221
GOSUB to the resident @FSPEC service at 441CH to parse the first device specification at (HL) into (DE); it returns NZ on a malformed spec.
5224
If @FSPEC returned NZ (invalid), JUMP to 5331H to report Device spec required.
5227
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (the asterisk character) confirms a device specification.
5228
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
522A
If register A is not an asterisk (NZ, not a device), JUMP to 5331H to report Device spec required.
522D
LD DE,53C2H 11 C2 53
Point register pair DE at 53C2H, the FCB work area for the second device specification.
5230
GOSUB to the resident @FSPEC service at 441CH to parse the second device specification into (DE).
5233
If @FSPEC returned NZ (invalid), JUMP to 5331H to report Device spec required.
5236
LD A,(DE) 1A
Load register A with the first FCB byte at (DE) to confirm a device.
5237
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
5239
If register A is not an asterisk (NZ), JUMP to 5331H to report Device spec required.
523C
LD DE,(53A3H) ED 5B A3 53
Load register pair DE from 53A3H, the two-character name of the first device.
5240
LD (52CEH),DE ED 53 CE 52
Self-Modifying Code
Store the first device name (register pair DE) into the operand at 52CEH, the name field inside the link-driver stub template.
5244
LD (539DH),DE ED 53 9D 53
Self-Modifying Code
Store the first device name (register pair DE) into the operand at 539DH, the LKxxxx module-name template.
5248
GOSUB to the find-device helper at 52F0H to locate the first device's control block; it returns HL pointing at the block or a not-found error.
524B
If the device was not found (NZ), JUMP to the error handler at 5326H.

524EH - Validate the Devices and Build the Link Driver

Locates both device control blocks, refuses a device that is already routed, captures the first device's existing driver vector, allocates space (reserving high memory when needed) and copies the relocatable link-driver stub into it, patching the new driver in front of the first device.

524E
BIT 4,(HL) CB 66
Test bit 4 of the first device's control-block flag byte at (HL); bit 4 marks a device that is already routed and cannot be linked.
5250
If bit 4 is set (NZ, already routed), JUMP to 532DH to display Can't Link a Routed Device.
5253
PUSH HL E5
Save the first device's control-block pointer (register pair HL) on the stack.
5254
LD DE,(53C3H) ED 5B C3 53
Load register pair DE from 53C3H, the two-character name of the second device.
5258
LD (52D0H),DE ED 53 D0 52
Self-Modifying Code
Store the second device name (register pair DE) into the operand at 52D0H, the second name field inside the link-driver stub template.
525C
LD (539FH),DE ED 53 9F 53
Self-Modifying Code
Store the second device name (register pair DE) into the operand at 539FH, the LKxxxx module-name template.
5260
GOSUB to the find-device helper at 52F0H to locate the second device's control block.
5263
If the second device was not found (NZ), JUMP to the error handler at 5326H.
5266
LD (52DEH),HL 22 DE 52
Self-Modifying Code
Store the second device's control-block pointer (register pair HL) into the operand at 52DEH inside the stub's output path.
5269
LD (52EBH),HL 22 EB 52
Self-Modifying Code
Store the second device's control-block pointer (register pair HL) into the operand at 52EBH inside the stub's input path.
526C
POP HL E1
Restore the first device's control-block pointer from the stack into register pair HL.
526D
LD A,L 7D
Copy the first control block's low address (register L) into register A to test for the keyboard control block.
526E
CP 15H FE 15
Compare register A against 15H, the low address of the resident keyboard control block.
5270
INC HL 23
INCrement HL to the control block's driver-vector field.
5271
If the block was not the keyboard block (NZ), JUMP to 527DH to capture its driver vector.
5273
LD A,(430FH) 3A 0F 43
Load register A from the resident system flag byte at 430FH.
5276
BIT 5,A CB 6F
Test bit 5 of register A (nested-context flag).
5278
If bit 5 is clear (Z, at command level), JUMP to 527DH to proceed.
527A
LD HL,43BEH 21 BE 43
Otherwise point register pair HL at 43BEH, the KIJCL$ keyboard-JCL control block, so a linked keyboard chains through the JCL device.
527D
PUSH HL E5
Save the control-block pointer (register pair HL) on the stack.
527E
LD A,(HL) 7E
Load register A with the driver-vector low byte at (HL).
527F
INC HL 23
INCrement HL to the driver-vector high byte.
5280
LD H,(HL) 66
Load register H with the driver-vector high byte at (HL).
5281
LD L,A 6F
Copy the low byte (register A) into register L so register pair HL now holds the first device's current driver address.
5282
LD (52D7H),HL 22 D7 52
Self-Modifying Code
Store the first device's driver address (register pair HL) into the operand at 52D7H, the output-path call inside the stub.
5285
LD (52E6H),HL 22 E6 52
Self-Modifying Code
Store the first device's driver address (register pair HL) into the operand at 52E6H, the input-path call inside the stub.
5288
LD DE,539BH 11 9B 53
Point register pair DE at 539BH, the LKxxxx module-name template, to register the new module.
528B
GOSUB to the link-module helper at 5316H to obtain the module control block; it returns NZ if no resident slot is available.
528E
If no module slot was returned (NZ), JUMP to 5299H to reserve high memory instead.
5290
LD (52C9H),DE ED 53 C9 52
Self-Modifying Code
Store the returned module address (register pair DE) into the operand at 52C9H, the stub's module link field.
5294
LD BC,0029H 01 29 00
Load register pair BC with 0029H (41), the length of the link-driver stub to be copied.
5297
JUMP to 52A9H to copy the stub into the module area.
5299
LD HL,(4049H) 2A 49 40
No resident slot: load register pair HL from the resident HIGH$ word at 4049H.
529C
LD (52C9H),HL 22 C9 52
Self-Modifying Code
Store the current HIGH$ (register pair HL) into the operand at 52C9H as the stub's link field.
529F
LD BC,0029H 01 29 00
Load register pair BC with 0029H (41), the size to reserve for the stub.
52A2
XOR A AF
Set register A to zero and clear the carry flag before subtracting.
52A3
SBC HL,BC ED 42
Subtract BC (41) from HL (HIGH$), lowering the ceiling to make room for the stub.
52A5
LD (4049H),HL 22 49 40
Store the new ceiling (register pair HL) into the resident HIGH$ word at 4049H, reserving the space.
52A8
INC HL 23
INCrement HL to the first byte of the reserved area.
52A9
PUSH HL E5
Save the destination address (register pair HL) on the stack.
52AA
EX DE,HL EB
Exchange DE and HL so register pair DE addresses the destination for the stub copy.
52AB
LD HL,52C7H 21 C7 52
Point register pair HL at 52C7H, the link-driver stub template.
52AE
LDIR ED B0
Block-move BC (41) bytes from (HL)=52C7H to (DE), placing the patched link-driver stub into the module area.
52B0
POP DE D1
Restore the destination (module) address from the stack into register pair DE.
52B1
POP HL E1
Restore the first device's control-block pointer from the stack into register pair HL.
52B2
LD (HL),E 73
Store the low byte of the new driver address (register E) into the device's driver vector at (HL), pointing the device at the link stub.
52B3
INC HL 23
INCrement HL to the driver-vector high byte.
52B4
LD (HL),D 72
Store the high byte of the new driver address (register D) into the device's driver vector, completing the link.

52B5H - Overlay Exit and Caller Stack Restore

Restores the caller's stack pointer saved at entry and returns to the LDOS command level, or aborts to DOS when the system flag requires it.

52B5
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status returned to the caller.
52B8
LD SP,0000H 31 00 00
Self-Modifying Code
Load register SP from the operand at 52B9H, set at entry to the caller's stack pointer, restoring the caller's stack for the return.
52BB
LD A,H 7C
Copy the high byte of the status (register H) into register A.
52BC
OR L B5
OR register A with the low byte (register L); the Z flag is set when the status is zero (success).
52BD
RET Z C8
If the Z flag is set (success), RETurn to the LDOS command level.
52BE
LD A,(430FH) 3A 0F 43
On a non-success status, load register A from the resident system flag byte at 430FH.
52C1
BIT 5,A CB 6F
Test bit 5 of register A, the abort-to-DOS request flag.
52C3
RET Z C8
If bit 5 is zero (Z), RETurn normally to the caller.
52C4
Otherwise JUMP to the resident @ABORT vector at 4030H to abort to DOS.

52C7H - LINK Data: Relocatable Link-Driver Stub Template

The 41-byte link-driver stub copied into the allocated area by the block move at 52AEH. It is a small character driver: on an output call it passes the byte to the first device's original driver and then to the second (linked) device; the operands shown as 0000H are self-modified before the copy with the two device driver addresses and control blocks.

52C7-52C8
DEFB 18H,09H 18 09
Module Header
JR +9 (18 09) that skips the module header when the relocated stub is entered.
52C9-52CA
DEFB 00H,00H 00 00
Module Link Field
Two bytes forming the forward link in the resident module chain.
52CB
DEFB 06H 06
Module Name
The link module name: a length byte (06H) and the text LK followed by the two-character device name field at 52CEH-52CFH, which is self-modified from the first device name by the store at 5240H (and 52D0H-52D1H by 5258H).
52CC-52D1
DEFM "LKxxxx" 4C 4B 78 78 78 78
Continuation of the block described above.
52D2
DEFM "8" 38
Output Path
The stub's output routine. It saves registers, calls the first device's original driver at the operand patched into 52D7H (by 5282H), then prepares the second device's control block at the operand patched into 52DEH (by 5266H).
52D3-52DF
DEFB 11H,F5H,C5H,CDH,00H,00H,C1H,F5H,E1H,E3H,11H,00H,00H 11 F5 C5 CD 00 00 C1 F5 E1 E3 11 00 00
Continuation of the block described above.
52E0-52E4
DEFB CDH,1BH,00H,F1H,C9H CD 1B 00 F1 C9
Second-Device Output
Calls the ROM @PUT routine (001BH) to send the byte to the linked second device, then returns.
52E5-52EF
DEFB CDH,00H,00H,B7H,C0H,11H,00H,00H,C3H,13H,00H CD 00 00 B7 C0 11 00 00 C3 13 00
Input/Control Path
Calls the first device's driver at the operand patched into 52E6H (by 5285H); on a non-zero result it prepares the second device's control block (operand at 52EBH, patched by 5269H) and jumps to the ROM @GET routine (0013H).

52F0H - Helper: Find a Device Control Block by Name

Searches the resident device control block chains (the KIDCB$ block at 4015H and the auxiliary chain at 43C0H) for a control block whose two-character name matches register pair DE, returning its address in HL or the device-not-found error.

52F0
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the resident KIDCB$ device control block chain.
52F3
PUSH HL E5
Save the current control-block pointer (register pair HL) on the stack.
52F4
LD A,L 7D
Copy the block's low address (register L) into register A to compute the name-field offset.
52F5
ADD A,06H C6 06
ADD 06H to register A to index the device name inside the current control block.
52F7
LD L,A 6F
Copy the result (register A) into register L so HL addresses the name field.
52F8
LD A,(HL) 7E
Load register A with the first device-name character at (HL).
52F9
INC L 2C
INCrement register L to the second name character.
52FA
CP E BB
Compare register A against register E (the low byte of the requested name).
52FB
If they differ (NZ), JUMP to 5304H to advance to the next control block.
52FD
LD A,(HL) 7E
Load register A with the second device-name character at (HL).
52FE
CP D BA
Compare register A against register D (the high byte of the requested name).
52FF
If they differ (NZ), JUMP to 5304H to advance to the next control block.
5301
POP HL E1
The names match. Discard the saved pointer into register pair HL (which addresses the matched name field's block).
5302
XOR A AF
Set register A to zero, the found status (Z flag set).
5303
RET C9
RETurn to the caller with the matched control block.
5304
POP AF F1
No match. Restore/discard the saved pointer by popping into AF.
5305
INC L 2C
INCrement register L to step toward the next control block in the chain.
5306
If the increment did not wrap the low byte to zero (NZ), JUMP to 530CH to continue.
5308
LD A,08H 3E 08
The standard chain end was reached. Load register A with 08H, the device-not-found error number.
530A
OR A B7
OR register A with itself to set the NZ flag for the not-found result.
530B
RET C9
RETurn to the caller with the not-found status.
530C
LD A,L 7D
Copy the running block low address (register L) into register A to test the chain boundary.
530D
CP 2DH FE 2D
Compare register A against 2DH, the boundary between the standard and auxiliary control-block chains.
530F
If not at the boundary (NZ), JUMP back to 52F3H to test the next control block.
5311
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device control block chain, and continue the search there.
5314
JUMP back to 52F3H to search the auxiliary chain.

5316H - Helper: Obtain the Link-Module Control Block

Issues a resident supervisor call to obtain the control block for the new link module and returns the pointer taken from its +02/+03 field.

5316
GOSUB to 5323H to issue the resident supervisor call that returns the link-module control block.
5319
PUSH HL E5
Save the returned pointer (register pair HL) on the stack.
531A
POP IX DD E1
Pop it into register pair IX so IX indexes the returned control block.
531C
LD E,(IX+02H) DD 5E 02
Load register E with the byte at IX+02H, the low byte of the module's data pointer.
531F
LD D,(IX+03H) DD 56 03
Load register D with the byte at IX+03H, the high byte of the module's data pointer, so register pair DE holds the module pointer.
5322
RET C9
RETurn to the caller with the module pointer.
5323
LD A,0BCH 3E BC
Load register A with 0BCH, the resident supervisor request code for the link-module service.
5325
RST 28 EF
Execute RST 28H to invoke the resident supervisor service selected by register A (request code 0BCH).

5326H - Error Handler and Message Dispatch

Reports a numeric error through @ERROR, and provides the three refusal messages (routed device, device spec required, command-level only). The three message entries share overlapping bytes so that one of three addresses is loaded into HL depending on the entry point.

5326
OR 0C0H F6 C0
Error handler. OR register A (the error number) with 0C0H, setting the message-only and return-to-caller option bits expected by the resident @ERROR service.
5328
GOSUB to the resident @ERROR service at 4409H to report the error.
532B
JUMP to 533BH to exit with a failure status.
532D
LD HL,5341H 21 41 53
Routed-device path. Point register pair HL at 5341H, the Can't Link a Routed Device message.
5330
LD IX,535CH DD 21 5C 53
Overlapping Code
As assembled this is LD IX,535CH (bytes DD 21 5C 53). When control jumps to 5331H (skipping the DD prefix byte), the bytes 21 5C 53 read as LD HL,535CH, loading the Device spec required message address for that entry.
5334
LD IX,5371H DD 21 71 53
Overlapping Code
As assembled this is LD IX,5371H (bytes DD 21 71 53). When control jumps to 5335H (skipping the DD prefix byte), the bytes 21 71 53 read as LD HL,5371H, loading the Can't -- Only valid at LDOS command level message address for that entry.
5338
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message addressed by HL.
533B
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the failure status.
533E
JUMP to the exit at 52B8H to restore the caller's stack and return the failure status.

5341H - LINK Data: Messages and Module Name Template

The refusal messages and the link-module display-name template.

5341-535A
DEFM "Can't Link a Routed Device" 43 61 6E 27 74 20 4C 69 6E 6B 20 61 20 52 6F 75 74 65 64 20 44 65 76 69 63 65
Message
The Can't Link a Routed Device text, carriage-return terminated, addressed at 5341H by the entry at 532DH.
535B
DEFB 0DH 0D
Continuation of the block described above.
535C-536F
DEFM "Device spec required" 44 65 76 69 63 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64
Message
The Device spec required text, carriage-return terminated, addressed at 535CH by the overlapping entry at 5331H.
5370
DEFB 0DH 0D
Continuation of the block described above.
5371-5399
DEFM "Can't -- Only valid at LDOS command level" 43 61 6E 27 74 20 2D 2D 20 4F 6E 6C 79 20 76 61 6C 69 64 20 61 74 20 4C 44 4F 53 20 63 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C
Message
The Can't -- Only valid at LDOS command level text, carriage-return terminated, addressed at 5371H by the overlapping entry at 5335H.
539A
DEFB 0DH 0D
Continuation of the block described above.
539B-53A0
DEFM "LKxxxx" 4C 4B 78 78 78 78
Module Name Template
The LKxxxx display-name template (LK plus a four-character field) and its 00H terminator, used to name the installed link module.
53A1
DEFB 00H 00
Continuation of the block described above.