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 - Overlay 1

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.

54A9H - MEMORY Data: Reserved-Block Module-Header Template

The 10-byte resident-module header that the ADD keyword copies to the top of memory to mark the block it has just reserved. Its link and name fields are patched in code before the copy.

54A9-54AA
DEFB 18H,08H 18 08
Reserved-block module header template (54A9H-54B2H, 10 bytes)
Copied into high memory by the ADD routine at 52C5H (LDIR of 000AH bytes). These two bytes are a JR +8 relative jump: when the reserved &-block is later entered as a resident high-memory module, this jump skips the 8-byte module header to the block body.
54AB-54AC
DEFB 00H,00H 00 00
Module chain link field. Left as 00H,00H in the template and patched at 52AAH (LD (54ABH),HL) with the previous HIGH$ value so the reserved block links into the resident high-memory module chain.
54AD
DEFB 05H 05
Module name length byte: the name that follows is 5 characters long.
54AE
DEFM "&" 26
First character of the reserved-block module name (an ampersand), the tag LDOS uses for a MEMORY-reserved high block.
54AF-54B2
DEFM "nnnn" 6E 6E 6E 6E
Four-character name field. Overwritten at 52B9H (via the binary-to-hex helper at 4D76H) with the reserved byte count in hex, giving the block the display name &XXXX.

54B3H - MEMORY Data: Error Messages

The two error strings displayed by the MEMORY overlay: the command-level restriction and the range-error report. Both are carriage-return terminated.

54B3-54DB
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. Its address is loaded into HL at 5491H and displayed by the resident @LOGOT service at 447BH (called at 5498H) when MEMORY is invoked from anywhere other than the LDOS command line.
54DC
DEFB 0DH 0D
Carriage return (0DH) terminating the message above.
54DD-54E7
DEFM "Range error" 52 61 6E 67 65 20 65 72 72 6F 72
Message
The Range error text. Its address is loaded into IX at 5494H as the companion message for the same command-level/range error report driven from 5491H-5498H.
54E8
DEFB 0DH 0D
Carriage return (0DH) terminating the message above.

54E9H - MEMORY Data: @PARAM Keyword Descriptor Table

The parameter table handed to the resident @PARAM service at 5204H. Each 8-byte entry is a 6-character keyword name followed by the two-byte address of the instruction operand that @PARAM overwrites when that keyword appears. Every keyword is listed twice: spelled in full and as its one-letter abbreviation.

54E9-54EE
DEFM "HIGH " 48 49 47 48 20 20
@PARAM parameter descriptor table (54E9H-5558H)
Address passed to the resident @PARAM parser in DE at 5204H. @PARAM scans the command tail; when it matches a keyword it writes the supplied value into the two-byte operand cell named by that entry, self-modifying the instruction that later tests the keyword. This entry is the full keyword HIGH, whose value cell is the LD operand at 5295H.
54EF-54F0
DEFW 5295H 95 52
Pointer for the HIGH entry: the address (5295H) of the two-byte operand cell @PARAM patches when this keyword is present.
54F1-54F6
DEFM "H " 48 20 20 20 20 20
Single-letter abbreviation H for the HIGH keyword; same value cell at 5295H as the full form above.
54F7-54F8
DEFW 5295H 95 52
Pointer for the H entry: the address (5295H) of the two-byte operand cell @PARAM patches when this keyword is present.
54F9-54FE
DEFM "ADD " 41 44 44 20 20 20
Full keyword ADD; @PARAM writes its value into the operand cell at 523CH.
54FF-5500
DEFW 523CH 3C 52
Pointer for the ADD entry: the address (523CH) of the two-byte operand cell @PARAM patches when this keyword is present.
5501-5506
DEFM "A " 41 20 20 20 20 20
Single-letter abbreviation A for the ADD keyword; same value cell at 523CH as the full form above.
5507-5508
DEFW 523CH 3C 52
Pointer for the A entry: the address (523CH) of the two-byte operand cell @PARAM patches when this keyword is present.
5509-550E
DEFM "WORD " 57 4F 52 44 20 20
Full keyword WORD; @PARAM writes its value into the operand cell at 525FH.
550F-5510
DEFW 525FH 5F 52
Pointer for the WORD entry: the address (525FH) of the two-byte operand cell @PARAM patches when this keyword is present.
5511-5516
DEFM "W " 57 20 20 20 20 20
Single-letter abbreviation W for the WORD keyword; same value cell at 525FH as the full form above.
5517-5518
DEFW 525FH 5F 52
Pointer for the W entry: the address (525FH) of the two-byte operand cell @PARAM patches when this keyword is present.
5519-551E
DEFM "BYTE " 42 59 54 45 20 20
Full keyword BYTE; @PARAM writes its value into the operand cell at 5266H.
551F-5520
DEFW 5266H 66 52
Pointer for the BYTE entry: the address (5266H) of the two-byte operand cell @PARAM patches when this keyword is present.
5521-5526
DEFM "B " 42 20 20 20 20 20
Single-letter abbreviation B for the BYTE keyword; same value cell at 5266H as the full form above.
5527-5528
DEFW 5266H 66 52
Pointer for the B entry: the address (5266H) of the two-byte operand cell @PARAM patches when this keyword is present.
5529-552E
DEFM "GO " 47 4F 20 20 20 20
Full keyword GO; @PARAM writes its value into the operand cell at 5460H.
552F-5530
DEFW 5460H 60 54
Pointer for the GO entry: the address (5460H) of the two-byte operand cell @PARAM patches when this keyword is present.
5531-5536
DEFM "G " 47 20 20 20 20 20
Single-letter abbreviation G for the GO keyword; same value cell at 5460H as the full form above.
5537-5538
DEFW 5460H 60 54
Pointer for the G entry: the address (5460H) of the two-byte operand cell @PARAM patches when this keyword is present.
5539-553E
DEFM "CLEAR " 43 4C 45 41 52 20
Full keyword CLEAR; @PARAM writes its value into the operand cell at 520EH.
553F-5540
DEFW 520EH 0E 52
Pointer for the CLEAR entry: the address (520EH) of the two-byte operand cell @PARAM patches when this keyword is present.
5541-5546
DEFM "C " 43 20 20 20 20 20
Single-letter abbreviation C for the CLEAR keyword; same value cell at 520EH as the full form above.
5547-5548
DEFW 520EH 0E 52
Pointer for the C entry: the address (520EH) of the two-byte operand cell @PARAM patches when this keyword is present.
5549-554E
DEFM "PRINT " 50 52 49 4E 54 20
Full keyword PRINT; @PARAM writes its value into the operand cell at 542EH.
554F-5550
DEFW 542EH 2E 54
Pointer for the PRINT entry: the address (542EH) of the two-byte operand cell @PARAM patches when this keyword is present.
5551-5556
DEFM "P " 50 20 20 20 20 20
Single-letter abbreviation P for the PRINT keyword; same value cell at 542EH as the full form above.
5557-5558
DEFW 542EH 2E 54
Pointer for the P entry: the address (542EH) of the two-byte operand cell @PARAM patches when this keyword is present.
5559
DEFB 00H 00
Zero byte marking the end of the @PARAM descriptor table.

555AH - MEMORY Data: Value-Display Templates

The two templates the HIGH and ADD keywords use to echo an address in both hexadecimal and decimal. The lower-case placeholder characters are overwritten in code with the formatted digits.

555A-5569
DEFM " High = X'xxxx'" 20 20 48 69 67 68 20 3D 20 58 27 78 78 78 78 27
Template
The High = X'xxxx' report line. Printed from 52E1H; the xxxx hexadecimal field at 5565H is overwritten with the current HIGH$ address by 52DBH.
556A
DEFB 0DH 0D
Carriage return (0DH) terminating the report line above.
556B-558E
DEFM "X'dddd' = ddddd ('dddd' => X'dddd')" 58 27 64 64 64 64 27 20 3D 20 64 64 64 64 64 20 20 28 27 64 64 64 64 27 20 3D 3E 20 58 27 64 64 64 64 27 29
Template
The ADD-keyword value echo, X'dddd' = ddddd ('dddd' => X'dddd'). The first hex field (556DH) and the decimal field (5575H) are filled by 5244H/524CH; the parenthesised echo hex fields (557EH, 5589H) by 5257H/527BH. 5583H is the single-byte format position (selected at 5286H) and 558EH the word format position (selected at 5281H).

558FH - MEMORY Data: Directory Headings and Summary Labels

The title, summary-line labels and column headings the directory display copies into its 5200H work buffer before printing the high-memory module table.

558F-55A3
DEFM "High Memory Directory" 48 69 67 68 20 4D 65 6D 6F 72 79 20 44 69 72 65 63 74 6F 72 79
Heading
The High Memory Directory title line, copied (0015H = 21 bytes) to the 5200H work buffer by 5357H.
55A4-55AA
DEFM "HIGH$ =" 48 49 47 48 24 20 3D
Summary-line label HIGH$ =, copied (0007H bytes) to 5219H by 5362H ahead of the formatted HIGH$ value.
55AB-55B1
DEFM "Start =" 53 74 61 72 74 20 3D
Summary-line label Start = held in the same label group. Present in the string pool between the HIGH$ and Length labels that 5362H/5375H copy around it.
55B2-55B9
DEFM "Length =" 4C 65 6E 67 74 68 20 3D
Summary-line label Length =, copied (0008H bytes) to 522CH by 5375H ahead of the computed length.
55BA-55F2
DEFM "Module Start Address End Address Length" 4D 6F 64 75 6C 65 20 20 20 20 20 20 20 20 20 53 74 61 72 74 20 41 64 64 72 65 73 73 20 20 20 20 20 20 45 6E 64 20 41 64 64 72 65 73 73 20 20 20 20 20 20 4C 65 6E 67 74 68
Heading
The module-table column headings (Module / Start Address / End Address / Length), copied (003AH = 58 bytes) to the 5200H work buffer by 5398H.
55F3
DEFB 0DH 0D
Carriage return (0DH) terminating the column-heading line above.

55F4H - MEMORY Data: Fallback Name and Hex-Address Template

The placeholder name used for anonymous modules and the X'____' template used to print a 16-bit address. These occupy the final bytes of the MEMORY overlay (through 5603H).

55F4-55FC
DEFM "<unknown>" 3C 75 6E 6B 6E 6F 77 6E 3E
Fallback Name
The <unknown> text, loaded into HL at 53E8H and printed in place of a module name when a high-memory module header carries no printable name.
55FD-5603
DEFM "X' '" 58 27 20 20 20 20 27
Template
The X'____' hex-address display template (X' followed by four spaces and a closing quote). The four spaces at 55FFH receive the hex digits produced by the address-format helper at 53FFH; 5408H loads the full string and 5401H the digit field.

Disassembly - Overlay 2 - DIR

5200H - DIR Overlay Entry: Filespec, Drive and Option Parse

Entry of the DIR command overlay, which displays a disk directory. It first saves the caller's stack pointer for a clean return, then parses the command tail: an optional filespec mask (name and extension held in the 5B6AH/5B72H match buffers), an optional drive number, and the option keywords (A, I/INV, S/SYS, P, N, DATE, MOD, SORT) through the resident @PARAM service. Register HL points at the command tail on entry, set up by the resident overlay loader.

5200
LD (540DH),SP ED 73 0D 54
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn instruction at 540CH 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-flag reset helper at 58E8H, which clears the low bits of the resident keyboard flag KFLAG$ (4423H) so a stale pause or BREAK does not fire; it returns register A as zero.
5207
LD A,(HL) 7E
Load register A with the first character of the DIR command tail. Register pair HL is the command-line scan pointer set up by the overlay loader on entry.
5208
INC HL 23
Advance the command-line scan pointer HL to the next character.
5209
CP 30H FE 30
Compare register A (the first command character) against 0 (30H) to test whether the command begins with a drive digit. If A is below 30H the CARRY flag is set.
520B
If register A is below 0 (CARRY set, not a digit), JUMP to 5211H to treat the character as the start of a filespec mask.
520D
CP 3AH FE 3A
Compare register A against : (3AH), one past 9. If A is below 3AH (and, from the test above, at or above 30H) it is a digit 0 through 9, and the CARRY flag is set.
520F
If register A is a digit (CARRY set), JUMP to 5238H to read it as the drive number.
5211
LD DE,5B6AH 11 6A 5B
Point register pair DE at the 8-byte filename match buffer at 5B6AH, where the name portion of the filespec mask is stored for comparison against each directory entry.
5214
LD B,08H 06 08
Load register B with 8, the maximum length of the file name field being copied.
5216
CP 2DH FE 2D
Compare register A (the current command character) against - (2DH), the partial-match marker that lists every file whose name contains the following text.
5218
If register A is not - (NZ), JUMP to 521FH to copy the name characters directly.
521A
LD (549DH),A 32 9D 54
Store the - character (register A) into the partial-match flag at 549DH; a later test at 5493H uses it to decide whether an embedded-substring match is wanted.
521D
LD A,(HL) 7E
Load register A with the next command character (the first character of the name text after the -). HL is the command-line scan pointer.
521E
INC HL 23
Advance the command-line scan pointer HL past that character.
521F
GOSUB to the name-copy helper at 57C2H, which copies up to register B characters of the file name from the command line (HL) into the match buffer (DE), folding lower case to upper case and stopping at a delimiter; it returns the terminating character in register A.
5222
CP 2FH FE 2F
Compare the terminating character (register A) against / (2FH), the separator that introduces a file extension.
5224
If the terminator is not / (NZ, no extension given), JUMP to 5230H.
5226
LD DE,5B72H 11 72 5B
Point register pair DE at the 3-byte extension match buffer at 5B72H.
5229
LD B,03H 06 03
Load register B with 3, the maximum length of the extension field.
522B
LD A,(HL) 7E
Load register A with the first extension character from the command line. HL is the scan pointer.
522C
INC HL 23
Advance the command-line scan pointer HL.
522D
GOSUB to the name-copy helper at 57C2H to copy up to 3 extension characters (register B) into the extension match buffer (DE), folding to upper case; it returns the terminating character in register A.
5230
CP 3AH FE 3A
Compare the terminating character (register A) against : (3AH), the separator that introduces an explicit drive number.
5232
LD C,00H 0E 00
Load register C with zero as the default first drive to scan when no explicit drive is given.
5234
If the terminator is not : (NZ, no explicit drive), JUMP to 5244H with C holding the default drive 0.
5236
LD A,(HL) 7E
Load register A with the drive-number character following the :. HL is the scan pointer.
5237
INC HL 23
Advance the command-line scan pointer HL.
5238
INC HL 23
Advance the command-line scan pointer HL past the drive digit. This is also the entry reached from 520FH when the command began with a drive digit; register A holds that digit.
5239
SUB 30H D6 30
Subtract 0 (30H) from register A to convert the ASCII drive digit to a binary drive number 0 through 7.
523B
CP 08H FE 08
Compare the binary drive number (register A) against 8, the number of possible drives. If A is 8 or greater the NO CARRY flag is set, marking an out-of-range drive.
523D
If the drive number is 8 or greater (NO CARRY), JUMP to the error handler at 5A35H to report a parameter error.
5240
LD C,A 4F
Copy the validated drive number (register A) into register C, the drive being scanned.
5241
LD (53FEH),A 32 FE 53
Store the drive number (register A) into the single-drive flag at 53FEH; when set, the exit code at 541CH stops after this one drive instead of scanning all drives.
5244
DEC HL 2B
Step the command-line scan pointer HL back one character so the parameter scan that follows re-reads the delimiter that ended the filespec.
5245
LD A,C 79
Copy the drive number (register C) into register A.
5246
LD (52AEH),A 32 AE 52
Self-Modifying Code
Store the drive number (register A) into the operand of the LD C,nn instruction at 52ADH, seeding the per-drive loop so it starts at the requested drive rather than drive 0.
5249
LD DE,5A42H 11 42 5A
Point register pair DE at the local @PARAM keyword descriptor table at 5A42H, which lists the DIR options (A, I, INV, S, SYS, P, N, DATE, MOD, SORT) and the operand cells they set.
524C
GOSUB to the resident @PARAM service at 4476H to parse the remaining command line against the option table at DE; it deposits each supplied option's value into that option's operand cell in this overlay and returns NZ on a parameter error.
524F
If @PARAM reported a bad option (NZ), JUMP to the error handler at 5A35H to report a parameter error.

5252H - DIR Setup: Busy-State Check, Sort-Buffer Ceiling and Date Filter

Prepares the global state for the listing. It notes whether the system is busy (which suppresses the in-memory sort buffer), computes the ceiling below HIGH$ into which sorted entries may be gathered, forces non-stop output when the printer option is active, and parses the optional DATE range into the start and end compare values, before falling into the per-drive scan loop.

5252
LD A,(4758H) 3A 58 47
Load register A with the resident SYS1 status byte at 4758H, whose bit 1 is the system-busy flag (set when DIR is invoked from within a running program rather than at the command level).
5255
BIT 1,A CB 4F
Test bit 1 of register A (the SYS1 status byte just loaded) to determine whether the system is busy.
5257
LD HL,0000H 21 00 00
Load register pair HL with zero, the value used to disable the in-memory sort collection when busy.
525A
If bit 1 was clear (Z, not busy), JUMP to 525FH leaving the sort-collection pointer untouched.
525C
LD (54CFH),HL 22 CF 54
Store zero (register pair HL) into the sort-collection flag at 54CFH, disabling the gather-and-sort path so that when the system is busy DIR streams each entry straight to the display.
525F
LD HL,(4049H) 2A 49 40
Load register pair HL with the resident HIGH$ word at 4049H, the current top of user memory, below which the sort buffer is placed.
5262
LD DE,0FFDFH 11 DF FF
Load register pair DE with 0FFDFH, which is -33 in two's complement, the headroom reserved below HIGH$.
5265
ADD HL,DE 19
Add DE (-33) to HL (HIGH$), leaving HL at 33 bytes below the top of memory as the ceiling for the sort buffer.
5266
LD (5BE3H),HL 22 E3 5B
Store that ceiling (register pair HL) into 5BE3H, the upper limit the entry-gather routine checks so the sort buffer never overruns high memory.
5269
LD HL,(578FH) 2A 8F 57
Load register pair HL with the printer-echo flag word at 578FH, which the P option sets so that every displayed line is also sent to the printer.
526C
LD A,H 7C
Copy the high byte of the printer-echo flag (register H) into register A to test the whole word for zero.
526D
OR L B5
OR register L (the low byte of the printer-echo flag) into register A; the Z flag is now set only if the printer-echo flag is zero (P not given).
526E
If the printer-echo flag is zero (Z, P not given), JUMP to 5273H leaving the page-pause behaviour unchanged.
5270
LD (58FFH),HL 22 FF 58
Store the printer-echo flag (register pair HL) into 58FFH, the suppress-pause flag that is the operand of the LD DE at 58FEH in the pause routine; a nonzero value makes the listing run without stopping each screen while it is being printed.
5273
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the DATE-argument pointer. This operand at 5274H is patched by @PARAM when the DATE option is given, with the address of the date text; it is 0000H when DATE was not requested.
5276
LD A,H 7C
Copy the high byte of the DATE-argument pointer (register H) into register A to test it for zero.
5277
OR L B5
OR register L (the low byte of the DATE-argument pointer) into register A; the Z flag is set only if no DATE argument was supplied.
5278
If no DATE argument was given (Z), JUMP to 52ADH to begin the drive scan without a date filter.
527A
LD A,(HL) 7E
Load register A with the first character of the DATE argument. HL points at the date text supplied by @PARAM.
527B
CP 2DH FE 2D
Compare register A against - (2DH), which as the first character means an open-ended range (list everything up to the end date).
527D
If the argument begins with - (Z, no start date), JUMP to 5294H to parse the end date only.
527F
LD A,80H 3E 80
Load register A with 80H, the bit that marks a start date as present.
5281
LD (5BE0H),A 32 E0 5B
Store 80H into the date-filter mode flag at 5BE0H, recording that a start date has been given (bit 7).
5284
GOSUB to the date-parse helper at 5806H, which reads an MM/DD/YY field from the command line (HL) and returns the packed year/day compare value in register pair BC.
5287
LD (5BE5H),BC ED 43 E5 5B
Store the parsed start-date compare value (register pair BC) into 5BE5H, against which each file's modification date is later tested.
528B
LD A,(HL) 7E
Load register A with the character after the start date. HL is the command-line scan pointer left by the date parser.
528C
CP 22H FE 22
Compare register A against " (22H), which ends a single-date specification (that date only).
528E
If the argument ends here with " (Z, a single date), JUMP to 52A1H to use the start date as the end date too.
5290
CP 2DH FE 2D
Compare register A against - (2DH), the separator between a start date and an end date.
5292
If the character is not - (NZ, no end date follows), JUMP to 52ADH to begin the drive scan with just the start date.
5294
INC HL 23
Advance the command-line scan pointer HL past the - range separator.
5295
LD A,(HL) 7E
Load register A with the first character of the end date. HL is the scan pointer.
5296
CP 22H FE 22
Compare register A against " (22H), an immediate close meaning no end date.
5298
If the end date is closed immediately with " (Z), JUMP to 52ADH to begin the drive scan.
529A
CP 0DH FE 0D
Compare register A against a carriage return (0DH), the end of the command line.
529C
If the command line ends here (Z, CR), JUMP to 52ADH to begin the drive scan.
529E
GOSUB to the date-parse helper at 5806H to read the end date from the command line (HL), returning the packed compare value in register pair BC.
52A1
LD A,(5BE0H) 3A E0 5B
Load register A with the date-filter mode flag at 5BE0H (bit 7 = start date present) so its end-date bit can be added.
52A4
OR 01H F6 01
Set bit 0 of register A, marking that an end date is present in the date filter.
52A6
LD (5BE0H),A 32 E0 5B
Store the updated mode flag (register A) back into 5BE0H, now recording start (bit 7) and end (bit 0) dates as appropriate.
52A9
LD (5BE7H),BC ED 43 E7 5B
Store the end-date compare value (register pair BC) into 5BE7H, the upper bound each file's modification date is tested against.
52AD
LD C,00H 0E 00
Self-Modifying Code
Load register C with the first drive to scan. This operand at 52AEH was set at 5246H to the requested drive number, or remains 0 to scan from drive 0.
52AF
LD A,0FH 3E 0F
Load register A with 15, the number of directory lines shown before the display pauses for a keypress.
52B1
LD (58F3H),A 32 F3 58
Self-Modifying Code
Store 15 (register A) into the line counter at 58F3H, the operand the paged-display routine at 58F2H decrements to time each page pause.

52B4H - Per-Drive Loop: Drive Check, GAT Read, Free-Granule Count and Drive-Type Field

Top of the per-drive scan loop. For the current drive it verifies the drive is ready, loads that drive's Drive Control Table (DCT) into IY, determines whether extended date stamping is enabled for it, reads the Granule Allocation Table (GAT) into the shared buffer, counts the free granules, and builds the drive-type descriptor (floppy single/double density and sides, or hard-disk head count) for the header line. Register C holds the drive number on entry.

52B4
PUSH BC C5
Save the loop registers on the stack; register C holds the current drive number being scanned. This is the loop re-entry reached from 5406H and 5429H when advancing to the next drive.
52B5
LD A,03H 3E 03
Load register A with 3, the per-line output-mode selector value.
52B7
LD (55A2H),A 32 A2 55
Store 3 into the output-mode cell at 55A2H, which the entry-format routine at 5509H reads to decide how each directory line is emitted.
52BA
LD A,C 79
Copy the current drive number (register C) into register A.
52BB
ADD A,30H C6 30
Add 0 (30H) to convert the drive number in register A to its ASCII digit.
52BD
LD (5B02H),A 32 02 5B
Store the ASCII drive digit into 5B02H, the drive field of the directory read setup and the header line.
52C0
GOSUB to the resident @CKDRV service at 44B8H to check that the drive in register C is present and ready; it returns NZ if the drive is not available.
52C3
If the drive is not present or ready (NZ), JUMP to 541BH to skip it and advance to the next drive.
52C6
GOSUB to the resident GETDCT service at 478FH, which sets register pair IY to the base of this drive's 10-byte Drive Control Table (DCT$ = 4700H + drive number times 10).
52C9
LD B,C 41
Copy the drive number (register C) into register B for the rotate count that follows.
52CA
LD A,(475DH) 3A 5D 47
Load register A with the resident per-drive extended-dating flags at 475DH, one bit per drive marking whether that drive records time as well as date.
52CD
INC B 04
Increment register B so the rotate count below is the drive number plus one, bringing this drive's flag bit to the carry.
52CE
RRCA 0F
Rotate the extended-dating flags (register A) right; repeated the required number of times, this positions this drive's flag bit.
52CF
DECrement register B and LOOP BACK to 52CEH until the rotate has been done drive-number-plus-one times, leaving this drive's dating bit in the carry / low bit of register A.
52D1
SBC A,A 9F
Set register A to 0FFH if the carry (this drive's extended-dating bit) is set, or 00H if clear, forming an all-ones or all-zeros flag.
52D2
LD (56ACH),A 32 AC 56
Store that extended-dating flag (00H or 0FFH, register A) into 56ACH, which the date-decode helper at 57DDH tests to decide whether to include the time field.
52D5
LD D,(IY+09H) FD 56 09
Load register D with DCT offset 09H, this drive's directory cylinder number, as the cylinder for the GAT read.
52D8
LD E,B 58
Load register E with register B, which is now zero after the loop, selecting sector 0 (the GAT sector) on the directory cylinder.
52D9
LD HL,4200H 21 00 42
Point register pair HL at the shared sector buffer SBUFF$ (4200H) that will receive the GAT sector.
52DC
GOSUB to the resident RDSSEC service at 4B45H to read the GAT (cylinder in register D, sector 0 in register E) into the buffer at HL; it returns NZ on a disk error.
52DF
If the GAT read failed (NZ), JUMP to the error handler at 5A37H to report the disk error.
52E2
LD A,(IY+08H) FD 7E 08
Load register A with DCT offset 08H, whose low 5 bits are the sectors-per-granule value for this drive.
52E5
AND 1FH E6 1F
Mask register A to its low 5 bits, isolating the sectors-per-granule count minus one.
52E7
INC A 3C
Increment register A to the true sectors-per-granule count.
52E8
LD (579BH),A 32 9B 57
Store the sectors-per-granule count (register A) into 579BH, used later when converting free granules to a byte count.
52EB
LD D,L 55
Set register D to register L (zero, the low byte of the 4200H buffer pointer), clearing the high byte of the free-granule counter.
52EC
LD E,L 5D
Set register E to register L (zero) as well, so register pair DE starts the free-granule count at zero.
52ED
LD B,(IY+06H) FD 46 06
Load register B with DCT offset 06H, the highest cylinder number on this drive.
52F0
INC B 04
Increment register B to the number of cylinders (and therefore the number of GAT bytes to scan, one per cylinder).
52F1
PUSH BC C5
Save the cylinder count (register B) on the stack for reuse after the free-granule scan.
52F2
LD A,(HL) 7E
Load register A with the GAT byte for the current cylinder; each bit that is set marks an allocated granule, each clear bit a free granule. HL walks the GAT in the 4200H buffer.
52F3
SCF 37
Set the carry flag to 1 so it shifts a one into the top of the GAT byte, marking each granule as it is counted.
52F4
RRA 1F
Rotate register A right through carry: the low granule bit moves into the carry for testing, and a one enters at the top.
52F5
If the shifted-out bit was 1 (CARRY, that granule is allocated), JUMP to 52F8H without counting it.
52F7
INC DE 13
The granule was free (bit 0): increment the free-granule counter in register pair DE.
52F8
CP 0FFH FE FF
Compare register A against 0FFH to detect when all the granule bits of this cylinder's byte have been shifted through (the byte is now all ones).
52FA
If the GAT byte is not yet all ones (NZ), LOOP BACK to 52F3H to test the next granule bit.
52FC
INC L 2C
Advance the GAT pointer (register L) to the next cylinder's allocation byte.
52FD
DECrement the cylinder count (register B) and LOOP BACK to 52F2H until every cylinder's GAT byte has been counted; register pair DE now holds the total free granules.
52FF
LD HL,5B21H 21 21 5B
Point register pair HL at the free-space field 5B21H in the header work buffer.
5302
GOSUB to the decimal-format helper at 5796H, which converts the free-granule count (register pair DE) to a kilobyte figure written at the buffer (HL) and returns the tenths digit in register A.
5305
LD (5B27H),A 32 27 5B
Store the tenths digit (register A) into 5B27H, the fractional position of the Free=nnn.nK figure.
5308
POP AF F1
Recover the cylinder count saved at 52F1H into register A (its flags are discarded).
5309
LD L,A 6F
Copy the cylinder count (register A) into register L.
530A
LD H,00H 26 00
Clear register H so register pair HL is the 16-bit cylinder count.
530C
PUSH HL E5
Save the cylinder count (register pair HL) for the disk-capacity calculation later.
530D
LD DE,5B16H 11 16 5B
Point register pair DE at the cylinders field 5B16H in the header buffer.
5310
GOSUB to the decimal-format helper at 5888H to write the cylinder count (register pair HL) as decimal digits into the buffer at DE.
5313
LD HL,3148H 21 48 31
Load register pair HL with the default drive-type characters (register L = 1, register H = H), overwritten below according to the drive geometry.
5316
BIT 3,(IY+03H) FD CB 03 5E
Test bit 3 of DCT offset 03H, which is set for a rigid (hard) drive and clear for a floppy.
531A
If the drive is a floppy (Z, bit 3 clear), JUMP to 5329H to build the floppy density/side descriptor.
531C
LD A,(IY+07H) FD 7E 07
Hard drive: load register A with DCT offset 07H, whose upper bits encode the number of heads/platters.
531F
RLCA 07
Rotate register A left to move the head-count field toward the low bits.
5320
RLCA 07
Rotate register A left again.
5321
RLCA 07
Rotate register A left a third time; the head-count field now sits in the low 3 bits.
5322
AND 07H E6 07
Mask register A to the low 3 bits, isolating the head count.
5324
ADD A,31H C6 31
Add 1 (31H) to convert the head count in register A to an ASCII digit.
5326
LD H,A 67
Store the head-count digit (register A) into register H, the second character of the drive-type field.
5327
JUMP to 533AH to store the completed hard-drive type field.
5329
LD L,44H 2E 44
Floppy: load register L with D (44H), the base density letter (assume double density).
532B
BIT 6,(IY+03H) FD CB 03 76
Test bit 6 of DCT offset 03H, which is set for double density and clear for single density.
532F
If the drive is double density (NZ), JUMP to 5333H keeping the D letter.
5331
LD L,53H 2E 53
Single density: change register L to S (53H).
5333
BIT 5,(IY+04H) FD CB 04 6E
Test bit 5 of DCT offset 04H, which is set when the floppy drive is double-sided.
5337
If the drive is single-sided (Z), JUMP to 533AH to store the type field as is.
5339
INC H 24
Double-sided: increment register H (the digit character) to reflect two sides in the drive-type field.
533A
LD (5B19H),HL 22 19 5B
Store the completed drive-type field (register pair HL, the density/side letters or hard-drive head digit) into 5B19H in the header line buffer.

533DH - Disk Capacity, Directory Capacity, Disk Name and Header Display

Completes the header line for this drive. It computes the granules-per-cylinder and the total granule capacity, formats it as a kilobyte figure, works out the directory-entry capacity, counts the directory slots in the Hash Index Table (HIT), copies the disk name and creation date out of the GAT sector, then displays the assembled header line and the column-heading separator before dropping into the directory read loop.

533D
POP HL E1
Recover the cylinder count (register pair HL) saved at 530CH for the capacity multiply.
533E
LD A,(IY+08H) FD 7E 08
Load register A with DCT offset 08H, whose upper 3 bits hold the granules-per-track value.
5341
AND 0E0H E6 E0
Mask register A to its top 3 bits, isolating the granules-per-track field.
5343
RLCA 07
Rotate register A left to begin moving the granules-per-track field down to the low bits.
5344
RLCA 07
Rotate register A left again.
5345
RLCA 07
Rotate register A left a third time; the granules-per-track value now sits in the low bits.
5346
INC A 3C
Increment register A to the true granules-per-track count.
5347
BIT 5,(IY+04H) FD CB 04 6E
Test bit 5 of DCT offset 04H, set when the drive is double-sided (two tracks per cylinder).
534B
If the drive is single-sided (Z), JUMP to 534EH with register A holding granules per cylinder equal to granules per track.
534D
ADD A,A 87
Double-sided: double register A so it holds granules per cylinder (both sides).
534E
PUSH AF F5
Save the granules-per-cylinder value (register A) for the sectors-per-cylinder computation below.
534F
GOSUB to the resident @MULT service at 44C1H to multiply the cylinder count (register pair HL) by granules per cylinder (register A); it returns the high 16 bits of the product in HL and the low byte in register A.
5352
LD D,L 55
Copy register L (product bits 8 to 15) into register D as the high byte of the total granule count.
5353
LD E,A 5F
Copy register A (product bits 0 to 7) into register E; register pair DE now holds the total granules on the disk.
5354
LD HL,5B29H 21 29 5B
Point register pair HL at the disk-capacity field 5B29H in the header buffer.
5357
GOSUB to the decimal-format helper at 5796H to convert the total granule count (register pair DE) to a kilobyte figure at the buffer (HL); it returns the tenths digit in register A.
535A
LD (5B2FH),A 32 2F 5B
Store the tenths digit (register A) into 5B2FH, the fractional position of the capacity figure.
535D
POP BC C1
Recover the granules-per-cylinder value into register B (saved at 534EH); register C receives the discarded flags.
535E
LD A,(579BH) 3A 9B 57
Load register A with the sectors-per-granule count stored at 579BH.
5361
LD C,A 4F
Copy sectors-per-granule (register A) into register C as the repeated-addition addend.
5362
XOR A AF
Clear register A to zero to accumulate the sectors-per-cylinder product.
5363
ADD A,C 81
Add sectors-per-granule (register C) into register A.
5364
DECrement the granules-per-cylinder count (register B) and LOOP BACK to 5363H, leaving register A as sectors per cylinder (granules per cylinder times sectors per granule).
5366
LD HL,0100H 21 00 01
Load register pair HL with 256, the base used when scaling the directory-entry capacity.
5369
SUB 02H D6 02
Subtract 2 from the sectors-per-cylinder count in register A, discounting the two directory-cylinder sectors reserved for the GAT and HIT.
536B
CP 20H FE 20
Compare register A against 32 to decide how the directory-entry capacity is scaled.
536D
If the remaining sector count is 32 or more (NO CARRY), JUMP to 5378H using register pair HL as it stands.
536F
SLA A CB 27
Shift register A left, multiplying the remaining sector count by 2.
5371
SLA A CB 27
Shift register A left again (times 4).
5373
SLA A CB 27
Shift register A left a third time, giving 8 directory entries per remaining sector.
5375
LD L,A 6F
Copy the directory-entry capacity (register A) into register L.
5376
LD H,00H 26 00
Clear register H so register pair HL is the 16-bit directory-entry capacity.
5378
LD (53A4H),HL 22 A4 53
Self-Modifying Code
Store the directory-entry capacity (register pair HL) into the operand of the LD DE,nnnn instruction at 53A3H, seeding the directory-slot count below.
537B
LD DE,5B38H 11 38 5B
Point register pair DE at the directory-capacity field 5B38H in the header buffer.
537E
GOSUB to the decimal-format helper at 5888H to write the directory-entry capacity (register pair HL) as decimal digits into the buffer at DE.
5381
LD HL,42D0H 21 D0 42
Point register pair HL at offset D0H of the GAT sector in the buffer (4200H+D0H), where the 8-character disk name is stored.
5384
LD DE,5B04H 11 04 5B
Point register pair DE at the disk-name field 5B04H in the header buffer.
5387
LD BC,0008H 01 08 00
Load register pair BC with 8, the length of the disk name.
538A
LDIR ED B0
Block-copy the 8-character disk name from the GAT sector (HL) into the header buffer (DE).
538C
INC DE 13
Advance the destination pointer DE past a separator position in the header buffer.
538D
LD C,08H 0E 08
Reload register C with 8 for the next copy (register B is already zero after the LDIR).
538F
LDIR ED B0
Block-copy the 8-character disk creation date from the GAT sector (HL, now at offset D8H) into the header buffer (DE).
5391
POP BC C1
Recover the drive number into register C from the copy saved at 52B4H.
5392
PUSH BC C5
Re-save the drive number (register C) for the directory read loop that follows.
5393
GOSUB to the resident DIRCYL service at 4B65H, which seeks this drive to its directory cylinder and prepares for directory-sector reads.
5396
LD E,01H 1E 01
Load register E with 1, selecting sector 1 of the directory cylinder (the Hash Index Table).
5398
LD HL,5C00H 21 00 5C
Point register pair HL at the buffer at 5C00H that will receive the HIT sector.
539B
GOSUB to the resident RDSSEC service at 4B45H to read the HIT (sector 1 in register E) into the buffer at HL; it returns NZ on a disk error.
539E
LD A,16H 3E 16
Load register A with 16H (error code 22, HIT read error) in case the read failed.
53A0
If the HIT read failed (NZ), JUMP to the error handler at 5A37H with the HIT-read error code in register A.
53A3
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the directory-entry capacity. This operand at 53A4H was set at 5378H; DE is the running directory-slot count.
53A6
DEC DE 1B
Decrement the running directory-slot count in register pair DE for the slot about to be examined.
53A7
LD A,(42CDH) 3A CD 42
Load register A with the GAT configuration byte at 42CDH in the GAT sector, whose bit 7 selects how reserved directory slots are handled.
53AA
RLCA 07
Rotate register A left so the configuration bit 7 moves into the carry.
53AB
If that configuration bit was set (CARRY), JUMP to 53B2H to test this HIT byte directly.
53AD
LD A,L 7D
Load register A with register L, the low byte of the HIT pointer (the directory slot index).
53AE
AND 0D8H E6 D8
Mask the slot index (register A) with 0D8H to detect the reserved low directory slots (boot, directory and system files).
53B0
If this is a reserved slot (Z), JUMP to 53B7H without counting it.
53B2
LD A,(HL) 7E
Load register A with this slot's HIT byte; a zero byte marks a free directory slot. HL walks the HIT in the 5C00H buffer.
53B3
OR A B7
Test the HIT byte (register A) for zero.
53B4
If the slot is in use (NZ, nonzero hash), JUMP to 53B7H without counting it as free.
53B6
INC DE 13
The slot is free: increment the directory-slot count in register pair DE.
53B7
INC L 2C
Advance the HIT pointer (register L) to the next directory slot.
53B8
If the HIT pointer has not wrapped to zero (NZ), LOOP BACK to 53A6H to examine the next slot; register pair DE ends with the free directory-slot count.
53BA
EX DE,HL EB
Exchange DE and HL so register pair HL holds the free directory-slot count for formatting.
53BB
LD DE,5B34H 11 34 5B
Point register pair DE at the free-directory-slots field 5B34H in the header buffer.
53BE
GOSUB to the decimal-format helper at 5888H to write the free directory-slot count (register pair HL) as decimal digits into the buffer at DE.
53C1
LD HL,5AFBH 21 FB 5A
Point register pair HL at the assembled header summary line at 5AFBH (Drive, disk name, date, capacity and free figures).
53C4
GOSUB to the display helper at 577CH, which sends the header line (HL) to the video and, when the P option is active, to the printer.
53C7
GOSUB to the paged-display helper at 58F2H to count the line and pause the screen if it is full.
53CA
LD A,0DH 3E 0D
Load register A with a carriage return (0DH).
53CC
GOSUB to the printer-only output helper at 578EH to send the carriage return to the printer when the P option is active.
53CF
GOSUB to the separator helper at 5921H, which prints the column-heading rule beneath the header.
53D2
POP BC C1
Recover the drive number into register C (saved at 5392H) for the directory scan.
53D3
LD HL,5E00H 21 00 5E
Point register pair HL at 5E00H, the base of the high-memory buffer that collects entries when sorting.
53D6
LD (5BE1H),HL 22 E1 5B
Store that base (register pair HL) into 5BE1H, the append pointer for the sort-collection buffer.
53D9
LD HL,5C00H 21 00 5C
Point register pair HL at 5C00H, the start of the directory records to scan for this drive.
53DC
JUMP to 542DH to enter the directory-record read loop.

53DEH - Record Advance, Drive-Loop Exit and Drive-Not-Ready Skip

Advances to the next directory record and, when a directory sector is exhausted, either sorts and flushes the collected entries or moves on. When the last record of the drive is done it either exits (single drive requested) or steps to the next drive. It also holds the common overlay exit and the path taken when a drive is not ready.

53DE
POP HL E1
Discard the directory-record pointer that was saved during name matching (this entry point is reached after a matched or filtered file).
53DF
POP BC C1
Recover the record index into register B and the drive number into register C, saved at 5432H before the entry was examined.
53E0
LD H,5CH 26 5C
Set register H to 5CH, the high byte of the directory-record buffer page.
53E2
LD L,B 68
Set register L to the record index (register B); register pair HL now points at the current directory record in the 5C00H buffer.
53E3
LD A,L 7D
Copy the record offset (register L) into register A to advance it.
53E4
ADD A,20H C6 20
Add 32 (one directory record) to register A to step to the next record.
53E6
LD L,A 6F
Store the advanced offset (register A) back into register L.
53E7
If the offset did not wrap past the end of the buffer page (NO CARRY), JUMP to 542DH to process the next record.
53E9
INC L 2C
The buffer page is exhausted: nudge register L for the end-of-sector test below.
53EA
BIT 5,L CB 6D
Test bit 5 of register L to determine whether more directory records remain to be read for this drive.
53EC
If more records remain (Z), JUMP to 542DH to continue reading directory records.
53EE
LD A,(54CFH) 3A CF 54
Load register A with the sort-collection flag at 54CFH (nonzero when the SORT option gathered entries in high memory).
53F1
OR A B7
Test the sort flag (register A) for zero.
53F2
If entries were collected for sorting (NZ), GOSUB to the sort engine at 5944H to sort them by name and display them.
53F5
LD A,0DH 3E 0D
Load register A with a carriage return (0DH) to end the drive's listing.
53F7
GOSUB to the character-output helper at 5789H to send the carriage return to the video display.
53FA
GOSUB to the paged-display helper at 58F2H to count the line and pause if the screen is full.
53FD
LD A,0FFH 3E FF
Self-Modifying Code
Load register A with the single-drive flag. This operand at 53FEH is 0FFH to scan all drives, or the requested drive number when an explicit drive was given at 5241H.
53FF
INC A 3C
Increment register A: a scan-all flag of 0FFH becomes 0 (Z), while an explicit drive number becomes nonzero (NZ).
5400
If a single drive was requested (NZ), JUMP to 5409H to finish after this drive.
5402
INC C 0C
Advance the drive number in register C to the next drive.
5403
LD A,C 79
Copy the new drive number (register C) into register A to test its range.
5404
CP 08H FE 08
Compare the drive number (register A) against 8, the number of drives.
5406
If the drive number is below 8 (CARRY), JUMP back to 52B4H to list the next drive.
5409
LD HL,0000H 21 00 00
Load register pair HL with zero, the success status for the return.
540C
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer. This operand at 540DH was set from SP at overlay entry (5200H).
540F
LD A,H 7C
Copy the high byte of the status (register H) into register A to test it.
5410
OR L B5
OR the low byte of the status (register L) into register A; the Z flag is set when the status is zero (success).
5411
RET Z C8
If the status is zero (Z, success), RETURN to the resident dispatcher.
5412
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag SFLAG$ at 430FH, whose bit 5 is set when not at the LDOS command level.
5415
BIT 5,A CB 6F
Test bit 5 of SFLAG$ (register A) to determine whether the command was issued at the command level.
5417
RET Z C8
If at the command level (Z, bit 5 clear), RETURN to the dispatcher despite the error status.
5418
Otherwise JUMP to the resident @ABORT service at 4030H to abort to DOS.
541B
POP BC C1
Drive-not-ready path from 52C3H: recover the loop registers (register C is the drive number) saved at 52B4H.
541C
LD A,(53FEH) 3A FE 53
Load register A with the single-drive flag at 53FEH (0FFH to scan all drives, or the requested drive number).
541F
INC A 3C
Increment register A so the scan-all value 0FFH becomes 0 (Z) while an explicit drive number stays nonzero (NZ); this sets the flag for the test below.
5420
LD A,20H 3E 20
Load register A with 20H (error code 32, illegal drive number) without disturbing the flag just set.
5422
If an explicit drive was requested but is not ready (NZ), JUMP to the error handler at 5A37H with the illegal-drive code in register A.
5425
INC C 0C
Scanning all drives: advance the drive number in register C to the next drive.
5426
LD A,C 79
Copy the drive number (register C) into register A to test its range.
5427
CP 08H FE 08
Compare the drive number (register A) against 8.
5429
If the drive number is below 8 (CARRY), JUMP back to 52B4H to try the next drive.
542C
RET C9
All drives scanned: RETURN to the resident dispatcher.

542DH - Directory Record Read Loop: Attribute, Name and Date Filters

The heart of the listing. For each directory slot it reads the record, rejects empty, secondary-extent, system, invisible and undated records according to the options in force, matches the file name and extension against the mask, applies the date range filter, and then either collects the record in the sort buffer or displays it immediately. Register B holds the record index and register C the drive number throughout.

542D
LD A,(HL) 7E
Load register A with the first byte (the attribute byte) of the directory record. HL points at the record in the 5C00H buffer.
542E
OR A B7
Test the attribute byte (register A); a zero byte marks an empty slot.
542F
If the slot is empty (Z), JUMP to 53E3H to advance to the next record.
5431
LD B,L 45
Save the record offset (register L) into register B as the record index for this slot.
5432
PUSH BC C5
Save the record index (register B) and drive number (register C) across the record's processing.
5433
LD A,L 7D
Copy the record offset (register L) into register A to derive the containing directory sector.
5434
AND 0E0H E6 E0
Mask register A to its top 3 bits, giving the offset of the directory sector holding this record (8 records per 256-byte sector).
5436
LD L,A 6F
Store the sector-aligned offset (register A) into register L.
5437
XOR B A8
Exclusive-OR the original record offset (register B) into register A, isolating the record's position within its sector.
5438
CP 0FFH FE FF
Self-Modifying Code
Compare register A against the last-read sector marker; the 0FFH operand at 5439H is rewritten below so a directory sector already in the buffer is not read again.
543A
If this record is already in the buffer (Z, same sector as last read), JUMP to 5445H skipping the disk read.
543C
LD (5439H),A 32 39 54
Self-Modifying Code
Store this record's in-sector position (register A) into the comparison operand at 5439H, recording which directory sector is now being read.
543F
GOSUB to the resident DIRRD service at 4B10H to read the directory record's sector into the 4200H buffer (record number in register B, drive in register C); it returns NZ on a disk error and register pair HL pointing at the record.
5442
If the directory read failed (NZ), JUMP to the error handler at 5A37H.
5445
LD H,42H 26 42
Set register H to 42H so register pair HL addresses the record inside the shared 4200H directory buffer.
5447
BIT 4,(HL) CB 66
Test bit 4 of the record's attribute byte (at HL), which is set when the directory entry is in use.
5449
If the entry is not in use (Z), JUMP to 53DFH to advance to the next record.
544C
BIT 7,(HL) CB 7E
Test bit 7 of the attribute byte (at HL), which is set for a secondary extent (continuation) directory entry.
544E
If this is a secondary extent (NZ), JUMP to 53DFH to skip it (only primary entries are listed).
5451
BIT 6,(HL) CB 76
Test bit 6 of the attribute byte (at HL), which is set for a system file.
5453
If the file is not a system file (Z), JUMP to 545FH to check the invisible attribute.
5455
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the system-file filter. The operand at 5456H is set nonzero by @PARAM when the S or SYS option is given, and left zero otherwise.
5458
LD A,D 7A
Copy the high byte of the system-file filter (register D) into register A.
5459
OR E B3
OR the low byte (register E) into register A; the Z flag is set when the S/SYS option was not given.
545A
If system files were not requested (Z), JUMP to 53DFH to skip this system file.
545D
System files requested: JUMP to 546BH to continue with the date-stamp filter.
545F
BIT 3,(HL) CB 5E
Test bit 3 of the attribute byte (at HL), which is set for an invisible file.
5461
If the file is not invisible (Z), JUMP to 546BH.
5463
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the invisible-file filter. The operand at 5464H is set nonzero by @PARAM when the I or INV option is given.
5466
LD A,D 7A
Copy the high byte of the invisible-file filter (register D) into register A.
5467
OR E B3
OR the low byte (register E) into register A; the Z flag is set when the I/INV option was not given.
5468
If invisible files were not requested (Z), JUMP to 53DFH to skip this invisible file.
546B
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the date-stamp filter. The operand at 546CH is set nonzero by @PARAM when the MOD option (date-stamped files only) is given.
546E
LD A,D 7A
Copy the high byte of the date-stamp filter (register D) into register A.
546F
OR E B3
OR the low byte (register E) into register A; the Z flag is set when the MOD option was not given.
5470
If the MOD option was not given (Z), JUMP to 5479H to the name match without the date-stamp check.
5472
INC L 2C
Advance register L to the record's second byte (the flags/month byte at offset 1). HL now addresses it.
5473
BIT 6,(HL) CB 76
Test bit 6 of the flags byte (at HL), which is set when the file carries a modification date/time stamp.
5475
If the file has no date stamp (Z) while MOD was requested, JUMP to 53DFH to skip it.
5478
DEC L 2D
Step register L back to the attribute byte so HL again addresses the start of the record.
5479
PUSH HL E5
Save the record pointer (register pair HL) across the name match and date-range filter.
547A
LD A,L 7D
Copy the record offset (register L) into register A to reach the name field.
547B
ADD A,05H C6 05
Add 5 to register A to point at the file name, which begins at offset 5 in the directory record.
547D
LD L,A 6F
Store the adjusted offset (register A) into register L so HL addresses the record's name field.
547E
LD DE,5B6AH 11 6A 5B
Point register pair DE at the 11-byte name/extension match mask at 5B6AH built during command parsing.
5481
LD B,0BH 06 0B
Load register B with 11, the combined length of the name (8) and extension (3) to compare.
5483
LD A,(DE) 1A
Load register A with the next mask character from the match buffer (DE).
5484
CP 24H FE 24
Compare the mask character (register A) against $ (24H), the single-character wildcard.
5486
If the mask character is a wildcard $ (Z), JUMP to 548FH accepting this position.
5488
CP (HL) BE
Compare the mask character (register A) against the directory name character at HL.
5489
If they are equal (Z), JUMP to 548FH accepting this position.
548B
CP 20H FE 20
Compare the mask character (register A) against a space (20H), which matches any trailing character.
548D
If the mask character is not a space and did not match (NZ), JUMP to 549CH to reject the name.
548F
INC HL 23
Advance the directory name pointer HL to the next character.
5490
INC DE 13
Advance the mask pointer DE to the next character.
5491
DECrement register B and LOOP BACK to 5483H until all 11 name and extension positions have been compared.
5493
LD A,(549DH) 3A 9D 54
Load register A with the partial-match flag at 549DH (nonzero when the command used the - substring-match marker).
5496
OR A B7
Test the partial-match flag (register A) for zero.
5497
If partial-match mode is in force (NZ), JUMP to 53DEH to move on (a full match already implies acceptance in that mode).
549A
JUMP to 54A2H to apply the date-range filter to this matched file.
549C
LD A,00H 3E 00
Self-Modifying Code
Load register A with the partial-match flag. This operand at 549DH holds the - marker (nonzero) when substring matching is active, or zero for an exact match.
549E
OR A B7
Test the partial-match flag (register A) for zero.
549F
If exact matching is in force and the name did not match (Z), JUMP to 53DEH to skip this file.
54A2
POP HL E1
Recover the record pointer (register pair HL) saved at 5479H.
54A3
PUSH HL E5
Re-save the record pointer for use after the date filter.
54A4
INC HL 23
Advance register pair HL to the record's date field (the flags/month byte at offset 1).
54A5
GOSUB to the date-decode helper at 57DDH, which reads the packed date from the record (HL) and returns a comparable year/day value in register pair DE.
54A8
LD A,(5BE0H) 3A E0 5B
Load register A with the date-filter mode flag at 5BE0H (bit 7 = start date present, bit 0 = end date present).
54AB
RLCA 07
Rotate register A left so the start-date bit (bit 7) moves into the carry.
54AC
If no start date was given (NO CARRY), JUMP to 54BCH to check the end date.
54AE
LD A,D 7A
Copy the high byte of the file's date (register D) into register A.
54AF
OR E B3
OR the low byte of the file's date (register E) into register A; the Z flag is set when the file has no date.
54B0
If the file has no date (Z) while a start date filters the list, JUMP to 53DEH to skip it.
54B3
LD HL,(5BE5H) 2A E5 5B
Load register pair HL with the start-date compare value from 5BE5H.
54B6
EX DE,HL EB
Exchange DE and HL so HL holds the file date and DE the start date for the comparison.
54B7
RST 18 DF
Call the ROM compare routine (RST 18H, CPDEHL) to compare register pair HL (file date) against DE (start date), setting the carry if HL is below DE.
54B8
EX DE,HL EB
Exchange DE and HL back so register pair DE again holds the file date for the end-date test.
54B9
If the file date is before the start date (CARRY), JUMP to 53DEH to skip it.
54BC
LD A,(5BE0H) 3A E0 5B
Load register A with the date-filter mode flag at 5BE0H again for the end-date test.
54BF
RRCA 0F
Rotate register A right so the end-date bit (bit 0) moves into the carry.
54C0
If no end date was given (NO CARRY), JUMP to 54CEH to decide how the accepted file is emitted.
54C2
LD A,D 7A
Copy the high byte of the file's date (register D) into register A.
54C3
OR E B3
OR the low byte of the file's date (register E) into register A; the Z flag is set when the file has no date.
54C4
If the file has no date (Z) while an end date filters the list, JUMP to 53DEH to skip it.
54C7
LD HL,(5BE7H) 2A E7 5B
Load register pair HL with the end-date compare value from 5BE7H.
54CA
RST 18 DF
Call the ROM compare routine (RST 18H, CPDEHL) to compare register pair HL (end date) against DE (file date), setting the carry when the file date is past the end date.
54CB
If the file date is after the end date (CARRY), JUMP to 53DEH to skip it.
54CE
LD DE,0FFFFH 11 FF FF
Self-Modifying Code
Load register pair DE with the sort-collection flag. This operand at 54CFH is nonzero when the SORT option is active and zero otherwise.
54D1
LD A,D 7A
Copy the high byte of the sort flag (register D) into register A.
54D2
OR E B3
OR the low byte (register E) into register A; the Z flag is set when sorting is not active.
54D3
POP HL E1
Recover the record pointer (register pair HL) saved at 54A3H.
54D4
If sorting is not active (Z), JUMP to 5503H to display this record immediately.
54D6
PUSH HL E5
Save the record pointer (register pair HL) while its sort key is computed.
54D7
GOSUB to the file-size helper at 571FH, which returns the file's size measured across its extents in registers DE and BC for storage as the sort key.
54DA
POP HL E1
Recover the record pointer (register pair HL).
54DB
PUSH HL E5
Re-save the record pointer for the block copy below.
54DC
POP IX DD E1
Copy the record pointer into register pair IX so the size can be written into the record's fields.
54DE
LD (IX+16H),E DD 73 16
Store register E (size low byte) into record offset 16H, part of the field reused to carry the sort key.
54E1
LD (IX+17H),D DD 72 17
Store register D (size high byte) into record offset 17H.
54E4
LD (IX+18H),C DD 71 18
Store register C (size extension low byte) into record offset 18H.
54E7
LD (IX+19H),B DD 70 19
Store register B (size extension high byte) into record offset 19H, completing the 4-byte size key inside the record.
54EA
LD DE,(5BE1H) ED 5B E1 5B
Load register pair DE with the sort-collection append pointer from 5BE1H, the next free slot in the high-memory buffer.
54EE
PUSH HL E5
Save the record pointer (register pair HL) across the copy.
54EF
LD BC,0020H 01 20 00
Load register pair BC with 32, the length of a directory record.
54F2
LDIR ED B0
Block-copy the 32-byte record from the directory buffer (HL) into the sort-collection buffer (DE).
54F4
LD (5BE1H),DE ED 53 E1 5B
Store the advanced append pointer (register pair DE) back into 5BE1H for the next collected record.
54F8
LD HL,(5BE3H) 2A E3 5B
Load register pair HL with the sort-buffer ceiling from 5BE3H.
54FB
SBC HL,DE ED 52
Subtract the append pointer (register pair DE) from the ceiling (register pair HL); a borrow indicates the buffer is full.
54FD
If the buffer still has room (NO CARRY), JUMP to 53DEH to collect the next file.
5500
Otherwise JUMP to 5A29H to report that there is not enough memory for the sort buffer.
5503
Not sorting: GOSUB to the entry-format helper at 5509H to format and display this directory record immediately.
5506
JUMP to 53DFH to advance to the next directory record.

5509H - Format One Directory Line: File Name, Extension and Attribute Letters

Helper that formats and prints one directory entry. This first part emits the file name and extension (padded to a fixed column), then the attribute letters S (system), I (invisible), P (protected/access), the modified marker and the plus marker, each shown as its letter when the attribute is set or a hyphen when it is not. Register pair HL addresses the directory record on entry.

5509
LD A,L 7D
Copy the record offset (register L) into register A to locate the name field.
550A
AND 0E0H E6 E0
Mask register A to the record's base offset within the sector (clearing the low 5 bits).
550C
ADD A,05H C6 05
Add 5 to register A to reach the name field, which begins at offset 5 in the record.
550E
LD L,A 6F
Store the adjusted offset (register A) into register L so HL addresses the name.
550F
LD C,0DH 0E 0D
Load register C with 13, the width of the combined name-and-extension display column, counted down as characters are emitted.
5511
LD B,08H 06 08
Load register B with 8, the maximum number of name characters.
5513
LD A,(HL) 7E
Load register A with the next file-name character from the record (HL).
5514
INC HL 23
Advance the name pointer HL.
5515
CP 20H FE 20
Compare register A against a space (20H), which marks the end of the name.
5517
If the name ended (Z, space), JUMP to 5521H to move to the extension.
5519
GOSUB to the character-output helper at 5789H to display the name character in register A.
551C
DEC C 0D
Decrement the column-width counter in register C for the character just emitted.
551D
DECrement register B and LOOP BACK to 5513H until all 8 name characters have been handled.
551F
JUMP to 5525H to handle the extension.
5521
LD A,L 7D
Copy the name pointer (register L) into register A.
5522
ADD A,B 80
Add the remaining name count (register B) to register A to skip over the unused name positions.
5523
DEC A 3D
Decrement register A to land on the extension field that follows the 8-character name.
5524
LD L,A 6F
Store the extension offset (register A) into register L so HL addresses the extension.
5525
LD A,(HL) 7E
Load register A with the first extension character from the record (HL).
5526
CP 20H FE 20
Compare register A against a space (20H); a space means the file has no extension.
5528
If there is no extension (Z), JUMP to 553EH to pad the column.
552A
LD A,2FH 3E 2F
Load register A with / (2FH), the separator printed before the extension.
552C
GOSUB to 5789H to display the / separator.
552F
DEC C 0D
Decrement the column-width counter (register C) for the separator.
5530
LD B,03H 06 03
Load register B with 3, the maximum number of extension characters.
5532
LD A,(HL) 7E
Load register A with the next extension character from the record (HL).
5533
INC HL 23
Advance the extension pointer HL.
5534
CP 20H FE 20
Compare register A against a space (20H) marking the end of the extension.
5536
If the extension ended (Z), JUMP to 553EH to pad the column.
5538
GOSUB to 5789H to display the extension character in register A.
553B
DEC C 0D
Decrement the column-width counter (register C).
553C
DECrement register B and LOOP BACK to 5532H until all 3 extension characters are handled.
553E
GOSUB to the space-output helper at 5787H to emit a padding space.
5541
DEC C 0D
Decrement the column-width counter (register C) for the padding space.
5542
If the column is not yet full (NZ), LOOP BACK to 553EH to emit another padding space.
5544
LD A,L 7D
Copy the current offset (register L) into register A to return to the record's attribute byte.
5545
AND 0E0H E6 E0
Mask register A back to the record's base offset (the attribute byte at offset 0).
5547
LD L,A 6F
Store the base offset (register A) into register L so HL addresses the attribute byte.
5548
LD B,(HL) 46
Load register B with the record's attribute byte (at HL) for the attribute-letter tests.
5549
BIT 6,B CB 70
Test bit 6 of the attribute byte (register B), set for a system file.
554B
LD A,53H 3E 53
Load register A with S (53H), the system-file letter.
554D
If the file is a system file (NZ), JUMP to 5551H keeping the S.
554F
LD A,2DH 3E 2D
Otherwise load register A with - (2DH) to show the system attribute is off.
5551
GOSUB to 5789H to display the system attribute character (register A).
5554
BIT 3,B CB 58
Test bit 3 of the attribute byte (register B), set for an invisible file.
5556
LD A,49H 3E 49
Load register A with I (49H), the invisible-file letter.
5558
If the file is invisible (NZ), JUMP to 555CH keeping the I.
555A
LD A,2DH 3E 2D
Otherwise load register A with - (2DH).
555C
GOSUB to 5789H to display the invisible attribute character (register A).
555F
PUSH HL E5
Save the attribute-byte pointer (register pair HL).
5560
LD A,L 7D
Copy the record offset (register L) into register A to reach the password/access field.
5561
ADD A,10H C6 10
Add 10H to register A to reach record offset 16H, the update-password / access word.
5563
LD L,A 6F
Store the offset (register A) into register L so HL addresses that word.
5564
LD E,(HL) 5E
Load register E with the low byte of the update-password/access word (at HL).
5565
INC L 2C
Advance register L to the high byte of that word.
5566
LD D,(HL) 56
Load register D with the high byte; register pair DE now holds the update-password/access word.
5567
LD HL,4296H 21 96 42
Load register pair HL with 4296H, the blank-password hash value, for comparison.
556A
SBC HL,DE ED 52
Subtract the record's password word (register pair DE) from the blank-password value (register pair HL); the Z flag is set when the file has no update password.
556C
If the file has no update password (Z), JUMP to 5575H to show a hyphen for the protection column.
556E
LD A,B 78
Load register A with the attribute byte (register B) to test the access level.
556F
AND 07H E6 07
Mask register A to the low 3 bits, the file's access-level field.
5571
LD A,50H 3E 50
Load register A with P (50H), the protected-file letter.
5573
If the file has a restricted access level (NZ), JUMP to 5577H keeping the P.
5575
LD A,2DH 3E 2D
Otherwise load register A with - (2DH) to show no protection.
5577
LD (55C7H),A 32 C7 55
Self-Modifying Code
Store the protection character (register A) into the operand at 55C7H, where the detail formatter at 55C5H reuses it.
557A
GOSUB to 5789H to display the protection character (register A).
557D
POP HL E1
Recover the attribute-byte pointer (register pair HL).
557E
LD A,2AH 3E 2A
Load register A with * (2AH), the modified-since-backup marker.
5580
BIT 5,B CB 68
Test bit 5 of the attribute byte (register B), set when the file has been modified.
5582
If the file has been modified (NZ), JUMP to 5586H keeping the *.
5584
LD A,2DH 3E 2D
Otherwise load register A with - (2DH).
5586
GOSUB to 5789H to display the modified marker (register A).
5589
INC HL 23
Advance register pair HL to the record's flags byte at offset 1.
558A
BIT 6,(HL) CB 76
Test bit 6 of the flags byte (at HL), set when the file carries a date/time stamp.
558C
LD A,2BH 3E 2B
Load register A with + (2BH), the marker shown when a date stamp is present.
558E
If the file has a date stamp (NZ), JUMP to 5592H keeping the +.
5590
LD A,2DH 3E 2D
Otherwise load register A with - (2DH).
5592
GOSUB to 5789H to display the date-stamp marker (register A).
5595
DEC HL 2B
Step register pair HL back to the attribute byte at offset 0.
5596
GOSUB to the space-output helper at 5787H to emit a separating space after the attribute letters.
5599
LD DE,0FFFFH 11 FF FF
Self-Modifying Code
Load register pair DE with the detail-columns flag. This operand at 559AH is nonzero when the A (all detail) or SORT option requests the LRL/records/EOF/size/date columns.
559C
LD A,D 7A
Copy the high byte of the detail flag (register D) into register A.
559D
OR E B3
OR the low byte (register E) into register A; the Z flag is set when detail columns are not wanted.
559E
If detail columns are requested (NZ), GOSUB to 55C5H to append the LRL, record count, EOF, size and modification date/time.
55A1
LD A,00H 3E 00
Self-Modifying Code
Load register A with the output-pass counter. This operand at 55A2H governs the two-across column layout so entries are emitted in pairs per line.
55A3
DEC A 3D
Decrement the pass counter (register A).
55A4
LD (55A2H),A 32 A2 55
Store the decremented pass counter (register A) back into 55A2H.
55A7
RET NZ C0
If the line is not yet complete (NZ, more entries fit across), RETURN to gather the next entry on the same line.
55A8
LD A,03H 3E 03
Load register A with 3 to reset the pass counter for the next output line.
55AA
LD (55A2H),A 32 A2 55
Store the reset pass counter (register A) into 55A2H.
55AD
LD A,(559AH) 3A 9A 55
Load register A with the detail-columns flag at 559AH to decide how the line is terminated.
55B0
OR A B7
Test the detail-columns flag (register A) for zero.
55B1
LD A,0DH 3E 0D
Load register A with a carriage return (0DH) to end the line.
55B3
PUSH AF F5
Save register A (the carriage return) and the detail-flag test result.
55B4
If detail columns were off (Z), GOSUB to 5789H to send the carriage return to the video display.
55B7
POP AF F1
Recover register A (the carriage return) and the detail-flag test result.
55B8
If detail columns were on (NZ), GOSUB to the printer-only helper at 578EH to send the carriage return (the detail line was already sent to the display by the field formatters).
55BB
GOSUB to the paged-display helper at 58F2H to count the line and pause if the screen is full.
55BE
GOSUB to the pause/BREAK helper at 58C7H, which honours a pause key and detects BREAK.
55C1
RET Z C8
If BREAK was not pressed (Z), RETURN to continue the listing.
55C2
If BREAK was pressed, JUMP to 5A3CH to abandon the listing.

55C5H - Detail Columns: Access, LRL, Records, EOF, Granules, Size and Modification Date/Time

Fills the detail portion of the line buffer for the A (all) and SORT listings: the access code, the logical record length, the record count, the end-of-file byte, the granule/extent count, the file size in kilobytes, and the modification date and time. It then displays the assembled line. Register pair HL addresses the directory record on entry.

55C5
PUSH HL E5
Save the record pointer (register pair HL).
55C6
LD A,00H 3E 00
Self-Modifying Code
Load register A with the protection character. This operand at 55C7H was set at 5577H to P or -.
55C8
SUB 2DH D6 2D
Subtract - (2DH) from register A; the Z flag is set when the file is unprotected.
55CA
If the file is unprotected (Z), JUMP to 55CFH using access level 0.
55CC
LD A,(HL) 7E
Load register A with the attribute byte (at HL) of the record.
55CD
AND 07H E6 07
Mask register A to the low 3 bits, the file's access-level field.
55CF
ADD A,A 87
Double register A to form a 2-byte index into the access-code table.
55D0
LD C,A 4F
Copy the index (register A) into register C.
55D1
LD B,00H 06 00
Clear register B so register pair BC is the 16-bit table index.
55D3
LD HL,5AEBH 21 EB 5A
Point register pair HL at the access-code table at 5AEBH (two characters per access level).
55D6
ADD HL,BC 09
Add the index (register pair BC) to HL to select this file's 2-character access code.
55D7
LD DE,5B3CH 11 3C 5B
Point register pair DE at the access field 5B3CH in the detail line buffer.
55DA
LD BC,0002H 01 02 00
Load register pair BC with 2, the length of the access code.
55DD
LDIR ED B0
Block-copy the 2-character access code from the table (HL) into the buffer (DE).
55DF
POP HL E1
Recover the record pointer (register pair HL).
55E0
PUSH HL E5
Re-save the record pointer.
55E1
INC L 2C
Advance register L toward the EOF field.
55E2
INC L 2C
Advance register L again.
55E3
INC L 2C
Advance register L to record offset 3, the end-of-file byte.
55E4
LD A,(HL) 7E
Load register A with the EOF byte (record offset 3), the byte position within the last sector.
55E5
PUSH AF F5
Save the EOF byte (register A) for the record-count and size math.
55E6
INC L 2C
Advance register L to record offset 4, the logical record length.
55E7
LD A,(HL) 7E
Load register A with the logical record length (LRL) byte.
55E8
LD (5603H),A 32 03 56
Self-Modifying Code
Store the LRL (register A) into the operand at 5603H, reused below in the size calculation.
55EB
PUSH HL E5
Save the pointer to the LRL byte (register pair HL).
55EC
LD L,A 6F
Copy the LRL (register A) into register L.
55ED
LD H,00H 26 00
Clear register H so register pair HL is the 16-bit LRL.
55EF
OR A B7
Test the LRL (register A) for zero.
55F0
If the LRL is nonzero (NZ), JUMP to 55F3H.
55F2
INC H 24
An LRL of 0 means 256: set register H so register pair HL is 256.
55F3
INC DE 13
Advance the buffer pointer DE to the LRL display field.
55F4
GOSUB to the decimal-format helper at 5888H to write the LRL (register pair HL) into the buffer at DE.
55F7
POP HL E1
Recover the pointer to the LRL byte (register pair HL).
55F8
LD A,L 7D
Copy the record offset (register L) into register A to reach the ending record number.
55F9
ADD A,10H C6 10
Add 10H to register A to reach record offset 14H, the ending record number (ERN) word.
55FB
LD L,A 6F
Store the offset (register A) into register L so HL addresses the ERN.
55FC
LD E,(HL) 5E
Load register E with the low byte of the ending record number.
55FD
INC L 2C
Advance register L to the high byte of the ERN.
55FE
LD D,(HL) 56
Load register D with the high byte; register pair DE now holds the ending record number.
55FF
POP BC C1
Recover the EOF byte into register B (saved at 55E5H).
5600
PUSH BC C5
Re-save the EOF byte (register B).
5601
EX DE,HL EB
Exchange DE and HL so register pair HL holds the ending record number for the division.
5602
LD A,00H 3E 00
Self-Modifying Code
Load register A with the LRL saved at 55E8H (operand 5603H), the divisor for the record-count math.
5604
OR A B7
Test the LRL (register A) for zero.
5605
If the LRL is zero (Z, whole-sector records), JUMP to 561FH using the ending record number directly.
5607
LD E,A 5F
Copy the LRL (register A) into register E for the second division.
5608
INC B 04
Increment register B to test the EOF byte for zero without altering it lastingly.
5609
DEC B 05
Decrement register B back, setting the Z flag when the EOF byte is zero.
560A
If the EOF byte is zero (Z), JUMP to 560DH.
560C
DEC HL 2B
A nonzero EOF means the last record is partial: decrement the record count in register pair HL.
560D
GOSUB to the resident @DIV service at 44C4H to divide the record count (register pair HL) by the LRL (register A); it returns the quotient in HL and the remainder in register A, converting sector records to logical records.
5610
LD C,L 4D
Copy the quotient low byte (register L) into register C for the second division stage.
5611
LD D,H 54
Copy the quotient high byte (register H) into register D.
5612
LD H,A 67
Move the remainder (register A) into register H as the high byte of the next dividend.
5613
LD L,B 68
Set register L from register B (the EOF-derived low byte) for the next dividend.
5614
LD A,E 7B
Load register A with the LRL (register E) as the divisor.
5615
GOSUB to @DIV at 44C4H again to complete the logical-record-count conversion; quotient in HL, remainder in register A.
5618
LD H,C 61
Set register H from register C (the earlier quotient low byte) to assemble the full record count.
5619
OR A B7
Test the remainder (register A) for zero.
561A
If there is no remainder (Z), JUMP to 561DH.
561C
INC HL 23
A remainder means one more partial record: increment the record count in register pair HL.
561D
LD A,D 7A
Load register A with register D to test the high part of the count for overflow.
561E
OR A B7
Test register A for zero, setting the Z flag when the record count fits the display field.
561F
LD DE,5B43H 11 43 5B
Point register pair DE at the record-count field 5B43H in the detail buffer.
5622
If the record count fits (Z), JUMP to 562EH to format it.
5624
LD HL,5BDBH 21 DB 5B
The count overflows the field: point register pair HL at the 5-character overflow marker (asterisks) at 5BDBH.
5627
LD BC,0005H 01 05 00
Load register pair BC with 5, the marker length.
562A
LDIR ED B0
Block-copy the overflow marker from HL into the record-count field (DE).
562C
JUMP to 5631H to format the EOF field.
562E
GOSUB to the decimal-format helper at 588CH to write the record count (register pair HL) into the buffer at DE.
5631
POP HL E1
Recover the EOF byte in register H (the pushed BC from 5600H).
5632
DEC H 25
Decrement register H (the EOF byte) to form the last-record byte offset.
5633
LD L,H 6C
Copy the EOF value (register H) into register L.
5634
LD H,00H 26 00
Clear register H so register pair HL is the 16-bit EOF value.
5636
LD DE,5B49H 11 49 5B
Point register pair DE at the EOF field 5B49H in the detail buffer.
5639
GOSUB to 5888H to write the EOF value (register pair HL) into the buffer at DE.
563C
POP HL E1
Recover the record pointer (register pair HL) saved at 563DH... the record base for the size fields.
563D
PUSH HL E5
Re-save the record pointer.
563E
GOSUB to the size helper at 5709H, which returns the file's granule/extent count in register pair DE and its size in register pair BC (from the stored sort key when sorting, or computed fresh).
5641
PUSH DE D5
Save the granule/extent count (register pair DE).
5642
LD L,C 69
Copy the size low byte (register C) into register L.
5643
LD H,B 60
Copy the size high byte (register B) into register H; register pair HL is the granule size figure.
5644
LD DE,5B4DH 11 4D 5B
Point register pair DE at the granule/extent field 5B4DH in the detail buffer.
5647
LD A,20H 3E 20
Load register A with a space (20H) as the leading-zero pad character.
5649
GOSUB to the 2-digit decimal helper at 58A0H to write the granule/extent count (register pair HL) into the buffer at DE.
564C
POP DE D1
Recover the granule/extent count (register pair DE) as the value to convert to kilobytes.
564D
LD HL,5B52H 21 52 5B
Point register pair HL at the size-in-kilobytes field 5B52H in the detail buffer.
5650
GOSUB to the decimal-K helper at 5796H to convert the granule count (register pair DE) to a kilobyte figure at the buffer (HL); it returns the tenths digit in register A.
5653
LD (5B58H),A 32 58 5B
Store the tenths digit (register A) into the fractional position 5B58H of the size figure.
5656
LD HL,5B59H 21 59 5B
Point register pair HL at the date-template source 5B59H.
5659
LD DE,5B5AH 11 5A 5B
Point register pair DE at the date field 5B5AH in the detail buffer.
565C
LD BC,000FH 01 0F 00
Load register pair BC with 15, the width of the date/time area to blank.
565F
LDIR ED B0
Block-fill the date/time area (DE) by propagating the blank template (HL) across 15 positions.
5661
POP HL E1
Recover the record pointer (register pair HL).
5662
LD DE,5B5AH 11 5A 5B
Point register pair DE at the date field 5B5AH to fill from the record.
5665
INC HL 23
Advance register pair HL to the record's flags/month byte at offset 1.
5666
BIT 7,(HL) CB 7E
Test bit 7 of the flags byte (at HL), which distinguishes the two date-stamp encodings.
5668
LD A,3AH 3E 3A
Load register A with : (3AH) as the date separator for the time-bearing form.
566A
If bit 7 was set (NZ), JUMP to 566EH keeping the : separator.
566C
LD A,3DH 3E 3D
Otherwise load register A with = (3DH) as the separator.
566E
LD (5B51H),A 32 51 5B
Store the chosen separator (register A) into 5B51H of the detail buffer.
5671
INC HL 23
Advance register pair HL to the record's date byte at offset 2.
5672
LD A,(HL) 7E
Load register A with the packed date byte (at HL); zero means the file has no date stamp.
5673
OR A B7
Test the date byte (register A) for zero.
5674
If the file has no date (Z), JUMP to 56FDH to display the line with a blank date field.
5677
RRCA 0F
Rotate register A right to begin extracting the month field from the packed date.
5678
RRCA 0F
Rotate register A right again.
5679
RRCA 0F
Rotate register A right a third time, aligning the month field.
567A
AND 1FH E6 1F
Mask register A to 5 bits, isolating the month number.
567C
LD B,2FH 06 2F
Load register B with 2FH so the tens-of-month digit starts at 0 minus one.
567E
INC B 04
Increment the tens digit (register B) for each ten counted off the month.
567F
SUB 0AH D6 0A
Subtract 10 from the month (register A).
5681
If the month is still 10 or more (NO CARRY), LOOP BACK to 567EH to count another ten.
5683
ADD A,3AH C6 3A
Add 3AH to the remainder (register A) to convert the units of the month to an ASCII digit (correcting the over-subtraction).
5685
PUSH AF F5
Save the units digit (register A).
5686
LD A,B 78
Load register A with the tens digit (register B).
5687
LD (DE),A 12
Store the tens-of-month digit (register A) into the date field (DE).
5688
INC DE 13
Advance the date-field pointer DE.
5689
POP AF F1
Recover the units-of-month digit (register A).
568A
LD (DE),A 12
Store the units-of-month digit (register A) into the date field (DE).
568B
INC DE 13
Advance the date-field pointer DE.
568C
LD A,2DH 3E 2D
Load register A with - (2DH), the date separator.
568E
LD (DE),A 12
Store the separator (register A) into the date field (DE).
568F
INC DE 13
Advance the date-field pointer DE.
5690
PUSH HL E5
Save the record date pointer (register pair HL).
5691
DEC HL 2B
Step register pair HL back to the flags/month byte (offset 1) to read the day.
5692
LD A,(HL) 7E
Load register A with the flags/month byte, whose low nibble carries the month for the month-name lookup.
5693
AND 0FH E6 0F
Mask register A to the low nibble, the 1-to-12 month number.
5695
DEC A 3D
Decrement register A to a 0-based month index.
5696
LD C,A 4F
Copy the month index (register A) into register C.
5697
RLCA 07
Double register A (times 2).
5698
ADD A,C 81
Add the month index (register C) to make the index times 3 (3-character month names).
5699
LD C,A 4F
Copy the scaled index (register A) into register C.
569A
LD B,00H 06 00
Clear register B so register pair BC is the 16-bit month-name index.
569C
LD HL,5BB7H 21 B7 5B
Point register pair HL at the 3-character month-name table at 5BB7H.
569F
ADD HL,BC 09
Add the index (register pair BC) to HL to select this month's name.
56A0
LD C,03H 0E 03
Load register C with 3, the month-name length.
56A2
LDIR ED B0
Block-copy the 3-character month name from the table (HL) into the date field (DE).
56A4
LD A,2DH 3E 2D
Load register A with - (2DH), the separator before the year.
56A6
LD (DE),A 12
Store the separator (register A) into the date field (DE).
56A7
INC DE 13
Advance the date-field pointer DE.
56A8
POP HL E1
Recover the record date pointer (register pair HL).
56A9
LD C,38H 0E 38
Load register C with 8 (38H) as the leading digit of the year (198x/200x range).
56AB
LD A,00H 3E 00
Clear register A to select the year path in the shared time/year formatter below.
56AD
OR A B7
Set the Z flag (register A is zero) to mark the year-formatting path.
56AE
PUSH AF F5
Save the path flag (register A and its Z flag).
56AF
If this were the time path (NZ), it would branch to 56B6H; on the year path (Z) it falls through.
56B1
LD A,(HL) 7E
Load register A with the record date byte (at HL) holding the packed year bits.
56B2
AND 07H E6 07
Mask register A to the low 3 bits, the year offset from the decade base.
56B4
JUMP to 56CCH to emit the two year digits.
56B6
LD A,L 7D
Time path: copy the record offset (register L) into register A to reach the time byte.
56B7
ADD A,11H C6 11
Add 11H to register A to reach record offset 12H/13H, the packed modification time.
56B9
LD L,A 6F
Store the offset (register A) into register L so HL addresses the time byte.
56BA
LD A,(HL) 7E
Load register A with the packed time byte (at HL).
56BB
AND 1FH E6 1F
Mask register A to 5 bits, isolating the hour or minute field.
56BD
CP 14H FE 14
Compare register A against 20 to fold values into the two-digit range.
56BF
If the value is below 20 (CARRY), JUMP to 56C5H.
56C1
SUB 14H D6 14
Subtract 20 from register A.
56C3
LD C,30H 0E 30
Set register C to 0 (30H) plus the tens carried, seeding the tens digit.
56C5
CP 0AH FE 0A
Compare register A against 10 to separate tens from units.
56C7
If below 10 (CARRY), JUMP to 56CCH with the units in register A.
56C9
INC C 0C
Increment the tens digit (register C).
56CA
SUB 0AH D6 0A
Subtract 10 from register A, leaving the units.
56CC
LD B,A 47
Save the units value (register A) into register B.
56CD
LD A,C 79
Load register A with the tens digit character (register C).
56CE
LD (DE),A 12
Store the tens digit (register A) into the field (DE).
56CF
INC DE 13
Advance the field pointer DE.
56D0
LD A,B 78
Load register A with the units value (register B).
56D1
ADD A,30H C6 30
Add 0 (30H) to convert the units to an ASCII digit.
56D3
LD (DE),A 12
Store the units digit (register A) into the field (DE).
56D4
POP AF F1
Recover the path flag saved at 56AEH (Z on the year path, NZ on the time path).
56D5
If this was the year path (Z), JUMP to 56FDH to display the completed line.
56D7
LD A,(HL) 7E
Time path: load register A with the time byte (at HL) again for the minutes.
56D8
DEC HL 2B
Step register pair HL back one byte.
56D9
LD L,(HL) 6E
Load register L from the preceding byte, forming the pointer to the minute field.
56DA
LD B,03H 06 03
Load register B with 3 as the shift count to align the minutes field.
56DC
SRL L CB 3D
Shift register L right through carry, moving the minutes bits down.
56DE
RRA 1F
Rotate register A right through carry, assembling the minutes value.
56DF
DECrement register B and LOOP BACK to 56DCH to complete the 3-bit alignment.
56E1
RRA 1F
Rotate register A right once more.
56E2
RRA 1F
Rotate register A right again to finish positioning the minutes.
56E3
AND 3FH E6 3F
Mask register A to 6 bits, isolating the 0-to-59 minutes value.
56E5
PUSH AF F5
Save the minutes value (register A).
56E6
LD H,00H 26 00
Clear register H for the 2-digit format call.
56E8
LD DE,5B64H 11 64 5B
Point register pair DE at the minutes position 5B64H in the time field.
56EB
LD A,30H 3E 30
Load register A with 0 (30H) as the leading-zero pad.
56ED
GOSUB to the 2-digit decimal helper at 58A0H to write the hours (register pair HL) into the field at DE.
56F0
LD A,3AH 3E 3A
Load register A with : (3AH), the hours/minutes separator.
56F2
LD (DE),A 12
Store the : separator (register A) into the time field (DE).
56F3
INC DE 13
Advance the time-field pointer DE.
56F4
POP AF F1
Recover the minutes value (register A).
56F5
LD L,A 6F
Copy the minutes value (register A) into register L.
56F6
LD H,00H 26 00
Clear register H so register pair HL is the 16-bit minutes value.
56F8
LD A,30H 3E 30
Load register A with 0 (30H) as the leading-zero pad.
56FA
GOSUB to 58A0H to write the minutes (register pair HL) into the time field at DE.
56FD
LD HL,5B3CH 21 3C 5B
Point register pair HL at the assembled detail line at 5B3CH.
5700
GOSUB to the display helper at 577CH to send the detail line (HL) to the video and, when the P option is active, to the printer.
5703
LD A,01H 3E 01
Load register A with 1, the pass count for the detail (one-per-line) layout.
5705
LD (55A2H),A 32 A2 55
Store 1 into the pass counter at 55A2H so each detail entry occupies its own line.
5708
RET C9
RETURN to the caller (the format routine at 559EH).

5709H - File-Size Helpers: Stored Key and Extent Walk

Returns a file's granule/extent count in register pair DE and its size measure in register pair BC. When sorting, the value was pre-computed and stored in the record; otherwise it is computed here by walking the file's extents, following the secondary-extent (FXDE) chain and reading further directory sectors as needed.

5709
LD A,(54CFH) 3A CF 54
Load register A with the sort-collection flag at 54CFH (nonzero while a SORT listing is being displayed from the buffer).
570C
OR A B7
Test the sort flag (register A) for zero.
570D
If not sorting (Z), JUMP to 571FH to compute the size fresh from the extents.
570F
PUSH HL E5
Save the record pointer (register pair HL).
5710
POP IX DD E1
Move the record pointer into register pair IX to read the stored size key.
5712
LD E,(IX+16H) DD 5E 16
Load register E from record offset 16H, the low byte of the stored granule/extent count.
5715
LD D,(IX+17H) DD 56 17
Load register D from record offset 17H, completing the granule/extent count in register pair DE.
5718
LD C,(IX+18H) DD 4E 18
Load register C from record offset 18H, the low byte of the stored size measure.
571B
LD B,(IX+19H) DD 46 19
Load register B from record offset 19H, completing the size measure in register pair BC.
571E
RET C9
RETURN with the stored granule/extent count in DE and size in BC.
571F
LD DE,0000H 11 00 00
Clear register pair DE to accumulate the granule count.
5722
LD BC,0000H 01 00 00
Clear register pair BC to count the extents.
5725
LD A,L 7D
Copy the record offset (register L) into register A to reach the extent list.
5726
ADD A,16H C6 16
Add 16H to register A to reach record offset 16H, the start of the four 2-byte extents.
5728
LD L,A 6F
Store the offset (register A) into register L so HL addresses the extents.
5729
LD A,(HL) 7E
Load register A with the extent's starting cylinder byte (at HL).
572A
INC L 2C
Advance register L to the extent's granule byte.
572B
CP 0FEH FE FE
Compare register A against 0FEH; values 0FEH (link) and 0FFH (end) mark the end of the extents in this record.
572D
If this is a link or end marker (NO CARRY), JUMP to 573CH to follow the FXDE chain or finish.
572F
INC BC 03
Count this extent by incrementing register pair BC.
5730
LD A,(HL) 7E
Load register A with the extent's granule byte (at HL).
5731
INC L 2C
Advance register L to the next extent.
5732
AND 1FH E6 1F
Mask register A to the low 5 bits, the granule-count-minus-one of this extent.
5734
INC A 3C
Increment register A to the true granule count of this extent.
5735
ADD A,E 83
Add the running granule total's low byte (register E) to register A.
5736
LD E,A 5F
Store the new low byte (register A) back into register E.
5737
If the granule total did not carry (NO CARRY), LOOP BACK to 5729H for the next extent.
5739
INC D 14
Propagate the carry into the high byte of the granule total (register D).
573A
LOOP BACK to 5729H for the next extent.
573C
RET NZ C0
If the marker was 0FFH (end, NZ from the 0FEH compare), RETURN with the totals in DE and BC.
573D
LD A,(HL) 7E
A link marker (0FEH): load register A with the FXDE link byte (at HL) pointing at the secondary extent record.
573E
AND 1FH E6 1F
Mask register A to the low 5 bits, the secondary record's directory-entry index.
5740
PUSH AF F5
Save the secondary record index (register A).
5741
XOR (HL) AE
Exclusive-OR the raw link byte (at HL) with the masked index to recover the sector-selecting bits.
5742
LD L,A 6F
Store the result (register A) into register L to address the secondary record.
5743
POP AF F1
Recover the secondary record index (register A).
5744
PUSH HL E5
Save the computed record pointer (register pair HL).
5745
LD HL,5439H 21 39 54
Point register pair HL at the last-read directory-sector marker at 5439H.
5748
CP (HL) BE
Compare the secondary record index (register A) against the marker to see if that sector is already in a buffer.
5749
POP HL E1
Recover the record pointer (register pair HL).
574A
LD H,42H 26 42
Set register H to 42H, addressing the primary directory buffer.
574C
If the secondary record is in the 4200H buffer (Z), LOOP BACK to 5725H to sum its extents.
574E
CP 0FFH FE FF
Compare the index (register A) against 0FFH, the marker for the alternate 5D00H buffer.
5750
LD H,5DH 26 5D
Set register H to 5DH, addressing the alternate directory buffer.
5752
If the secondary record is already in the 5D00H buffer (Z), LOOP BACK to 5725H.
5754
LD (574FH),A 32 4F 57
Self-Modifying Code
Store the secondary record index (register A) into the operand at 574FH, recording which record now occupies the 5D00H buffer.
5757
PUSH BC C5
Save the extent count (register pair BC).
5758
PUSH DE D5
Save the granule total (register pair DE).
5759
OR L B5
OR register L into register A to combine the record index with the sector bits.
575A
LD B,A 47
Save the combined value (register A) into register B for the sector calculation.
575B
LD A,(5B02H) 3A 02 5B
Load register A with the ASCII drive digit at 5B02H set for this drive.
575E
SUB 30H D6 30
Subtract 0 (30H) to convert it to a binary drive number.
5760
LD C,A 4F
Copy the drive number (register A) into register C for the read.
5761
GOSUB to the resident DIRCYL service at 4B65H to seek this drive to its directory cylinder.
5764
LD A,B 78
Load register A with the combined record value (register B).
5765
AND 1FH E6 1F
Mask register A to the low 5 bits, the record's sector position.
5767
ADD A,02H C6 02
Add 2 to skip the GAT and HIT sectors, giving the directory sector number.
5769
LD E,A 5F
Copy the sector number (register A) into register E for the read.
576A
LD HL,5D00H 21 00 5D
Point register pair HL at the alternate directory buffer at 5D00H.
576D
GOSUB to the resident RDSSEC service at 4B45H to read the secondary directory sector (register E) into the buffer at HL.
5770
LD A,11H 3E 11
Load register A with 11H (error code 17, directory read error) in case the read failed.
5772
If the read failed (NZ), JUMP to the error handler at 5A37H.
5775
LD A,B 78
Load register A with the combined record value (register B) to form the in-buffer offset.
5776
AND 0E0H E6 E0
Mask register A to the record's base offset within the sector.
5778
POP DE D1
Recover the granule total (register pair DE).
5779
POP BC C1
Recover the extent count (register pair BC).
577A
LOOP BACK to 5726H (register A holds the secondary record base) to sum the extents of the secondary record.

577CH - Output Helpers: Line, Character, Space and Printer

The low-level output primitives. 577CH displays a whole message and echoes it to the printer under the P option; 5787H emits a space; 5789H sends one character to the video and then, via 578EH, to the printer when the P option is active.

577C
GOSUB to the resident @DSPLY service at 4467H to display the carriage-return-terminated message addressed by register pair HL on the video.
577F
LD A,(578FH) 3A 8F 57
Load register A with the printer-echo flag at 578FH, set by the P option.
5782
OR A B7
Test the printer-echo flag (register A) for zero.
5783
If printer echo is on (NZ), JUMP to the resident @PRINT service at 446AH to send the same message (register pair HL) to the printer, whose RET returns to the caller.
5786
RET C9
Otherwise RETURN to the caller.
5787
LD A,20H 3E 20
Load register A with a space (20H), then fall into the character-output helper below.
5789
PUSH AF F5
Save the character in register A across the video call.
578A
CALL 0033H CD 33 00
GOSUB to the ROM display routine @DSP at 0033H to show the character in register A at the cursor.
578D
POP AF F1
Recover the character (register A) for the printer path.
578E
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the printer-echo flag. This operand at 578FH is nonzero when the P option is active.
5791
INC E 1C
Increment register E; when the flag was 0FFH this sets the Z flag to select the printer.
5792
JP Z,003BH CA 3B 00
If printer echo is active (Z), JUMP to the ROM printer routine @PRT at 003BH to print the character in register A; its RET returns to the caller.
5795
RET C9
Otherwise RETURN to the caller.

5796H - Granules-to-Kilobytes Formatter

Converts a granule count in register pair DE to a kilobyte figure written as decimal at the buffer addressed by register pair HL, returning the tenths digit in register A. It multiplies granules by sectors-per-granule to get sectors, divides by four (256 bytes per sector over 1024 bytes per kilobyte), and maps the fractional sectors to a tenths character.

5796
LD (57ABH),HL 22 AB 57
Self-Modifying Code
Store the destination buffer pointer (register pair HL) into the operand at 57ABH used by the LD DE below.
5799
EX DE,HL EB
Exchange DE and HL so register pair HL holds the granule count to convert.
579A
LD A,00H 3E 00
Self-Modifying Code
Load register A with the sectors-per-granule value. This operand at 579BH was set at 52E8H from the drive geometry.
579C
GOSUB to the resident @MULT service at 44C1H to multiply the granule count (register pair HL) by sectors-per-granule (register A), giving the sector count as HL (high 16 bits) and register A (low byte).
579F
PUSH AF F5
Save the product's low byte (register A), which carries the fractional sectors.
57A0
LD H,L 65
Move the product's mid byte (register L) into register H.
57A1
LD L,A 6F
Move the product's low byte (register A) into register L; register pair HL is now the 16-bit sector count.
57A2
SRL H CB 3C
Shift the sector count high byte (register H) right, dividing by two.
57A4
RR L CB 1D
Rotate the low byte (register L) right through carry to complete the divide-by-two.
57A6
SRL H CB 3C
Shift register H right again, dividing by four in total.
57A8
RR L CB 1D
Rotate register L right again; register pair HL now holds the size in kilobytes (256 bytes per sector, 4 sectors per kilobyte).
57AA
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the destination buffer pointer saved at 5796H (operand 57ABH).
57AD
GOSUB to the 5-digit decimal helper at 588CH to write the kilobyte value (register pair HL) into the buffer at DE.
57B0
POP AF F1
Recover the fractional-sectors byte (register A).
57B1
AND 03H E6 03
Mask register A to the low 2 bits, the remainder of the divide-by-four (quarter-kilobyte units).
57B3
LD B,A 47
Copy the quarter count (register A) into register B for the mapping below.
57B4
LD A,30H 3E 30
Load register A with 0 (30H), the tenths digit for a zero remainder.
57B6
RET Z C8
If the remainder is zero (Z), RETURN with tenths 0.
57B7
DEC B 05
Decrement the quarter count (register B).
57B8
LD A,32H 3E 32
Load register A with 2 (32H), the tenths digit for a quarter (.25 rounded to .2).
57BA
RET Z C8
If the remainder was one quarter (Z), RETURN with tenths 2.
57BB
DEC B 05
Decrement the quarter count (register B) again.
57BC
LD A,35H 3E 35
Load register A with 5 (35H), the tenths digit for a half (.5).
57BE
RET Z C8
If the remainder was two quarters (Z), RETURN with tenths 5.
57BF
LD A,38H 3E 38
Otherwise load register A with 8 (38H), the tenths digit for three quarters (.75 rounded to .8).
57C1
RET C9
RETURN with the tenths digit in register A.

57C2H - Copy File-Name Field with Upper-Case Folding

Copies up to register B characters of a file name or extension from the command line (register pair HL) into the match buffer (register pair DE), folding lower case to upper case, passing the dollar wildcard through unchanged, and stopping at a delimiter. It returns the terminating character in register A.

57C2
CP 24H FE 24
Compare the current character (register A) against $ (24H), the wildcard, which is copied unchanged.
57C4
If the character is a wildcard (Z), JUMP to 57D6H to store it as is.
57C6
CP 41H FE 41
Compare register A against A (41H) to classify letters.
57C8
If the character is A or above (NO CARRY), JUMP to 57D0H to handle possible lower case.
57CA
CP 3AH FE 3A
Compare register A against : (3AH); characters from : up to below A are delimiters.
57CC
RET NC D0
If the character is : or above but below A (NO CARRY), RETURN; the name field ended.
57CD
CP 30H FE 30
Compare register A against 0 (30H).
57CF
RET C D8
If the character is below 0 (CARRY, a delimiter), RETURN.
57D0
CP 61H FE 61
Compare register A against a (61H) to detect lower-case letters.
57D2
If the character is below a (CARRY, already upper case or a digit), JUMP to 57D6H to store it.
57D4
XOR 20H EE 20
Exclusive-OR register A with 20H to fold the lower-case letter to upper case.
57D6
LD (DE),A 12
Store the character (register A) into the match buffer (DE).
57D7
INC DE 13
Advance the match-buffer pointer DE.
57D8
LD A,(HL) 7E
Load register A with the next command-line character (at HL).
57D9
INC HL 23
Advance the command-line pointer HL.
57DA
DECrement register B and LOOP BACK to 57C2H until the field length is exhausted.
57DC
RET C9
RETURN with the terminating character in register A.

57DDH - Decode a Directory Date to a Comparable Value

Reads the packed modification date from a directory record (register pair HL at the flags/month byte) and returns a single comparable year/day value in register pair DE, drawing the year either from the record's short field or, when extended dating is enabled for the drive, from the extended-date word.

57DD
LD A,(HL) 7E
Load register A with the flags/month byte (record offset 1) at HL.
57DE
AND 0FH E6 0F
Mask register A to the low nibble, the month number 1 to 12.
57E0
LD E,00H 1E 00
Clear register E to begin assembling the comparable value.
57E2
SRL A CB 3F
Shift the month (register A) right, moving its low bit into the carry.
57E4
RR E CB 1B
Rotate register E right through carry, capturing that month bit at the top of the value.
57E6
LD D,A 57
Store the remaining month bits (register A) into register D as the high part of the comparable value.
57E7
INC HL 23
Advance register pair HL to the record's date byte at offset 2.
57E8
LD A,(HL) 7E
Load register A with the packed date byte (day and year bits).
57E9
AND 0F8H E6 F8
Mask register A to the top 5 bits, the day of the month.
57EB
RRCA 0F
Rotate register A right to position the day field.
57EC
OR E B3
OR the captured month bit (register E) into register A.
57ED
LD E,A 5F
Store the combined day/month low part (register A) into register E.
57EE
LD A,(56ACH) 3A AC 56
Load register A with the extended-dating flag at 56ACH (0FFH when this drive records the year in the extended field).
57F1
OR A B7
Test the extended-dating flag (register A) for zero.
57F2
If extended dating is enabled (NZ), JUMP to 57FDH to take the year from the extended field.
57F4
LD A,(HL) 7E
Short-date path: load register A with the date byte (at HL) again for its year bits.
57F5
AND 07H E6 07
Mask register A to the low 3 bits, the year offset within the decade.
57F7
RLCA 07
Rotate register A left to position the year field in the high part of the value.
57F8
RLCA 07
Rotate register A left again.
57F9
RLCA 07
Rotate register A left a third time.
57FA
OR D B2
OR the month high bits (register D) into register A.
57FB
LD D,A 57
Store the combined year/month high part (register A) into register D; register pair DE is now the comparable date value.
57FC
RET C9
RETURN with the comparable date in register pair DE.
57FD
LD A,L 7D
Extended-date path: copy the record offset (register L) into register A to reach the extended-date field.
57FE
ADD A,11H C6 11
Add 11H to register A to reach record offset 12H/13H, the extended date/year word.
5800
LD L,A 6F
Store the offset (register A) into register L so HL addresses the extended-year byte.
5801
LD A,(HL) 7E
Load register A with the extended-year byte (at HL).
5802
AND 1FH E6 1F
Mask register A to 5 bits, the extended year offset from 1980.
5804
JUMP back to 57F7H to fold the year into the comparable value.

5806H - Parse a Date Argument and Validate It

Parses an MM/DD/YY date field from the command line (register pair HL), validates the month against 12 and the day against the days-in-month table (allowing for a leap year), packs it into the comparable year/day form in register pair BC, and jumps to the parameter-error handler on any bad value. Helpers 5856H, 586BH and 5881H parse the individual fields.

5806
LD A,(HL) 7E
Load register A with the first date character from the command line (at HL).
5807
LD C,2FH 0E 2F
Load register C with / (2FH), the date-field separator for the field parser.
5809
GOSUB to the three-field parser at 5856H to read month, day and year into the scratch cells 5BEBH, 5BEAH and 5BE9H; it returns NZ on a malformed field.
580C
If the date was malformed (NZ), JUMP to the parameter-error handler at 5A2DH.
580F
LD A,(DE) 1A
Load register A with the parsed year value (DE addresses the year scratch cell).
5810
CP 0CH FE 0C
Compare the year (register A) against 12 to distinguish two-digit years in the 2000s from those in the 1900s.
5812
If the year is 12 or more (NO CARRY, a 19xx year), JUMP to 5817H.
5814
ADD A,64H C6 64
Otherwise add 100 (64H) to the year (register A) to place a 00-to-11 value in the 2000-to-2011 range.
5816
LD (DE),A 12
Store the adjusted year (register A) back into the year scratch cell (DE).
5817
EX DE,HL EB
Exchange DE and HL so register pair HL addresses the year scratch cell for the leap-year test.
5818
AND 03H E6 03
Mask the year (register A) to its low 2 bits; a value of zero marks a leap year.
581A
LD HL,5B77H 21 77 5B
Point register pair HL at the days-in-month table at 5B77H (February's entry is bumped for a leap year).
581D
If it is not a leap year (NZ), JUMP to 5820H leaving February at 28.
581F
INC (HL) 34
Leap year: increment the days-in-month table's leading entry so February allows 29 days.
5820
LD A,(5BEBH) 3A EB 5B
Load register A with the parsed month from 5BEBH.
5823
DEC A 3D
Decrement the month (register A) to a 0-based index.
5824
CP 0CH FE 0C
Compare the month index (register A) against 12 to validate it.
5826
If the month is out of range (NO CARRY, above 12), JUMP to 5833H to report the error.
5828
DEC HL 2B
Step register pair HL back to the base of the days-in-month table.
5829
ADD A,L 85
Add the month index (register A) to register L to index that month's entry.
582A
LD L,A 6F
Store the index (register A) into register L.
582B
If the index did not carry (NO CARRY), JUMP to 582EH.
582D
INC H 24
Propagate the carry into register H so HL correctly addresses the month's day count.
582E
LD A,(5BEAH) 3A EA 5B
Load register A with the parsed day from 5BEAH.
5831
DEC A 3D
Decrement the day (register A) to a 0-based value for the comparison.
5832
CP (HL) BE
Compare the day (register A) against this month's day count (at HL); a day past the count sets NO CARRY.
5833
If the month or day is out of range (NO CARRY), JUMP to the parameter-error handler at 5A2DH.
5836
LD HL,5BEBH 21 EB 5B
Point register pair HL at the parsed month cell 5BEBH to pack the comparable value.
5839
LD B,(HL) 46
Load register B with the month (at HL).
583A
LD C,00H 0E 00
Clear register C to begin packing.
583C
SRL B CB 38
Shift the month (register B) right, moving its low bit into the carry.
583E
RR C CB 19
Rotate register C right through carry, capturing the month bit at the top.
5840
DEC HL 2B
Step register pair HL back to the parsed day cell.
5841
LD A,(HL) 7E
Load register A with the day (at HL).
5842
DEC HL 2B
Step register pair HL back to the parsed year cell.
5843
RLCA 07
Rotate the day (register A) left to position it.
5844
RLCA 07
Rotate the day (register A) left again.
5845
OR C B1
OR the captured month bit (register C) into the day (register A).
5846
LD C,A 4F
Store the combined day/month low part (register A) into register C.
5847
LD A,(HL) 7E
Load register A with the year (at HL).
5848
SUB 50H D6 50
Subtract 80 (50H) from the year (register A) to make it an offset from 1980.
584A
CP 70H FE 70
Compare the year offset (register A) against 112 to catch out-of-range years.
584C
If the year offset is in range (CARRY), JUMP to 584FH.
584E
XOR A AF
Otherwise clear register A, forcing an out-of-range year to zero.
584F
RLCA 07
Rotate the year offset (register A) left to position it in the value.
5850
RLCA 07
Rotate the year offset (register A) left again.
5851
RLCA 07
Rotate the year offset (register A) left a third time.
5852
OR B B0
OR the month high bit (register B) into register A.
5853
LD B,A 47
Store the combined year/month high part (register A) into register B; register pair BC is now the comparable date value.
5854
EX DE,HL EB
Exchange DE and HL to restore the command-line pointer into register pair HL.
5855
RET C9
RETURN with the packed comparable date in register pair BC.

5856H - Date-Field and Number Parsers

Supporting parsers for the date argument: 5856H reads three separator-delimited numeric fields into consecutive scratch cells; 586BH reads a one- or two-digit decimal number; and 5881H converts a single ASCII digit to binary and reports whether it was a valid digit.

5856
LD DE,5BEBH 11 EB 5B
Point register pair DE at the highest date scratch cell 5BEBH (the fields are stored downward).
5859
LD B,03H 06 03
Load register B with 3, the number of date fields (month, day, year).
585B
PUSH DE D5
Save the scratch-cell pointer (register pair DE).
585C
GOSUB to the number parser at 586BH to read one decimal field from the command line (register pair HL) into register A.
585F
POP DE D1
Recover the scratch-cell pointer (register pair DE).
5860
RET NZ C0
If the field was invalid (NZ), RETURN reporting the error.
5861
LD (DE),A 12
Store the parsed field value (register A) into the scratch cell (DE).
5862
DEC B 05
Decrement the remaining-field count (register B).
5863
RET Z C8
If all three fields are read (Z), RETURN success.
5864
DEC DE 1B
Step the scratch-cell pointer DE down to the next field's cell.
5865
LD A,(HL) 7E
Load register A with the separator character following the field (at HL).
5866
INC HL 23
Advance the command-line pointer HL past the separator.
5867
CP C B9
Compare the character (register A) against the expected separator (register C, the /).
5868
If the separator matched (Z), LOOP BACK to 585BH to read the next field.
586A
RET C9
Otherwise RETURN (NZ), leaving the caller to treat the value as complete or malformed.
586B
GOSUB to the digit converter at 5881H to read the first digit; NO CARRY marks a non-digit.
586E
If the first character is not a digit (NO CARRY), JUMP to 587FH to report the error.
5870
LD E,A 5F
Save the first digit value (register A) into register E.
5871
RLCA 07
Double register A (times 2).
5872
RLCA 07
Double register A again (times 4).
5873
ADD A,E 83
Add the saved digit (register E) to make the digit times 5.
5874
RLCA 07
Double register A to make the digit times 10.
5875
LD E,A 5F
Save the tens value (register A) into register E.
5876
GOSUB to 5881H to read the second digit.
5879
If there is no second digit (NO CARRY, a one-digit number), JUMP to 587FH.
587B
ADD A,E 83
Add the tens value (register E) to the units (register A) to form the two-digit number.
587C
LD E,A 5F
Store the number (register A) into register E.
587D
CP A BF
Set the Z flag (register A equals itself) to report success.
587E
RET C9
RETURN with the parsed number in register E and register A (success, Z).
587F
OR A B7
For a one-digit number, clear the carry and set flags on the accumulated value in register A.
5880
RET C9
RETURN with the one-digit value.
5881
LD A,(HL) 7E
Load register A with the next command-line character (at HL).
5882
INC HL 23
Advance the command-line pointer HL.
5883
SUB 30H D6 30
Subtract 0 (30H) to convert the character to a binary digit value.
5885
CP 0AH FE 0A
Compare the value (register A) against 10; a valid digit sets the carry, a non-digit clears it.
5887
RET C9
RETURN with the digit value in register A and the carry marking validity.

5888H - Decimal Formatters

Right-justified decimal output into a buffer (register pair DE) from a 16-bit value (register pair HL). Entry points select the field width: 5888H and 588CH format up to five digits, 589AH three, and 58A0H two. Leading zeros are shown as the pad character in register A. 58ACH extracts one decimal digit for a given power of ten.

5888
LD A,20H 3E 20
Load register A with a space (20H) as the leading-zero pad, then fall into the 5-digit formatter.
588A
JUMP to 589AH to format from the hundreds place (the value is under 1000 here).
588C
LD A,20H 3E 20
Load register A with a space (20H) as the leading-zero pad for the 5-digit form.
588E
LD BC,2710H 01 10 27
Load register pair BC with 10000 to extract the ten-thousands digit.
5891
GOSUB to 58ACH to emit the ten-thousands digit of register pair HL into the buffer (DE).
5894
LD BC,03E8H 01 E8 03
Load register pair BC with 1000 for the thousands digit.
5897
GOSUB to 58ACH to emit the thousands digit.
589A
LD BC,0064H 01 64 00
Load register pair BC with 100 for the hundreds digit.
589D
GOSUB to 58ACH to emit the hundreds digit.
58A0
LD BC,000AH 01 0A 00
Load register pair BC with 10 for the tens digit (the 2-digit entry point).
58A3
GOSUB to 58ACH to emit the tens digit.
58A6
LD A,L 7D
Load register A with the remaining units (register L).
58A7
ADD A,30H C6 30
Add 0 (30H) to convert the units to an ASCII digit.
58A9
LD (DE),A 12
Store the units digit (register A) into the buffer (DE).
58AA
INC DE 13
Advance the buffer pointer DE.
58AB
RET C9
RETURN with the number formatted into the buffer.
58AC
PUSH DE D5
Save the buffer pointer (register pair DE) across the digit extraction.
58AD
LD E,A 5F
Save the pad character (register A) into register E.
58AE
LD D,0FFH 16 FF
Set register D to 0FFH so the count below starts at zero after the first increment.
58B0
XOR A AF
Clear register A (and the carry) before the subtraction.
58B1
INC D 14
Increment the digit counter (register D) for each successful subtraction of the power of ten.
58B2
SBC HL,BC ED 42
Subtract the power of ten (register pair BC) from the value (register pair HL).
58B4
If the value did not go negative (NO CARRY), LOOP BACK to 58B0H to subtract again.
58B6
ADD HL,BC 09
Add the power of ten (register pair BC) back once to restore the remainder in register pair HL.
58B7
LD A,E 7B
Recover the pad character (register E) into register A.
58B8
LD B,D 42
Copy the digit count (register D) into register B for the leading-zero test.
58B9
POP DE D1
Recover the buffer pointer (register pair DE).
58BA
LD (DE),A 12
Store the pad character (register A) into the buffer position, in case the digit is a suppressed leading zero.
58BB
INC B 04
Increment register B to test the digit count for zero.
58BC
DEC B 05
Decrement register B back, setting the Z flag when the digit is zero.
58BD
If the digit is zero (Z, leading zero), JUMP to 58C5H leaving the pad character in place.
58BF
LD A,B 78
Load register A with the digit value (register B).
58C0
ADD A,30H C6 30
Add 0 (30H) to convert the digit to ASCII.
58C2
LD (DE),A 12
Store the ASCII digit (register A) into the buffer (DE), overwriting the pad.
58C3
LD A,30H 3E 30
Load register A with 0 (30H) so once a nonzero digit is seen, later zeros are printed rather than padded.
58C5
INC DE 13
Advance the buffer pointer DE to the next digit position.
58C6
RET C9
RETURN with this digit written and register A holding the updated pad character.

58C7H - Pause/BREAK Check and Keyboard-Flag Reset

Honours a keyboard pause and detects BREAK between listing lines, using the resident keyboard flag KFLAG$ (4423H) and the ROM keyboard scan. 58E8H resets the keyboard flag at the start of the command. The check is skipped unless the command is running at the LDOS command level.

58C7
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag SFLAG$ at 430FH, whose bit 5 marks that the command is not at the LDOS command level.
58CA
AND 20H E6 20
Mask register A to bit 5, the not-command-level flag.
58CC
XOR 20H EE 20
Invert bit 5 so the Z flag is set when the command is not at the command level.
58CE
RET Z C8
If not at the command level (Z), RETURN without pausing.
58CF
LD A,(4423H) 3A 23 44
Load register A with the resident keyboard flag KFLAG$ at 4423H (bit 0 = pause requested, bit 1 = BREAK).
58D2
BIT 0,A CB 47
Test bit 0 of KFLAG$ (register A), the pause request.
58D4
RET NZ C0
If a pause is not being held (NZ), RETURN to continue the listing.
58D5
BIT 1,A CB 4F
Test bit 1 of KFLAG$ (register A), the BREAK flag.
58D7
RET Z C8
If BREAK was not pressed (Z), RETURN to continue.
58D8
LD A,(4423H) 3A 23 44
Pause loop: reload the keyboard flag KFLAG$ (4423H) into register A.
58DB
BIT 0,A CB 47
Test bit 0 of KFLAG$ (register A), the pause request.
58DD
RET NZ C0
If the pause has been released (NZ), RETURN to resume the listing.
58DE
CALL 002BH CD 2B 00
GOSUB to the ROM keyboard-scan routine @KBD at 002BH to sample a key while paused.
58E1
OR A B7
Test the returned key (register A) for none pressed (zero).
58E2
If no key is pressed (Z), LOOP BACK to 58D8H to keep waiting.
58E4
CP 60H FE 60
Compare the key (register A) against 60H (a shift/graphics code to ignore).
58E6
If that code was seen (Z), LOOP BACK to 58D8H to keep waiting.
58E8
LD A,(4423H) 3A 23 44
Reset entry (also called at overlay start): load the keyboard flag KFLAG$ (4423H) into register A.
58EB
AND 0F8H E6 F8
Clear the low 3 bits of register A, resetting the pause, BREAK and related keyboard flags.
58ED
LD (4423H),A 32 23 44
Store the cleared flags (register A) back into KFLAG$ (4423H).
58F0
XOR A AF
Clear register A and set the Z flag to report no BREAK.
58F1
RET C9
RETURN with the keyboard flags reset.

58F2H - Paged-Display Line Counter and Separator

Counts displayed lines and, when a screen is full and pausing is enabled, waits for a key (honouring BREAK to abort and C/space to run non-stop) and reprints the column headings. 5921H prints the column-heading line and a 64-character rule beneath the drive header.

58F2
LD A,00H 3E 00
Self-Modifying Code
Load register A with the remaining-lines counter. This operand at 58F3H was set to 15 and is decremented per line.
58F4
DEC A 3D
Decrement the line counter (register A) for the line just shown.
58F5
LD (58F3H),A 32 F3 58
Store the decremented counter (register A) back into 58F3H.
58F8
RET NZ C0
If the screen is not yet full (NZ), RETURN.
58F9
LD A,0FH 3E 0F
The screen is full: load register A with 15 to reset the line counter.
58FB
LD (58F3H),A 32 F3 58
Store 15 (register A) into the line counter at 58F3H for the next screen.
58FE
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the suppress-pause flag. This operand at 58FFH is nonzero to run non-stop (set for printer output or after a C keypress).
5901
LD A,E 7B
Copy the low byte of the suppress-pause flag (register E) into register A.
5902
OR D B2
OR the high byte (register D) into register A; the Z flag is set when pausing is enabled.
5903
RET NZ C0
If pausing is suppressed (NZ), RETURN without stopping.
5904
LD A,(430FH) 3A 0F 43
Load register A with the system flag SFLAG$ at 430FH to check the command level.
5907
AND 20H E6 20
Mask register A to bit 5, the not-command-level flag.
5909
RET NZ C0
If not at the command level (NZ), RETURN without pausing.
590A
CALL 0049H CD 49 00
GOSUB to the ROM wait-for-key routine @KEY at 0049H to wait for the operator at the full screen.
590D
CP 01H FE 01
Compare the key (register A) against 01H, the BREAK code.
590F
If BREAK was pressed (Z), JUMP to 5A3CH to abandon the listing.
5912
SUB 43H D6 43
Subtract C (43H) from the key (register A) to test for the continuous-listing key.
5914
If the key was C (Z), JUMP to 591AH to disable further pausing.
5916
SUB 20H D6 20
Subtract 20H to test for lower-case c as well.
5918
If the key was neither C nor c (NZ), JUMP to 591EH to just clear the screen and continue.
591A
LD (58FFH),DE ED 53 FF 58
Store register pair DE (nonzero here) into the suppress-pause flag at 58FFH so the rest of the listing runs non-stop.
591E
CALL 01C9H CD C9 01
GOSUB to the ROM clear-screen routine at 01C9H to clear the display before continuing, then fall into the separator to reprint the headings.
5921
LD A,(559AH) 3A 9A 55
Load register A with the detail-columns flag at 559AH (nonzero when the A or SORT option is active).
5924
OR A B7
Test the detail-columns flag (register A) for zero.
5925
RET Z C8
If the detail columns are not shown (Z), RETURN without a heading rule.
5926
LD HL,5AABH 21 AB 5A
Point register pair HL at the column-heading line at 5AABH (Filespec / Attrib / LRL / #Recs / EOF / DE / File Size / MOD Date Time).
5929
GOSUB to the display helper at 577CH to show the column-heading line (HL).
592C
LD A,0DH 3E 0D
Load register A with a carriage return (0DH).
592E
GOSUB to 5789H to send the carriage return to the display.
5931
GOSUB back to 58F2H to count the heading line toward the next page pause.
5934
LD B,40H 06 40
Load register B with 64, the width of the underline rule.
5936
LD A,2DH 3E 2D
Load register A with - (2DH), the rule character.
5938
GOSUB to 5789H to display one hyphen of the rule.
593B
DECrement register B and LOOP BACK to 5936H until all 64 hyphens are drawn.
593D
LD A,0DH 3E 0D
Load register A with a carriage return (0DH) to end the rule.
593F
GOSUB to the printer-only helper at 578EH to send the carriage return to the printer.
5942
JUMP to 58F2H (as a tail call) to count the rule line and return.

5944H - Name-Sort Engine (Shell Sort of Collected Entries)

When the SORT option is active, the matching records were gathered in the high-memory buffer from 5E00H. This routine builds a table of pointers to those records, sorts the pointers by file name and extension using a diminishing-gap (Shell) sort, and then displays the records in sorted order through the line formatter at 5509H.

5944
LD HL,(5BE1H) 2A E1 5B
Load register pair HL with the sort-collection append pointer from 5BE1H, one past the last collected record.
5947
LD DE,5E00H 11 00 5E
Load register pair DE with 5E00H, the base of the collected records.
594A
LD (HL),E 73
Store the base low byte (register E) at the end of the collection as a terminator low byte.
594B
INC HL 23
Advance register pair HL.
594C
LD (HL),D 72
Store the base high byte (register D) as the terminator high byte.
594D
DEC HL 2B
Step register pair HL back to the append pointer.
594E
XOR A AF
Clear register A and the carry for the subtraction.
594F
SBC HL,DE ED 52
Subtract the base (register pair DE) from the append pointer (register pair HL), giving the total bytes collected.
5951
RET Z C8
If nothing was collected (Z), RETURN.
5952
LD B,05H 06 05
Load register B with 5, the shift count to divide the byte total by 32 (record size).
5954
SRL H CB 3C
Shift the byte total high byte (register H) right.
5956
RR L CB 1D
Rotate the low byte (register L) right through carry.
5958
DECrement register B and LOOP BACK to 5954H until the total is divided by 32; register pair HL is the record count.
595A
LD B,L 45
Copy the record count low byte (register L) into register B for the pointer-build loop.
595B
PUSH BC C5
Save the record count (register B).
595C
LD (5998H),HL 22 98 59
Store the record count (register pair HL) into 5998H for the sort core.
595F
LD A,L 7D
Copy the count low byte (register L) into register A.
5960
OR H B4
OR the high byte (register H) into register A; the Z flag is set when there are no records.
5961
If there are no records (Z), JUMP to 5984H.
5963
ADD HL,HL 29
Double the record count (register pair HL) to size the 2-byte pointer table.
5964
EX DE,HL EB
Move the pointer-table size into register pair DE.
5965
LD HL,(5BE3H) 2A E3 5B
Load register pair HL with the buffer ceiling from 5BE3H.
5968
XOR A AF
Clear register A and the carry.
5969
SBC HL,DE ED 52
Subtract the pointer-table size (register pair DE) from the ceiling (register pair HL) to check it fits above the records.
596B
If the pointer table would overflow memory (CARRY), JUMP to 5A29H to report insufficient sort memory.
596E
LD HL,(5BE1H) 2A E1 5B
Load register pair HL with the append pointer (5BE1H); the pointer table is built just past the records.
5971
LD DE,5E00H 11 00 5E
Load register pair DE with 5E00H, the first record address.
5974
LD (HL),E 73
Store the record address low byte (register E) into the pointer table (at HL).
5975
INC HL 23
Advance the pointer-table pointer HL.
5976
LD (HL),D 72
Store the record address high byte (register D) into the pointer table.
5977
INC HL 23
Advance the pointer-table pointer HL to the next slot.
5978
LD A,E 7B
Copy the record address low byte (register E) into register A to step to the next record.
5979
ADD A,20H C6 20
Add 32 (one record) to register A.
597B
LD E,A 5F
Store the advanced low byte (register A) into register E.
597C
If the record address did not carry (NO CARRY), JUMP to 597FH.
597E
INC D 14
Propagate the carry into the record address high byte (register D).
597F
DECrement the record count (register B) and LOOP BACK to 5974H until every record has a table entry.
5981
GOSUB to the sort core at 5997H to sort the pointer table by file name.
5984
POP BC C1
Recover the record count into register B for the display loop.
5985
LD HL,(5BE1H) 2A E1 5B
Load register pair HL with the pointer table base (5BE1H).
5988
LD E,(HL) 5E
Load register E with the low byte of the next sorted record pointer (at HL).
5989
INC HL 23
Advance the pointer-table pointer HL.
598A
LD D,(HL) 56
Load register D with the high byte; register pair DE points at the record to display.
598B
INC HL 23
Advance the pointer-table pointer HL to the next entry.
598C
PUSH HL E5
Save the pointer-table pointer (register pair HL).
598D
PUSH BC C5
Save the remaining-record count (register B).
598E
EX DE,HL EB
Move the record pointer into register pair HL for the formatter.
598F
GOSUB to the line formatter at 5509H to display this sorted record (register pair HL).
5992
POP BC C1
Recover the remaining-record count (register B).
5993
POP HL E1
Recover the pointer-table pointer (register pair HL).
5994
DECrement register B and LOOP BACK to 5988H until all sorted records are displayed.
5996
RET C9
RETURN to the drive loop.
5997
LD HL,0000H 21 00 00
Sort core: clear register pair HL to seed the gap.
599A
LD (599EH),HL 22 9E 59
Store zero into the gap cell at 599EH.
599D
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the current gap. This operand at 599EH holds the diminishing sort gap (initialised from the record count on the first pass).
59A0
SRL D CB 3A
Shift the gap high byte (register D) right, halving the gap.
59A2
RR E CB 1B
Rotate the gap low byte (register E) right through carry to complete the halving.
59A4
LD A,D 7A
Copy the halved gap high byte (register D) into register A.
59A5
OR E B3
OR the low byte (register E) into register A; the Z flag is set when the gap has shrunk to zero.
59A6
RET Z C8
If the gap is zero (Z), the sort is complete: RETURN.
59A7
LD (599EH),DE ED 53 9E 59
Store the new gap (register pair DE) back into 599EH.
59AB
LD HL,(5998H) 2A 98 59
Load register pair HL with the record count from 5998H.
59AE
SBC HL,DE ED 52
Subtract the gap (register pair DE) from the count (register pair HL), giving the number of gapped comparisons for this pass.
59B0
LD (5A1FH),HL 22 1F 5A
Store that comparison count (register pair HL) into 5A1FH for the pass loop limit.
59B3
LD HL,0000H 21 00 00
Clear register pair HL to seed the outer index.
59B6
LD (59BAH),HL 22 BA 59
Store zero into the outer-index cell at 59BAH.
59B9
LD HL,0000H 21 00 00
Clear register pair HL to seed the inner index.
59BC
LD (59C0H),HL 22 C0 59
Store zero into the inner-index cell at 59C0H.
59BF
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the outer index. This operand at 59BAH walks the elements to be gap-inserted.
59C2
LD DE,(599EH) ED 5B 9E 59
Load register pair DE with the current gap from 599EH.
59C6
ADD HL,DE 19
Add the gap (register pair DE) to the outer index (register pair HL), giving the compare partner index.
59C7
ADD HL,HL 29
Double register pair HL to convert the index to a 2-byte pointer-table offset.
59C8
PUSH HL E5
Save the partner offset (register pair HL).
59C9
LD HL,(59C0H) 2A C0 59
Load register pair HL with the inner index from 59C0H.
59CC
ADD HL,HL 29
Double the inner index for the 2-byte pointer offset.
59CD
LD BC,(5BE1H) ED 4B E1 5B
Load register pair BC with the pointer-table base from 5BE1H.
59D1
ADD HL,BC 09
Add the base (register pair BC) to the inner offset, giving the address of the inner pointer.
59D2
EX DE,HL EB
Move the inner pointer address into register pair DE.
59D3
POP HL E1
Recover the partner offset (register pair HL).
59D4
ADD HL,BC 09
Add the base (register pair BC) to the partner offset, giving the address of the partner pointer.
59D5
PUSH HL E5
Save the partner pointer address (register pair HL).
59D6
PUSH DE D5
Save the inner pointer address (register pair DE).
59D7
LD B,0BH 06 0B
Load register B with 11, the name/extension length to compare.
59D9
PUSH BC C5
Save the compare length (register B).
59DA
LD A,(HL) 7E
Load register A with the low byte of the partner record pointer (at HL).
59DB
INC HL 23
Advance register pair HL to the high byte.
59DC
LD H,(HL) 66
Load register H with the high byte of the partner record pointer.
59DD
LD L,A 6F
Set register L to the saved low byte; register pair HL now points at the partner record.
59DE
LD BC,0005H 01 05 00
Load register pair BC with 5, the offset to the record's name field.
59E1
ADD HL,BC 09
Add 5 (register pair BC) to HL so it addresses the partner record's name.
59E2
EX DE,HL EB
Swap so register pair HL now holds the inner pointer address and DE the partner name pointer.
59E3
LD A,(HL) 7E
Load register A with the low byte of the inner record pointer (at HL).
59E4
INC HL 23
Advance register pair HL to the high byte.
59E5
LD H,(HL) 66
Load register H with the high byte of the inner record pointer.
59E6
LD L,A 6F
Set register L to the saved low byte; register pair HL now points at the inner record.
59E7
ADD HL,BC 09
Add 5 (register pair BC) so HL addresses the inner record's name.
59E8
POP BC C1
Recover the compare length into register B.
59E9
LD A,(DE) 1A
Load register A with the next character of the partner name (at DE).
59EA
SUB (HL) 96
Subtract the corresponding inner-name character (at HL) from register A to compare them.
59EB
If the partner name sorts before the inner name (CARRY), JUMP to 59F5H to swap the two pointers.
59ED
If the names differ and the partner sorts after (NZ), JUMP to 5A14H leaving them in order.
59EF
INC DE 13
The characters are equal: advance the partner name pointer DE.
59F0
INC HL 23
Advance the inner name pointer HL.
59F1
DECrement the compare length (register B) and LOOP BACK to 59E9H to compare the next character.
59F3
The names are equal: JUMP to 5A14H without swapping.
59F5
POP DE D1
Recover the inner pointer address (register pair DE) for the swap.
59F6
POP HL E1
Recover the partner pointer address (register pair HL).
59F7
LD B,02H 06 02
Load register B with 2, the pointer size to exchange.
59F9
LD C,(HL) 4E
Load register C with a byte of the partner pointer (at HL).
59FA
EX DE,HL EB
Swap to address the inner pointer with register pair HL.
59FB
LD A,(HL) 7E
Load register A with the corresponding byte of the inner pointer (at HL).
59FC
LD (HL),C 71
Store the partner byte (register C) into the inner pointer slot.
59FD
EX DE,HL EB
Swap back to address the partner pointer.
59FE
LD (HL),A 77
Store the inner byte (register A) into the partner pointer slot, completing the exchange of this byte.
59FF
INC HL 23
Advance the partner pointer address HL.
5A00
INC DE 13
Advance the inner pointer address DE.
5A01
DECrement register B and LOOP BACK to 59F9H to swap the second pointer byte.
5A03
LD HL,(599EH) 2A 9E 59
Load register pair HL with the current gap from 599EH.
5A06
EX DE,HL EB
Move the gap into register pair DE.
5A07
LD HL,(59C0H) 2A C0 59
Load register pair HL with the inner index from 59C0H.
5A0A
XOR A AF
Clear register A and the carry.
5A0B
SBC HL,DE ED 52
Subtract the gap (register pair DE) from the inner index (register pair HL) to step the insertion back.
5A0D
LD (59C0H),HL 22 C0 59
Store the stepped-back inner index (register pair HL) into 59C0H.
5A10
If the inner index did not go negative (NO CARRY), LOOP BACK to 59BFH to keep inserting this element.
5A12
Otherwise JUMP to 5A16H to advance to the next element.
5A14
POP DE D1
Recover the inner pointer address (register pair DE), discarded because no swap was needed.
5A15
POP HL E1
Recover the partner pointer address (register pair HL), discarded.
5A16
LD HL,(59BAH) 2A BA 59
Load register pair HL with the outer index from 59BAH.
5A19
INC HL 23
Increment the outer index (register pair HL) to the next element.
5A1A
LD (59BAH),HL 22 BA 59
Store the advanced outer index (register pair HL) into 59BAH.
5A1D
XOR A AF
Clear register A and the carry for the limit test.
5A1E
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the pass comparison limit. This operand at 5A1FH was set at 59B0H to the record count minus the gap.
5A21
SBC HL,DE ED 52
Subtract the limit (register pair DE) from the outer index (register pair HL) to test the end of the pass.
5A23
If the pass is finished (NO CARRY), JUMP to 599DH to halve the gap and start the next pass.
5A26
Otherwise JUMP to 59B9H to process the next element in this pass.

5A29H - Error Handlers and Common Exit

The overlay's error exits. 5A29H reports insufficient sort memory as a message, 5A35H raises a parameter error, and 5A37H raises the disk or drive error whose code is already in register A; all set the failure status and jump to the shared exit at 540CH.

5A29
LD HL,5B82H 21 82 5B
Point register pair HL at the Insufficient memory for SORT buffer message at 5B82H.
5A2C
LD IX,5BA7H DD 21 A7 5B
Deliberate Instruction Overlap
On the fall-through this loads register pair IX with 5BA7H and is inert; the message pointer was already set to 5B82H ("Insufficient memory for SORT buffer!") at 5A29H. Entered one byte later at 5A2DH from the date parser (580CH and 5833H), the bytes 21 A7 5B decode as LD HL,5BA7H, selecting the "Bad date format" message.
5A30
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message (register pair HL).
5A33
JUMP to 5A3CH to set the failure status and exit.
5A35
LD A,2CH 3E 2C
Parameter-error entry: load register A with 2CH (error code 44, parameter error).
5A37
OR 0C0H F6 C0
Disk-error entry (register A already holds the error code): set bits 7 and 6 to request the standard error display and return handling.
5A39
GOSUB to the resident @ERROR service at 4409H to display the error text for the code in register A.
5A3C
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the failure status for the exit.
5A3F
JUMP to the shared exit at 540CH (the LD SP that restores the caller's stack and returns or aborts).

5A42H - DIR Option Keyword Table (@PARAM)

The parameter descriptor table handed to the resident @PARAM service at 524CH. Each entry is a 6-character space-padded keyword followed by the two-byte address of the operand cell that @PARAM sets when the keyword is present. Full names and one- or three-letter abbreviations share the same cell. A zero byte terminates the table. This is data, not code.

5A42-5A49
DEFM "A " DEFW 559AH 41 20 20 20 20 20 9A 55
All Columns
The A keyword sets the detail-columns flag at 559AH so the LRL, #Recs, EOF, DE, File Size and MOD Date/Time columns are shown.
5A4A-5A51
DEFM "I " DEFW 5464H 49 20 20 20 20 20 64 54
Invisible
The I keyword sets the invisible-file filter at 5464H so invisible files are listed.
5A52-5A59
DEFM "INV " DEFW 5464H 49 4E 56 20 20 20 64 54
Invisible
The full INV spelling sets the same invisible-file filter cell 5464H.
5A5A-5A61
DEFM "P " DEFW 578FH 50 20 20 20 20 20 8F 57
Printer
The P keyword sets the printer-echo flag at 578FH so the listing is also sent to the printer.
5A62-5A69
DEFM "S " DEFW 5456H 53 20 20 20 20 20 56 54
System
The S keyword sets the system-file filter at 5456H so system files are listed.
5A6A-5A71
DEFM "SYS " DEFW 5456H 53 59 53 20 20 20 56 54
System
The full SYS spelling sets the same system-file filter cell 5456H.
5A72-5A79
DEFM "N " DEFW 58FFH 4E 20 20 20 20 20 FF 58
Non-Stop
The N keyword sets the suppress-pause flag at 58FFH so the listing runs without stopping each screen.
5A7A-5A81
DEFM "DATE " DEFW 5274H 44 41 54 45 20 20 74 52
Date Filter
The DATE keyword places the following date argument's address into 5274H, enabling the modification-date range filter.
5A82-5A89
DEFM "D " DEFW 5274H 44 20 20 20 20 20 74 52
Date Filter
The D abbreviation sets the same date-filter cell 5274H.
5A8A-5A91
DEFM "MOD " DEFW 546CH 4D 4F 44 20 20 20 6C 54
Modified Only
The MOD keyword sets the date-stamp filter at 546CH so only date-stamped files are listed.
5A92-5A99
DEFM "M " DEFW 546CH 4D 20 20 20 20 20 6C 54
Modified Only
The M abbreviation sets the same date-stamp filter cell 546CH.
5A9A-5AA1
DEFM "SORT " DEFW 54CFH 53 4F 52 54 20 20 CF 54
Sort
The SORT keyword sets the sort-collection flag at 54CFH so entries are gathered and displayed in name order.
5AA2-5AA9
DEFM "O " DEFW 54CFH 4F 20 20 20 20 20 CF 54
Sort
The O abbreviation sets the same sort-collection cell 54CFH.
5AAA
DEFB 00H 00
Zero terminator marking the end of the @PARAM option table.

5AABH - Column Heading, Access-Code Table and Display Templates

The static text the listing copies into its work buffers: the detail-column heading line, the two-character access-abbreviation table indexed by access level, the drive-header summary template and the per-file detail-line template. This is data, not code.

5AAB-5AEA
DEFM "Filespec Attrib LRL #Recs EOF DE File Size MOD Date Time" + 03H 46 69 6C 65 73 70 65 63 ... 54 69 6D 65 03
Column Heading
The ETX-terminated (03H) heading line printed by the separator routine at 5926H when the detail columns are shown.
5AEB-5AFA
DEFM "ALKINM WRRDEXNO" 41 4C 4B 49 4E 4D 20 20 57 52 52 44 45 58 4E 4F
Access Abbreviation Table
Eight two-character access codes indexed by the file's access level (record attribute low 3 bits), copied to the line at 55D3H.
5AFB-5B3B
DEFM "Drive :d packname packdate cyldh Free=sssss.s/sssss.s Fi=nnn/nnn" + 03H 44 72 69 76 65 20 3A 64 ... 6E 6E 6E 03
Drive Header Template
The ETX-terminated drive summary line. The lower-case placeholders (drive digit, pack name/date, cylinders/heads, free and total kilobytes, free and total directory slots) are overwritten in code before display.
5B3C-5B69
DEFM "pr lrl #recs eof de sxxxxx.xx dd-mmm-yy " + 03H 70 72 20 6C 72 6C 20 23 ... 20 20 20 03
Detail Line Template
The ETX-terminated per-file detail line. The placeholders (access code, LRL, record count, EOF, granule/extent count, size, and modification date/time) are filled by the formatter at 55C5H.

5B6AH - Match Buffer, Days-per-Month, Messages and Month Names

The remaining data: the name/extension match buffer built during command parsing, the days-per-month validation table, the two error messages, the three-letter month-name table used to format dates, and the record-count overflow marker. This is data, not code, and occupies the final bytes of the DIR overlay through 5BE0H.

5B6A-5B75
DEFM " " 20 20 20 20 20 20 20 20 20 20 20 20
Name Match Buffer
Twelve spaces (name 8, extension 3, plus a guard) into which 57C2H copies the filespec mask; each directory entry's name is compared against this at 547EH.
5B76-5B81
DEFB 1FH,1CH,1FH,1EH,1FH,1EH,1FH,1FH,1EH,1FH,1EH,1FH 1F 1C 1F 1E 1F 1E 1F 1F 1E 1F 1E 1F
Days per Month
The maximum day for each month, January through December (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31). The February entry at 5B77H is incremented to 29 in a leap year at 581FH during date validation.
5B82-5BA6
DEFM "Insufficient memory for SORT buffer!" + 0DH 49 6E 73 75 66 66 69 63 69 65 6E 74 ... 21 0D
Sort-Memory Message
The carriage-return-terminated message displayed by the error handler at 5A29H when the sort buffer will not fit.
5BA7-5BB6
DEFM "Bad date format" + 0DH 42 61 64 20 64 61 74 65 20 66 6F 72 6D 61 74 0D
Bad-Date Message
The carriage-return-terminated message for a malformed DATE argument (reached via the parameter-error path from 5A2DH).
5BB7-5BDA
DEFM "JanFebMarAprMayJunJulAugSepOctNovDec" 4A 61 6E 46 65 62 4D 61 72 ... 4E 6F 76 44 65 63
Month-Name Table
Twelve three-character month names indexed by month at 569CH to format the modification date.
5BDB-5BDF
DEFM "*****" 2A 2A 2A 2A 2A
Overflow Marker
The five asterisks copied into the record-count field at 5624H when the record count exceeds the display width. A zero pad byte at 5BE0H ends the overlay image.

Disassembly - Overlay 3 - REMOVE

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.

Disassembly - Overlay 4 - LIB

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.

52C7H - LIB Data: Directory Heading

The single carriage-return-terminated string the LIB command prints as the title of the command directory.

52C7-52D1
DEFM "Library <A>" 4C 69 62 72 61 72 79 20 3C 41 3E
Heading
The Library <A> directory heading. Its address is loaded into HL at 5222H (and again at 5273H) and printed at the top of the LIB command listing to label the Library A command set serviced by SYS6.
52D2
DEFB 0DH 0D
Carriage return (0DH) terminating the heading above and marking the final byte of the LIB overlay.

Disassembly - Overlay 5 - DO

5200H - DO Overlay Entry: Parse JCL Filespec, Open Source and Create Compiled File

Entry of the DO command overlay, the Job Control Language processor. It saves the caller's stack, recognises the leading *, = and $ forms, parses the JCL source filespec (applying the default /JCL extension) and opens it, finds an available drive for the compiled output, and creates the SYSTEM/JCL file that the resident keyboard driver will later replay. Register pair HL points at the command tail on entry.

5200
LD (5306H),SP ED 73 06 53
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn at 5305H so the overlay exit can restore the caller's stack. Register SP holds the LDOS command-level stack on entry.
5204
LD A,(HL) 7E
Load register A with the first character of the DO command tail. Register pair HL is the command-line pointer set up by the overlay loader.
5205
CP 2AH FE 2A
Compare register A against * (2AH), the form that resumes an already-active JCL job.
5207
If the command begins with * (Z), JUMP to 532BH to set up the resume path.
520A
CP 3DH FE 3D
Compare register A against = (3DH), the form that re-executes with the previous file specification.
520C
If the command begins with = (Z), JUMP to 5314H to reuse the prior file specification.
520F
CP 24H FE 24
Compare register A against $ (24H), the prefix that suppresses screen display of the JCL as it runs.
5211
If the command does not begin with $ (NZ), JUMP to 521DH to parse the filespec.
5213
LD (52C0H),A 32 C0 52
Self-Modifying Code
Store the $ character into the quiet-mode flag operand at 52C0H, so the run does not echo each JCL line to the display.
5216
INC HL 23
Advance the command-line pointer HL past the $.
5217
LD A,(HL) 7E
Load register A with the next command character.
5218
CP 20H FE 20
Compare register A against a space (20H) that may follow the $.
521A
If the next character is not a space (NZ), JUMP to 521DH to parse the filespec from here.
521C
INC HL 23
Advance the command-line pointer HL past the space.
521D
LD DE,57BCH 11 BC 57
Point register pair DE at the source-file FCB at 57BCH for the filespec parse.
5220
GOSUB to the resident @FSPEC service at 441CH to parse the JCL filespec from the command line (HL) into the FCB (DE); it returns NZ on a bad specification.
5223
If the filespec was invalid (NZ), JUMP to 5798H to report the File spec required error.
5226
PUSH HL E5
Save the command-line pointer (register pair HL) for continued parsing after the file is opened.
5227
LD HL,581FH 21 1F 58
Point register pair HL at the default extension string JCL at 581FH.
522A
GOSUB to the resident @FEXT service at 4473H to apply the default /JCL extension (register pair HL) to the FCB when the filespec gave none.
522D
LD HL,5B00H 21 00 5B
Point register pair HL at the source-file record buffer at 5B00H.
5230
LD B,L 45
Set register B to register L (zero), the record length argument (0 selects the file's own logical record length) for the open.
5231
GOSUB to the resident @OPEN service at 4424H to open the JCL source file (FCB at 57BCH, buffer at HL); it returns NZ if the file cannot be opened.
5234
If the source file could not be opened (NZ), JUMP to 5791H to report the error.
5237
LD C,0FFH 0E FF
Load register C with 0FFH so the drive-search loop below starts at drive 0 after the first increment.
5239
INC C 0C
Advance register C to the next candidate drive for the compiled output file.
523A
LD A,C 79
Copy the drive number (register C) into register A to test its range.
523B
CP 08H FE 08
Compare the drive number (register A) against 8.
523D
If no writable drive was found by drive 8 (NO CARRY), JUMP to 57ACH to report the failure.
5240
GOSUB to the resident @CKDRV service at 44B8H to check whether the drive in register C is present and writable; it returns NZ if absent and CARRY if write-protected.
5243
If the drive is not present (NZ), LOOP BACK to 5239H to try the next drive.
5245
If the drive is write-protected (CARRY), LOOP BACK to 5239H to try the next drive.
5247
LD A,C 79
Copy the chosen drive number (register C) into register A.
5248
ADD A,30H C6 30
Add 0 (30H) to convert the drive number to an ASCII digit.
524A
LD H,A 67
Store the drive digit (register A) into register H.
524B
LD L,3AH 2E 3A
Load register L with : (3AH); register pair HL now holds the drive suffix (digit and colon) for the output filename.
524D
LD (5823H),HL 22 23 58
Store the drive suffix (register pair HL) into the SYSTEM/JCL output filename at 5823H.
5250
GOSUB to the FCB-setup helper at 5330H, which copies the SYSTEM/JCL output filename template into the output FCB at 4358H.
5253
LD DE,4358H 11 58 43
Point register pair DE at the resident job FCB JFCB$ (4358H) used for the compiled output file.
5256
LD HL,5C00H 21 00 5C
Point register pair HL at the output record buffer at 5C00H.
5259
GOSUB to the resident @INIT service at 4420H to create (or truncate) the compiled SYSTEM/JCL file (FCB at DE, buffer at HL); it returns NZ on failure.
525C
If the output file could not be created (NZ), JUMP to 57ACH to report the failure.

525FH - Command-Tail Scan: Parameters and Keyin Prompt

Scans the remainder of the DO command line for the parameter assignments and the optional keyboard prompt. A left parenthesis introduces a parameter definition; a semicolon prompts the operator for a line of keyboard input that is logged to the compiled file. When the command tail ends (carriage return) it hands over to the JCL compilation pass.

525F
POP HL E1
Recover the command-line pointer (register pair HL) saved at 5226H after the source file was opened.
5260
LD A,(HL) 7E
Load register A with the next command-tail character (at HL).
5261
CP 0DH FE 0D
Compare register A against a carriage return (0DH), the end of the command line.
5263
If the command tail is finished (Z), JUMP to 5384H to begin compiling the JCL source.
5266
INC HL 23
Advance the command-line pointer HL.
5267
GOSUB to the delimiter helper at 577FH, which sets the Z flag when the character in register A is a space or comma to be skipped.
526A
If the character is a space or comma (Z), LOOP BACK to 5260H to skip it.
526C
CP 28H FE 28
Compare register A against ( (28H), which introduces a parameter assignment list.
526E
If a parameter list begins (Z), JUMP to 533CH to parse the assignments.
5271
CP 3BH FE 3B
Compare register A against ; (3BH), which requests a line of keyboard input.
5273
If the character is neither ( nor ; (NZ), JUMP to 578FH to report a parameter error.
5276
LD A,3FH 3E 3F
Load register A with ? (3FH), the keyboard-input prompt character.
5278
CALL 0033H CD 33 00
GOSUB to the ROM display routine @DSP at 0033H to show the ? prompt.
527B
LD HL,4318H 21 18 43
Point register pair HL at the resident input buffer INBUF$ (4318H) to receive the typed line.
527E
LD B,3FH 06 3F
Load register B with 63, the maximum input length.
5280
CALL 0040H CD 40 00
GOSUB to the ROM line-input routine @KEYIN at 0040H to read a line into the buffer (HL); it returns CARRY if BREAK was pressed.
5283
If BREAK was pressed (CARRY), JUMP to 578FH to abandon the operation.
5286
GOSUB to the resident @LOGER service at 447EH to log the typed line into the compiled keyboard stream.
5289
LOOP BACK to 5260H to continue scanning the command tail.
528B
LD HL,(5906H) 2A 06 59
Include-return helper: load register pair HL with the include-nesting pointer at 5906H (top of the saved-FCB stack).
528E
DEC HL 2B
Step register pair HL back to the most recently pushed saved FCB.
528F
LD DE,57DBH 11 DB 57
Point register pair DE just below the source FCB area at 57DBH for the block move.
5292
LD BC,0020H 01 20 00
Load register pair BC with 32, the size of a saved FCB.
5295
LDDR ED B8
Block-copy (descending) the 32-byte saved FCB from the nesting stack (HL) back into the active source FCB area (DE), restoring the enclosing file.
5297
INC HL 23
Adjust register pair HL to the new top of the nesting stack.
5298
LD (5906H),HL 22 06 59
Store the reduced nesting pointer (register pair HL) back into 5906H.
529B
LD DE,57BCH 11 BC 57
Point register pair DE at the restored source FCB at 57BCH.
529E
GOSUB to the resident @RREAD service at 4454H to re-establish the enclosing file's record position; it returns NZ on error.
52A1
If the reposition failed (NZ), JUMP to 5791H to report the error.
52A4
RET C9
RETURN to the caller with the enclosing include file restored.

52A5H - Close the Compiled File, Patch @EXIT and Launch the JCL

Reached when compilation finishes. It unwinds any remaining include nesting, closes the compiled SYSTEM/JCL file and, unless quiet mode was requested, reopens it, arms the resident @EXIT vector with the JCL launch stub, and issues the supervisor request that begins replaying the compiled job through the keyboard driver.

52A5
LD HL,(5906H) 2A 06 59
Load register pair HL with the include-nesting pointer at 5906H.
52A8
LD DE,5908H 11 08 59
Load register pair DE with 5908H, the base (empty) value of the nesting stack.
52AB
XOR A AF
Clear register A and the carry.
52AC
SBC HL,DE ED 52
Subtract the base (register pair DE) from the nesting pointer (register pair HL); the Z flag is set when no include is still open.
52AE
If nothing is nested (Z), JUMP to 52B6H to close the compiled file.
52B0
GOSUB to 528BH to pop one include level.
52B3
JUMP to 53BAH to continue reading the enclosing file.
52B6
LD DE,4358H 11 58 43
Point register pair DE at the compiled-file FCB JFCB$ (4358H).
52B9
GOSUB to the resident @CLOSE service at 4428H to close and flush the compiled SYSTEM/JCL file.
52BC
If the close failed (NZ), JUMP to 5791H to report the error.
52BF
LD A,00H 3E 00
Self-Modifying Code
Load register A with the quiet-mode flag. This operand at 52C0H holds the $ character when the DO command was prefixed with $ to suppress screen echo, or zero otherwise.
52C1
OR A B7
Test the quiet-mode flag (register A) for zero.
52C2
If quiet mode was requested (NZ), JUMP to 5302H to exit without launching (the compiled file is left for later use).
52C4
LD DE,4358H 11 58 43
Point register pair DE at the compiled-file FCB (4358H) to reopen it for replay.
52C7
LD HL,4200H 21 00 42
Point register pair HL at the shared buffer SBUFF$ (4200H) for the reopen.
52CA
LD B,L 45
Set register B to register L (zero), the record-length argument for the open.
52CB
GOSUB to the resident @OPEN service at 4424H to reopen the compiled SYSTEM/JCL file for the keyboard driver to read.
52CE
If the reopen failed (NZ), JUMP to 5791H to report the error.
52D1
LD HL,5814H 21 14 58
Point register pair HL at the 4-byte launch stub at 5814H (a PUSH AF followed by an @ERROR request).
52D4
LD DE,4409H 11 09 44
Point register pair DE at the resident @ERROR vector (4409H) that the stub overwrites.
52D7
LD BC,0004H 01 04 00
Load register pair BC with 4, the stub length.
52DA
LDIR ED B0
Block-copy the 4-byte launch stub from 5814H (HL) over the resident @ERROR vector (DE) so a JCL error unwinds through the launcher.
52DC
LD HL,430FH 21 0F 43
Point register pair HL at the resident system flag SFLAG$ (430FH).
52DF
RES 7,(HL) CB BE
Clear bit 7 of SFLAG$ (at HL), the DEBUG-armed flag, so the launched job does not re-enter DEBUG.
52E1
LD A,0C9H 3E C9
Load register A with 0C9H, a Z80 RET opcode.
52E3
LD (4315H),A 32 15 43
Store the RET (register A) into the resident breakpoint hook at 4315H, disarming any DEBUG re-entry.
52E6
BIT 5,(HL) CB 6E
Test bit 5 of SFLAG$ (at HL), set when the command is not at the LDOS command level.
52E8
If not at the command level (NZ), JUMP to 52FFH to launch without repatching @EXIT.
52EA
LD HL,402DH 21 2D 40
Point register pair HL at the resident @EXIT vector (402DH).
52ED
LD DE,4065H 11 65 40
Point register pair DE at the DEBUG save area (4065H), used here to stash the original @EXIT bytes.
52F0
LD C,06H 0E 06
Load register C with 6, the number of @EXIT-vector bytes to save and replace.
52F2
PUSH BC C5
Save the count (register C).
52F3
LDIR ED B0
Block-copy the 6 original @EXIT bytes from 402DH (HL) into the save area (DE).
52F5
LD HL,580EH 21 0E 58
Point register pair HL at the 6-byte JCL launch stub at 580EH.
52F8
POP BC C1
Recover the count into register C.
52F9
LDIR ED B0
Block-copy the 6-byte launch stub from 580EH (HL) over the resident @EXIT vector (DE) so that exiting the launched job returns into the JCL launcher.
52FB
LD SP,(5306H) ED 7B 06 53
Restore the caller's stack pointer from the operand saved at 5306H before transferring control.
52FF
LD A,9DH 3E 9D
Load register A with RST 28H request code 9DH, the supervisor request that begins executing the compiled JCL through the keyboard driver.
5301
RST 28 EF
Issue the RST 28H supervisor call with code 9DH to launch the compiled SYSTEM/JCL job.
5302
LD HL,0000H 21 00 00
Load register pair HL with zero, the success status for the return.
5305
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer. This operand at 5306H was set from SP at overlay entry (5200H).
5308
LD A,H 7C
Copy the status high byte (register H) into register A to test it.
5309
OR L B5
OR the status low byte (register L) into register A; the Z flag is set on success.
530A
RET Z C8
If the status is success (Z), RETURN to the resident dispatcher.
530B
LD A,(430FH) 3A 0F 43
Load register A with SFLAG$ (430FH) to check the command level.
530E
BIT 5,A CB 6F
Test bit 5 of SFLAG$ (register A), the not-command-level flag.
5310
RET Z C8
If at the command level (Z), RETURN despite the error.
5311
Otherwise JUMP to the resident @ABORT service at 4030H.

5314H - Reuse-Filespec and Resume Entry Setups

Handles the two special command forms. The = form parses a fresh filespec but skips the leading spaces so the previous drive context is reused; the * form resumes an already-active job. The shared helper at 5330H seeds the compiled-output FCB from its template.

5314
INC HL 23
The = form: advance the command-line pointer HL past the =.
5315
LD A,(HL) 7E
Load register A with the next command character.
5316
CP 20H FE 20
Compare register A against a space (20H).
5318
If it is a space (Z), LOOP BACK to 5314H to skip leading spaces.
531A
LD DE,4358H 11 58 43
Point register pair DE at the job FCB JFCB$ (4358H) to receive the filespec.
531D
GOSUB to the resident @FSPEC service at 441CH to parse the filespec (HL) into the FCB (DE); it returns NZ on a bad specification.
5320
If the filespec was invalid (NZ), JUMP to 5798H to report the File spec required error.
5323
LD HL,581FH 21 1F 58
Point register pair HL at the default extension string JCL at 581FH.
5326
GOSUB to the resident @FEXT service at 4473H to apply the default /JCL extension.
5329
JUMP to 52C4H to open and launch the named compiled file directly.
532B
The * resume form: GOSUB to 5330H to seed the job FCB from the SYSTEM/JCL template.
532E
JUMP to 52C4H to open and resume the compiled file.
5330
LD HL,5818H 21 18 58
FCB-template helper: point register pair HL at the SYSTEM/JCL filename template at 5818H.
5333
LD DE,4358H 11 58 43
Point register pair DE at the job FCB JFCB$ (4358H).
5336
LD BC,0020H 01 20 00
Load register pair BC with 32, the FCB length.
5339
LDIR ED B0
Block-copy the 32-byte filename template from 5818H (HL) into the job FCB (DE).
533B
RET C9
RETURN with the job FCB seeded.

533CH - Parameter List Parse and Label/Compile Control

Parses the parenthesised parameter list on the DO command, entering each name=value pair into the symbol table (or capturing a name to search for a matching label). When the parameters are done it locates the requested label in the source and begins the line-by-line compilation pass.

533C
GOSUB to the name scanner at 5620H to read a symbol name from the command line (HL) into the name buffer at 57DCH.
533F
If the scan stopped on a delimiter rather than a name character (NZ), JUMP to 5355H to handle it.
5341
PUSH AF F5
Save the terminating character (register A).
5342
LD A,00H 3E 00
Self-Modifying Code
Load register A with the parse-mode flag. This operand at 5343H is zero to define parameters and nonzero when capturing a name to match against a label.
5344
OR A B7
Test the parse-mode flag (register A) for zero.
5345
If capturing a name for a label match (NZ), JUMP to 5371H.
5347
GOSUB to the symbol-lookup helper at 56EAH to find this name in the symbol table; it returns Z if not found.
534A
If the name is not already defined (Z), JUMP to 57B0H to report an undefined-parameter error.
534D
GOSUB to 56CDH to copy the name into the pending symbol-table entry.
5350
POP AF F1
Recover the terminating character (register A).
5351
CP 3DH FE 3D
Compare register A against = (3DH), which introduces the parameter's value.
5353
If a value follows (Z), JUMP to 5367H to scan it.
5355
GOSUB to the delimiter helper at 577FH; the Z flag is set for a space or comma between assignments.
5358
If the character is a separator (Z), LOOP BACK to 533CH for the next assignment.
535A
CP 29H FE 29
Compare register A against ) (29H), the end of the parameter list.
535C
If the list is closed (Z), JUMP to 5260H to continue the command-tail scan.
535F
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5361
If the command line ended (Z), JUMP to 5384H to begin compilation.
5364
Otherwise JUMP to 578FH to report a parameter error.
5367
GOSUB to the value scanner at 562BH to read the parameter's value string into the value buffer at 57E5H.
536A
PUSH AF F5
Save the terminating character (register A).
536B
GOSUB to 56DFH to store the value into the symbol-table entry.
536E
POP AF F1
Recover the terminating character (register A).
536F
JUMP to 5355H to look for the next assignment.
5371
PUSH HL E5
Label-capture path: save the command-line pointer (register pair HL).
5372
LD HL,57DCH 21 DC 57
Point register pair HL at the scanned name buffer at 57DCH.
5375
LD DE,5805H 11 05 58
Point register pair DE at the label-search buffer at 5805H.
5378
LD BC,0008H 01 08 00
Load register pair BC with 8, the name length.
537B
LDIR ED B0
Block-copy the 8-character name from the name buffer (HL) into the label-search buffer (DE).
537D
XOR A AF
Clear register A.
537E
LD (5343H),A 32 43 53
Store zero into the parse-mode flag at 5343H, returning to the define-parameters mode.
5381
POP HL E1
Recover the command-line pointer (register pair HL).
5382
JUMP to 536EH to continue scanning assignments.
5384
LD A,(568EH) 3A 8E 56
Load register A with the label-search flag at 568EH, set when the command named a label to jump to.
5387
OR A B7
Test the label-search flag (register A) for zero.
5388
If no label was requested (Z), JUMP to 53BAH to compile from the top of the file.
538A
GOSUB to the source-line reader at 549DH to read the next JCL line into the line buffer at 59D8H; it returns Z at end of file.
538D
If a line was read (Z clear inverted here), JUMP to 53A0H to test it for the label.
538F
LD HL,(5906H) 2A 06 59
At end of file: load register pair HL with the include-nesting pointer at 5906H.
5392
LD DE,5908H 11 08 59
Load register pair DE with the empty-stack base 5908H.
5395
XOR A AF
Clear register A and the carry.
5396
SBC HL,DE ED 52
Subtract the base (register pair DE) from the nesting pointer (register pair HL); the Z flag is set when no include is open.
5398
If the label was never found and nothing is nested (Z), JUMP to 57A4H to report the label-not-found error.
539B
GOSUB to 528BH to pop the include level and resume the enclosing file.
539E
LOOP BACK to 538AH to keep searching for the label.
53A0
LD HL,59D8H 21 D8 59
Point register pair HL at the source-line buffer at 59D8H.
53A3
LD A,(HL) 7E
Load register A with the first character of the line.
53A4
CP 40H FE 40
Compare register A against @ (40H), the label-definition marker.
53A6
If the line is not a label definition (NZ), LOOP BACK to 538AH to read the next line.
53A8
INC HL 23
Advance register pair HL past the @ to the label name.
53A9
EX DE,HL EB
Move the label-name pointer into register pair DE for the comparison.
53AA
LD HL,5805H 21 05 58
Point register pair HL at the requested label in the search buffer at 5805H.
53AD
LD BC,0808H 01 08 08
Load register B with 8 (the entry count) and register C with 8 (the compare length) for the table compare.
53B0
GOSUB to the string-compare helper at 5716H to compare the line's label (DE) against the requested label (HL); it returns NZ on a mismatch.
53B3
If this is not the requested label (NZ), LOOP BACK to 538AH to keep searching.
53B5
The label was found: JUMP to 53BAH to begin compiling from the following line.
53B7
Line-complete entry: GOSUB to the line-writer at 54CEH to emit the assembled line to the compiled file.
53BA
Main compile loop: GOSUB to 549DH to read the next source line into 59D8H; it returns NZ at end of file.
53BD
If the source is exhausted (NZ), JUMP to 52A5H to close and launch the compiled job.

53C0H - Compile One Source Line: Copy with %Hex and #Parameter Escapes

Compiles the current source line at 59D8H into the output line buffer at 5200H. Characters are copied through, but % introduces a two-digit hexadecimal byte, # introduces a #name# parameter substitution, // at the start marks a JCL directive, and @ ends the compilation. A doubled %% or ## is the literal character.

53C0
LD HL,59D8H 21 D8 59
Point register pair HL at the source-line buffer at 59D8H.
53C3
LD DE,5200H 11 00 52
Point register pair DE at the output line buffer at 5200H (the overlay's entry area, reused now that entry is complete).
53C6
LD A,(HL) 7E
Load register A with the next source character (at HL).
53C7
INC HL 23
Advance the source pointer HL.
53C8
CP 40H FE 40
Compare register A against @ (40H), a label line that ends the compilation.
53CA
If a label line is reached (Z), JUMP to 52A5H to close and launch the compiled job.
53CD
CP 2FH FE 2F
Compare register A against / (2FH), which may begin a // directive.
53CF
If the character is not / (NZ), JUMP to 53D5H to test the escapes.
53D1
CP (HL) BE
Compare register A against the next character (at HL) to detect a second /.
53D2
If the line begins with // (Z), JUMP to 546FH to process it as a JCL directive.
53D5
CP 23H FE 23
Compare register A against # (23H), the parameter-substitution escape.
53D7
If it is # (Z), JUMP to 53FEH to handle the substitution.
53D9
CP 25H FE 25
Compare register A against % (25H), the hexadecimal-byte escape.
53DB
If the character is not % (NZ), JUMP to 53F4H to copy it literally.
53DD
GOSUB to 53E2H to decode the two hexadecimal digits following the % into a byte in register A.
53E0
JUMP to 53FAH to fetch the next source character.
53E2
CP (HL) BE
Compare the % (register A) against the next character (at HL) to detect a doubled %%.
53E3
If the next character is also % (Z, a literal percent), JUMP to 5406H to store one %.
53E5
GOSUB to the hex-nibble helper at 540AH to convert the first hexadecimal digit (at HL) to a value in register A.
53E8
INC HL 23
Advance the source pointer HL past the first digit.
53E9
RLCA 07
Shift the first nibble (register A) left toward the high nibble.
53EA
RLCA 07
Shift left again.
53EB
RLCA 07
Shift left again.
53EC
RLCA 07
Shift left a fourth time; the first nibble now occupies the high 4 bits of register A.
53ED
LD C,A 4F
Save the high nibble (register A) into register C.
53EE
GOSUB to 540AH to convert the second hexadecimal digit (at HL) to a value in register A.
53F1
OR C B1
OR the high nibble (register C) into register A to form the full byte.
53F2
JUMP to 5406H to store the assembled byte.
53F4
LD (DE),A 12
Store the literal character (register A) into the output line buffer (DE).
53F5
INC DE 13
Advance the output pointer DE.
53F6
CP 0DH FE 0D
Compare the stored character (register A) against a carriage return (0DH), the end of the line.
53F8
If the line is complete (Z), JUMP to 53B7H to write the compiled line to the file.
53FA
LD A,(HL) 7E
Load register A with the next source character (at HL).
53FB
INC HL 23
Advance the source pointer HL.
53FC
LOOP BACK to 53D5H to process the character.
53FE
GOSUB to 5403H to handle the #: a doubled ## stores a literal, otherwise the name substitution runs.
5401
JUMP to 53FAH to fetch the next source character.
5403
CP (HL) BE
Compare the # (register A) against the next character (at HL) to detect a doubled ##.
5404
If the next character is not # (NZ), JUMP to 541BH to substitute the named parameter's value.
5406
INC HL 23
Doubled escape or hex byte: advance the source pointer HL past the second character.
5407
LD (DE),A 12
Store the literal character or assembled byte (register A) into the output buffer (DE).
5408
INC DE 13
Advance the output pointer DE.
5409
RET C9
RETURN to the compile loop.
540A
LD A,(HL) 7E
Hex-nibble helper: load register A with the hexadecimal digit character (at HL).
540B
SUB 30H D6 30
Subtract 0 (30H) from register A to convert a numeric digit.
540D
If the character was below 0 (CARRY, invalid), JUMP to 5419H to report a format error.
540F
CP 0AH FE 0A
Compare the value (register A) against 10 to accept the digits 0 through 9.
5411
RET C D8
If the value is a decimal digit (CARRY), RETURN with the nibble in register A.
5412
RES 5,A CB AF
Clear bit 5 of register A to fold a lower-case letter A-F to upper case.
5414
SUB 07H D6 07
Subtract 7 to map A-F to the values 10 through 15.
5416
CP 10H FE 10
Compare the value (register A) against 16 to validate the hexadecimal letter.
5418
RET C D8
If the value is a valid hex nibble (CARRY), RETURN with it in register A.
5419
Otherwise JUMP to 545AH to report an invalid JCL format.
541B
PUSH HL E5
Parameter substitution: save the source pointer (register pair HL).
541C
PUSH DE D5
Save the output pointer (register pair DE).
541D
GOSUB to the name scanner at 5620H to read the parameter name (from HL) into the name buffer at 57DCH.
5420
CP 23H FE 23
Compare the terminating character (register A) against the closing # (23H).
5422
If the name is not closed by # (NZ), JUMP to 545AH to report an invalid format.
5424
EX (SP),HL E3
Exchange the saved output pointer on the stack with register pair HL, so HL is the output pointer and the source pointer is on the stack.
5425
PUSH HL E5
Save the output pointer (register pair HL) again for the copy.
5426
GOSUB to the symbol-lookup helper at 56EAH to find the named parameter; it returns register pair DE pointing at the value and NZ if not found.
5429
If the parameter is undefined (NZ), JUMP to 543AH to copy the #name# literally.
542B
LD A,(DE) 1A
Load register A with the value's length byte (at DE).
542C
OR A B7
Test the value length (register A) for zero.
542D
If the value is empty (Z), JUMP to 543AH to keep the literal text.
542F
LD B,00H 06 00
Clear register B so register pair BC is the value length.
5431
LD C,A 4F
Set register C to the value length (register A).
5432
INC DE 13
Advance register pair DE past the length byte to the value text.
5433
POP HL E1
Recover the output pointer (register pair HL).
5434
EX DE,HL EB
Exchange so register pair HL addresses the value text and DE the output buffer.
5435
LDIR ED B0
Block-copy the parameter value (register C bytes) from the symbol table (HL) into the output buffer (DE).
5437
POP HL E1
Recover the source pointer (register pair HL) from the stack.
5438
POP AF F1
Discard the extra saved word to balance the stack.
5439
RET C9
RETURN to the compile loop with the value substituted.
543A
POP DE D1
Undefined-parameter path: recover the output pointer (register pair DE).
543B
POP AF F1
Discard the extra saved word.
543C
POP HL E1
Recover the source pointer (register pair HL).
543D
LD A,23H 3E 23
Load register A with # (23H) to re-emit the opening delimiter literally.
543F
LD (DE),A 12
Store the character (register A) into the output buffer (DE).
5440
INC DE 13
Advance the output pointer DE.
5441
LD A,(HL) 7E
Load register A with the next source character (at HL).
5442
INC HL 23
Advance the source pointer HL.
5443
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5445
If the line ended before a closing # (Z), JUMP to 545AH to report an invalid format.
5447
CP 23H FE 23
Compare register A against the closing # (23H).
5449
If the closing # has not been reached (NZ), LOOP BACK to 543FH to copy the literal name character.
544B
LD (DE),A 12
Store the closing # (register A) into the output buffer (DE).
544C
INC DE 13
Advance the output pointer DE.
544D
RET C9
RETURN to the compile loop with the literal #name# preserved.

544EH - Nesting Check, Error Prefix, Directive Dispatch, Source Reader and Line Writer

A cluster of compile-time services: 544EH tests whether IF nesting is balanced, 545AH prints the "Line nnnnn --" prefix and the invalid-format message, 546FH dispatches a // directive through the two keyword tables, 549DH reads the next source line and 54CEH writes a compiled line to the output file (skipping output while inside a false IF block).

544E
LD DE,(59A8H) ED 5B A8 59
Load register pair DE with the IF-nesting pointer at 59A8H (the top of the condition-state stack).
5452
LD HL,59AAH 21 AA 59
Point register pair HL at 59AAH, the base of the condition-state stack (no IF open).
5455
XOR A AF
Clear register A and the carry.
5456
SBC HL,DE ED 52
Subtract the nesting pointer (register pair DE) from the base (register pair HL); the Z flag is set when no IF is open.
5458
EX DE,HL EB
Exchange DE and HL so register pair HL holds the nesting pointer again for the caller.
5459
RET NZ C0
If an IF is still open (NZ), RETURN so the caller can push or pop the condition state.
545A
LD DE,59CFH 11 CF 59
Point register pair DE at the five-digit field 59CFH in the "Line nnnnn --" prefix.
545D
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the current source line number. This operand at 545EH is incremented for every line read at 549DH.
5460
GOSUB to the decimal helper at 5766H to write the line number (register pair HL) into the prefix field (DE).
5463
LD HL,59CAH 21 CA 59
Point register pair HL at the "Line nnnnn --" prefix text at 59CAH.
5466
GOSUB to the resident @LOGOT service at 447BH to display the line-number prefix (register pair HL).
5469
LD HL,58C4H 21 C4 58
Self-Modifying Code
Load register pair HL with the message address. This operand at 546AH is normally the Invalid JCL format message (58C4H) but is patched to the Line too long message (5839H) at 54C0H.
546C
JUMP to 57B3H to display the message (register pair HL) and abort the JCL run.
546F
INC HL 23
Directive dispatch: advance register pair HL past the second / to the directive name.
5470
GOSUB to the name scanner at 5620H to read the directive name into the name buffer at 57DCH.
5473
If no directive name was found (NZ), JUMP to 548AH to copy the line literally.
5475
GOSUB to 56FBH to look the name up in the block-directive table (IF, ELSE, END); it returns register pair DE = the handler and Z on a match.
5478
PUSH DE D5
Push the handler address (register pair DE) so a matching directive can be entered by return.
5479
RET Z C8
If a block directive matched (Z), RETURN to jump into its handler.
547A
POP DE D1
No block directive: discard the pushed address.
547B
LD DE,(59A8H) ED 5B A8 59
Load register pair DE with the IF-nesting pointer at 59A8H to read the current condition state.
547F
LD A,(DE) 1A
Load register A with the current condition-state byte (at DE); nonzero means an enclosing IF is false.
5480
OR A B7
Test the condition-state byte (register A) for zero.
5481
If an enclosing IF is false (NZ), JUMP to 53BAH to skip this directive and read the next line.
5484
GOSUB to 5704H to look the name up in the action-directive table (SET, RESET, ASSIGN, INCLUDE, QUIT); it returns register pair DE = the handler and Z on a match.
5487
PUSH DE D5
Push the handler address (register pair DE).
5488
RET Z C8
If an action directive matched (Z), RETURN to jump into its handler.
5489
POP DE D1
No directive matched: discard the pushed address.
548A
LD DE,59D8H 11 D8 59
Point register pair DE at the start of the source line at 59D8H to copy it literally.
548D
XOR A AF
Clear register A and the carry.
548E
SBC HL,DE ED 52
Subtract the line start (register pair DE) from the current scan point (register pair HL) to measure the consumed prefix.
5490
LD B,H 44
Copy the high byte of the length (register H) into register B.
5491
LD C,L 4D
Copy the low byte (register L) into register C; register pair BC is the copy length.
5492
LD HL,59D8H 21 D8 59
Point register pair HL at the source line (59D8H).
5495
LD DE,5200H 11 00 52
Point register pair DE at the output buffer (5200H).
5498
LDIR ED B0
Block-copy the unrecognised // line prefix from the source (HL) into the output buffer (DE).
549A
JUMP to 53FAH to compile the remainder of the line normally.
549D
LD HL,(545EH) 2A 5E 54
Source-line reader: load register pair HL with the current line number from 545EH.
54A0
INC HL 23
Increment the line number (register pair HL).
54A1
LD (545EH),HL 22 5E 54
Store the incremented line number (register pair HL) back into 545EH.
54A4
LD HL,59D8H 21 D8 59
Point register pair HL at the source-line buffer at 59D8H.
54A7
LD DE,57BCH 11 BC 57
Point register pair DE at the source-file FCB at 57BCH for the byte reads.
54AA
LD B,40H 06 40
Load register B with 64, the maximum line length.
54AC
CALL 0013H CD 13 00
GOSUB to the ROM device-input routine @GET at 0013H to read one byte from the source file (DE) into register A; it returns NZ at end of file or on error.
54AF
If the read did not return a data byte (NZ), JUMP to 54C5H to test for end of file.
54B1
OR A B7
Test the byte (register A) for zero (a padding byte).
54B2
If the byte is zero (Z), JUMP to 54CAH to treat it as end of data.
54B4
LD (HL),A 77
Store the source byte (register A) into the line buffer (at HL).
54B5
INC HL 23
Advance the line-buffer pointer HL.
54B6
CP 0DH FE 0D
Compare the byte (register A) against a carriage return (0DH), the end of the line.
54B8
RET Z C8
If the line ended (Z), RETURN with the line in the buffer.
54B9
DECrement register B and LOOP BACK to 54ACH until 64 characters have been read.
54BB
LD (HL),0DH 36 0D
Line too long: force a carriage return (0DH) into the buffer (at HL) to terminate it.
54BD
LD HL,5839H 21 39 58
Point register pair HL at the Line too long message at 5839H.
54C0
LD (546AH),HL 22 6A 54
Self-Modifying Code
Store the Line too long message address (register pair HL) into the operand at 546AH so the error printer at 5469H reports it.
54C3
JUMP to 545AH to print the line-number prefix and the Line too long message.
54C5
CP 1CH FE 1C
Compare the @GET status (register A) against 1CH, the end-of-file code.
54C7
If the status is not end of file (NZ, a real error), JUMP to 5791H to report it.
54CA
LD A,1CH 3E 1C
Load register A with 1CH, the end-of-file marker for the caller.
54CC
OR A B7
Test register A, setting NZ so the caller sees end of file.
54CD
RET C9
RETURN reporting end of file.
54CE
LD HL,(59A8H) 2A A8 59
Line writer: load register pair HL with the IF-nesting pointer at 59A8H.
54D1
LD A,(HL) 7E
Load register A with the current condition-state byte (at HL); nonzero means output is suppressed.
54D2
OR A B7
Test the condition-state byte (register A) for zero.
54D3
RET NZ C0
If an IF is false (NZ), RETURN without writing the line.
54D4
LD HL,5200H 21 00 52
Point register pair HL at the compiled output line at 5200H.
54D7
LD DE,4358H 11 58 43
Point register pair DE at the compiled-file FCB JFCB$ (4358H).
54DA
LD A,(HL) 7E
Load register A with the line's first character (at HL).
54DB
CP 2FH FE 2F
Compare register A against / (2FH) to detect a display-only line.
54DD
If the line does not start with / (NZ), JUMP to 54ECH to write it to the file.
54DF
INC HL 23
Advance register pair HL to the second character.
54E0
CP (HL) BE
Compare against the second character (at HL) to detect a second /.
54E1
DEC HL 2B
Step register pair HL back to the first character.
54E2
If it is not a // line (NZ), JUMP to 54ECH to write it.
54E4
LD A,(5202H) 3A 02 52
Load register A with the third character of the line (at 5202H).
54E7
CP 2EH FE 2E
Compare register A against . (2EH); a //. line is a comment displayed but not compiled.
54E9
If the line is a //. comment (Z), JUMP to the resident @DSPLY service at 4467H to display it and return to the caller.
54EC
LD A,(HL) 7E
Load register A with the next output-line character (at HL).
54ED
CALL 001BH CD 1B 00
GOSUB to the ROM device-output routine @PUT at 001BH to write the character (register A) to the compiled file (DE); it returns NZ on error.
54F0
If the write failed (NZ), JUMP to 5791H to report the error.
54F3
LD A,(HL) 7E
Load register A with the character just written (at HL) to test for the line end.
54F4
INC HL 23
Advance the output-line pointer HL.
54F5
CP 0DH FE 0D
Compare register A against a carriage return (0DH), the end of the line.
54F7
If the line is not finished (NZ), LOOP BACK to 54ECH to write the next character.
54F9
RET C9
RETURN with the compiled line written to the file.

54FAH - Directive Keyword Tables

The two keyword tables the directive dispatcher searches. The block table lists the always-processed directives IF, ELSE and END; the action table lists SET, RESET, ASSIGN, INCLUDE and QUIT, which run only when no enclosing IF is false. Each entry is a space-padded name followed by the two-byte handler address; a zero byte ends each table. This is data, not code.

54FA-5500
DEFM "IF " DEFW 5543H 49 46 20 20 20 43 55
IF Directive
The IF keyword and the address of its handler at 5543H.
5501-5507
DEFM "ELSE " DEFW 556BH 45 4C 53 45 20 6B 55
ELSE Directive
The ELSE keyword and the address of its handler at 556BH.
5508-550E
DEFM "END " DEFW 5576H 45 4E 44 20 20 76 55
END Directive
The END keyword and the address of its handler at 5576H.
550F
DEFB 00H 00
Zero terminator ending the block-directive table.
5510-5519
DEFM "SET " DEFW 55A5H 53 45 54 20 20 20 20 20 A5 55
SET Directive
The SET keyword and the address of its handler at 55A5H.
551A-5523
DEFM "RESET " DEFW 55B4H 52 45 53 45 54 20 20 20 B4 55
RESET Directive
The RESET keyword and the address of its handler at 55B4H.
5524-552D
DEFM "ASSIGN " DEFW 55C6H 41 53 53 49 47 4E 20 20 C6 55
ASSIGN Directive
The ASSIGN keyword and the address of its handler at 55C6H.
552E-5537
DEFM "INCLUDE " DEFW 55DFH 49 4E 43 4C 55 44 45 20 DF 55
INCLUDE Directive
The INCLUDE keyword and the address of its handler at 55DFH.
5538-5541
DEFM "QUIT " DEFW 5614H 51 55 49 54 20 20 20 20 14 56
QUIT Directive
The QUIT keyword and the address of its handler at 5614H.
5542
DEFB 00H 00
Zero terminator ending the action-directive table.

5543H - IF, ELSE, END Handlers and the Condition Evaluator

The block-control directives. IF evaluates its condition (a parameter name, optionally negated with - and combined with &) and pushes a true/false state; ELSE inverts the current state; END pops it. The condition state stack lives at 59AA and above, with 59A8H pointing at the current level.

5543
IF handler: GOSUB to the condition evaluator at 557FH, which returns register A nonzero when the condition is true.
5546
If the condition is false (Z), JUMP to 5568H to push a false state.
5548
CP 0DH FE 0D
Compare the terminating character (register A) against a carriage return (0DH).
554A
If the condition line ended (Z), JUMP to 555AH to push a true state.
554C
CP 2BH FE 2B
Compare register A against + (2BH), a continuation of the condition.
554E
If a + continuation follows (Z), LOOP BACK to 5543H to evaluate the rest.
5550
CP 26H FE 26
Compare register A against & (26H), the AND connective.
5552
If the character is not & (NZ, a syntax error), JUMP to 55A8H to report an invalid format.
5554
INC HL 23
Advance register pair HL over the rest of the condition text (already resolved to true above).
5555
LD A,(HL) 7E
Load register A with the next character (at HL).
5556
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5558
If the line has not ended (NZ), LOOP BACK to 5554H to skip to the end.
555A
LD A,0FFH 3E FF
Load register A with 0FFH, the true condition value to push.
555C
LD HL,(59A8H) 2A A8 59
Load register pair HL with the condition-state pointer at 59A8H.
555F
OR (HL) B6
OR the enclosing state (at HL) into register A, so a nested IF inside a false block stays false.
5560
INC HL 23
Advance register pair HL to the new (deeper) condition-state slot.
5561
LD (HL),A 77
Store the combined state (register A) into the new slot (at HL).
5562
LD (59A8H),HL 22 A8 59
Store the advanced pointer (register pair HL) back into 59A8H, pushing the IF level.
5565
JUMP to 53BAH to read the next source line.
5568
XOR A AF
Clear register A to push a false-active state (a value that suppresses output but not the block).
5569
JUMP to 555CH to push the state.
556B
ELSE handler: GOSUB to 544EH to confirm an IF is open and get its state pointer in register pair HL.
556E
LD A,(HL) 7E
Load register A with the current condition state (at HL).
556F
CPL 2F
Complement register A to invert the condition for the ELSE branch.
5570
DEC HL 2B
Step register pair HL back to the enclosing state.
5571
OR (HL) B6
OR the enclosing state (at HL) into register A so an outer false block still suppresses the ELSE branch.
5572
INC HL 23
Advance register pair HL back to the current state slot.
5573
LD (HL),A 77
Store the inverted state (register A) into the current slot (at HL).
5574
JUMP to 55B1H to read the next source line.
5576
END handler: GOSUB to 544EH to confirm an IF is open and get its state pointer in register pair HL.
5579
DEC HL 2B
Step register pair HL back one level, popping this IF.
557A
LD (59A8H),HL 22 A8 59
Store the reduced pointer (register pair HL) into 59A8H, closing the IF block.
557D
JUMP to 55B1H to read the next source line.
557F
Condition evaluator: GOSUB to 5589H to evaluate one term (a parameter name, possibly negated), returning register A nonzero when true.
5582
RET NZ C0
If the term is true (NZ), RETURN with the true result.
5583
CP 26H FE 26
Compare the terminating character (register A) against & (26H), the AND connective.
5585
If another term is ANDed on (Z), LOOP BACK to 557FH to evaluate it.
5587
XOR A AF
Clear register A to report the overall condition false.
5588
RET C9
RETURN with the false result.
5589
LD A,(HL) 7E
Term evaluator: load register A with the next condition character (at HL).
558A
CP 2DH FE 2D
Compare register A against - (2DH), the negation prefix.
558C
If the term is not negated (NZ), JUMP to 5598H to test the parameter directly.
558E
INC HL 23
Advance register pair HL past the -.
558F
GOSUB to 5598H to test whether the parameter is defined.
5592
If the parameter is defined (NZ), JUMP to 5595H to negate the result.
5594
OR 0AFH F6 AF
Combine the defined/undefined result so the negation yields the opposite truth value in register A.
5596
LD A,B 78
Load register A with the terminating character saved in register B for the caller's connective test.
5597
RET C9
RETURN with the negated term result.
5598
GOSUB to the name scanner at 5620H to read the parameter name.
559B
RET NZ C0
If no valid name was read (NZ), RETURN.
559C
PUSH AF F5
Save the terminating character (register A).
559D
PUSH HL E5
Save the source pointer (register pair HL).
559E
GOSUB to the symbol-lookup helper at 56EAH; it returns register B nonzero when the parameter is defined.
55A1
POP HL E1
Recover the source pointer (register pair HL).
55A2
POP BC C1
Recover the terminating character into register B (and the flags into register C).
55A3
LD A,B 78
Load register A with the defined flag / terminating character (register B) for the caller.
55A4
RET C9
RETURN with the parameter's defined status.
55A5
SET handler: GOSUB to 5620H to read the parameter name.
55A8
If no valid name (NZ), JUMP to 545AH to report an invalid format (also the shared error entry for the directive handlers).
55AB
GOSUB to 56EAH to see whether the parameter already exists; register pair DE points at the entry or a free slot.
55AE
If the parameter is new (NZ), GOSUB to 56CDH to create the symbol-table entry with its name.
55B1
JUMP to 53BAH to read the next source line.
55B4
RESET handler: GOSUB to 5620H to read the parameter name.
55B7
If no valid name (NZ), JUMP to 55A8H to report an invalid format.
55B9
GOSUB to 56EAH to locate the parameter; register pair DE points at its entry when found.
55BC
If the parameter is not defined (NZ), JUMP to 55B1H (nothing to reset).
55BE
LD HL,0FFF8H 21 F8 FF
Load register pair HL with -8 to reach the entry's name field from its value pointer.
55C1
ADD HL,DE 19
Add the entry pointer (register pair DE) to HL, addressing the first byte of the entry's name.
55C2
LD (HL),20H 36 20
Store a space (20H) over the first name character (at HL), marking the symbol-table entry as free.
55C4
JUMP to 55B1H to read the next source line.
55C6
ASSIGN handler: GOSUB to 5620H to read the parameter name.
55C9
If no valid name (NZ), JUMP to 55A8H to report an invalid format.
55CB
PUSH AF F5
Save the terminating character (register A).
55CC
GOSUB to 56EAH to find the parameter or a free slot.
55CF
If the parameter is new (NZ), GOSUB to 56CDH to create its entry.
55D2
POP AF F1
Recover the terminating character (register A).
55D3
CP 3DH FE 3D
Compare register A against = (3DH), which introduces the value.
55D5
If a value follows (Z), GOSUB to the value scanner at 562BH to read it.
55D8
If no = value was given (NZ), JUMP to 55A8H to report an invalid format.
55DA
GOSUB to 56DFH to store the value into the symbol-table entry.
55DD
JUMP to 55B1H to read the next source line.
55DF
PUSH HL E5
INCLUDE handler: save the source pointer (register pair HL).
55E0
LD DE,(5906H) ED 5B 06 59
Load register pair DE with the include-nesting pointer at 5906H.
55E4
LD HL,59A8H 21 A8 59
Point register pair HL at 59A8H, the limit above which nesting would overrun the condition stack.
55E7
OR A B7
Clear the carry for the subtraction.
55E8
SBC HL,DE ED 52
Subtract the nesting pointer (register pair DE) from the limit (register pair HL); the Z flag is set when the nesting stack is full.
55EA
If the include nesting is full (Z), JUMP to 579CH to report Too many nested INCLUDEs.
55ED
LD HL,57BCH 21 BC 57
Point register pair HL at the active source FCB at 57BCH to save it.
55F0
LD BC,0020H 01 20 00
Load register pair BC with 32, the FCB size.
55F3
LDIR ED B0
Block-copy the 32-byte active FCB (HL) onto the nesting stack (DE), saving the enclosing file's position.
55F5
LD (5906H),DE ED 53 06 59
Store the advanced nesting pointer (register pair DE) into 5906H.
55F9
POP HL E1
Recover the source pointer (register pair HL) to parse the included filespec.
55FA
LD DE,57BCH 11 BC 57
Point register pair DE at the source FCB (57BCH) for the new file.
55FD
GOSUB to the resident @FSPEC service at 441CH to parse the included filespec (HL) into the FCB (DE).
5600
If the filespec is invalid (NZ), JUMP to 55A8H to report an invalid format.
5602
LD HL,581FH 21 1F 58
Point register pair HL at the default extension JCL at 581FH.
5605
GOSUB to the resident @FEXT service at 4473H to apply the default /JCL extension.
5608
LD HL,5B00H 21 00 5B
Point register pair HL at the source record buffer at 5B00H.
560B
LD B,L 45
Set register B to register L (zero), the open's record-length argument.
560C
GOSUB to the resident @OPEN service at 4424H to open the included file.
560F
If the included file could not be opened (NZ), JUMP to 545AH to report the error.
5612
JUMP to 55B1H to begin reading from the included file.
5614
LD DE,4358H 11 58 43
QUIT handler: point register pair DE at the compiled-file FCB (4358H).
5617
GOSUB to the resident @CLOSE service at 4428H to close the compiled file.
561A
LD HL,59D8H 21 D8 59
Point register pair HL at the current source line at 59D8H to show it with the abort message.
561D
JUMP to 57B3H to display the line and abandon the JCL run.

5620H - Symbol Scanners, Store, Lookup and Table-Compare Engine

The symbol-table machinery. 5620H scans a parameter name and 562BH a value into work buffers; 5667H is the shared token scanner; 56CDH and 56DFH copy the name and value into a table entry; 56EAH looks a name up in the symbol table at 5D00H; 56FBH and 5704H look a directive name up in the keyword tables; and 5716H is the table-compare engine they all share.

5620
PUSH DE D5
Name scanner: save register pair DE across the scan.
5621
LD B,08H 06 08
Load register B with 8, the maximum name length.
5623
LD DE,57DCH 11 DC 57
Point register pair DE at the name buffer at 57DCH.
5626
GOSUB to the token scanner at 5667H to read up to 8 name characters from the source (HL) into the buffer (DE).
5629
POP DE D1
Recover register pair DE.
562A
RET C9
RETURN with the name in the buffer and the terminating character in register A.
562B
PUSH DE D5
Value scanner: save register pair DE.
562C
LD B,20H 06 20
Load register B with 32, the maximum value length.
562E
LD DE,57E5H 11 E5 57
Point register pair DE at the value buffer at 57E5H.
5631
GOSUB to the value-token scanner at 564AH to read the value string into the buffer (DE).
5634
PUSH AF F5
Save the terminating character (register A).
5635
PUSH HL E5
Save the source pointer (register pair HL).
5636
EX DE,HL EB
Move the end-of-value pointer into register pair HL to measure the length.
5637
LD DE,57E5H 11 E5 57
Point register pair DE at the value buffer start (57E5H).
563A
XOR A AF
Clear register A and the carry.
563B
SBC HL,DE ED 52
Subtract the buffer start (register pair DE) from the end pointer (register pair HL), giving the value length.
563D
LD A,L 7D
Copy the length low byte (register L) into register A.
563E
CP 21H FE 21
Compare the length (register A) against 33 to catch an over-long value.
5640
If the value is too long (NO CARRY), JUMP to 57A0H to report Symbol string too long.
5643
LD (57E4H),A 32 E4 57
Store the value length (register A) into the length byte at 57E4H ahead of the value.
5646
POP HL E1
Recover the source pointer (register pair HL).
5647
POP AF F1
Recover the terminating character (register A).
5648
POP DE D1
Recover register pair DE.
5649
RET C9
RETURN with the value and its length byte in the buffer.
564A
Value-token scanner: GOSUB to 5667H to read one token into the buffer.
564D
GOSUB to the delimiter helper at 577FH; the Z flag marks a space or comma that ends the value.
5650
RET Z C8
If a delimiter ended the value (Z), RETURN.
5651
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5653
RET Z C8
If the line ended (Z), RETURN.
5654
CP 3DH FE 3D
Compare register A against = (3DH).
5656
RET Z C8
If an equals ends the token (Z), RETURN.
5657
CP 28H FE 28
Compare register A against ( (28H).
5659
RET Z C8
If a left parenthesis ends the token (Z), RETURN.
565A
CP 29H FE 29
Compare register A against ) (29H).
565C
RET Z C8
If a right parenthesis ends the token (Z), RETURN.
565D
CP 23H FE 23
Compare register A against # (23H), which may embed a nested substitution in the value.
565F
If the character is not # (NZ), LOOP BACK to 564AH to continue the token.
5661
GOSUB to 5403H to handle the embedded # (literal or substitution).
5664
LD A,(HL) 7E
Load register A with the next source character (at HL).
5665
LOOP BACK to 564DH to keep scanning the value.
5667
LD A,B 78
Token scanner: copy the remaining-length count (register B) into register A.
5668
LD (56C9H),A 32 C9 56
Self-Modifying Code
Store the remaining count into the operand at 56C9H, tracking how much of the field is still unused for the trailing-space fill.
566B
INC B 04
Increment register B to compensate for the decrement at the first stored character.
566C
LD A,(HL) 7E
Load register A with the next source character (at HL).
566D
CP 03H FE 03
Compare register A against the ETX end marker (03H).
566F
If the field ended (Z), JUMP to 56BDH to pad the buffer with spaces.
5671
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5673
If the line ended (Z), JUMP to 56BDH to pad the buffer.
5675
INC HL 23
Advance the source pointer HL.
5676
CP 22H FE 22
Compare register A against a double quote (22H), which toggles literal mode.
5678
If the character is not a quote (NZ), JUMP to 5681H to classify it.
567A
XOR 22H EE 22
Exclusive-OR register A with the quote value to toggle the literal-mode flag between 0 and 22H.
567C
LD (567BH),A 32 7B 56
Self-Modifying Code
Store the toggled literal-mode flag into the operand at 567BH read below.
567F
LOOP BACK to 566CH for the next character.
5681
LD C,A 4F
Save the character (register A) into register C.
5682
LD A,(567BH) 3A 7B 56
Load register A with the literal-mode flag at 567BH.
5685
OR A B7
Test the literal-mode flag (register A) for zero.
5686
LD A,C 79
Restore the character (register C) into register A.
5687
If not in literal mode (Z), JUMP to 56AFH to test the character normally (below); in quotes it is stored verbatim.
5689
CP 40H FE 40
Compare register A against @ (40H), the label marker.
568B
If the character is not @ (NZ), JUMP to 569AH to range-check it.
568D
SUB 00H D6 00
Self-Modifying Code
Subtract the label-flag operand at 568EH from register A (patched below to record a label was seen).
568F
If a second label marker is seen (Z), JUMP to 57A8H to report Too many Proc labels.
5692
LD (568EH),A 32 8E 56
Store the label flag (register A) into 568EH, recording that a label was encountered.
5695
LD (5343H),A 32 43 53
Store the same flag into the parse-mode cell at 5343H so the parameter parser switches to label-capture.
5698
LOOP BACK to 566CH for the next character.
569A
CP 2EH FE 2E
Compare register A against . (2EH), the lowest accepted name character.
569C
If the character is below . (CARRY, a delimiter), JUMP to 56BDH to end the token.
569E
CP 3BH FE 3B
Compare register A against ; (3BH).
56A0
If the character is a digit or punctuation below ; (CARRY), JUMP to 56AFH to store it.
56A2
CP 41H FE 41
Compare register A against A (41H).
56A4
If the character is between ; and A (CARRY, a delimiter), JUMP to 56BDH to end the token.
56A6
CP 5BH FE 5B
Compare register A against [ (5BH), one past Z.
56A8
If the character is an upper-case letter (CARRY), JUMP to 56AFH to store it.
56AA
GOSUB to the upper-case helper at 5785H to fold a lower-case letter; it returns CARRY for a non-letter.
56AD
If the character is not a letter (CARRY), JUMP to 56BDH to end the token.
56AF
DEC B 05
Decrement the remaining-length count (register B).
56B0
If the field is now full (Z), JUMP to 56BAH to stop storing but keep consuming.
56B2
LD (DE),A 12
Store the character (register A) into the buffer (at DE).
56B3
XOR A AF
Clear register A.
56B4
LD (56C9H),A 32 C9 56
Clear the unused-count operand at 56C9H, since a character was stored.
56B7
INC DE 13
Advance the buffer pointer DE.
56B8
LOOP BACK to 566CH for the next character.
56BA
INC B 04
Field full: restore register B so the loop keeps consuming source without overflowing the buffer.
56BB
LOOP BACK to 566CH for the next character.
56BD
LD C,A 4F
End of token: save the terminating character (register A) into register C.
56BE
PUSH DE D5
Save the buffer pointer (register pair DE).
56BF
JUMP to 56C5H to enter the space-fill loop with the current count.
56C1
LD A,20H 3E 20
Load register A with a space (20H) as the pad character.
56C3
LD (DE),A 12
Store the pad space (register A) into the buffer (at DE).
56C4
INC DE 13
Advance the buffer pointer DE.
56C5
DECrement register B and LOOP BACK to 56C1H to space-fill the remainder of the fixed-width field.
56C7
POP DE D1
Recover the buffer pointer (register pair DE).
56C8
LD A,00H 3E 00
Self-Modifying Code
Load register A with the unused-count flag at the 56C9H operand; nonzero when no name characters were stored.
56CA
OR A B7
Test register A, setting the Z flag when at least one character was scanned.
56CB
LD A,C 79
Load register A with the terminating character (register C) for the caller.
56CC
RET C9
RETURN with the token in the buffer, the terminator in register A, and the empty/non-empty status in the Z flag.
56CD
PUSH HL E5
Name-store helper: save the source pointer (register pair HL).
56CE
LD HL,57DCH 21 DC 57
Point register pair HL at the scanned name buffer at 57DCH.
56D1
LD BC,0008H 01 08 00
Load register pair BC with 8, the name length.
56D4
LDIR ED B0
Block-copy the 8-character name from the buffer (HL) into the symbol-table entry (at DE).
56D6
XOR A AF
Clear register A to zero-terminate the value area of the new entry.
56D7
LD (DE),A 12
Store a zero length (register A) into the entry's value field (at DE).
56D8
LD HL,0021H 21 21 00
Load register pair HL with 33, the offset to the end of the entry.
56DB
ADD HL,DE 19
Add the entry pointer (register pair DE) to HL, addressing the entry terminator.
56DC
LD (HL),A 77
Store zero (register A) at the entry terminator (at HL), marking the end of the table.
56DD
POP HL E1
Recover the source pointer (register pair HL).
56DE
RET C9
RETURN with the new entry's name written.
56DF
PUSH HL E5
Value-store helper: save the source pointer (register pair HL).
56E0
LD HL,57E4H 21 E4 57
Point register pair HL at the value buffer (length byte first) at 57E4H.
56E3
LD BC,0021H 01 21 00
Load register pair BC with 33, the length byte plus the 32-byte value.
56E6
LDIR ED B0
Block-copy the value (HL) into the symbol-table entry (at DE).
56E8
POP HL E1
Recover the source pointer (register pair HL).
56E9
RET C9
RETURN with the value stored.
56EA
PUSH HL E5
Symbol-lookup helper: save the source pointer (register pair HL).
56EB
LD DE,57DCH 11 DC 57
Point register pair DE at the name to find at 57DCH.
56EE
LD HL,5D00H 21 00 5D
Point register pair HL at the symbol table at 5D00H.
56F1
LD BC,0829H 01 29 08
Load register B with 8 (name compare length) and register C with 29H (41, the entry stride: 8 name + 1 length + 32 value).
56F4
GOSUB to the table-compare engine at 5716H to find the name; register pair HL is left pointing at the entry's value on a match.
56F7
LD D,H 54
Copy the found pointer high byte (register H) into register D.
56F8
LD E,L 5D
Copy the low byte (register L) into register E; register pair DE now points at the value (or free slot).
56F9
POP HL E1
Recover the source pointer (register pair HL).
56FA
RET C9
RETURN with the entry in register pair DE and the found/not-found status in the flags.
56FB
PUSH HL E5
Block-directive lookup: save the source pointer (register pair HL).
56FC
LD HL,54FAH 21 FA 54
Point register pair HL at the block-directive table at 54FAH.
56FF
LD BC,0507H 01 07 05
Load register B with 5 (name compare length) and register C with 7 (entry stride: 5 name + 2 address).
5702
JUMP to the shared lookup tail at 570BH.
5704
PUSH HL E5
Action-directive lookup: save the source pointer (register pair HL).
5705
LD HL,5510H 21 10 55
Point register pair HL at the action-directive table at 5510H.
5708
LD BC,080AH 01 0A 08
Load register B with 8 (name compare length) and register C with 0AH (entry stride: 8 name + 2 address).
570B
LD DE,57DCH 11 DC 57
Point register pair DE at the scanned directive name at 57DCH.
570E
GOSUB to the table-compare engine at 5716H to find the directive; HL is left pointing at the handler address on a match.
5711
LD E,(HL) 5E
Load register E with the handler address low byte (at HL).
5712
INC HL 23
Advance register pair HL to the high byte.
5713
LD D,(HL) 56
Load register D with the handler address high byte; register pair DE is the handler.
5714
POP HL E1
Recover the source pointer (register pair HL).
5715
RET C9
RETURN with the handler in register pair DE and the match status in the flags.
5716
LD A,(HL) 7E
Table-compare engine: load register A with the first byte of the current table entry (at HL).
5717
OR A B7
Test the byte for zero, which marks the end of the table.
5718
If this is not the terminator (NZ), JUMP to 571CH to compare the entry.
571A
INC A 3C
End of table: set register A to 1 to report not found.
571B
RET C9
RETURN with the not-found status (NZ).
571C
LD A,(DE) 1A
Load register A with the first character of the search name (at DE).
571D
GOSUB to the upper-case helper at 5785H to fold the search character.
5720
CP (HL) BE
Compare the search character (register A) against the entry's first character (at HL).
5721
If the first characters match (Z), JUMP to 572AH to compare the rest.
5723
PUSH BC C5
Save the compare parameters (register pair BC).
5724
LD B,00H 06 00
Clear register B so register pair BC is the entry stride (register C).
5726
ADD HL,BC 09
Add the stride (register pair BC) to HL, advancing to the next table entry.
5727
POP BC C1
Recover the compare parameters (register pair BC).
5728
LOOP BACK to 5716H to test the next entry.
572A
PUSH HL E5
Save the entry pointer (register pair HL).
572B
PUSH DE D5
Save the search-name pointer (register pair DE).
572C
PUSH BC C5
Save the compare parameters (register pair BC).
572D
DEC B 05
Decrement the compare length (register B) for the first character already matched.
572E
INC DE 13
Advance the search-name pointer DE.
572F
INC HL 23
Advance the entry pointer HL.
5730
LD A,(DE) 1A
Load register A with the next search character (at DE).
5731
CP 20H FE 20
Compare register A against a space (20H), which ends the search name.
5733
If the search name ended (Z), JUMP to 575CH to confirm the entry ends too.
5735
CP 0DH FE 0D
Compare register A against a carriage return (0DH).
5737
If the search name ended with a carriage return (Z), JUMP to 575CH.
5739
GOSUB to 5785H to fold the search character to upper case.
573C
CP (HL) BE
Compare the search character (register A) against the entry character (at HL).
573D
If the characters differ (NZ), JUMP to 574CH to reject or continue.
573F
DECrement the compare length (register B) and LOOP BACK to 572EH for the next character.
5741
POP BC C1
Full name matched: recover the compare parameters (register pair BC).
5742
POP DE D1
Recover the search-name pointer (register pair DE).
5743
POP HL E1
Recover the entry pointer (register pair HL).
5744
PUSH BC C5
Re-save the compare parameters (register pair BC).
5745
LD C,B 48
Copy the name compare length (register B) into register C to skip to the entry's data field.
5746
LD B,00H 06 00
Clear register B so register pair BC is the name length.
5748
ADD HL,BC 09
Add the name length (register pair BC) to HL so it points past the name at the entry's value or handler.
5749
POP BC C1
Recover the compare parameters (register pair BC).
574A
XOR A AF
Clear register A to report a match (Z).
574B
RET C9
RETURN with the match (Z) and HL at the entry's data.
574C
CP 30H FE 30
Mismatch: compare the search character (register A) against 0 (30H) to allow numeric-suffixed names.
574E
If below 0 (CARRY, a delimiter), JUMP to 575CH.
5750
CP 3AH FE 3A
Compare register A against : (3AH).
5752
If the character is a digit (CARRY), JUMP to 5761H to try the next entry (this one did not match).
5754
CP 41H FE 41
Compare register A against A (41H).
5756
If between : and A (CARRY, a delimiter), JUMP to 575CH.
5758
CP 5BH FE 5B
Compare register A against [ (5BH).
575A
If the character is a letter (CARRY), JUMP to 5761H to try the next entry.
575C
LD A,(HL) 7E
Load register A with the entry character (at HL) to confirm the entry also ends here.
575D
CP 20H FE 20
Compare register A against a space (20H), the entry's padding.
575F
If the entry ends here too (Z), JUMP to 5741H to accept the match.
5761
POP BC C1
Not this entry: recover the compare parameters (register pair BC).
5762
POP DE D1
Recover the search-name pointer (register pair DE).
5763
POP HL E1
Recover the entry pointer (register pair HL).
5764
JUMP to 5723H to advance to the next table entry.

5766H - Decimal Formatter, Delimiter/Upper-Case Helpers and Error Dispatcher

The remaining code: 5766H writes a right-justified 5-digit line number, 577FH tests for a space or comma delimiter, 5785H folds a letter to upper case, and 578FH onward reports the JCL errors. The message dispatcher at 5798H uses a chain of DD-prefixed loads so that entering one byte later selects a different message pointer.

5766
LD B,05H 06 05
Decimal formatter: load register B with 5, the field width.
5768
LD A,20H 3E 20
Load register A with a space (20H) to blank the field.
576A
LD (DE),A 12
Store a space (register A) into the field (at DE).
576B
INC DE 13
Advance the field pointer DE.
576C
DECrement register B and LOOP BACK to 576AH to blank all 5 positions.
576E
PUSH DE D5
Save the field-end pointer (register pair DE).
576F
DEC DE 1B
Step register pair DE back to the next digit position (filling right to left).
5770
LD A,0AH 3E 0A
Load register A with 10, the divisor for the next decimal digit.
5772
GOSUB to the resident @DIV service at 44C4H to divide the value (register pair HL) by 10; the quotient stays in HL and the remainder digit is returned in register A.
5775
ADD A,30H C6 30
Add 0 (30H) to the remainder (register A) to make an ASCII digit.
5777
LD (DE),A 12
Store the digit (register A) into the field (at DE).
5778
DEC DE 1B
Step register pair DE back to the next digit position.
5779
LD A,H 7C
Copy the quotient high byte (register H) into register A.
577A
OR L B5
OR the low byte (register L) into register A; the Z flag is set when the value is exhausted.
577B
If digits remain (NZ), LOOP BACK to 576FH for the next digit.
577D
POP DE D1
Recover the field-end pointer (register pair DE).
577E
RET C9
RETURN with the number formatted right-justified in the field.
577F
CP 20H FE 20
Delimiter helper: compare register A against a space (20H).
5781
RET Z C8
If the character is a space (Z), RETURN with the Z flag set.
5782
CP 2CH FE 2C
Compare register A against a comma (2CH), also a delimiter; the Z flag is set on a match.
5784
RET C9
RETURN with the Z flag marking a space or comma.
5785
CP 61H FE 61
Upper-case helper: compare register A against a (61H).
5787
RET C D8
If the character is below a (CARRY, not lower case), RETURN unchanged.
5788
CP 7BH FE 7B
Compare register A against { (7BH), one past z.
578A
CCF 3F
Complement the carry so a letter a-z now clears it and a non-letter sets it.
578B
RET C D8
If the character is above z (CARRY, not lower case), RETURN unchanged.
578C
XOR 20H EE 20
Exclusive-OR register A with 20H to fold the lower-case letter to upper case.
578E
RET C9
RETURN with the upper-cased character in register A.
578F
LD A,2CH 3E 2C
Parameter-error entry: load register A with 2CH (error code 44, parameter error).
5791
OR 0C0H F6 C0
Disk/DOS-error entry (register A already holds the code): set bits 7 and 6 to request the standard error display and return handling.
5793
GOSUB to the resident @ERROR service at 4409H to display the error text for the code in register A.
5796
JUMP to 57B6H to set the failure status and exit.

Overlapping Code
The rows from 5798H to 57B2H are a seven-way message selector. Falling in at 5798H sets HL to the File spec required message and the following DD-prefixed loads are inert. Entering one byte later, at the address inside each DD-prefixed load, skips the DD prefix so the bytes read as LD HL,nnnn and select a different message: 579CH the nested-INCLUDEs message, 57A0H symbol-string-too-long, 57A4H procedure-not-found, 57A8H too-many-Proc-labels, 57ACH can't-create, 57B0H multiply-defined. All paths fall through to the display at 57B3H.

5798
LD HL,5825H 21 25 58
Fall-through entry: point register pair HL at the File spec required message at 5825H.
579B
LD IX,58ECH DD 21 EC 58
On fall-through this loads register pair IX with 58ECH and is inert; entered at 579CH the bytes 21 EC 58 read as LD HL,58ECH, selecting the Too many nested INCLUDEs message.
579F
LD IX,5848H DD 21 48 58
Inert on fall-through; entered at 57A0H it reads as LD HL,5848H, the Symbol string too long message.
57A3
LD IX,5860H DD 21 60 58
Inert on fall-through; entered at 57A4H it reads as LD HL,5860H, the Procedure not found message.
57A7
LD IX,5875H DD 21 75 58
Inert on fall-through; entered at 57A8H it reads as LD HL,5875H, the Too many Proc labels message.
57AB
LD IX,588BH DD 21 8B 58
Inert on fall-through; entered at 57ACH it reads as LD HL,588BH, the Can't create SYSTEM/JCL file message.
57AF
LD IX,58A9H DD 21 A9 58
Inert on fall-through; entered at 57B0H it reads as LD HL,58A9H, the Multiply defined parameter message.
57B3
GOSUB to the resident @LOGOT service at 447BH to display the selected message (register pair HL).
57B6
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the failure status for the exit.
57B9
JUMP to the shared exit at 5305H (which restores the caller's stack and returns or aborts).

580DH - Launch Stubs, Filename Template and Error Messages

The data area (ORG 580DH). It holds the launch stubs copied over the resident @EXIT and @ERROR vectors, the SYSTEM/JCL filename template and default extension, the nine error messages, the include-nesting base pointer, the IF-condition state pointer and the "Line nnnnn --" error prefix. This is data, not code.

580D
DEFB 00H 00
Alignment pad byte before the stubs.
580E-5813
DEFB 3E ADH EFH 3E BDH EFH 3E AD EF 3E BD EF
@EXIT Launch Stub
Copied over the resident @EXIT vector at 402DH (52F9H). It issues RST 28H request 0ADH then 0BDH so that exiting the launched job returns into the JCL launcher.
5814-5817
DEFB F5H 3E 96H EFH F5 3E 96 EF
@ERROR Launch Stub
Copied over the resident @ERROR vector at 4409H (52DAH). It pushes AF then issues RST 28H request 96H (@ERROR) so a JCL error is reported through the standard error path.
5818-5824
DEFM "SYSTEM/JCL:d" + 03H 53 59 53 54 45 4D 2F 4A 43 4C 03 03 03
Filename Template
The SYSTEM/JCL compiled-file name copied into the job FCB at 5330H. The drive suffix at 5823H is patched with the chosen drive at 524DH. The JCL portion at 581FH also serves as the default extension applied by @FEXT.
5825-5838
DEFM "File spec required!" + 0DH 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21 0D
Message
Displayed by the error dispatcher entry at 5798H.
5839-5847
DEFM "Line too long!" + 0DH 4C 69 6E 65 20 74 6F 6F 20 6C 6F 6E 67 21 0D
Message
Selected by patching the 546AH operand when a source line exceeds 64 characters.
5848-585F
DEFM "Symbol string too long!" + 0DH 53 79 6D 62 6F 6C 20 73 74 72 69 6E 67 20 74 6F 6F 20 6C 6F 6E 67 21 0D
Message
Displayed via the 57A0H entry when a parameter value exceeds 32 characters.
5860-5874
DEFM "Procedure not found!" + 0DH 50 72 6F 63 65 64 75 72 65 20 6E 6F 74 20 66 6F 75 6E 64 21 0D
Message
Displayed via the 57A4H entry when a requested label is not present.
5875-588A
DEFM "Too many Proc labels!" + 0DH 54 6F 6F 20 6D 61 6E 79 20 50 72 6F 63 20 6C 61 62 65 6C 73 21 0D
Message
Displayed via the 57A8H entry when more than one label marker is seen.
588B-58A8
DEFM "Can't create SYSTEM/JCL file!" + 0DH 43 61 6E 27 74 20 63 72 65 61 74 65 20 53 59 53 54 45 4D 2F 4A 43 4C 20 66 69 6C 65 21 0D
Message
Displayed via the 57ACH entry when the compiled output file cannot be created.
58A9-58C3
DEFM "Multiply defined parameter" + 0DH 4D 75 6C 74 69 70 6C 79 20 64 65 66 69 6E 65 64 20 70 61 72 61 6D 65 74 65 72 0D
Message
Displayed via the 57B0H entry for a duplicate or undefined parameter.
58C4-58EB
DEFM "Invalid JCL format, processing aborted!" + 0DH 49 6E 76 61 6C 69 64 20 4A 43 4C 20 66 6F 72 6D 61 74 2C 20 70 72 6F 63 65 73 73 69 6E 67 20 61 62 6F 72 74 65 64 21 0D
Message
The default message displayed by the 5469H error printer after the Line nnnnn -- prefix.
58EC-5905
DEFM "Too many nested INCLUDEs!" + 0DH 54 6F 6F 20 6D 61 6E 79 20 6E 65 73 74 65 64 20 49 4E 43 4C 55 44 45 73 21 0D
Message
Displayed via the 579CH entry when the INCLUDE nesting stack is full.
5906-5907
DEFW 5908H 08 59
Include-Nesting Pointer
The top of the saved-FCB nesting stack; initialised to 5908H (empty) and advanced by INCLUDE.
59A8-59AA
DEFW 59AAH, DEFB 00H AA 59 00
IF-State Pointer
59A8H points at the current condition-state slot (base 59AAH); the byte at 59AAH is the state (zero = active/true, nonzero = output suppressed).
59CA-59D7
DEFM "Line xxxxx -->" 4C 69 6E 65 20 78 78 78 78 78 20 2D 2D 3E
Line Prefix
The error-line prefix; the five xxxxx at 59CFH are overwritten with the current line number by the formatter at 5766H before the message is shown.

Disassembly - Overlay 6 - SPOOL

5200H - SPOOL Command Entry and Re-open of an Installed Spooler

Entry of the SPOOL command overlay. It first checks the resident pointer at 4DF0H/4DF1H that records whether a spooler is already installed. If one is installed, its saved parameters are copied into this overlay's work cells and the option table pointer is switched to the reduced keyword set, so an active spooler can only be paused, resumed, cleared or turned off. If no spooler is installed yet, control drops through to the command-level guard.

5200
LD (5639H),SP ED 73 39 56
Self-Modifying Code
Store the caller's stack pointer into the operand of the LD SP,nnnn instruction at 5638H, so the overlay exit can restore the caller's stack. Register SP holds the LDOS command-level stack on entry.
5204
LD DE,584EH 11 4E 58
Point register pair DE at 584EH, the start of this overlay's 10-byte module-descriptor scratch area (module base at +00/+01, buffer ceiling at +02/+03, requested memory size at +04/+05, spool-to-disk drive at +06/+07, task link at +08/+09).
5207
PUSH DE D5
Save register pair DE (584EH, the module-descriptor scratch pointer) on the stack so it can be moved into IY.
5208
POP IY FD E1
Restore the module-descriptor pointer 584EH into register pair IY; from here IY indexes the descriptor fields.
520A
LD IX,441FH DD 21 1F 44
Point register pair IX at 441FH, the resident system flag byte. IX+00H is the flag byte at 441FH (bit0 = spooler installed, bit3 = KI/DVR device driver active); IX+04H is KFLAG$ at 4423H (bit4 = despooling enabled).
520E
LD A,(4DF1H) 3A F1 4D
Load register A with the high byte of the resident installed-spooler pointer at 4DF0H/4DF1H. A non-zero value means a spooler module is already resident in high memory.
5211
OR A B7
Test register A (the installed-spooler pointer high byte). If it is zero, no spooler is installed and the Z flag is set.
5212
If the Z flag is set (no spooler installed yet), JUMP to 523FH to run the command-level guard and a full parameter parse.
5214
PUSH HL E5
A spooler is already installed. Save register pair HL (the command-line scan pointer) on the stack.
5215
LD H,A 67
Move the installed-spooler pointer high byte (register A, from 4DF1H) into register H.
5216
LD A,(4DF0H) 3A F0 4D
Load register A with the low byte of the installed-spooler pointer from 4DF0H.
5219
LD L,A 6F
Move the installed-spooler pointer low byte (register A, from 4DF0H) into register L, so HL now points at the resident spooler module.
521A
LD (55AFH),HL 22 AF 55
Self-Modifying Code
Store the resident spooler module base (register pair HL) into the operand of the LD HL,nnnn instruction at 55AEH, which the CLEAR-queue handler uses to reach the module.
521D
LD BC,000AH 01 0A 00
Load register pair BC with 000AH (10 bytes), the length of the module descriptor to copy.
5220
LDIR ED B0
Block-copy 10 bytes from the resident spooler module (HL) to this overlay's descriptor scratch at 584EH (DE), so the installed spooler's saved settings become the working descriptor.
5222
LD E,(IY+04H) FD 5E 04
Load register E with descriptor byte IY+04H, the low byte of the installed spooler's requested memory size.
5225
LD D,(IY+05H) FD 56 05
Load register D with descriptor byte IY+05H, the high byte of the installed spooler's requested memory size.
5228
LD (538EH),DE ED 53 8E 53
Store the recovered memory size (register pair DE) into cell 538EH, this overlay's MEM keyword value cell, so it reflects the running spooler.
522C
LD E,(IY+06H) FD 5E 06
Load register E with descriptor byte IY+06H, the low byte of the installed spooler's spool-to-disk drive setting.
522F
LD D,(IY+07H) FD 56 07
Load register D with descriptor byte IY+07H, the high byte of the spool-to-disk drive setting.
5232
LD (5356H),DE ED 53 56 53
Store the recovered disk setting (register pair DE) into cell 5356H, this overlay's DISK keyword value cell.
5236
LD HL,5803H 21 03 58
Load register pair HL with 5803H, the address of the reduced option table (the OFF, PAUSE, RESUME and CLEAR entries only).
5239
LD (52C7H),HL 22 C7 52
Self-Modifying Code
Store 5803H (register pair HL) into the operand of the LD DE,nnnn instruction at 52C6H, replacing the full option-table pointer 57E3H so an already-active spooler accepts only the OFF, PAUSE, RESUME and CLEAR keywords.
523C
POP HL E1
Restore register pair HL (the command-line scan pointer) from the stack.
523D
JUMP to 5259H to parse the output device or file specification, bypassing the command-level guard (an installed spooler may always be adjusted).

523FH - Command-Level and Busy-State Guard

Reached only when no spooler is installed. SPOOL may be installed only from LDOS Ready with no user program resident and no busy background task, so this block refuses the command if a program occupies the @EXIT return vector or if the SYS1 busy flag is set.

523F
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH.
5242
BIT 5,A CB 6F
Test bit 5 of register A (SFLAG$). Bit 5 set means execution is not at the LDOS command level.
5244
LD A,(402DH) 3A 2D 40
Load register A with the first byte of the resident @EXIT vector at 402DH. A value of C3H (a JP opcode) means a user program has claimed the exit path.
5247
If bit 5 was clear (at command level), the Z flag is set; JUMP to 524CH keeping the @EXIT byte just loaded.
5249
LD A,(4065H) 3A 65 40
Not at command level: load register A with the saved A-register byte at 4065H (the register-snapshot slot) to test whether a resident program is present.
524C
CP 0C3H FE C3
Compare register A against C3H (a JP opcode), the signature of an installed program on the exit path.
524E
If register A equals C3H (a program is resident), JUMP to 5658H to refuse with the message Can't -- Valid only at LDOS Command level!.
5251
LD A,(4758H) 3A 58 47
Load register A with the SYS1 status byte at 4758H.
5254
BIT 1,A CB 4F
Test bit 1 of register A (the SYS1 status byte). Bit 1 set means a background task is busy.
5256
If bit 1 was set (busy), the NZ flag is set; JUMP to 5658H to refuse the command. Otherwise fall through to the filespec parse.

5259H - Parse the Output Device or Spool Filespec

Determines what the spooler will intercept. The command tail is parsed by the resident @FSPEC service into a local file control block at 57B8H. When no operand or a bare device is given, the default printer device *PR is used; a device operand builds a matching device/SPL spool filename, and a disk filespec is copied to the runtime control block.

5259
LD DE,57B8H 11 B8 57
Point register pair DE at 57B8H, the local file control block that @FSPEC will fill from the command tail.
525C
GOSUB to the resident @FSPEC service at 441CH to parse the next filespec on the command line into the FCB at 57B8H. It returns the NZ flag if no valid filespec was found.
525F
PUSH HL E5
Save register pair HL (the command-line pointer returned by @FSPEC) on the stack.
5260
If @FSPEC set NZ (no filespec supplied), JUMP to 5284H to install the default printer device.
5262
LD A,(DE) 1A
Load register A with the first character of the parsed spec at (DE), the start of the FCB at 57B8H.
5263
CP 2AH FE 2A
Compare register A against 2AH, the asterisk that marks a device specification such as *PR.
5265
If register A is an asterisk (a device spec), JUMP to 5287H to build the spool filename from the device name.
5267
EX DE,HL EB
A disk filespec was given. Exchange DE and HL so register pair HL points at the parsed FCB at 57B8H.
5268
LD DE,59AFH 11 AF 59
Point register pair DE at 59AFH, the resident spooler runtime control block and FCB work area.
526B
PUSH DE D5
Save register pair DE (59AFH, the runtime control block) on the stack.
526C
LD BC,0020H 01 20 00
Load register pair BC with 0020H (32 bytes), the length of a file control block.
526F
LDIR ED B0
Block-copy the 32-byte FCB from 57B8H (HL) to the runtime control block at 59AFH (DE), making the disk file the spool destination.
5271
GOSUB to the helper at 5278H to reset the FCB at 57B8H to the default printer device *PR.
5274
XOR A AF
Set register A to zero (and set the Z flag) to signal no ':' drive suffix follows.
5275
POP DE D1
Restore register pair DE (59AFH, the runtime control block) from the stack.
5276
JUMP to 5297H to apply the default spool extension and finish the filename.

Default Printer Device Helper
The four-instruction subroutine at 5278H copies the default device spec into the working FCB.

5278
LD HL,57DFH 21 DF 57
Point register pair HL at 57DFH, the default printer device spec *PR terminated by 03H.
527B
LD DE,57B8H 11 B8 57
Point register pair DE at 57B8H, the working FCB to overwrite with the default device.
527E
LD BC,0004H 01 04 00
Load register pair BC with 0004H (4 bytes), the length of the *PR,03 spec.
5281
LDIR ED B0
Block-copy the 4-byte *PR device spec from 57DFH (HL) to the working FCB at 57B8H (DE).
5283
RET C9
Return to the caller.
5284
No filespec was supplied: GOSUB to 5278H to load the default printer device *PR into the FCB at 57B8H, then fall through.
5287
POP HL E1
Device path: restore register pair HL (the command-line pointer from @FSPEC) from the stack.
5288
LD DE,(57B9H) ED 5B B9 57
Load register pair DE with the two device-name characters at 57B9H, the name field of the parsed device FCB.
528C
LD (57D8H),DE ED 53 D8 57
Store the two device-name characters (register pair DE) into the disk spool-file name template at 57D8H, replacing its XX placeholder so the overflow file is named devname/SPL.
5290
LD DE,59AFH 11 AF 59
Point register pair DE at 59AFH, the runtime control block, ready for @FSPEC to parse the spool filename into it.
5293
GOSUB to @FSPEC at 441CH to parse whatever remains of the command tail into the runtime control block at 59AFH.
5296
PUSH HL E5
Save register pair HL (the command-line pointer) on the stack.
5297
PUSH AF F5
Save register AF (the @FSPEC status, whose NZ flag says no name was parsed) on the stack.
5298
LD HL,57D8H 21 D8 57
Point register pair HL at the disk spool-file name template at 57D8H (devname/SPL).
529B
If @FSPEC found no spool name (NZ flag), GOSUB @FSPEC at 441CH to parse the template at 57D8H into the runtime FCB instead.
529E
LD HL,57DBH 21 DB 57
Point register pair HL at 57DBH, the default spool extension /SPL text.
52A1
GOSUB to the resident @FEXT service at 4473H to apply the default /SPL extension to the runtime FCB if the operator supplied none.
52A4
POP AF F1
Restore register AF (the earlier @FSPEC status) from the stack.
52A5
POP HL E1
Restore register pair HL (the command-line pointer) from the stack.
52A6
CP 3AH FE 3A
Compare register A (the delimiter that ended the last filespec) against 3AH, a colon introducing a :d drive suffix.
52A8
If the delimiter is not a colon (no drive follows), JUMP to 52C6H to parse the option keywords.

Copy Drive Suffix
A colon was found; copy the :d drive text onto the end of the spool name.

52AA
LD A,(DE) 1A
Load register A with the character at (DE), scanning the runtime FCB for its terminator.
52AB
CP 0DH FE 0D
Compare register A against 0DH, a carriage return terminator.
52AD
If register A is a carriage return (end of name), JUMP to 52B6H to append the colon.
52AF
CP 03H FE 03
Compare register A against 03H, the alternate ETX terminator.
52B1
If register A is 03H (end of name), JUMP to 52B6H to append the colon.
52B3
INC DE 13
INCrement register pair DE to the next character of the runtime FCB name.
52B4
LOOP BACK to 52AAH to keep scanning for the name terminator.
52B6
LD A,3AH 3E 3A
Load register A with 3AH, a colon, to separate the name from the drive digit.
52B8
LD (DE),A 12
Store the colon (register A) over the terminator at (DE).
52B9
INC DE 13
INCrement register pair DE past the colon.
52BA
LD A,(HL) 7E
Load register A with the drive character at (HL) from the command line.
52BB
CP 0DH FE 0D
Compare register A against 0DH, a carriage return (no drive digit present).
52BD
If register A is a carriage return (a colon with no drive digit is a syntax error), JUMP to 5647H to report a parameter error.
52C0
INC HL 23
INCrement register pair HL past the drive character.
52C1
LD (DE),A 12
Store the drive character (register A) into the runtime FCB name at (DE).
52C2
INC DE 13
INCrement register pair DE past the drive character.
52C3
LD A,03H 3E 03
Load register A with 03H, the ETX terminator, to close the name.
52C5
LD (DE),A 12
Store the ETX terminator (register A) at (DE) to end the runtime FCB name.

52C6H - Decode the Option Keywords and Dispatch Sub-commands

The resident @PARAM service scans the command tail against this overlay's keyword table. Each keyword deposits its value into the operand field of an instruction below. The four flag keywords (OFF/N, RESUME/R, PAUSE/P, CLEAR/C) leave an FFH marker that the INC E tests detect, dispatching to the matching sub-command handler; MEM and DISK leave numeric values in cells 538EH and 5356H used by the install path.

52C6
LD DE,57E3H 11 E3 57
Point register pair DE at 57E3H, the option keyword descriptor table. If a spooler was already installed this operand was patched to 5803H, the reduced table.
52C9
GOSUB to the resident @PARAM service at 4476H to match the keywords MEM, DISK, OFF/N, PAUSE, RESUME and CLEAR and store each supplied value into the operand cell named by the table.
52CC
If @PARAM reported an unrecognised keyword (NZ flag), JUMP to 5647H to report a parameter error.
52CF
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the OFF/N flag cell at 52D0H, which @PARAM sets to 00FFH when the OFF or N keyword was given (otherwise 0000H).
52D2
INC E 1C
INCrement register E. If the OFF/N flag byte was FFH it wraps to 00H and sets the Z flag.
52D3
If the OFF/N keyword was given (Z flag), JUMP to 5539H to remove the spooler and reclaim its memory.
52D6
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the RESUME/R flag cell at 52D7H, set to 00FFH by @PARAM when the RESUME or R keyword was given.
52D9
INC E 1C
INCrement register E; an FFH RESUME/R flag wraps to 00H and sets the Z flag.
52DA
If the RESUME/R keyword was given (Z flag), JUMP to 5524H to resume despooling.
52DD
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the PAUSE/P flag cell at 52DEH, set to 00FFH by @PARAM when the PAUSE or P keyword was given.
52E0
INC E 1C
INCrement register E; an FFH PAUSE/P flag wraps to 00H and sets the Z flag.
52E1
If the PAUSE/P keyword was given (Z flag), JUMP to 550FH to pause despooling.
52E4
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the CLEAR/C flag cell at 52E5H, set to 00FFH by @PARAM when the CLEAR or C keyword was given.
52E7
INC E 1C
INCrement register E; an FFH CLEAR/C flag wraps to 00H and sets the Z flag.
52E8
If the CLEAR/C keyword was given (Z flag), JUMP to 55A7H to empty the spool queue. Otherwise this is a fresh install request and control falls through.

52EBH - Reject a Duplicate Install and Locate the Output Driver

No sub-command keyword was given, so this is a request to install the spooler. The routine refuses if a spooler is already active, refuses if the keyboard/device driver (KI/DVR) is not present, then finds the device control block for the output device and follows any route chain to the real driver.

52EB
LD A,(IX+00H) DD 7E 00
Load register A with the resident flag byte IX+00H at 441FH (bit0 = spooler installed, bit3 = KI/DVR active).
52EE
RRCA 0F
Rotate register A right so its old bit 0 (spooler installed) lands in the carry flag.
52EF
If the carry flag is set (a spooler is already installed), JUMP to 5627H to report Spooler is already active.
52F2
BIT 3,A CB 5F
Test bit 3 of register A (the rotated flag byte). Bit 3 reflects whether the KI/DVR device driver is active.
52F4
If bit 3 is clear (no KI/DVR driver), JUMP to 5650H to report SPOOLER requires KI/DVR active!.
52F7
LD DE,(57B9H) ED 5B B9 57
Load register pair DE with the two-character device name at 57B9H (the parsed output device, defaulting to PR).
52FB
GOSUB to the find-driver helper at 55F1H, which searches the KIDCB$ chain at 4015H and the auxiliary DCB chain at 43C0H for a device control block whose name matches register pair DE; on success HL points at the DCB, otherwise error 08H is returned.
52FE
If no matching device control block was found (NZ flag), JUMP to 5649H to report the resident error.

Follow Route Chain
If the located device is routed, walk the link fields to the ultimate device control block.

5301
BIT 4,(HL) CB 66
Test bit 4 of the device control block type byte at (HL). Bit 4 set means the device is routed to another device.
5303
If bit 4 is clear (not routed), JUMP to 530CH; register pair HL already points at the real driver.
5305
INC HL 23
INCrement register pair HL to the low byte of the routed device's forward pointer.
5306
LD A,(HL) 7E
Load register A with the low byte of the routed forward pointer at (HL).
5307
INC HL 23
INCrement register pair HL to the high byte of the routed forward pointer.
5308
LD H,(HL) 66
Load register H with the high byte of the routed forward pointer at (HL).
5309
LD L,A 6F
Move the saved low byte (register A) into register L, so HL now points at the next device control block in the route chain.
530A
LOOP BACK to 5301H to keep following the route chain until a non-routed device is reached.
530C
BIT 3,(IX+00H) DD CB 00 5E
Test bit 3 of the resident flag byte IX+00H at 441FH (the KI/DVR-active flag) again before sizing the buffer.
5310
If bit 3 is clear, JUMP to 5337H, skipping the driver-table free-memory calculation.
5312
PUSH HL E5
Save register pair HL (the resolved device control block pointer) on the stack.
5313
LD A,(4DF6H) 3A F6 4D
Load register A with the low byte of the resident driver-table pointer at 4DF6H/4DF7H.
5316
LD L,A 6F
Move the driver-table pointer low byte (register A) into register L.
5317
LD A,(4DF7H) 3A F7 4D
Load register A with the high byte of the resident driver-table pointer from 4DF7H.
531A
LD H,A 67
Move the driver-table pointer high byte (register A) into register H, so HL addresses the driver table.
531B
INC HL 23
INCrement register pair HL past the driver-table link word (byte 1 of 4).
531C
INC HL 23
INCrement register pair HL (byte 2 of 4).
531D
INC HL 23
INCrement register pair HL (byte 3 of 4).
531E
INC HL 23
INCrement register pair HL to the driver name-length byte (byte 4 of 4).
531F
LD E,(HL) 5E
Load register E with the driver name-length byte at (HL).
5320
INC E 1C
INCrement register E so it spans the name plus its length byte.
5321
LD D,00H 16 00
Load register D with 00H, making register pair DE the byte offset past the driver name.
5323
ADD HL,DE 19
Add register pair DE to HL so HL points just past the driver's name field.
5324
EX DE,HL EB
Exchange DE and HL so register pair DE holds that address.
5325
LD HL,0008H 21 08 00
Load register pair HL with 0008H, the offset to the module's high-memory pointer field.
5328
ADD HL,DE 19
Add register pair DE so HL addresses the driver's stored top-of-buffer word.
5329
LD A,(HL) 7E
Load register A with the low byte of that stored word at (HL).
532A
INC HL 23
INCrement register pair HL to the high byte.
532B
LD H,(HL) 66
Load register H with the high byte of the stored word at (HL).
532C
LD L,A 6F
Move the saved low byte (register A) into register L, so HL is the driver's current buffer ceiling.
532D
EX DE,HL EB
Exchange DE and HL so register pair DE holds the driver's buffer ceiling.
532E
EX (SP),HL E3
Exchange register pair HL with the saved device pointer on the stack, bringing the earlier value back into HL.
532F
EX DE,HL EB
Exchange DE and HL again to line up the operands for the subtraction.
5330
XOR A AF
Set register A to zero and clear the carry flag before the subtraction.
5331
SBC HL,DE ED 52
Subtract register pair DE from HL to compute the free space between the driver and its ceiling.
5333
POP DE D1
Restore register pair DE from the stack (the device pointer saved at 5312H).
5334
If the difference is non-zero, JUMP to 5337H keeping HL as the available size.
5336
EX DE,HL EB
If the difference was zero, exchange DE and HL so HL carries the device pointer instead.

5337H - Size the Buffer and Pre-allocate the Spool Disk File

Records the computed buffer size, then decides between a memory-only spooler and a disk-backed one. When a spool-to-disk drive was requested the routine creates the /SPL overflow file through @INIT, pre-extends it to the required record count with @POSN/@WRITE, and marks its directory entry so the allocation is retained.

5337
LD (5442H),HL 22 42 54
Store the available buffer size (register pair HL) into cell 5442H, the buffer-size limit used later when reserving memory.
533A
LD DE,(5356H) ED 5B 56 53
Load register pair DE with the DISK keyword value at 5356H, the spool-to-disk drive number (zero means memory-only).
533E
LD (IY+06H),E FD 73 06
Store the disk drive low byte (register E) into descriptor byte IY+06H.
5341
LD (IY+07H),D FD 72 07
Store the disk drive high byte (register D) into descriptor byte IY+07H.
5344
LD A,D 7A
Move register D (disk value high byte) into register A to test the value.
5345
OR E B3
OR register E into A so A is zero only if the whole disk value is zero.
5346
If the disk value is zero (memory-only spooler), JUMP to 538DH, skipping disk-file creation.
5348
LD DE,59AFH 11 AF 59
Point register pair DE at 59AFH, the spooler FCB for the /SPL overflow file.
534B
LD HL,4200H 21 00 42
Point register pair HL at 4200H, the shared sector buffer @INIT will use.
534E
LD B,L 45
Load register B with L (00H), the logical record length request meaning full 256-byte records.
534F
GOSUB to the resident @INIT service at 4420H to create and open the /SPL overflow file described by the FCB at 59AFH.
5352
If @INIT failed (NZ flag), JUMP to 5649H to report the resident error.
5355
LD BC,0004H 01 04 00
Load register pair BC with 0004H, the base multiplier used to turn the buffer size into a record count.
5358
LD A,B 78
Move register B (record-count high byte) into register A to range-check it.
5359
AND 0F0H E6 F0
Mask register A with F0H to test the top nibble of the record count for overflow.
535B
If any top-nibble bit is set (the request is too large), JUMP to 5647H to report a parameter error.
535E
SLA C CB 21
Shift register C left one bit (first of two doublings of the record count).
5360
RL B CB 10
Rotate register B left through carry to carry the shift into the high byte.
5362
SLA C CB 21
Shift register C left again (second doubling).
5364
RL B CB 10
Rotate register B left through carry so register pair BC now holds the record count.
5366
LD (53EFH),BC ED 43 EF 53
Store the record count (register pair BC) into cell 53EFH for the pre-allocation loop.
536A
DEC BC 0B
DECrement register pair BC to the last record number (record count minus one).
536B
GOSUB to the resident @POSN service at 4442H to position the /SPL file at the last record BC, forcing allocation of every record up to it.
536E
GOSUB to the resident @WRITE service at 4439H to write that last record, committing the file's granule allocation.
5371
If @WRITE failed (NZ flag), JUMP to 5649H to report the resident error.
5374
GOSUB to the resident @REW service at 443FH to rewind the /SPL file to its first record.
5377
GOSUB to the resident @WEOF service at 444EH to write the end-of-file mark for the pre-allocated file.
537A
LD BC,(59B5H) ED 4B B5 59
Load register pair BC with the directory locator at 59B5H (the FCB drive and directory record number of the /SPL file).
537E
GOSUB to the resident DIRRD service at 4B10H to read that directory record; HL returns pointing at the 32-byte record.
5381
If DIRRD failed (NZ flag), JUMP to 5649H to report the resident error.
5384
INC HL 23
INCrement register pair HL to directory record byte +01, the flags/date byte.
5385
SET 7,(HL) CB FE
Set bit 7 of directory byte +01 at (HL) so the file's full granule allocation is retained and not trimmed on close.
5387
GOSUB to the resident DIRWR service at 4B1FH to write the modified directory record back.
538A
If DIRWR failed (NZ flag), JUMP to 5649H to report the resident error.
538D
LD BC,0001H 01 01 00
Load register pair BC with 0001H, the minimum one-record size used for a memory-only spooler.
5390
LD A,B 78
Move register B (size high byte) into register A to test for overflow.
5391
OR A B7
Test register A. A non-zero high byte means the requested size is out of range.
5392
If register B is non-zero (size too large), LOOP BACK to 535BH to report a parameter error; otherwise fall through.

5394H - Reserve High Memory, Build the Spooler Module and Go Operational

The final install stage. It validates the requested size against the top of memory, computes the byte length of the circular spool buffer, lowers HIGH$ to carve the module out of high memory, zero-fills and threads the buffer queue, copies the SPOOL module header, patches the resident despool routine's pointer operands, adds the despool routine as interrupt task slot 9, hooks the KI keyboard-service task (@KITSK at 4300H) so disk-overflow data can be refilled outside interrupt time, and marks the spooler installed and enabled before jumping to the success message.

5394
LD (IY+04H),C FD 71 04
Store the size low byte (register C) into descriptor byte IY+04H, recording the requested spool size.
5397
LD (IY+05H),B FD 70 05
Store the size high byte (register B) into descriptor byte IY+05H.
539A
LD A,(404AH) 3A 4A 40
Load register A with the top-of-memory page marker at 404AH (the high byte of the memory ceiling).
539D
SUB 81H D6 81
Subtract 81H from register A to convert the page marker into a count of available high-memory pages.
539F
RRA 1F
Rotate register A right through carry, halving the page count as part of the size check.
53A0
SRL A CB 3F
Shift register A right logically, scaling the available-page count to the buffer's record units.
53A2
SUB C 91
Subtract register C (the requested size low byte) from register A; a borrow means the request exceeds free memory.
53A3
If the subtraction borrowed (carry set, request too large), JUMP to 5647H to report a parameter error.
53A6
LD HL,(5356H) 2A 56 53
Load register pair HL with the DISK value at 5356H as the base of the byte-size computation.
53A9
ADD HL,BC 09
Add the record count (register pair BC) to HL.
53AA
ADD HL,HL 29
Double register pair HL (multiply by two).
53AB
ADD HL,HL 29
Double register pair HL again (times four).
53AC
INC HL 23
INCrement register pair HL to include the queue control overhead.
53AD
ADD HL,HL 29
Double register pair HL again (times eight).
53AE
ADD HL,HL 29
Double register pair HL a final time so HL is the buffer byte length.
53AF
PUSH HL E5
Save the buffer byte length (register pair HL) on the stack.
53B0
LD A,(4DF1H) 3A F1 4D
Load register A with the installed-spooler pointer high byte at 4DF1H to see whether a module base already exists.
53B3
OR A B7
Test register A. Zero means no module base is recorded yet.
53B4
If no module base exists (Z flag), JUMP to 53BEH to allocate one from HIGH$.
53B6
LD L,(IY+00H) FD 6E 00
Reusing an existing module: load register L with descriptor byte IY+00H (module base low byte).
53B9
LD H,(IY+01H) FD 66 01
Load register H with descriptor byte IY+01H (module base high byte), so HL is the existing module base.
53BC
JUMP to 53C7H to record the module base and build the queue.
53BE
LD HL,(4049H) 2A 49 40
Load register pair HL with the resident HIGH$ ceiling at 4049H, the current top of user memory.
53C1
LD (IY+00H),L FD 75 00
Store the module base low byte (register L) into descriptor byte IY+00H.
53C4
LD (IY+01H),H FD 74 01
Store the module base high byte (register H) into descriptor byte IY+01H.
53C7
LD (5846H),HL 22 46 58
Store the module base (register pair HL) into cell 5846H for the queue-slot builder.
53CA
INC HL 23
INCrement register pair HL past the module base.
53CB
LD L,00H 2E 00
Load register L with 00H, aligning HL to a page boundary above the module base.
53CD
LD A,(538EH) 3A 8E 53
Load register A with the MEM keyword value at 538EH (the requested buffer memory in pages).
53D0
RLCA 07
Rotate register A left (times two) toward the page span the buffer occupies.
53D1
RLCA 07
Rotate register A left again (times four).
53D2
LD B,A 47
Move the scaled page count (register A) into register B for the queue-slot loop.
53D3
NEG ED 44
Negate register A to form the negative page span for address arithmetic.
53D5
ADD A,H 84
Add register H to register A, adjusting the high byte down by the page span.
53D6
LD H,A 67
Move the adjusted high byte (register A) back into register H, so HL is the top of the buffer.
53D7
LD (59CFH),HL 22 CF 59
Store the buffer top (register pair HL) into the despool routine's cell at 59CFH.
53DA
LD (59D1H),HL 22 D1 59
Store the buffer top (register pair HL) into the despool routine's cell at 59D1H.
53DD
LD C,H 4C
Move register H into register C to seed the per-slot page counter.
53DE
POP DE D1
Restore the buffer byte length (register pair DE) from the stack.
53DF
XOR A AF
Set register A to zero and clear the carry flag before the subtraction.
53E0
SBC HL,DE ED 52
Subtract the byte length (register pair DE) from HL to find the buffer base address.
53E2
PUSH HL E5
Save the buffer base (register pair HL) on the stack.

Build Queue Slot Table
Thread the fixed-size queue slots so each slot links to the next.

53E3
LD (HL),A 77
Write zero (register A) into the current queue slot's first link byte at (HL).
53E4
INC HL 23
INCrement register pair HL to the slot's second link byte.
53E5
LD (HL),A 77
Write zero (register A) into the slot's second link byte at (HL).
53E6
INC HL 23
INCrement register pair HL to the slot's page byte.
53E7
LD (HL),C 71
Write the slot's page number (register C) at (HL).
53E8
INC HL 23
INCrement register pair HL to the slot's fourth byte.
53E9
LD (HL),A 77
Write zero (register A) into the slot's fourth byte at (HL).
53EA
INC HL 23
INCrement register pair HL to the next slot.
53EB
INC C 0C
INCrement register C to the next slot's page number.
53EC
DECrement register B and LOOP BACK to 53E3H until every queue slot page has been threaded.
53EE
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the slot-count operand at 53EFH, which was set to the record count at 5366H.
53F1
LD A,D 7A
Move register D (slot-count high byte) into register A to test for zero.
53F2
OR E B3
OR register E into A so A is zero only when no data slots remain.
53F3
If no data slots remain (Z flag), JUMP to 540AH to finish the queue tail.
53F5
LD BC,0000H 01 00 00
Load register pair BC with 0000H, the running data-slot index.
53F8
LD (HL),00H 36 00
Write 00H into the current data slot's first byte at (HL).
53FA
INC HL 23
INCrement register pair HL to the slot's second byte.
53FB
LD (HL),00H 36 00
Write 00H into the slot's second byte at (HL).
53FD
INC HL 23
INCrement register pair HL to the slot's index low byte.
53FE
LD (HL),C 71
Write the data-slot index low byte (register C) at (HL).
53FF
INC HL 23
INCrement register pair HL to the slot's index high byte.
5400
LD (HL),B 70
Write the data-slot index high byte (register B) at (HL).
5401
SET 7,(HL) CB FE
Set bit 7 of that index high byte at (HL) to flag the slot as a valid data record.
5403
INC HL 23
INCrement register pair HL to the next data slot.
5404
INC BC 03
INCrement register pair BC to the next data-slot index.
5405
DEC DE 1B
DECrement register pair DE, the remaining data-slot count.
5406
LD A,D 7A
Move register D (remaining count high byte) into register A to test for zero.
5407
OR E B3
OR register E into A so A is zero when the count reaches zero.
5408
If data slots remain (NZ flag), LOOP BACK to 53F8H to thread the next one.
540A
LD (HL),A 77
Finish the queue: write zero (register A) into the tail slot's first byte at (HL).
540B
INC HL 23
INCrement register pair HL to the tail slot's second byte.
540C
LD (HL),A 77
Write zero (register A) into the tail slot's second byte at (HL).
540D
INC HL 23
INCrement register pair HL to the tail slot's third byte.
540E
CPL 2F
Complement register A to FFH, the end-of-queue marker.
540F
LD (HL),A 77
Write the FFH end-of-queue marker (register A) at (HL).
5410
INC HL 23
INCrement register pair HL to the tail slot's fourth byte.
5411
LD (HL),A 77
Write the FFH marker (register A) into the tail slot's fourth byte at (HL).
5412
POP HL E1
Restore the buffer base (register pair HL) from the stack.
5413
PUSH HL E5
Save the buffer base (register pair HL) again for the pointer patches that follow.
5414
LD (59D3H),HL 22 D3 59
Store the buffer base (register pair HL) into the despool routine's cell at 59D3H.
5417
LD (59D5H),HL 22 D5 59
Store the buffer base (register pair HL) into the despool routine's cell at 59D5H.
541A
LD (59D7H),HL 22 D7 59
Store the buffer base (register pair HL) into the despool routine's cell at 59D7H.
541D
LD A,H 7C
Move register H (buffer base high byte) into register A.
541E
LD (HL),L 75
Write the buffer base low byte (register L) into the first queue-head byte at (HL).
541F
INC HL 23
INCrement register pair HL to the second queue-head byte.
5420
LD (HL),A 77
Write the buffer base high byte (register A) into the second queue-head byte at (HL), seeding the queue head pointer.
5421
POP HL E1
Restore the buffer base (register pair HL) from the stack.
5422
LD BC,002CH 01 2C 00
Load register pair BC with 002CH (44 bytes), the length of the resident spooler control block.
5425
XOR A AF
Set register A to zero and clear the carry flag before the subtraction.
5426
SBC HL,BC ED 42
Subtract register pair BC from HL so HL points at the control block just below the buffer.
5428
PUSH HL E5
Save the control-block address (register pair HL) on the stack.
5429
EX DE,HL EB
Exchange DE and HL so register pair DE holds the control-block destination.
542A
LD HL,59AFH 21 AF 59
Point register pair HL at 59AFH, the assembled control block image in this overlay.
542D
LDIR ED B0
Block-copy the 44-byte control block from 59AFH (HL) into the reserved high-memory module (DE).
542F
POP HL E1
Restore the control-block address (register pair HL) from the stack.
5430
PUSH HL E5
Save the control-block address (register pair HL) again for the operand patches.
5431
LD (5865H),HL 22 65 58
Self-Modifying Code
Store the control-block address (register pair HL) into the operand at 5865H of the resident queue-write routine.
5434
LD (5911H),HL 22 11 59
Self-Modifying Code
Store the control-block address (register pair HL) into the operand at 5911H of the resident despool routine.
5437
LD (5950H),HL 22 50 59
Self-Modifying Code
Store the control-block address (register pair HL) into the operand at 5950H of the resident disk-refill routine.
543A
LD BC,0023H 01 23 00
Load register pair BC with 0023H (35 bytes), the offset from the control block to the queue-slot table.
543D
ADD HL,BC 09
Add register pair BC to HL so HL points at the queue-slot table inside the module.
543E
LD (5946H),HL 22 46 59
Self-Modifying Code
Store the queue-slot table address (register pair HL) into the operand at 5946H of the resident disk-refill routine.
5441
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the buffer-size limit; the operand at 5442H/5443H was written at 5337H (LD (5442H),HL), so HL points into the driver/buffer area from which the original driver vector is fetched.
5444
LD (5907H),HL 22 07 59
Store the buffer-limit pointer (register pair HL) into cell 5907H, the operand of the disk-refill routine's LD IX,(5907H) so it can reach the device driver table.
5447
INC HL 23
INCrement register pair HL past the first byte of the driver-table entry the buffer-limit pointer addresses.
5448
LD C,(HL) 4E
Load register C with the original device driver vector low byte at (HL).
5449
INC HL 23
INCrement register pair HL to the device driver vector high byte.
544A
LD B,(HL) 46
Load register B with the device driver vector high byte at (HL), so register pair BC is the original driver entry.
544B
LD (592FH),BC ED 43 2F 59
Self-Modifying Code
Store the original driver entry (register pair BC) into the operand at 592FH of the resident despool routine so it can still reach the real device.
544F
LD (590AH),BC ED 43 0A 59
Self-Modifying Code
Store the original driver entry (register pair BC) into the operand at 590AH of the resident despool routine.
5453
LD A,(4300H) 3A 00 43
Load register A with the first byte of the resident @KITSK hook at 4300H, the KI keyboard-service task vector SPOOL will replace with a JP.
5456
LD HL,(4301H) 2A 01 43
Load register pair HL with the current @KITSK target at 4301H so the previous KI-task handler can be chained after the spooler's.
5459
LD (593FH),A 32 3F 59
Self-Modifying Code
Store the saved @KITSK opcode byte (register A) into the operand at 593FH of the resident routine so the previous KI-task handler still runs.
545C
LD (5940H),HL 22 40 59
Self-Modifying Code
Store the saved @KITSK target (register pair HL) into the operand at 5940H of the resident routine so the prior KI-task handler is preserved.
545F
POP HL E1
Restore the control-block address (register pair HL) from the stack.
5460
LD BC,016BH 01 6B 01
Load register pair BC with 016BH, the length of the resident spooler routine block to be located below the control block.
5463
XOR A AF
Set register A to zero and clear the carry flag before the subtraction.
5464
SBC HL,BC ED 42
Subtract register pair BC from HL so HL points below the routine block.
5466
DEC HL 2B
DECrement register pair HL to the new HIGH$ ceiling one byte below the module.
5467
LD A,(4DF1H) 3A F1 4D
Load register A with the installed-spooler pointer high byte at 4DF1H to see whether HIGH$ must be lowered.
546A
OR A B7
Test register A. Zero means this is a fresh install and HIGH$ has not yet been lowered.
546B
If no spooler was installed before (Z flag), JUMP to 547FH to claim the memory by lowering HIGH$.
546D
LD E,(IY+02H) FD 5E 02
Reusing memory: load register E with descriptor byte IY+02H, the previous buffer ceiling low byte.
5470
LD D,(IY+03H) FD 56 03
Load register D with descriptor byte IY+03H, the previous buffer ceiling high byte.
5473
EX DE,HL EB
Exchange DE and HL so register pair HL holds the previous ceiling and DE the new one.
5474
XOR A AF
Set register A to zero and clear the carry flag before comparing the ceilings.
5475
SBC HL,DE ED 52
Subtract register pair DE from HL to compare the new module size against the previously reserved space.
5477
EX DE,HL EB
Exchange DE and HL back so register pair HL is the new ceiling again.
5478
If the sizes match (Z flag), JUMP to 5488H reusing the existing reservation.
547A
If the new module is smaller (carry set), JUMP to 5488H; the existing reservation still fits.
547C
Otherwise the new module needs more memory than was reserved; JUMP to 5654H to report Request exceeds available memory!.
547F
LD (4049H),HL 22 49 40
Store the new ceiling (register pair HL) into the resident HIGH$ word at 4049H, reserving the module's high memory.
5482
LD (IY+02H),L FD 75 02
Store the new ceiling low byte (register L) into descriptor byte IY+02H.
5485
LD (IY+03H),H FD 74 03
Store the new ceiling high byte (register H) into descriptor byte IY+03H.
5488
INC HL 23
INCrement register pair HL to the first byte of the reserved module.
5489
PUSH HL E5
Save the module start (register pair HL) on the stack.
548A
LD DE,00C3H 11 C3 00
Load register pair DE with 00C3H, the offset to the queue-write entry within the module.
548D
ADD HL,DE 19
Add register pair DE to HL so HL points at the resident queue-write entry.
548E
LD (IY+08H),L FD 75 08
Store the queue-write entry low byte (register L) into descriptor byte IY+08H, the module's task link.
5491
LD (IY+09H),H FD 74 09
Store the queue-write entry high byte (register H) into descriptor byte IY+09H.
5494
POP HL E1
Restore the module start (register pair HL) from the stack.
5495
PUSH HL E5
Save the module start (register pair HL) again for the next offset calculation.
5496
LD DE,00C3H 11 C3 00
Load register pair DE with 00C3H, the same queue-write entry offset.
5499
ADD HL,DE 19
Add register pair DE to HL to re-form the queue-write entry address.
549A
LD (592CH),HL 22 2C 59
Self-Modifying Code
Store the queue-write entry (register pair HL) into the operand at 592CH of the resident despool routine.
549D
POP HL E1
Restore the module start (register pair HL) from the stack.
549E
PUSH HL E5
Save the module start (register pair HL) again.
549F
LD DE,001FH 11 1F 00
Load register pair DE with 001FH, the offset to another resident entry point within the module.
54A2
ADD HL,DE 19
Add register pair DE to HL to form that entry address.
54A3
LD (585FH),HL 22 5F 58
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 585FH of the resident queue-write routine.
54A6
POP HL E1
Restore the module start (register pair HL) from the stack.
54A7
PUSH HL E5
Save the module start (register pair HL) again.
54A8
LD DE,00FEH 11 FE 00
Load register pair DE with 00FEH, the offset to a further resident entry point.
54AB
ADD HL,DE 19
Add register pair DE to HL to form that entry address.
54AC
LD (589BH),HL 22 9B 58
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 589BH of the resident despool routine.
54AF
LD (593DH),HL 22 3D 59
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 593DH of the resident despool routine.
54B2
POP HL E1
Restore the module start (register pair HL) from the stack.
54B3
PUSH HL E5
Save the module start (register pair HL) again.
54B4
LD DE,00B7H 11 B7 00
Load register pair DE with 00B7H, the offset to the resident disk-service entry point.
54B7
ADD HL,DE 19
Add register pair DE to HL to form that entry address.
54B8
LD (5875H),HL 22 75 58
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 5875H of the resident routine.
54BB
LD (5897H),HL 22 97 58
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 5897H of the resident routine.
54BE
LD (58F9H),HL 22 F9 58
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 58F9H of the resident routine.
54C1
LD (597AH),HL 22 7A 59
Self-Modifying Code
Store that entry address (register pair HL) into the operand at 597AH of the resident routine.
54C4
POP DE D1
Restore the module start into register pair DE as the destination for the module header.
54C5
PUSH DE D5
Save the module start (register pair DE) again on the stack.
54C6
LD HL,5844H 21 44 58
Point register pair HL at 5844H, the SPOOL module header template (link word, marker and the name SPOOL).
54C9
LDIR ED B0
Block-copy the module header from 5844H (HL) into the start of the reserved module (DE).
54CB
POP HL E1
Restore the module start (register pair HL) from the stack.
54CC
PUSH HL E5
Save the module start (register pair HL) again.
54CD
LD DE,000AH 11 0A 00
Load register pair DE with 000AH (10 bytes), the length of the module header just copied.
54D0
ADD HL,DE 19
Add register pair DE to HL so HL points just past the header, at the module descriptor area.
54D1
LD (4DF0H),HL 22 F0 4D
Store the module descriptor address (register pair HL) into the resident installed-spooler pointer at 4DF0H/4DF1H, recording that a spooler is now resident.
54D4
POP HL E1
Restore the module start (register pair HL) from the stack.
54D5
PUSH HL E5
Save the module start (register pair HL) again.
54D6
LD DE,(5442H) ED 5B 42 54
Load register pair DE with the buffer-size limit saved at 5442H.
54DA
EX DE,HL EB
Exchange DE and HL so register pair HL holds the buffer-size limit and DE the module start.
54DB
INC HL 23
INCrement register pair HL past the module link word.
54DC
LD (HL),E 73
Store the module-start low byte (register E) into the module at (HL).
54DD
INC HL 23
INCrement register pair HL to the next byte.
54DE
LD (HL),D 72
Store the module-start high byte (register D) at (HL), recording the module's own base inside its header.
54DF
POP HL E1
Restore the module start (register pair HL) from the stack.
54E0
PUSH HL E5
Save the module start (register pair HL) again.
54E1
LD DE,00B2H 11 B2 00
Load register pair DE with 00B2H, the offset to the resident task entry within the module.
54E4
ADD HL,DE 19
Add register pair DE to HL to form the task entry address.
54E5
LD D,H 54
Move register H into register D (copy the task entry high byte).
54E6
LD E,L 5D
Move register L into register E, so register pair DE now holds the task entry address.
54E7
LD BC,0002H 01 02 00
Load register pair BC with 0002H, the offset to the task's self-pointer field.
54EA
ADD HL,BC 09
Add register pair BC to HL to point at the task self-pointer field.
54EB
EX DE,HL EB
Exchange DE and HL so register pair HL holds the task entry and DE the self-pointer field.
54EC
LD (HL),E 73
Store the self-pointer low byte (register E) into the task entry at (HL).
54ED
INC HL 23
INCrement register pair HL to the next byte.
54EE
LD (HL),D 72
Store the self-pointer high byte (register D) at (HL), so the task can locate itself.
54EF
DEC HL 2B
DECrement register pair HL back to the task entry address.
54F0
EX DE,HL EB
Exchange DE and HL so register pair DE holds the task entry address for @ADTSK.
54F1
LD A,09H 3E 09
Load register A with 09H, the interrupt task slot number the despool routine will occupy.
54F3
GOSUB to the resident @ADTSK service at 4410H to install the despool routine (register pair DE) as interrupt task slot 9, so despooling runs on the real-time clock tick.
54F6
POP HL E1
Restore the module start (register pair HL) from the stack.
54F7
PUSH HL E5
Save the module start (register pair HL) again for the driver-hook patch.
54F8
LD DE,00F8H 11 F8 00
Load register pair DE with 00F8H, the offset to the module's queue-write entry that the output hook will call.
54FB
ADD HL,DE 19
Add register pair DE to HL to form that entry address.
54FC
LD (4301H),HL 22 01 43
Store that entry address (register pair HL) into the resident @KITSK target at 4301H, so each keyboard poll runs the spooler's disk-despool assist.
54FF
LD A,0C3H 3E C3
Load register A with C3H, a JP opcode, to activate the output hook.
5501
LD (4300H),A 32 00 43
Store the JP opcode (register A) into the resident @KITSK hook at 4300H, arming the KI-poll entry into the spooler's disk-despool assist.
5504
SET 0,(IX+00H) DD CB 00 C6
Set bit 0 of the resident flag byte IX+00H at 441FH to mark the spooler installed.
5508
SET 4,(IX+04H) DD CB 04 E6
Set bit 4 of KFLAG$ at IX+04H (4423H) to enable despooling on the clock tick.
550C
JUMP to 5623H to display Spooler is now operational and return to the caller.

550FH - PAUSE and RESUME Sub-commands

Two small handlers reached when the spooler is already installed. PAUSE clears the despool-enable bit so queued output stops printing; RESUME sets it so printing continues. Each first checks that a spooler is installed and reports the outcome by jumping into the status-message selector.

550F
BIT 0,(IX+00H) DD CB 00 46
PAUSE entry. Test bit 0 of the resident flag byte IX+00H at 441FH (the spooler-installed flag).
5513
If bit 0 is clear (no spooler installed), JUMP to 562BH to report Spooler is not active.
5516
BIT 4,(IX+04H) DD CB 04 66
Test bit 4 of KFLAG$ at IX+04H (4423H), the despool-enable flag, to learn whether despooling was already paused.
551A
RES 4,(IX+04H) DD CB 04 A6
Reset bit 4 of KFLAG$ at IX+04H (4423H) to stop despooling. The Z flag from the test at 5516H is preserved.
551E
If bit 4 was already clear (Z flag, despooling was already paused), JUMP to 562FH to report Spooler already active but paused.
5521
Otherwise JUMP to 561FH to report Despooling now paused.
5524
BIT 0,(IX+00H) DD CB 00 46
RESUME entry. Test bit 0 of the resident flag byte IX+00H at 441FH (the spooler-installed flag).
5528
If bit 0 is clear (no spooler installed), JUMP to 562BH to report Spooler is not active.
552B
BIT 4,(IX+04H) DD CB 04 66
Test bit 4 of KFLAG$ at IX+04H (4423H), the despool-enable flag, to learn whether despooling was already running.
552F
SET 4,(IX+04H) DD CB 04 E6
Set bit 4 of KFLAG$ at IX+04H (4423H) to resume despooling. The Z flag from the test at 552BH is preserved.
5533
If bit 4 was already set (NZ flag, despooling was already running), JUMP to 5627H to report Spooler is already active.
5536
Otherwise JUMP to 561BH to report Despooling now resumed.

5539H - OFF: Remove the Spooler and Reclaim Its Memory

Reached by the OFF or N keyword. It marks the spooler uninstalled, restores the original output-driver hook from the resident driver table, removes the despool interrupt task, and if the module still sits at the top of memory hands its space back to HIGH$. It then re-executes a Reset command against the freed device to unlink its driver.

5539
BIT 0,(IX+00H) DD CB 00 46
OFF entry. Test bit 0 of the resident flag byte IX+00H at 441FH (the spooler-installed flag).
553D
If bit 0 is clear (no spooler installed), JUMP to 562BH to report Spooler is not active.
5540
RES 0,(IX+00H) DD CB 00 86
Reset bit 0 of the resident flag byte IX+00H at 441FH to mark the spooler no longer installed.
5544
RES 4,(IX+04H) DD CB 04 A6
Reset bit 4 of KFLAG$ at IX+04H (4423H) to disable despooling.
5548
LD HL,4512H 21 12 45
Point register pair HL at 4512H, the resident device-table pointer that leads to the saved original output-hook bytes.
554B
LD A,(HL) 7E
Load register A with the low byte of the pointer at (HL), 4512H.
554C
INC HL 23
INCrement register pair HL to the high byte of the pointer.
554D
LD H,(HL) 66
Load register H with the high byte of the pointer at (HL).
554E
LD L,A 6F
Move the saved low byte (register A) into register L, so HL now addresses the resident device table.
554F
LD BC,0049H 01 49 00
Load register pair BC with 0049H, the offset to the saved original output-hook bytes within that table.
5552
ADD HL,BC 09
Add register pair BC to HL so HL points at the saved hook opcode and target.
5553
DI F3
Disable interrupts while the output hook is restored, so no despool tick fires mid-change.
5554
LD A,(HL) 7E
Load register A with the saved original hook opcode byte at (HL).
5555
LD (4300H),A 32 00 43
Store the saved opcode (register A) into the resident output hook at 4300H, restoring the pre-spool handler.
5558
INC HL 23
INCrement register pair HL to the saved hook target low byte.
5559
LD A,(HL) 7E
Load register A with the saved hook target low byte at (HL).
555A
INC HL 23
INCrement register pair HL to the saved hook target high byte.
555B
LD H,(HL) 66
Load register H with the saved hook target high byte at (HL).
555C
LD L,A 6F
Move the saved low byte (register A) into register L, so HL is the original hook target.
555D
LD (4301H),HL 22 01 43
Store the original hook target (register pair HL) into the resident output-hook vector at 4301H.
5560
LD A,09H 3E 09
Load register A with 09H, the interrupt task slot number the despool routine occupied.
5562
GOSUB to the resident @RMTSK service at 4413H to remove the despool routine from interrupt task slot 9.
5565
EI FB
Re-enable interrupts now that the hook and task are restored.
5566
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return, to terminate the Reset command line built below.
5568
LD (57BBH),A 32 BB 57
Store the carriage return (register A) at 57BBH, ending the Reset command line just past the device name left in the FCB at 57B8H.
556B
LD HL,(4049H) 2A 49 40
Load register pair HL with the resident HIGH$ ceiling at 4049H, the current top of user memory.
556E
LD E,(IY+02H) FD 5E 02
Load register E with descriptor byte IY+02H, the module's reserved-ceiling low byte.
5571
LD D,(IY+03H) FD 56 03
Load register D with descriptor byte IY+03H, the module's reserved-ceiling high byte.
5574
XOR A AF
Set register A to zero and clear the carry flag before the comparison.
5575
SBC HL,DE ED 52
Subtract register pair DE (the module ceiling) from HL (HIGH$); a zero result means the module sits at the very top and its memory can be reclaimed.
5577
LD E,(IY+00H) FD 5E 00
Load register E with descriptor byte IY+00H, the module base low byte.
557A
LD (IY+00H),A FD 77 00
Store zero (register A) into descriptor byte IY+00H, clearing the module base low byte.
557D
LD D,(IY+01H) FD 56 01
Load register D with descriptor byte IY+01H, the module base high byte, so register pair DE is now the module base.
5580
LD (IY+01H),A FD 77 01
Store zero (register A) into descriptor byte IY+01H, clearing the module base high byte.
5583
LD HL,5713H 21 13 57
Point register pair HL at the message Can't reclaim memory space, the default outcome.
5586
If HIGH$ did not equal the module ceiling (NZ flag, something is stacked above the spooler), JUMP to 5595H to display Can't reclaim memory space without reclaiming.
5588
LD (4049H),DE ED 53 49 40
The module was at the top: store the module base (register pair DE) into the resident HIGH$ word at 4049H, giving the memory back.
558C
LD (4DF0H),A 32 F0 4D
Store zero (register A) into the low byte of the installed-spooler pointer at 4DF0H.
558F
LD (4DF1H),A 32 F1 4D
Store zero (register A) into the high byte of the installed-spooler pointer at 4DF1H, recording that no spooler is resident.
5592
LD HL,572EH 21 2E 57
Point register pair HL at the message Memory space reclaimed.
5595
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message that register pair HL points at.
5598
LD HL,57B2H 21 B2 57
Point register pair HL at 57B2H, the Reset command line (the text Reset followed by the device name in the FCB and the carriage return planted at 57BBH).
559B
PUSH HL E5
Save register pair HL (the Reset command line) on the stack.
559C
GOSUB to the resident @LOGOT service at 447BH to echo the Reset command line that register pair HL points at.
559F
POP HL E1
Restore register pair HL (the Reset command line) from the stack for the command-execute call.
55A0
LD SP,(5639H) ED 7B 39 56
Self-Modifying Code
Restore the caller's stack pointer from 5639H, the operand written on entry at 5200H.
55A4
JUMP to the resident command-execute entry at 4451H (RST 28H code A3H) to run the Reset command, unlinking the device driver the spooler had hooked.

55A7H - CLEAR: Empty the Spool Queue

Reached by the CLEAR or C keyword. It reaches into the resident spooler control block, zeroes every queue slot, and resets the queue head, tail and byte-count pointers so any buffered output is discarded while the spooler stays installed.

55A7
BIT 0,(IX+00H) DD CB 00 46
CLEAR entry. Test bit 0 of the resident flag byte IX+00H at 441FH (the spooler-installed flag).
55AB
If bit 0 is clear (no spooler installed), JUMP to 562BH to report Spooler is not active.
55AE
LD HL,0000H 21 00 00
Self-Modifying Code
Load register pair HL with the module base; the operand at 55AFH was set at 521AH when an installed spooler was re-opened.
55B1
LD DE,0161H 11 61 01
Load register pair DE with 0161H, the offset from the module base to the resident spooler control block.
55B4
ADD HL,DE 19
Add register pair DE to HL so HL points at the spooler control block.
55B5
PUSH IX DD E5
Save register pair IX (the 441FH flag pointer) on the stack.
55B7
PUSH HL E5
Save register pair HL (the control-block address) on the stack.
55B8
POP IX DD E1
Move the control-block address into register pair IX so IX now indexes the queue control fields.
55BA
LD L,(IX+24H) DD 6E 24
Load register L with control-block byte IX+24H, the queue-slot table pointer low byte.
55BD
LD H,(IX+25H) DD 66 25
Load register H with control-block byte IX+25H, the queue-slot table pointer high byte, so HL points at the slot table.
55C0
PUSH HL E5
Save register pair HL (the slot-table start) on the stack.

Zero Queue Slots
Walk the four-byte slots, clearing the first two bytes of each, until a slot whose fourth byte is FFH (the end marker) is reached.

55C1
XOR A AF
Set register A to zero to blank the slot link bytes.
55C2
LD (HL),A 77
Write zero (register A) into the current slot's first byte at (HL).
55C3
INC HL 23
INCrement register pair HL to the slot's second byte.
55C4
LD (HL),A 77
Write zero (register A) into the slot's second byte at (HL).
55C5
INC HL 23
INCrement register pair HL to the slot's third byte.
55C6
INC HL 23
INCrement register pair HL to the slot's fourth byte.
55C7
LD A,(HL) 7E
Load register A with the slot's fourth byte at (HL) to test for the end marker.
55C8
INC HL 23
INCrement register pair HL to the next slot.
55C9
INC A 3C
INCrement register A; an FFH end marker wraps to 00H and sets the Z flag.
55CA
If the fourth byte was not FFH (not the last slot), LOOP BACK to 55C1H to clear the next slot.
55CC
POP HL E1
Restore register pair HL (the slot-table start) from the stack.
55CD
LD (IX+26H),L DD 75 26
Store the slot-table start low byte (register L) into control-block byte IX+26H (queue head pointer).
55D0
LD (IX+27H),H DD 74 27
Store the slot-table start high byte (register H) into control-block byte IX+27H.
55D3
LD (IX+28H),L DD 75 28
Store the slot-table start low byte (register L) into control-block byte IX+28H (queue tail pointer).
55D6
LD (IX+29H),H DD 74 29
Store the slot-table start high byte (register H) into control-block byte IX+29H.
55D9
LD A,H 7C
Move register H (slot-table high byte) into register A.
55DA
LD (HL),L 75
Write the slot-table low byte (register L) into the first slot link byte at (HL).
55DB
INC HL 23
INCrement register pair HL to the second slot link byte.
55DC
LD (HL),A 77
Write the slot-table high byte (register A) into the second slot link byte at (HL), seeding the head slot's self-link.
55DD
INC HL 23
INCrement register pair HL to the slot's page byte.
55DE
LD B,(HL) 46
Load register B with the head slot's page byte at (HL).
55DF
XOR A AF
Set register A to zero to blank the queue counters.
55E0
LD (IX+21H),B DD 70 21
Store the head slot page (register B) into control-block byte IX+21H (current page).
55E3
LD (IX+20H),A DD 77 20
Store zero (register A) into control-block byte IX+20H (current byte index).
55E6
LD (IX+23H),B DD 70 23
Store the head slot page (register B) into control-block byte IX+23H (despool page).
55E9
LD (IX+22H),A DD 77 22
Store zero (register A) into control-block byte IX+22H (despool byte index), so the queue is empty.
55EC
POP IX DD E1
Restore register pair IX (the 441FH flag pointer) from the stack.
55EE
JUMP to 5617H to report SPOOL buffer cleared.

55F1H - Find a Device Control Block by Name

A helper that searches the resident device chains for a control block whose two-character name matches register pair DE. It scans the KI, DO and PR device control blocks starting at 4015H, then the auxiliary JL, SI and SO blocks at 43C0H. It returns register A zero (Z flag) with HL pointing at the block on a match, or error code 08H on exhaustion.

55F1
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the first resident device control block (KIDCB$).
55F4
PUSH HL E5
Save register pair HL (the current control-block base) on the stack.
55F5
LD A,L 7D
Move register L (the base low byte) into register A to compute the name-field offset.
55F6
ADD A,06H C6 06
Add 06H to register A, the offset from the control-block base to its two-character name field.
55F8
LD L,A 6F
Move the result (register A) back into register L, so HL addresses the name field.
55F9
LD A,(HL) 7E
Load register A with the first name character at (HL).
55FA
INC L 2C
INCrement register L to the second name character.
55FB
CP E BB
Compare register A against register E (the first character of the requested device name).
55FC
If the first characters differ (NZ flag), JUMP to 5605H to advance to the next control block.
55FE
LD A,(HL) 7E
Load register A with the second name character at (HL).
55FF
CP D BA
Compare register A against register D (the second character of the requested device name).
5600
If the second characters differ (NZ flag), JUMP to 5605H to advance to the next control block.
5602
POP HL E1
A match: restore register pair HL to the control-block base from the stack.
5603
XOR A AF
Set register A to zero and set the Z flag to signal success.
5604
RET C9
Return with HL pointing at the matched device control block and the Z flag set.
5605
POP AF F1
No match: discard the saved base by popping it into register AF.
5606
INC L 2C
INCrement register L toward the next control block; a wrap to 00H would signal the region end.
5607
If register L did not wrap (still within the region), JUMP to 560DH to test the region boundary.
5609
LD A,08H 3E 08
The chain is exhausted: load register A with 08H, the device-not-found error code.
560B
OR A B7
Test register A to set the NZ flag, marking the error return.
560C
RET C9
Return with register A holding error code 08H and the NZ flag set.
560D
LD A,L 7D
Load register A with register L to check the current control-block address.
560E
CP 2DH FE 2D
Compare register A against 2DH; address 402DH marks the end of the KI/DO/PR device blocks.
5610
If the end of the KI/DO/PR blocks has not been reached, LOOP BACK to 55F4H to test the next block.
5612
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the first auxiliary device control block (JL, SI and SO).
5615
JUMP to 55F4H to search the auxiliary device blocks.

5617H - Status Message Selector and Common Exit

A single tail that displays one of six status messages and returns. The six entry points overlap by design: each begins a three-byte LD IX,nnnn instruction, and a jump that lands one byte in skips the DD prefix so the same bytes decode as LD HL,nnnn, selecting that entry's message. The chosen message is shown through @LOGOT, then the overlay restores the caller's stack and returns, or aborts if it was not entered at command level.

Deliberate Instruction Overlap
On the fall-through at 5617H register pair HL is set to 5664H (SPOOL buffer cleared) and the following LD IX instructions are inert. Jumping to 561BH, 561FH, 5623H, 5627H, 562BH or 562FH skips a DD prefix so the same bytes load HL with 568FH, 5679H, 56F8H, 56BCH, 56A6H or 56D6H instead.

5617
LD HL,5664H 21 64 56
Fall-through entry (from the CLEAR handler): point register pair HL at the message SPOOL buffer cleared.
561A
LD IX,568FH DD 21 8F 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 561BH it decodes as LD HL,568FH, selecting the message Despooling now resumed.
561E
LD IX,5679H DD 21 79 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 561FH it decodes as LD HL,5679H, selecting the message Despooling now paused.
5622
LD IX,56F8H DD 21 F8 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 5623H it decodes as LD HL,56F8H, selecting the message Spooler is now operational.
5626
LD IX,56BCH DD 21 BC 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 5627H it decodes as LD HL,56BCH, selecting the message Spooler is already active.
562A
LD IX,56A6H DD 21 A6 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 562BH it decodes as LD HL,56A6H, selecting the message Spooler is not active.
562E
LD IX,56D6H DD 21 D6 56
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 562FH it decodes as LD HL,56D6H, selecting the message Spooler already active but paused.
5632
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated status message that register pair HL now points at.
5635
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status for the common exit.
5638
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer; the operand at 5639H was written on entry at 5200H. This is the overlay's common exit.
563B
LD A,H 7C
Move register H (status high byte) into register A to test the exit status.
563C
OR L B5
OR register L into A so A is zero only on a success return.
563D
RET Z C8
If the status is zero (success), RETurn to the RST 28H dispatcher.
563E
LD A,(430FH) 3A 0F 43
On an error status, load register A with the resident system flag byte SFLAG$ at 430FH.
5641
BIT 5,A CB 6F
Test bit 5 of register A (SFLAG$); bit 5 set means execution is not at the LDOS command level.
5643
RET Z C8
If bit 5 is clear (at command level), RETurn to the dispatcher with the error already reported.
5644
Otherwise JUMP to the resident @ABORT entry at 4030H to abort back to LDOS Ready.

5647H - Error Reporting and Refusal Messages

The failure tails. A parameter error loads code 2CH; resident-service failures enter with their own code already in register A; both pass through @ERROR. The refusal tail displays one of three messages through @LOGOT using the same DD-prefix overlap trick, then exits with a failure status.

5647
LD A,2CH 3E 2C
Parameter-error entry: load register A with 2CH (error code 44, parameter error).
5649
OR 0C0H F6 C0
Resident-error entry: set bits 6 and 7 of register A (the error code) to select the message-only, return-to-caller options for @ERROR.
564B
GOSUB to the resident @ERROR service at 4409H to display the system error message for the code in register A.
564E
JUMP to 565EH to set the failure status and exit.
5650
LD HL,5767H 21 67 57
Refusal entry: point register pair HL at the message SPOOLER requires KI/DVR active!.
5653
LD IX,5745H DD 21 45 57
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 5654H it decodes as LD HL,5745H, selecting the message Request exceeds available memory!.
5657
LD IX,5787H DD 21 87 57
Deliberate Instruction Overlap
On the fall-through this loads register pair IX (inert). Entered at 5658H it decodes as LD HL,5787H, selecting the message Can't -- Valid only at LDOS Command level!.
565B
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated refusal message that register pair HL points at.
565E
LD HL,0FFFFH 21 FF FF
Load register pair HL with FFFFH, the failure status for the common exit.
5661
JUMP to the common exit at 5638H to restore the caller's stack and return or abort.

5664H - Spooler Status, Outcome and Refusal Messages

The carriage-return-terminated text the handlers display through the resident @LOGOT service at 447BH. The status tail at 5617H and the refusal tail at 5650H select among these by loading the message address into register pair HL; none is a branch target, so the addresses are plain text here.

5664-5678
DEFM "SPOOL buffer cleared",0DH 53 50 4F 4F 4C 20 62 75 66 66 65 72 20 63 6C 65 61 72 65 64 0D
Message
Shown by the CLEAR handler once the queue has been emptied.
5679-568E
DEFM "Despooling now paused",0DH 44 65 73 70 6F 6F 6C 69 6E 67 20 6E 6F 77 20 70 61 75 73 65 64 0D
Message
Shown by the PAUSE handler when despooling was running and is now stopped.
568F-56A5
DEFM "Despooling now resumed",0DH 44 65 73 70 6F 6F 6C 69 6E 67 20 6E 6F 77 20 72 65 73 75 6D 65 64 0D
Message
Shown by the RESUME handler when despooling was paused and is now running.
56A6-56BB
DEFM "Spooler is not active",0DH 53 70 6F 6F 6C 65 72 20 69 73 20 6E 6F 74 20 61 63 74 69 76 65 0D
Message
Shown by any handler that finds bit 0 of the flag byte at 441FH clear (no spooler installed).
56BC-56D5
DEFM "Spooler is already active",0DH 53 70 6F 6F 6C 65 72 20 69 73 20 61 6C 72 65 61 64 79 20 61 63 74 69 76 65 0D
Message
Shown by RESUME or install when despooling was already enabled.
56D6-56F7
DEFM "Spooler already active but paused",0DH 53 70 6F 6F 6C 65 72 20 61 6C 72 65 61 64 79 20 61 63 74 69 76 65 20 62 75 74 20 70 61 75 73 65 64 0D
Message
Shown by the PAUSE handler when despooling was already paused.
56F8-5712
DEFM "Spooler is now operational",0DH 53 70 6F 6F 6C 65 72 20 69 73 20 6E 6F 77 20 6F 70 65 72 61 74 69 6F 6E 61 6C 0D
Message
Shown after a fresh install completes.
5713-572D
DEFM "Can't reclaim memory space",0DH 43 61 6E 27 74 20 72 65 63 6C 61 69 6D 20 6D 65 6D 6F 72 79 20 73 70 61 63 65 0D
Message
Shown by OFF when the module is not at the top of memory and its space cannot be returned to HIGH$ (4049H).
572E-5744
DEFM "Memory space reclaimed",0DH 4D 65 6D 6F 72 79 20 73 70 61 63 65 20 72 65 63 6C 61 69 6D 65 64 0D
Message
Shown by OFF when the module was at the top and HIGH$ (4049H) has been raised over it.
5745-5766
DEFM "Request exceeds available memory!",0DH 52 65 71 75 65 73 74 20 65 78 63 65 65 64 73 20 61 76 61 69 6C 61 62 6C 65 20 6D 65 6D 6F 72 79 21 0D
Message
Shown when the requested buffer is larger than the free high memory.
5767-5786
DEFM "SPOOLER requires KI/DVR active!",0DH 53 50 4F 4F 4C 45 52 20 72 65 71 75 69 72 65 73 20 4B 49 2F 44 56 52 20 61 63 74 69 76 65 21 0D
Message
Shown when bit 3 of the flag byte at 441FH is clear (the KI keyboard device driver is not present).
5787-57B1
DEFM "Can't -- Valid only at LDOS Command level!",0DH 43 61 6E 27 74 20 2D 2D 20 56 61 6C 69 64 20 6F 6E 6C 79 20 61 74 20 4C 44 4F 53 20 43 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C 21 0D
Message
Shown when SPOOL is invoked with a program resident or a task busy.
57B2-57B7
DEFM "Reset " 52 65 73 65 74 20
Reset Command Line
The word Reset and a trailing space. The OFF/reclaim path at 5598H appends the device name left in the FCB at 57B8H and the carriage return planted at 57BBH, then re-executes the whole line through the command-execute entry at 4451H to reset the device driver the spooler had hooked.

57D8H - Filename Templates and the Option Keyword Table

Two small filename templates followed by the @PARAM descriptor table the parse stage passes to the resident @PARAM service at 4476H (in DE, from 52C6H). Each 8-byte table entry is a six-character space-padded keyword and a two-byte pointer to the operand cell @PARAM writes when that keyword is present. The reduced table an installed spooler uses begins at the OFF entry (5803H).

57D8-57DE
DEFM "XX/SPL",03H 58 58 2F 53 50 4C 03
Disk overflow-file name template. The XX at 57D8H/57D9H is overwritten at 528CH with the two-character output device name, giving a spool file named devname/SPL.
57DF-57E2
DEFM "*PR",03H 2A 50 52 03
Default output device specification, the printer device *PR, copied into the working FCB at 57B8H by the helper at 5278H when no device is supplied.
57E3-57EA
DEFM "MEM " / DEFW 538EH 4D 45 4D 20 20 20 8E 53
@PARAM Keyword Entry
Full keyword MEM. @PARAM writes the requested buffer memory size into cell 538EH.
57EB-57F2
DEFM "M " / DEFW 538EH 4D 20 20 20 20 20 8E 53
@PARAM Keyword Entry
Abbreviation M for MEM; same value cell 538EH.
57F3-57FA
DEFM "DISK " / DEFW 5356H 44 49 53 4B 20 20 56 53
@PARAM Keyword Entry
Full keyword DISK (spool to disk). @PARAM writes the drive number into cell 5356H.
57FB-5802
DEFM "D " / DEFW 5356H 44 20 20 20 20 20 56 53
@PARAM Keyword Entry
Abbreviation D for DISK; same value cell 5356H.
5803-580A
DEFM "OFF " / DEFW 52D0H 4F 46 46 20 20 20 D0 52
@PARAM Keyword Entry
Full keyword OFF (remove the spooler). @PARAM writes 00FFH into flag cell 52D0H; the INC E test at 52CFH then dispatches to 5539H. First entry of the reduced table an installed spooler uses.
580B-5812
DEFM "N " / DEFW 52D0H 4E 20 20 20 20 20 D0 52
@PARAM Keyword Entry
Alias N for OFF; same flag cell 52D0H.
5813-581A
DEFM "PAUSE " / DEFW 52DEH 50 41 55 53 45 20 DE 52
@PARAM Keyword Entry
Full keyword PAUSE. @PARAM writes 00FFH into flag cell 52DEH; the INC E test at 52DDH dispatches to 550FH.
581B-5822
DEFM "P " / DEFW 52DEH 50 20 20 20 20 20 DE 52
@PARAM Keyword Entry
Abbreviation P for PAUSE; same flag cell 52DEH.
5823-582A
DEFM "RESUME" / DEFW 52D7H 52 45 53 55 4D 45 D7 52
@PARAM Keyword Entry
Full keyword RESUME. @PARAM writes 00FFH into flag cell 52D7H; the INC E test at 52D6H dispatches to 5524H.
582B-5832
DEFM "R " / DEFW 52D7H 52 20 20 20 20 20 D7 52
@PARAM Keyword Entry
Abbreviation R for RESUME; same flag cell 52D7H.
5833-583A
DEFM "CLEAR " / DEFW 52E5H 43 4C 45 41 52 20 E5 52
@PARAM Keyword Entry
Full keyword CLEAR. @PARAM writes 00FFH into flag cell 52E5H; the INC E test at 52E4H dispatches to 55A7H.
583B-5842
DEFM "C " / DEFW 52E5H 43 20 20 20 20 20 E5 52
@PARAM Keyword Entry
Abbreviation C for CLEAR; same flag cell 52E5H.
5843
DEFB 00H 00
Zero byte terminating the @PARAM keyword table.

5844H - SPOOL Resident Module Header and Descriptor Workspace

The header of the relocatable high-memory module. The install stage copies 016BH bytes from 5844H into the reserved module with the LDIR at 54C9H, so this header and the two routines that follow it run at their high-memory address, not here. The ten bytes at 584EH are the module descriptor scratch IY addresses while the module is being built.

5844-5845
DEFB 18H,12H 18 12
A JR +12H relative jump. When the block is later entered as a resident high-memory module this jump skips the 18-byte header to the module body.
5846-5847
DEFW 0000H 00 00
Self-Modifying Code
Module chain link field. Patched at 53C7H (LD (5846H),HL) with the module base so the block links into the resident high-memory module chain.
5848
DEFB 05H 05
Module name length: the name that follows is 5 characters long.
5849-584D
DEFM "SPOOL" 53 50 4F 4F 4C
The module name SPOOL, the tag this block carries in the resident high-memory module directory.
584E-5857
(reserved)
Module Descriptor Workspace
Ten uninitialised bytes (not loaded from the file). Register pair IY addresses this area during the build: +00/+01 module base, +02/+03 reserved ceiling, +04/+05 buffer size, +06/+07 spool-to-disk drive, +08/+09 the module task-entry link.

5858H - Resident Spooler Routine: Capture a Character into the Queue

The first relocatable routine of the module (it runs at its high-memory address after relocation; the addresses shown are the template addresses). This is the spooler half of the two-process design: it stores each captured output character into the circular queue, and when a queue page fills it either triggers the despooler or, for a disk-backed spooler, writes the full page out to the /SPL file through @POSN and @WRITE. Register pair IX addresses the control block at 59AFH; the LD IX operand cells and the CALL targets were patched to their high-memory values by the install stage.

5858
If the Z flag is set on entry, JUMP to 585DH to queue the character.
585A
LD A,C 79
Otherwise move the character (register C) into register A.
585B
OR A B7
Test register A; a zero character is ignored.
585C
RET C9
Return without queueing.
585D
PUSH AF F5
Save register AF across the queue-store call.
585E
GOSUB to the queue-store code at 5863H (relocated) to place the character.
5861
POP AF F1
Restore register AF.
5862
RET C9
Return to the caller.
5863
LD IX,59AFH DD 21 AF 59
Self-Modifying Code
Point register pair IX at the spooler control block; the operand at 5865H was patched to the module's high-memory control block by the install stage.
5867
LD L,(IX+20H) DD 6E 20
Load register L with control-block byte IX+20H, the current queue write-pointer low byte.
586A
LD H,(IX+21H) DD 66 21
Load register H with control-block byte IX+21H, the current queue write-pointer high byte (a page number), so HL is the write position.
586D
LD (HL),C 71
Store the captured character (register C) at the write position (HL).
586E
DI F3
Disable interrupts while the queue pointers are advanced (the despool interrupt task also touches them).
586F
INC (IX+20H) DD 34 20
INCrement the queue write-pointer low byte at control-block byte IX+20H; a wrap to zero means the current page is full.
5872
If the page filled (Z flag), JUMP to 587AH to advance to the next queue page.
5874
GOSUB to the despool core at 58FBH (relocated) to try to print a queued character now.
5877
EI FB
Re-enable interrupts.
5878
JUMP to 58C5H to finish.
587A
LD L,(IX+24H) DD 6E 24
Page full: load register L with control-block byte IX+24H, the queue-slot table pointer low byte.
587D
LD H,(IX+25H) DD 66 25
Load register H with control-block byte IX+25H, the queue-slot table pointer high byte, so HL scans the slot table.
5880
LD A,(HL) 7E
Load register A with the current slot's first link byte at (HL).
5881
INC HL 23
INCrement register pair HL to the slot's second link byte.
5882
OR (HL) B6
OR the second link byte into register A; a zero result marks a free slot.
5883
If both link bytes are zero (a free slot was found), JUMP to 588AH.
5885
INC HL 23
INCrement register pair HL past the slot page byte (byte 3 of 4).
5886
INC HL 23
INCrement register pair HL (byte 4 of 4).
5887
INC HL 23
INCrement register pair HL to the next slot.
5888
LOOP BACK to 5880H to test the next slot.
588A
DEC HL 2B
A free slot: DECrement register pair HL back to the slot's second byte.
588B
PUSH HL E5
Save the slot pointer (register pair HL) on the stack.
588C
INC HL 23
INCrement register pair HL to the slot's page byte.
588D
INC HL 23
INCrement register pair HL again.
588E
LD B,(HL) 46
Load register B with the slot's page number at (HL).
588F
INC HL 23
INCrement register pair HL to the slot's fourth byte.
5890
LD A,(HL) 7E
Load register A with the slot's fourth byte at (HL).
5891
CP 0FFH FE FF
Compare register A against FFH, the end-of-queue marker.
5893
If the slot is not the end marker, JUMP to 58A0H to link it into the queue.
5895
POP HL E1
End of queue reached: restore the slot pointer (register pair HL) from the stack.
5896
GOSUB to the despool core at 58FBH (relocated) to drain a character and free space.
5899
EI FB
Re-enable interrupts briefly.
589A
GOSUB to the disk-assist routine at 5942H (relocated) to page queue data to or from disk.
589D
DI F3
Disable interrupts again for the retry.
589E
LOOP BACK to 587AH to retry finding a free slot.
58A0
BIT 7,A CB 7F
Test bit 7 of register A (the slot's fourth byte); set means the slot is disk-backed.
58A2
If the slot is disk-backed (bit 7 set), JUMP to 58C7H to write the page to the /SPL file.
58A4
POP HL E1
Restore the slot pointer (register pair HL) from the stack.
58A5
PUSH HL E5
Save the slot pointer (register pair HL) again.
58A6
LD (HL),L 75
Write the slot pointer low byte (register L) into the slot's first link byte at (HL).
58A7
LD A,H 7C
Move register H (slot pointer high byte) into register A.
58A8
INC HL 23
INCrement register pair HL to the second link byte.
58A9
LD (HL),A 77
Write the slot pointer high byte (register A) into the second link byte, self-linking the new slot.
58AA
LD (IX+21H),B DD 70 21
Store the new page number (register B) into control-block byte IX+21H, the queue write-pointer page.
58AD
LD L,(IX+26H) DD 6E 26
Load register L with control-block byte IX+26H, the queue head pointer low byte.
58B0
LD H,(IX+27H) DD 66 27
Load register H with control-block byte IX+27H, the queue head pointer high byte.
58B3
LD (IX+2AH),L DD 75 2A
Store the head pointer low byte (register L) into control-block byte IX+2AH.
58B6
LD (IX+2BH),H DD 74 2B
Store the head pointer high byte (register H) into control-block byte IX+2BH, saving the previous head.
58B9
POP BC C1
Restore the new slot pointer into register pair BC from the stack.
58BA
LD (HL),C 71
Write the new slot pointer low byte (register C) into the old head slot's link at (HL).
58BB
INC HL 23
INCrement register pair HL to the link high byte.
58BC
LD (HL),B 70
Write the new slot pointer high byte (register B), chaining the new slot after the old head.
58BD
LD (IX+26H),C DD 71 26
Store the new slot pointer low byte (register C) into control-block byte IX+26H (queue head).
58C0
LD (IX+27H),B DD 70 27
Store the new slot pointer high byte (register B) into control-block byte IX+27H.
58C3
EI FB
Re-enable interrupts.
58C4
RET C9
Return to the caller.
58C5
JUMP to the disk-assist routine at 5942H (relocated) to complete any pending disk paging.
58C7
EI FB
Disk-backed slot: re-enable interrupts before the disk write.
58C8
LD C,B 48
Move the page number (register B) into register C for the record position.
58C9
AND 0FH E6 0F
Mask register A to the low nibble, the record number within the /SPL file.
58CB
LD B,A 47
Move the record number (register A) into register B.
58CC
PUSH IX DD E5
Save register pair IX (the control block) on the stack.
58CE
POP DE D1
Move the control-block address into register pair DE for @POSN (it holds the FCB).
58CF
GOSUB to the resident @POSN service at 4442H to position the /SPL file at record BC.
58D2
LD C,(IX+26H) DD 4E 26
Load register C with control-block byte IX+26H, the queue head pointer low byte.
58D5
LD B,(IX+27H) DD 46 27
Load register B with control-block byte IX+27H, the queue head pointer high byte.
58D8
POP HL E1
Restore the slot pointer (register pair HL) from the stack.
58D9
PUSH HL E5
Save the slot pointer (register pair HL) again.
58DA
LD (HL),C 71
Write the head pointer low byte (register C) into the slot link at (HL).
58DB
INC HL 23
INCrement register pair HL to the link high byte.
58DC
LD (HL),B 70
Write the head pointer high byte (register B) into the slot link.
58DD
POP BC C1
Restore the slot pointer into register pair BC from the stack.
58DE
LD L,(IX+2AH) DD 6E 2A
Load register L with control-block byte IX+2AH, the saved previous-head low byte.
58E1
LD H,(IX+2BH) DD 66 2B
Load register H with control-block byte IX+2BH, the saved previous-head high byte.
58E4
LD (HL),C 71
Write the slot pointer low byte (register C) into the previous head's link at (HL).
58E5
INC HL 23
INCrement register pair HL to the link high byte.
58E6
LD (HL),B 70
Write the slot pointer high byte (register B), threading the slot into the disk chain.
58E7
LD (IX+2AH),C DD 71 2A
Store the slot pointer low byte (register C) into control-block byte IX+2AH.
58EA
LD (IX+2BH),B DD 70 2B
Store the slot pointer high byte (register B) into control-block byte IX+2BH.
58ED
LD B,(IX+21H) DD 46 21
Load register B with control-block byte IX+21H, the queue write-pointer page.
58F0
LD (IX+04H),B DD 70 04
Store the page number (register B) into the FCB record-length field IX+04H for the write.
58F3
JUMP to the resident @WRITE service at 4439H to write the full page to the /SPL file, returning through it.

58F6H - Despool Interrupt Task Entry

The two-byte landing that @ADTSK was given as the module task entry (module+00B2H) at 54F3H. These bytes are not loaded from the file; on each real-time-clock tick execution passes through here and falls into the despool core at 58F8H.

58F6-58F7
(reserved)
Task Entry Landing
Two reserved bytes (not loaded from the file) forming the module task entry at module+00B2H. On each clock tick execution enters here and falls into the despool core at 58F8H below.

58F8H - Resident Spooler Routine: Despool Interrupt Task and Disk Refill

The despooler half of the module. The despool core is installed as interrupt task slot 9 (via @ADTSK at 54F3H) and, on each real-time-clock tick, sends one queued character to the printer through the saved printer driver. Because a sector transfer cannot run inside the interrupt, disk-backed data is refilled by the routine at 5942H, which is reached from the @KITSK keyboard hook on each keyboard poll. As above these run at the module's high-memory address; the LD IX operands and the CALL 0000H vectors were patched by the install stage.

58F8
Task entry: GOSUB to the despool core at 58FBH (relocated).
58FB
LD A,(4423H) 3A 23 44
Load register A with KFLAG$ at 4423H to test the despool-enable bit.
58FE
AND 10H E6 10
Mask register A to bit 4 (the despool-enable flag).
5900
RET Z C8
If bit 4 is clear (paused or not installed), RETurn without printing.
5901
LD C,00H 0E 00
Load register C with 00H, the status request for the printer driver readiness test.
5903
PUSH IX DD E5
Save register pair IX on the stack.
5905
LD IX,4025H DD 21 25 40
Point register pair IX at PRDCB$, the printer device control block at 4025H.
5909
CALL 0000H CD 00 00
Self-Modifying Code
GOSUB the saved printer driver; the operand at 590AH was patched by the install stage with the original PRDCB$ driver vector. It returns NZ if the printer is not ready.
590C
POP IX DD E1
Restore register pair IX from the stack.
590E
RET NZ C0
If the printer is not ready (NZ flag), RETurn and try again next tick.
590F
LD IX,59AFH DD 21 AF 59
Self-Modifying Code
Point register pair IX at the control block; the operand at 5911H was patched to the high-memory control block.
5913
LD A,(IX+23H) DD 7E 23
Load register A with control-block byte IX+23H, the despool read-pointer page.
5916
OR A B7
Test register A; zero means the queue is empty.
5917
RET Z C8
If the queue is empty (Z flag), RETurn.
5918
LD H,A 67
Move the despool read page (register A) into register H.
5919
CP (IX+21H) DD BE 21
Compare register A against control-block byte IX+21H, the queue write page.
591C
LD A,(IX+22H) DD 7E 22
Load register A with control-block byte IX+22H, the despool read-pointer low byte.
591F
If the read page differs from the write page (NZ flag), JUMP to 5925H to fetch a character.
5921
CP (IX+20H) DD BE 20
On the same page, compare the read low byte against control-block byte IX+20H, the write low byte.
5924
RET Z C8
If the read pointer has caught the write pointer (Z flag, nothing new), RETurn.
5925
LD L,A 6F
Move the despool read-pointer low byte (register A) into register L, so HL is the read position.
5926
XOR A AF
Set register A to zero.
5927
LD C,(HL) 4E
Load register C with the next queued character at the read position (HL).
5928
PUSH IX DD E5
Save register pair IX on the stack.
592A
LD IX,(5907H) DD 2A 07 59
Self-Modifying Code
Load register pair IX from cell 5907H, patched by the install stage with the device driver-table pointer.
592E
CALL 0000H CD 00 00
Self-Modifying Code
GOSUB the original device driver to print the character in register C; the operand at 592FH was patched with the saved driver entry.
5931
POP IX DD E1
Restore register pair IX (the control block) from the stack.
5933
INC (IX+22H) DD 34 22
INCrement control-block byte IX+22H, the despool read-pointer low byte; a wrap to zero means the page is drained.
5936
RET NZ C0
If the page is not yet drained (NZ flag), RETurn.
5937
LD (IX+23H),00H DD 36 23 00
Zero control-block byte IX+23H, the despool read-pointer page, to request the next page from the disk-assist routine.
593B
RET C9
Return from the despool core.
593C
@KITSK hook entry (module+00F8H): GOSUB the disk-assist routine at 5942H (relocated) on each keyboard poll to refill the queue from the /SPL file.
593F
DEFB 52H,6FH,79H 52 6F 79
Self-Modifying Code
Three template bytes overwritten at 5459H and 545CH with the saved @KITSK opcode (from 4300H) and target (from 4301H); at run time this is the JP that chains the previous keyboard-service handler after the spooler's.
5942
PUSH AF F5
Disk-assist entry (module+00FEH): save register AF.
5943
PUSH IX DD E5
Save register pair IX on the stack.
5945
LD A,(59D2H) 3A D2 59
Load register A with the disk-active flag at cell 59D2H (nonzero for a disk-backed spooler).
5948
OR A B7
Test register A.
5949
If this is not a disk-backed spooler (flag zero clears NZ)... if the flag is nonzero, JUMP to 5978H to just despool.
594B
PUSH HL E5
Disk-backed: save register pair HL.
594C
PUSH DE D5
Save register pair DE.
594D
PUSH BC C5
Save register pair BC.
594E
LD IX,59AFH DD 21 AF 59
Self-Modifying Code
Point register pair IX at the control block; the operand at 5950H was patched to the high-memory control block.
5952
LD L,(IX+28H) DD 6E 28
Load register L with control-block byte IX+28H, the disk read-chain pointer low byte.
5955
LD H,(IX+29H) DD 66 29
Load register H with control-block byte IX+29H, the disk read-chain pointer high byte.
5958
PUSH HL E5
Save the chain pointer (register pair HL) on the stack.
5959
LD C,(HL) 4E
Load register C with the chain-entry low byte at (HL).
595A
INC HL 23
INCrement register pair HL to the chain-entry high byte.
595B
LD B,(HL) 46
Load register B with the chain-entry high byte, so register pair BC is the next disk record.
595C
LD HL,0002H 21 02 00
Load register pair HL with 0002H, the offset to the entry's record/flag field.
595F
ADD HL,BC 09
Add register pair BC so HL addresses that field.
5960
LD A,(HL) 7E
Load register A with the disk record number for this chain entry.
5961
INC HL 23
INCrement register pair HL to the flag byte.
5962
BIT 7,(HL) CB 7E
Test bit 7 of the flag byte at (HL); set means the record is present on disk.
5964
If the record is on disk (bit 7 set), JUMP to 5981H to read it back into the queue.
5966
LD (IX+23H),A DD 77 23
Otherwise store the record number (register A) into control-block byte IX+23H, the despool read page.
5969
POP HL E1
Restore the chain pointer (register pair HL) from the stack.
596A
LD (HL),00H 36 00
Zero the chain-entry low byte at (HL).
596C
INC HL 23
INCrement register pair HL to the high byte.
596D
LD (HL),00H 36 00
Zero the chain-entry high byte, releasing the entry.
596F
LD (IX+28H),C DD 71 28
Store the next chain low byte (register C) into control-block byte IX+28H.
5972
LD (IX+29H),B DD 70 29
Store the next chain high byte (register B) into control-block byte IX+29H, advancing the read chain.
5975
POP BC C1
Restore register pair BC from the stack.
5976
POP DE D1
Restore register pair DE from the stack.
5977
POP HL E1
Restore register pair HL from the stack.
5978
DI F3
Disable interrupts around the despool call.
5979
GOSUB the despool core at 58FBH (relocated) to send a character to the printer.
597C
EI FB
Re-enable interrupts.
597D
POP IX DD E1
Restore register pair IX from the stack.
597F
POP AF F1
Restore register AF from the stack.
5980
RET C9
Return to the caller.
5981
LD C,A 4F
Read a disk record: move the record number (register A) into register C.
5982
LD A,(HL) 7E
Load register A with the flag byte at (HL).
5983
AND 0FH E6 0F
Mask register A to the low nibble, the record number within the /SPL file.
5985
LD B,A 47
Move the record number (register A) into register B.
5986
PUSH IX DD E5
Save register pair IX on the stack.
5988
POP DE D1
Move the control-block/FCB address into register pair DE for @POSN.
5989
GOSUB to the resident @POSN service at 4442H to position the /SPL file at record BC.
598C
POP HL E1
Restore the chain pointer (register pair HL) from the stack.
598D
PUSH HL E5
Save the chain pointer (register pair HL) again.
598E
INC HL 23
INCrement register pair HL to the slot's page field.
598F
INC HL 23
INCrement register pair HL again.
5990
LD B,(HL) 46
Load register B with the target queue page for the record.
5991
LD (IX+04H),B DD 70 04
Store the target page (register B) into the FCB field IX+04H for the read.
5994
GOSUB to the resident @READ service at 4436H to read the /SPL record back into the queue page.
5997
POP HL E1
Restore the chain pointer (register pair HL) from the stack.
5998
PUSH HL E5
Save the chain pointer (register pair HL) again.
5999
LD A,(HL) 7E
Load register A with the chain-entry low byte at (HL).
599A
INC HL 23
INCrement register pair HL to the high byte.
599B
LD H,(HL) 66
Load register H with the chain-entry high byte at (HL).
599C
LD L,A 6F
Move the saved low byte (register A) into register L, so HL is the next chain entry.
599D
LD C,(HL) 4E
Load register C with that entry's low byte at (HL).
599E
LD (HL),00H 36 00
Zero the entry low byte at (HL).
59A0
INC HL 23
INCrement register pair HL to the high byte.
59A1
LD B,(HL) 46
Load register B with the entry high byte at (HL).
59A2
LD (HL),00H 36 00
Zero the entry high byte, releasing it.
59A4
POP HL E1
Restore the chain pointer (register pair HL) from the stack.
59A5
LD (HL),C 71
Write the freed link low byte (register C) into the chain at (HL).
59A6
INC HL 23
INCrement register pair HL to the high byte.
59A7
LD (HL),B 70
Write the freed link high byte (register B) into the chain.
59A8
INC HL 23
INCrement register pair HL to the page field.
59A9
LD B,(HL) 46
Load register B with the recovered page number at (HL).
59AA
LD (IX+23H),B DD 70 23
Store the recovered page (register B) into control-block byte IX+23H, the despool read page, so the refilled data prints next.
59AD
LOOP BACK to 5975H to finish and despool.

59AFH - Spooler Control Block, Queue Image and Module End

The 44-byte spooler control block and queue image the install stage assembles here (at 59AFH) before copying it into the module with the LDIR at 542DH. It is not loaded from the file; its fields are the queue write pointer (+20/+21), despool read pointer (+22/+23), slot-table pointer (+24/+25), queue head (+26/+27), disk read chain (+28/+29) and saved-head (+2A/+2B) that the two routines above index through register pair IX. The two loaded bytes at 59D9H close the module.

59AF-59D8
(reserved)
Control Block and Queue Image
Forty-two bytes of spooler control block and queue-slot workspace built by the install stage (the pointer fields at 59CFH-59D7H are written at 53D7H-541AH; the disk-active flag sits at 59D2H). Copied into the high-memory module by the LDIR at 542DH.
59D9-59DA
NOP x 2 00 00
Two NOP bytes closing the module image. The overlay has no transfer address; it is entered by the resident loader, so this is the END of SPOOL.

Disassembly - Overlay 7 - COPY/APPEND

5200H - COPY / APPEND Overlay Entry Dispatch

First byte of Library A command overlay 7, loaded at 5200H by the resident overlay loader at 4BF5H when the resident RST 28H dispatcher (4BCDH) decodes request code 88H with the command number for COPY. The overlay carries two command bodies that share one exit and one common subroutine library: the COPY body at 52B1H and the APPEND body at 5203H. The first byte jumps straight to the COPY body, stepping over the APPEND body that follows.

5200
JUMP to 52B1H, the COPY command body. Entering the overlay at its first byte therefore runs COPY; the APPEND body at 5203H is reached instead when the overlay is entered for the APPEND command.

5203H - APPEND Command Entry, Spec Parse and Setup

Entry of the APPEND command. APPEND concatenates the source file onto the end of an existing destination file. It saves the caller stack, retargets the progress banner to "Appending: ", parses the source and destination file specifications, parses the APPEND option keywords, positions the destination to its current end of file, and then joins the shared copy engine.

5203
LD (548AH),SP ED 73 8A 54
Self-Modifying Code
Store the caller stack pointer (register SP, holding the LDOS command-level stack on entry) into the operand of the LD SP,nnnn instruction at 5489H, so the overlay exit at 5489H can restore the caller stack. The two-byte operand cell is 548AH.
5207
XOR A AF
Set register A to ZERO and clear all flags, preparing a zero byte to initialise the two APPEND flag cells below.
5208
LD (544BH),A 32 4B 54
Store the zero in register A into the flag cell 544BH, clearing one of the APPEND-mode state flags before parsing begins.
520B
LD (544CH),A 32 4C 54
Store the zero in register A into the flag cell 544CH, clearing the second APPEND-mode state flag before parsing begins.
520E
LD BC,5845H 01 45 58
Load register pair BC with 5845H, the address of the "Appending: " banner literal (5845H holds "Appending: " terminated by 03H).
5211
LD (56A4H),BC ED 43 A4 56
Self-Modifying Code
Store 5845H (register pair BC, the "Appending: " literal address) into the operand cell 56A4H, which is the address operand of the LD HL,nnnn instruction at 56A3H inside the banner-display routine 56A1H. This makes the shared banner routine print "Appending: " for APPEND instead of its default "Copying: " (583BH).
5215
GOSUB to 54B8H, which checks the SYS1 busy flag at 4758H and, when the system is idle, patches the copy-buffer ceiling (the high byte of HIGH$ at 4049H) into the three loop-limit comparisons at 53FBH, 5413H and 549DH, then clears the pause flags in KFLAG$ at 4423H.
5218
LD DE,5986H 11 86 59
Point register pair DE at 5986H, the source File Control Block (FCB) work area that @FSPEC will fill from the source file specification on the command line.
521B
GOSUB to the resident SYS0 service @FSPEC at 441CH to parse the source file specification from the command line into the source FCB at 5986H (register pair DE). @FSPEC returns the Z flag set on success and the NZ flag if the specification is missing or malformed.
521E
If the NZ flag is set (@FSPEC could not parse a source specification), JUMP to 5823H to display "File spec required" and abort the command.
5221
LD DE,59DAH 11 DA 59
Point register pair DE at 59DAH, the destination FCB work area that @FSPEC will fill from the destination file specification.
5224
GOSUB to @FSPEC at 441CH to parse the destination specification into the destination FCB at 59DAH (register pair DE). The Z flag is set on success; the NZ flag indicates the destination text ran out.
5227
If the NZ flag is set (the destination specification did not terminate cleanly), GOSUB to 5564H to append a carriage return (0DH) so the destination spec buffer is properly terminated.
522A
LD A,(59DAH) 3A DA 59
Load register A with the first byte of the destination FCB at 59DAH, which holds the first character of the destination specification (2AH for a device such as *KI or *PR, otherwise a filename character).
522D
CP 2AH FE 2A
Compare register A (the first destination character) against 2AH (ASCII: *). If it equals 2AH the destination is a device rather than a file and the Z flag is set.
522F
If the Z flag is set (the destination is a * device), JUMP to 5823H to display "File spec required", because APPEND requires a disk file as its destination, not a device.
5232
LD DE,5A4DH 11 4D 5A
Point register pair DE at 5A4DH, the APPEND keyword descriptor table (the STRIP, ECHO and X option keywords with the addresses of their self-modified operand cells) that @PARAM will scan.
5235
GOSUB to the resident SYS0 service @PARAM at 4476H to parse the option keywords on the command line against the descriptor table at 5A4DH (register pair DE). @PARAM returns the Z flag on success and the NZ flag on an unrecognised keyword.
5238
If the NZ flag is set (@PARAM found a bad option), JUMP to 5816H to report parameter error code 2CH (44 decimal, "parameter error") through @ERROR and abort.
523B
GOSUB to 558EH, which validates the drive digit that follows the ':' in the destination specification (at 59DAH) and reports "Destination spec required" (582FH) if it is absent or out of range.
523E
GOSUB to 5806H, which fills the record buffer at 5B00H with 24H spaces and opens the destination file into the destination FCB at 59DAH, leaving the open FCB ready for record I/O.
5241
GOSUB to 5690H, which copies the resolved destination file specification into the display buffer at 59CAH so the banner routine can show it after the word "to".
5244
GOSUB to 56BDH, which reads the destination directory record for the open FCB (using FCB+07H at 59E1H as the directory index into the sector buffer at 4200H) and returns that directory entry's first byte (its flag/attribute byte) in register A.
5247
LD (5260H),A 32 60 52
Self-Modifying Code
Store the destination directory flag byte (register A, just returned by 56BDH) into the operand cell 5260H, which is the immediate operand of the LD B,nn instruction at 525FH. The XOR B at 5261H later re-reads this saved byte to detect whether the destination attributes changed.
524A
LD (5448H),A 32 48 54
Store the same destination directory flag byte (register A) into the work cell 5448H, preserving the destination file's original attribute byte for the copy engine.
524D
GOSUB to 5803H, which points register pair DE at the source FCB (5986H), register pair HL at the record buffer (5B00H), and opens the source file for reading via the shared open helper.
5250
GOSUB to 568AH, which copies the resolved source file specification into the display buffer at 59B6H so the banner routine can show it after "Appending:".
5253
EX DE,HL EB
Exchange register pairs DE and HL so that HL points at the source FCB base (5986H) for the bit test on the next line.
5254
BIT 7,(HL) CB 7E
Test bit 7 of the byte at (HL), the source FCB flag byte at 5986H. Bit 7 set marks an open disk file; bit 7 clear marks a logical device. The Z flag reflects the tested bit.
5256
EX DE,HL EB
Exchange register pairs DE and HL back, restoring HL to its previous value and leaving DE pointing at the source FCB base (5986H).
5257
If the Z flag is set (source FCB bit 7 clear, meaning the source is a device), GOSUB to 56A1H to display the "Appending: source to destination" banner immediately, since a device source has no directory record to check first.
525A
If the Z flag is still set (source is a device), JUMP to 5275H to position the destination to end of file and begin the byte transfer, skipping the disk-source record-count logic below.
525C
The source is a disk file. GOSUB to 56BDH to read the source file's directory record and return its flag/attribute byte in register A for comparison.
525F
LD B,00H 06 00
Self-Modifying Code
Load register B with the destination directory flag byte that was patched into the operand cell 5260H at 5247H. The 00H shown is the initial listing value; at run time B holds the destination file's attribute byte.
5261
XOR B A8
Exclusive-OR register A (the source attribute byte) with register B (the destination attribute byte). Any bit that differs between the two attribute bytes leaves a 1 in register A and sets the NZ flag.
5262
If the NZ flag is set (the source and destination file attributes disagree, so their logical record lengths are incompatible for appending), JUMP to 582BH to display "Files have different LRLs" and abort.
5265
The attributes match. GOSUB to 56A1H to display the "Appending: source to destination" banner now that the destination has been validated.
5268
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand cell 5269H. The 0000H shown is the listing value; the STRIP option, when supplied, patches this operand so DE carries a non-zero record count. It selects whether the file's final partial sector is trimmed.
526B
LD A,D 7A
Copy the high byte of that patched value (register D) into register A to begin testing whether it is non-zero.
526C
OR E B3
OR register A (high byte) with register E (low byte). The Z flag is set only if the whole DE value is zero (STRIP not requested).
526D
If the NZ flag is set (a non-zero value was patched in), JUMP to 5275H to begin the transfer without the extra end-of-file test below.
526F
LD A,(59E2H) 3A E2 59
Load register A with the destination FCB+08H byte at 59E2H, the destination file's end-of-file offset within its last sector (the count of valid bytes in the final record).
5272
OR A B7
Test register A (the destination end-of-file offset). If it is zero the destination ends exactly on a sector boundary and the Z flag is set.
5273
If the Z flag is set (the destination file ends on a full-record boundary), JUMP to 5294H to pre-extend the destination by the source length rather than positioning inside a partial record.
5275
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB (59DAH) so the following @PEOF call operates on the destination file.
5278
GOSUB to the resident SYS0 service @PEOF at 4448H to position the destination file (its FCB at 59DAH, register pair DE) to its current end of file, so appended records are written after the existing data.
527B
LD A,(5269H) 3A 69 52
Load register A with the low byte of the STRIP operand at 5269H (the operand of the LD DE at 5268H) to test the STRIP request a second time.
527E
OR A B7
Test register A (the STRIP operand low byte). The Z flag is set if STRIP was not requested.
527F
If the Z flag is set (no STRIP), JUMP to 528BH to point the buffer at 5C00H and enter the byte-copy loop without backspacing.
5281
LD HL,59E3H 21 E3 59
Point register pair HL at 59E3H, the destination FCB+09H byte holding the current record position flag used by the backspace helper.
5284
LD B,(HL) 46
Save the current byte at 59E3H (register B) so it can be restored after the backspace below.
5285
LD (HL),01H 36 01
Store 01H into 59E3H to force the backspace helper to move back exactly one record before appending.
5287
GOSUB to the resident SYS0 service @BKSP at 4445H to back the destination file (its FCB at 59DAH) up by one record, so the STRIP append overwrites the destination's final partial record instead of following it.
528A
LD (HL),B 70
Restore the original byte (register B) into 59E3H, undoing the temporary 01H forced above.
528B
LD HL,5C00H 21 00 5C
Point register pair HL at 5C00H, the single-record byte-copy buffer used by the character-transfer loop.
528E
LD (59DDH),HL 22 DD 59
Store 5C00H (register pair HL) into the destination FCB+03H buffer-address field at 59DDH, so the destination's record I/O uses the 5C00H buffer.
5291
JUMP to 5519H to run the character-at-a-time copy loop, which reads bytes from the source and writes them to the appended destination.
5294
LD BC,(5992H) ED 4B 92 59
Load register pair BC with the source FCB+0CH word at 5992H, the source file's ending record number (its length measured in 256-byte records).
5298
LD A,B 78
Copy the high byte of the source record count (register B) into register A to test whether the source has any records.
5299
OR C B1
OR register A (high byte) with register C (low byte). The Z flag is set only if the source length in BC is zero (an empty source file).
529A
If the Z flag is set (the source file is empty, nothing to append), JUMP to 547AH to close the destination and exit cleanly.
529D
LD HL,(59E6H) 2A E6 59
Load register pair HL with the destination FCB+0CH word at 59E6H, the destination file's current ending record number (its present length in records).
52A0
PUSH HL E5
Save the destination's current record count (register pair HL) on the stack so it can be restored after computing the extended length.
52A1
ADD HL,BC 09
Add the source length (register pair BC) to the destination length (register pair HL), giving in HL the total record count the destination will need after the append.
52A2
LD B,H 44
Copy the high byte of the required total (register H) into register B.
52A3
LD C,L 4D
Copy the low byte of the required total (register L) into register C, so register pair BC now holds the destination's required final record count.
52A4
GOSUB to 54D4H, which positions the destination file to record BC-1 and writes an E5H-filled record there, pre-allocating enough disk space for the whole appended file up front so the copy cannot run out of space midway.
52A7
POP HL E1
Restore the destination's original record count (register pair HL) from the stack.
52A8
LD (59E6H),HL 22 E6 59
Store the original record count (register pair HL) back into the destination FCB+0CH word at 59E6H, so the pre-extend did not disturb the logical end of file the append will start from.
52AB
GOSUB to @PEOF at 4448H to reposition the destination file (its FCB at 59DAH) to its true end of file after the pre-extend, ready to receive the appended records.
52AE
JUMP to 53DCH, the shared block-copy engine, to read the source in full-memory chunks and write them onto the end of the destination file.

52B1H - COPY Command Entry, Spec Parse and Drive Setup

Entry of the COPY command, reached from the overlay's first byte at 5200H. COPY duplicates a source file or device to a destination file or device. It saves the caller stack, parses the source and destination specifications and the COPY option keywords, guards against running inside a JCL DO stream, extracts the destination drive digit into the disk-swap prompt strings, and prepares the directory information used to detect same-disk copies.

52B1
LD (548AH),SP ED 73 8A 54
Self-Modifying Code
Store the caller stack pointer (register SP, the LDOS command-level stack on entry) into the operand cell 548AH, the operand of the LD SP,nnnn exit instruction at 5489H, so the overlay can restore the caller stack when it finishes.
52B5
GOSUB to 54B8H to check the SYS1 busy flag at 4758H and, when idle, patch the copy-buffer ceiling (the high byte of HIGH$ at 4049H) into the loop limits at 53FBH, 5413H and 549DH, then clear the pause bits in KFLAG$ at 4423H.
52B8
LD DE,5986H 11 86 59
Point register pair DE at the source FCB work area at 5986H for the source specification parse.
52BB
GOSUB to @FSPEC at 441CH to parse the source specification into the source FCB at 5986H (register pair DE). The Z flag is set on success, the NZ flag on a missing or bad specification.
52BE
If the NZ flag is set (no valid source specification), JUMP to 5823H to display "File spec required" and abort.
52C1
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB work area at 59DAH for the destination specification parse.
52C4
GOSUB to @FSPEC at 441CH to parse the destination specification into the destination FCB at 59DAH (register pair DE). The Z flag is set on success, the NZ flag if the destination text ran out.
52C7
If the NZ flag is set (the destination specification did not terminate cleanly), GOSUB to 5564H to append a carriage return (0DH) and terminate the destination buffer.
52CA
LD DE,5A25H 11 25 5A
Point register pair DE at 5A25H, the COPY keyword descriptor table (the LRL, CLONE, X and related option keywords with the addresses of their self-modified operand cells) for @PARAM.
52CD
GOSUB to @PARAM at 4476H to parse the COPY option keywords on the command line against the table at 5A25H (register pair DE). The Z flag is set on success, the NZ flag on a bad keyword.
52D0
If the NZ flag is set (a bad option was given), JUMP to 5816H to report parameter error code 2CH (44 decimal) through @ERROR and abort.
52D3
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand cell 52D4H. The 0000H shown is the listing value; the X option (single-drive copy with disk-swap prompts) patches this operand non-zero. The low byte 52D4H is later read as the single-drive flag by the prompt routines at 570CH, 571EH and 5740H.
52D6
LD A,D 7A
Copy the high byte of the patched value (register D) into register A to test the X option.
52D7
OR E B3
OR register A (high byte) with register E (low byte). The Z flag is set only if the whole DE value is zero (the X single-drive option was not requested).
52D8
If the NZ flag is set (the X single-drive option was requested), JUMP to 52E5H to run the command-level guard and single-drive setup path.
52DA
GOSUB to 57CEH, which returns the Z flag set when either the source (5986H) or destination (59DAH) FCB begins with 2AH (a * device rather than a disk file).
52DD
If the Z flag is set (source or destination is a device), JUMP to 54F4H to run the character-at-a-time device copy loop, which cannot use fixed-record block transfer.
52E0
Both are disk files. GOSUB to 558EH to validate the drive digit after the ':' in the destination specification at 59DAH, reporting "Destination spec required" (582FH) if it is missing.
52E3
JUMP to 533DH to prepare the disk-to-disk copy (LRL check, directory read, buffer setup) without the single-drive prompt logic.
52E5
LD A,(430FH) 3A 0F 43
The X single-drive option was requested. Load register A with the resident system flag byte SFLAG$ at 430FH, whose bit 5 is set when the system is not at LDOS command level (for example inside a running program or JCL DO stream).
52E8
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ byte from 430FH). If bit 5 is set the system is not at command level and the NZ flag is set.
52EA
If the NZ flag is set (not at LDOS command level), JUMP to 5827H to display "Invalid command during processing", because a single-drive copy needs interactive disk swaps that cannot run inside JCL.
52ED
GOSUB to 57CEH again to test whether the source (5986H) or destination (59DAH) FCB is a * device; the Z flag is set if either is.
52F0
If the Z flag is set (a device was named), JUMP to 5823H to display "File spec required", since the X single-drive option applies only to disk-file copies.
52F3
LD HL,5986H 21 86 59
Point register pair HL at the source FCB/spec at 5986H so the loop below can scan the source specification text for its drive digit.
52F6
LD C,00H 0E 00
Initialise register C to 00H, the default drive number, in case no ":drive" appears in the specification.
52F8
LD A,(HL) 7E
Load register A with the current specification character at (HL) within the source spec at 5986H.
52F9
INC HL 23
Advance the scan pointer (register pair HL) to the next specification character.
52FA
CP 3AH FE 3A
Compare register A (the current character) against 3AH (ASCII: :). If it equals 3AH the drive digit follows and the Z flag is set.
52FC
If the Z flag is set (the ':' drive delimiter was found), JUMP to 5304H to read the drive digit that follows.
52FE
CP 20H FE 20
Compare register A (the current character) against 20H (ASCII space). If register A is below 20H (a control character such as the 0DH or 03H terminator) the CARRY flag is set.
5300
If the CARRY flag is set (end of the specification reached without a ':' ), JUMP to 5308H using the default drive number in register C.
5302
Loop Start
LOOP BACK to 52F8H to examine the next specification character while searching for the ':' drive delimiter.
5304
LD A,(HL) 7E
Load register A with the character following the ':' at (HL) within the source spec, the ASCII drive digit.
5305
SUB 30H D6 30
Subtract 30H (ASCII 0) from register A, converting the ASCII drive digit to its binary drive number.
5307
LD C,A 4F
Copy the binary drive number (register A) into register C.
5308
LD A,C 79
Copy the resolved drive number (register C) into register A for storing and for building the ASCII prompt digit.
5309
LD (5712H),A 32 12 57
Store the binary source drive number (register A) into the work cell 5712H, the drive whose GAT is read to verify the mounted disk during single-drive swaps.
530C
ADD A,30H C6 30
Add 30H (ASCII 0) back to register A, converting the binary drive number to its ASCII digit for display.
530E
LD (5938H),A 32 38 59
Self-Modifying Code
Store the ASCII drive digit (register A) into 5938H, the drive-number position inside the "Insert SOURCE disk in drive :0..." prompt string at 5919H, so the prompt names the correct drive.
5311
LD (5971H),A 32 71 59
Self-Modifying Code
Store the same ASCII drive digit (register A) into 5971H, the drive-number position inside the "Insert DESTINATION disk in drive :0..." prompt string at 594DH.
5314
LD HL,5986H 21 86 59
Point register pair HL at the source FCB/spec at 5986H as the copy source for the block move below.
5317
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB/spec at 59DAH as the copy destination for the block move.
531A
LD BC,0020H 01 20 00
Load register pair BC with the byte count 0020H (32) for the block move.
531D
LDIR ED B0
Block-move 32 bytes from the source FCB at 5986H (register pair HL) to the destination FCB at 59DAH (register pair DE), copying the full source FCB over the destination FCB. On a single-drive copy the two files share one physical drive, so the source FCB image is used as the working template.
531F
GOSUB to 57C5H, which loads request code 84H into register A and issues RST 28H to the resident dispatcher, the source-disk checkpoint used by the single-drive copy.
5322
LD HL,5919H 21 19 59
Point register pair HL at 5919H, the "Insert SOURCE disk in drive :n and press " prompt string.
5325
GOSUB to 576EH to display the SOURCE-disk prompt at (HL) and wait for the operator to mount the source disk and press ENTER.
5328
LD A,(5712H) 3A 12 57
Load register A with the binary source drive number saved at 5712H.
532B
LD C,A 4F
Copy the source drive number (register A) into register C, the drive argument expected by the GAT-read helper.
532C
GOSUB to 57EDH to read the Granule Allocation Table (GAT) sector of the disk now mounted in drive C into the resident sector buffer at 4200H, so the disk's identity can be captured. The NZ flag is returned on a read error.
532F
If the NZ flag is set (the GAT could not be read), JUMP to 5810H to report the disk error code through @ERROR and abort.
5332
LD HL,42CEH 21 CE 42
Point register pair HL at 42CEH, the disk-name-and-date identification field within the GAT sector just read into the resident sector buffer at 4200H.
5335
LD DE,59FAH 11 FA 59
Point register pair DE at 59FAH, the save area that will hold the source disk's identity for the later same-disk comparison.
5338
LD BC,0012H 01 12 00
Load register pair BC with the byte count 0012H (18) covering the disk name and date identity field.
533B
LDIR ED B0
Block-move the 18-byte disk identity from 42CEH in the sector buffer (register pair HL) to the save area at 59FAH (register pair DE), remembering which physical disk is the source so a later swap to the same disk can be detected.

533DH - Disk Copy Preparation: Open, LRL Check, Same-Disk Guard

Common disk-to-disk preparation reached by both the ordinary and single-drive COPY paths. It opens the source, records the source directory attributes and logical record length, prompts for and reads the destination disk's identity, guards against copying a disk onto itself, pre-extends the destination to the source length, and rewinds the source ready for the block-copy engine.

533D
GOSUB to 5803H to point register pair DE at the source FCB (5986H) and register pair HL at the record buffer (5B00H) and open the source file for reading.
5340
GOSUB to 568AH to copy the resolved source specification into the display buffer at 59B6H for the progress banner.
5343
GOSUB to 56CCH, which reads the source file's directory entry (indexed by FCB+07H at 598DH into the sector buffer at 4200H) and copies the file's date and access fields into the destination working record so the copy carries them forward.
5346
LD A,(598CH) 3A 8C 59
Load register A with the source FCB+06H byte at 598CH, the source file's drive-selection byte.
5349
GOSUB to 57DAH, which converts the drive number in register A into that drive's extended-dating bit mask and reads the SYS1 dating flags at 475DH; the Z flag reflects whether that drive uses extended date/time stamping.
534C
If the NZ flag is set (extended dating is active for this drive), JUMP to 5353H, leaving the destination attribute default in place.
534E
LD A,0FFH 3E FF
Load register A with 0FFH, the marker that suppresses extended date stamping on the destination.
5350
LD (5466H),A 32 66 54
Store 0FFH (register A) into the flag cell 5466H, recording that the destination directory record should not receive extended date/time bytes.
5353
LD A,L 7D
Copy the low byte of the directory-record pointer (register L, still addressing within the sector buffer at 4200H) into register A to step back to the logical-record-length byte.
5354
SUB 10H D6 10
Subtract 10H (16) from register A, moving the pointer back 16 bytes to the directory entry's logical record length field.
5356
LD L,A 6F
Copy the adjusted low byte (register A) back into register L, so register pair HL now addresses the source directory entry's LRL byte.
5357
LD A,(HL) 7E
Load register A with the source file's logical record length (LRL) byte at (HL).
5358
LD BC,0FF00H 01 00 FF
Load register pair BC with 0FF00H: register B is preset to 0FFH and register C to 00H, so INC B below rolls B to 00H and the following test can substitute a default LRL.
535B
INC B 04
Increment register B from 0FFH to 00H, which sets the Z flag only if the LRL byte handling requires the default; here it clears B and sets the Z flag.
535C
If the NZ flag is set, JUMP to 535FH keeping the LRL already in register A; otherwise fall through to substitute register C.
535E
LD C,A 4F
Copy the source LRL (register A) into register C, retaining the actual record length.
535F
LD A,C 79
Copy the resolved logical record length (register C) into register A.
5360
LD (5448H),A 32 48 54
Store the source LRL (register A) into the work cell 5448H, the record length the destination file will be created with so the copy is byte-for-byte compatible.
5363
LD A,(52D4H) 3A D4 52
Load register A with the single-drive flag at 52D4H (the low byte of the X-option operand at 52D3H). A non-zero value means the X single-drive disk-swap copy is active.
5366
OR A B7
Test register A (the single-drive flag). The Z flag is set when it is zero (an ordinary multi-drive copy).
5367
If the Z flag is set (not a single-drive copy), JUMP to 5396H, skipping the destination-disk swap prompt and the same-disk comparison.
5369
LD HL,594DH 21 4D 59
Single-drive copy: point register pair HL at 594DH, the "Insert DESTINATION disk in drive :n and press " prompt string.
536C
GOSUB to 576EH to display the DESTINATION-disk prompt at (HL) and wait for the operator to swap in the destination disk and press ENTER.
536F
LD A,(5712H) 3A 12 57
Load register A with the drive number saved at 5712H (the single shared drive being swapped).
5372
LD C,A 4F
Copy the drive number (register A) into register C for the GAT-read helper.
5373
GOSUB to 57EDH to read the GAT sector of the disk now mounted in drive C into the sector buffer at 4200H, capturing the destination disk's identity. The NZ flag signals a read error.
5376
If the NZ flag is set (the destination GAT could not be read), JUMP to 5810H to report the disk error and abort.
5379
LD HL,42CEH 21 CE 42
Point register pair HL at 42CEH, the disk name and date identity field of the just-read destination GAT in the sector buffer at 4200H.
537C
LD DE,5A0CH 11 0C 5A
Point register pair DE at 5A0CH, the save area for the destination disk's identity.
537F
PUSH DE D5
Save the destination-identity save-area pointer (register pair DE, 5A0CH) on the stack for the comparison below.
5380
LD BC,0012H 01 12 00
Load register pair BC with 0012H (18), the disk identity length.
5383
LDIR ED B0
Block-move the 18-byte destination disk identity from 42CEH (register pair HL) to the save area at 5A0CH (register pair DE).
5385
POP DE D1
Restore the destination-identity pointer (register pair DE, 5A0CH) from the stack.
5386
LD HL,59FAH 21 FA 59
Point register pair HL at 59FAH, the saved source disk identity captured earlier at 533BH, for the same-disk comparison.
5389
LD B,12H 06 12
Load register B with the compare length 12H (18) for the identity comparison loop.
538B
GOSUB to 5762H to compare the 18 bytes at the source identity (HL, 59FAH) against the destination identity (DE, 5A0CH). The Z flag is returned set only if the two disk identities are identical.
538E
If the NZ flag is set (the source and destination disks differ, which is correct), JUMP to 5396H to continue the copy.
5390
The disks are identical. GOSUB to 570CH to display the "Insert SYSTEM disk" reminder before reporting the error.
5393
JUMP to 581FH to display "Source and destination disks are the same" and abort, since the operator did not swap disks between the SOURCE and DESTINATION prompts.
5396
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the destination-create call.
5399
LD HL,5B00H 21 00 5B
Point register pair HL at the record buffer 5B00H, the buffer the new destination file will use for its records.
539C
GOSUB to 57FFH, which fills the record buffer at 5B00H with 20H spaces and creates or opens the destination file (its FCB at 59DAH) with the source's logical record length, ready to receive records.
539F
GOSUB to 5690H to copy the resolved destination specification into the display buffer at 59CAH for the progress banner.
53A2
LD A,(59E0H) 3A E0 59
Load register A with the destination FCB+06H byte at 59E0H, the destination file's drive-selection byte.
53A5
GOSUB to 57DAH to derive the destination drive's extended-dating bit mask and read the dating flags at 475DH; the Z flag reflects whether that drive uses extended dating.
53A8
If the Z flag is set (the destination drive does not use extended dating), JUMP to 53AEH without bumping the dating flag.
53AA
LD HL,5466H 21 66 54
Point register pair HL at the dating flag cell 5466H.
53AD
INC (HL) 34
Increment the byte at 5466H, recording that the destination directory record should receive extended date/time bytes.
53AE
LD A,(52D4H) 3A D4 52
Load register A with the single-drive flag at 52D4H again. A non-zero value marks the X single-drive copy.
53B1
OR A B7
Test register A (the single-drive flag); the Z flag is set for an ordinary copy.
53B2
If the NZ flag is set (single-drive copy), JUMP to 53C0H, skipping the same-file guard which does not apply once disks have been swapped.
53B4
LD HL,(598CH) 2A 8C 59
Load register pair HL with the source FCB+06H word at 598CH (the source drive/directory selector).
53B7
LD DE,(59E0H) ED 5B E0 59
Load register pair DE with the destination FCB+06H word at 59E0H (the destination drive/directory selector).
53BB
SBC HL,DE ED 52
Subtract register pair DE from register pair HL. The Z flag is set only if the source and destination resolved to the same drive and directory slot, meaning no distinct destination was supplied.
53BD
If the Z flag is set (source and destination are the same file), JUMP to 582FH to display "Destination spec required" and abort.
53C0
GOSUB to 570CH to show the "Insert SYSTEM disk" reminder (a no-op unless the single-drive flag at 52D4H is set).
53C3
GOSUB to 57C8H, which loads request code 8AH into register A and issues RST 28H to the resident dispatcher, the destination-disk checkpoint used by the single-drive copy.
53C6
GOSUB to 5740H to prompt "Insert DESTINATION disk" (a no-op unless the single-drive flag at 52D4H is set) before the pre-extend write.
53C9
GOSUB to 56A1H to display the "Copying: source to destination" progress banner.
53CC
LD BC,(5992H) ED 4B 92 59
Load register pair BC with the source FCB+0CH word at 5992H, the source file's ending record number (its length in 256-byte records).
53D0
GOSUB to 54D4H to position the destination to record BC-1 and write an E5H-filled record, pre-allocating the full destination file so the copy will not run out of disk space partway through.
53D3
LD HL,0000H 21 00 00
Load register pair HL with 0000H to reset the destination record counter.
53D6
LD (59E6H),HL 22 E6 59
Store 0000H (register pair HL) into the destination FCB+0CH word at 59E6H, resetting the destination's ending record number so the copy writes from the start.
53D9
GOSUB to the resident SYS0 service @REW at 443FH to rewind the source file (its FCB at 5986H) to its first record, ready for the block-copy engine to read from the beginning.

53DCH - Block Copy Engine: Full-Memory Read/Write Loop

The high-speed disk-to-disk copy loop shared by COPY and APPEND. It reads the source file into the large buffer that runs from 5B00H up to HIGH$ (as many 256-byte records as fit), then writes that whole block to the destination, and repeats until the source reaches end of file. Filling all free memory each pass minimises the number of disk-swap prompts on a single-drive copy.

53DC
Main Loop
GOSUB to 571EH to issue the "Insert SOURCE disk" prompt (a no-op unless the single-drive flag at 52D4H is set), then verify the mounted disk before each read pass.
53DF
LD HL,5B00H 21 00 5B
Point register pair HL at 5B00H, the base of the block-copy buffer, as the address for the first record of this read pass.
53E2
LD (5989H),HL 22 89 59
Loop Start
Store the current buffer address (register pair HL) into the source FCB+03H buffer-pointer field at 5989H, so the next @READ deposits its 256-byte record at this address.
53E5
LD DE,5986H 11 86 59
Point register pair DE at the source FCB at 5986H for the read.
53E8
GOSUB to the resident SYS0 service @READ at 4436H to read the next 256-byte record of the source file (its FCB at 5986H) into the buffer address held in FCB+03H at 5989H. The Z flag is returned on success; the NZ flag with an error code in register A on failure or end of file.
53EB
If the Z flag is set (a record was read successfully), JUMP to 53F8H to advance the buffer pointer and test whether the buffer is full.
53ED
CP 1CH FE 1C
Compare the returned error code (register A) against 1CH (28 decimal, "end of file encountered"). If it matches, the source has been fully read and the Z flag is set.
53EF
If the Z flag is set (end of file), JUMP to 5418H to write the final partial block and finish the copy.
53F1
CP 1DH FE 1D
Compare the error code (register A) against 1DH (29 decimal, "record number out of range"), which the record reader also returns at the physical end of the file's allocation.
53F3
If the Z flag is set (end of allocation), JUMP to 5418H to finish the copy.
53F5
Any other value in register A is a real read error: JUMP to 5810H to report it through @ERROR and abort.
53F8
INC H 24
Increment register H, advancing the buffer address (register pair HL) by 256 bytes to the next record slot.
53F9
LD A,H 7C
Copy the new buffer page (register H) into register A to test it against the buffer ceiling.
53FA
CP 60H FE 60
Self-Modifying Code
Compare register A (the current buffer page) against the buffer ceiling. The 60H shown is the default; the operand at 53FBH is patched by 54B8H to the high byte of HIGH$ (4049H), so the read buffer extends across all free memory from 5B00H up to HIGH$. The Z flag is set when the buffer is full.
53FC
Loop End
If the NZ flag is set (buffer not yet full), LOOP BACK to 53E2H to read another record into the next buffer slot.
53FE
The buffer is full. GOSUB to 5740H to prompt "Insert DESTINATION disk" (a no-op unless the single-drive flag at 52D4H is set) before writing the block.
5401
LD HL,5B00H 21 00 5B
Point register pair HL at the base of the block-copy buffer 5B00H for the write pass.
5404
LD (59DDH),HL 22 DD 59
Loop Start
Store the current buffer address (register pair HL) into the destination FCB+03H buffer-pointer field at 59DDH, so the next @WRITE takes its 256-byte record from this address.
5407
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the write.
540A
GOSUB to the resident SYS0 service @WRITE at 4439H to write the 256-byte record at the buffer address in FCB+03H (59DDH) to the destination file (its FCB at 59DAH). The Z flag is returned on success, the NZ flag with an error code in register A on failure.
540D
If the NZ flag is set (a write error, such as a full disk), JUMP to 5810H to report it through @ERROR and abort.
5410
INC H 24
Increment register H, advancing the buffer address (register pair HL) by 256 bytes to the next written record.
5411
LD A,H 7C
Copy the new buffer page (register H) into register A to test it against the buffer ceiling.
5412
CP 60H FE 60
Self-Modifying Code
Compare register A (the current buffer page) against the buffer ceiling. The 60H shown is the default; the operand at 5413H is patched by 54B8H to the high byte of HIGH$, so the whole read buffer is written back. The Z flag is set when the block has been fully written.
5414
Loop End
If the NZ flag is set (more records remain in the block), LOOP BACK to 5404H to write the next record.
5416
The block has been written. LOOP BACK to 53DCH to read and write the next full-memory block of the source file.

5418H - End of File: Final Block, Directory EOF Update and Exit

Reached when the source read reports end of file. It flushes the last partial buffer to the destination, copies the source's exact end-of-file offset into the destination directory record, writes that record back, then closes the file and falls into the common overlay exit that restores the caller stack and returns (or aborts if not at command level).

5418
GOSUB to 5498H to write out the records already read into the buffer this pass (the final, possibly partial, block) before closing the destination.
541B
LD HL,(598EH) 2A 8E 59
Load register pair HL with the source FCB+08H word at 598EH, the source file's end-of-file offset (the count of valid bytes in its final sector).
541E
LD (59E2H),HL 22 E2 59
Store the source end-of-file offset (register pair HL) into the destination FCB+08H word at 59E2H, so the destination file records the identical logical length as the source.
5421
GOSUB to 570CH to show the "Insert SYSTEM disk" reminder (a no-op unless the single-drive flag at 52D4H is set) before the final directory write.
5424
GOSUB to 57CBH, which loads request code 85H into register A and issues RST 28H to the resident dispatcher, the copy-completion checkpoint used by the single-drive copy.
5427
LD A,(5712H) 3A 12 57
Load register A with the drive number saved at 5712H to decide whether a destination-disk prompt is still needed.
542A
OR A B7
Test register A (the saved drive number); the Z flag is set when it is zero.
542B
If the Z flag is set, GOSUB to 5740H to prompt "Insert DESTINATION disk" (a no-op unless the single-drive flag at 52D4H is set) so the final directory update lands on the destination disk.
542E
LD BC,(59E0H) ED 4B E0 59
Load register pair BC with the destination FCB+06H word at 59E0H (the destination drive/directory selector) for the close.
5432
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the close.
5435
GOSUB to the resident SYS0 service @CLOSE at 4428H to close the destination file (its FCB at 59DAH), flushing its directory entry with the new end-of-file offset. The NZ flag signals a close error.
5438
If the NZ flag is set (the close failed), JUMP to 5810H to report it through @ERROR and abort.
543B
GOSUB to the resident SYS0 service DIRRD at 4B10H to read the destination file's directory record back into the sector buffer, returning HL pointing at the record so its attribute and date bytes can be finalised. The NZ flag signals a directory read error.
543E
If the NZ flag is set (the directory read failed), JUMP to 5810H to report the error and abort.
5441
PUSH BC C5
Save register pair BC (the destination drive/directory selector) on the stack across the directory-record edit.
5442
PUSH HL E5
Save register pair HL (the directory-record pointer returned by DIRRD) on the stack.
5443
LD A,04H 3E 04
Load register A with 04H, the offset from the directory record base to a field that must be cleared.
5445
ADD A,L 85
Add the directory-record low byte (register L) to register A, forming the low byte of the address of directory-record byte +04H.
5446
LD L,A 6F
Copy the computed low byte (register A) into register L, so register pair HL now points at directory-record byte +04H.
5447
LD (HL),00H 36 00
Store 00H into directory-record byte +04H, clearing that field of the destination directory entry.
5449
POP HL E1
Restore the directory-record base pointer (register pair HL) from the stack.
544A
LD DE,0FFFFH 11 FF FF
Self-Modifying Code
Load register pair DE from the operand cell 544BH/544CH (cleared to 0000H at 5208H/520BH by APPEND, left as 0FFFFH otherwise). It carries the update-timestamp value the CLONE option may patch; the test below decides whether to stamp the directory record.
544D
LD A,D 7A
Copy the high byte of that value (register D) into register A to test whether it is zero.
544E
OR E B3
OR register A (high byte) with register E (low byte); the Z flag is set only if the whole DE value is zero.
544F
If the Z flag is set (no directory field copy requested), JUMP to 5474H to write the directory record as-is.
5451
PUSH HL E5
Save the directory-record pointer (register pair HL) on the stack for the field copies below.
5452
EX DE,HL EB
Exchange register pairs DE and HL so register pair DE points at the directory record and register pair HL holds the source field address.
5453
LD HL,5A1EH 21 1E 5A
Point register pair HL at 5A1EH, a 3-byte source template (the CLONE date/attribute bytes) to copy into the directory record.
5456
LD BC,0003H 01 03 00
Load register pair BC with the byte count 0003H for the first field copy.
5459
LDIR ED B0
Block-move 3 bytes from the template at 5A1EH (register pair HL) into the directory record (register pair DE), stamping the cloned bytes.
545B
LD A,0DH 3E 0D
Load register A with 0DH (13), the offset to the next directory field to be written.
545D
ADD A,E 83
Add the directory-record low byte (register E) to register A, forming the low byte of directory-record byte +0DH within the record.
545E
LD E,A 5F
Copy the computed low byte (register A) into register E, so register pair DE now points at directory-record byte +0DH.
545F
LD BC,0004H 01 04 00
Load register pair BC with the byte count 0004H for the second field copy.
5462
LDIR ED B0
Block-move 4 more bytes from the template (register pair HL) into directory-record byte +0DH onward (register pair DE), completing the cloned attribute copy.
5464
POP HL E1
Restore the directory-record base pointer (register pair HL) from the stack.
5465
LD A,0FEH 3E FE
Load register A with 0FEH, the marker value tested next to decide whether to also copy the record's protection nibble.
5467
OR A B7
Test register A (0FEH); this clears the CARRY flag and leaves the NZ flag set for the branch below.
5468
Since the NZ flag is set, JUMP to 5474H to write the directory record, bypassing the protection-nibble copy below (which is entered only via a separate patched path).
546A
DEC DE 1B
Decrement register pair DE, backing up one byte within the directory record for the protection-nibble store.
546B
INC HL 23
Advance register pair HL past two source bytes (this INC and the next) to reach the protection byte.
546C
INC HL 23
Advance register pair HL again, so it addresses the source protection byte.
546D
LD A,(HL) 7E
Load register A with the source protection byte at (HL).
546E
AND 07H E6 07
Mask register A to its low three bits (07H), isolating the protection level (the access-permission nibble).
5470
LD (DE),A 12
Store the isolated protection level (register A) into the directory record at (DE).
5471
DEC DE 1B
Decrement register pair DE to the adjacent directory byte.
5472
XOR A AF
Set register A to ZERO and clear all flags, preparing a zero byte for the store below.
5473
LD (DE),A 12
Store the zero (register A) into the directory record at (DE), clearing the companion protection byte.
5474
POP BC C1
Restore register pair BC (the destination drive/directory selector saved at 5441H) for the directory write.
5475
GOSUB to the resident SYS0 service DIRWR at 4B1FH to write the edited directory record (register pair HL) back to the destination disk using the selector in register pair BC, committing the copied file's attributes and end of file.
5478
JUMP to 5480H to check the write result and fall into the common overlay exit.
547A
LD DE,59DAH 11 DA 59
Device-copy close entry (reached from the character-copy loop). Point register pair DE at the destination FCB at 59DAH for the close.
547D
GOSUB to @CLOSE at 4428H to close the destination file or device (its FCB at 59DAH). The NZ flag signals a close error.
5480
If the NZ flag is set (a close or directory-write error occurred), JUMP to 5810H to report it through @ERROR and abort.
5483
GOSUB to 570CH to show the final "Insert SYSTEM disk" reminder (a no-op unless the single-drive flag at 52D4H is set) so the operator can restore the system disk before returning to LDOS.
5486
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success return status (a non-zero value here would mark an aborting error path).
5489
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller stack pointer. The 0000H shown is the listing value; the operand cell 548AH was patched at 5203H/52B1H with the caller SP, so register SP is reloaded with the LDOS command-level stack. The DD-overlap-style shared error tail at 5835H also jumps here with register pair HL non-zero to mark an error exit.
548C
LD A,H 7C
Copy the high byte of the return status (register H) into register A to test whether the exit is clean.
548D
OR L B5
OR register A (status high byte) with register L (status low byte); the Z flag is set only if the status in HL is zero (a successful copy).
548E
RET Z C8
If the Z flag is set (successful completion), RETURN to the resident RST 28H dispatcher, ending the overlay normally.
548F
LD A,(430FH) 3A 0F 43
An error status was in HL. Load register A with the resident system flag byte SFLAG$ at 430FH, whose bit 5 marks that the system is not at LDOS command level.
5492
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ byte from 430FH); the Z flag is set when the system is at command level.
5494
RET Z C8
If the Z flag is set (at LDOS command level), RETURN to the dispatcher; the error was already reported, so a normal return is safe.
5495
Otherwise (not at command level, for example inside a JCL DO stream), JUMP to the resident SYS0 service @ABORT at 4030H to terminate the entire job rather than return to a program that expected the copy to succeed.

5498H - Final Partial Block Flush Helper

Called at end of file to write out whatever records were read into the block buffer during the last, incomplete read pass. Register H on entry holds the buffer page one past the last record read; the routine writes 5B00H up to that page to the destination.

5498
LD A,H 7C
Copy the buffer high page reached by the last read (register H) into register A to test whether any records were buffered.
5499
CP 5BH FE 5B
Compare register A (the buffer page) against 5BH, the base page of the buffer (5B00H). If they are equal no records were read this pass and the Z flag is set.
549B
RET Z C8
If the Z flag is set (nothing buffered), RETURN without writing.
549C
CP 60H FE 60
Self-Modifying Code
Compare register A (the buffer page) against the buffer ceiling. The 60H shown is the default; the operand at 549DH is patched by 54B8H to the high byte of HIGH$. If the buffer is exactly full the block was already written by the main loop and the Z flag is set.
549E
RET Z C8
If the Z flag is set (buffer was full and already flushed), RETURN without writing again.
549F
GOSUB to 5740H to prompt "Insert DESTINATION disk" (a no-op unless the single-drive flag at 52D4H is set) before writing the partial block.
54A2
LD B,H 44
Copy the end page (register H) into register B as the loop limit for the write below.
54A3
LD HL,5B00H 21 00 5B
Point register pair HL at the buffer base 5B00H, the first record to write.
54A6
LD (59DDH),HL 22 DD 59
Loop Start
Store the current buffer address (register pair HL) into the destination FCB+03H buffer-pointer field at 59DDH so @WRITE takes its record from here.
54A9
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the write.
54AC
GOSUB to @WRITE at 4439H to write the 256-byte record at the buffer address (59DDH) to the destination file (its FCB at 59DAH). The NZ flag signals a write error.
54AF
If the NZ flag is set (a write error), JUMP to 5810H to report it through @ERROR and abort.
54B2
INC H 24
Increment register H, advancing the buffer address (register pair HL) by 256 bytes to the next record.
54B3
LD A,H 7C
Copy the new buffer page (register H) into register A to compare against the end page.
54B4
CP B B8
Compare register A (the current buffer page) against register B (the end page). The Z flag is set when all buffered records have been written.
54B5
Loop End
If the NZ flag is set (records remain), LOOP BACK to 54A6H to write the next record of the final block.
54B7
RET C9
RETURN to the end-of-file handler once the final partial block has been written.

54B8H - Busy-Flag Check and Copy-Buffer Ceiling Patch

Called at the start of both command bodies. Unless a background task marks the system busy, it computes the top page of free memory from HIGH$ and patches that ceiling into the three copy-loop limit comparisons, so the block-copy buffer stretches from 5B00H up to HIGH$. It then clears the pause/scroll bits in KFLAG$.

54B8
PUSH HL E5
Save register pair HL (the caller command-line pointer) on the stack across this setup.
54B9
LD A,(4758H) 3A 58 47
Load register A with the SYS1 status byte at 4758H, whose bit 1 is the system-busy flag set when a background task (such as the spooler) owns memory.
54BC
BIT 1,A CB 4F
Test bit 1 of register A (the SYS1 status byte from 4758H). If the system is busy the NZ flag is set.
54BE
If the NZ flag is set (system busy), JUMP to 54CFH, leaving the copy buffer at its default 5B00H-5FFFH size and not extending into memory a task may own.
54C0
LD HL,(4049H) 2A 49 40
Load register pair HL with the resident HIGH$ word at 4049H, the address of the top of user-available memory.
54C3
INC HL 23
Increment register pair HL so it addresses the first byte above HIGH$ (HIGH$ points at the last used byte).
54C4
DEC H 25
Decrement register H, rounding the ceiling down to the start of the page that contains HIGH$+1, giving a whole-page buffer limit in register H.
54C5
LD A,H 7C
Copy the computed ceiling page (register H) into register A for the three operand patches below.
54C6
LD (53FBH),A 32 FB 53
Self-Modifying Code
Store the ceiling page (register A) into the operand cell 53FBH, the compare value of the CP 60H at 53FAH in the block-read loop, so reads fill memory up to HIGH$.
54C9
LD (5413H),A 32 13 54
Self-Modifying Code
Store the ceiling page (register A) into the operand cell 5413H, the compare value of the CP 60H at 5412H in the block-write loop, so the whole block is written back.
54CC
LD (549DH),A 32 9D 54
Self-Modifying Code
Store the ceiling page (register A) into the operand cell 549DH, the compare value of the CP 60H at 549CH in the final-block flush helper, so the partial-block test uses the same ceiling.
54CF
GOSUB to 57B0H to clear the low pause/scroll bits of KFLAG$ at 4423H, so screen paging does not interrupt the copy.
54D2
POP HL E1
Restore the caller command-line pointer (register pair HL) from the stack.
54D3
RET C9
RETURN to the command body with the buffer ceiling patched and paging disabled.

54D4H - Destination Pre-Extend Helper

Given a target record count in register pair BC, positions the destination file to record BC-1 and writes one E5H-filled record there. This forces the file system to allocate all the disk space the copy will need before any data is written, so a full disk is detected up front rather than after a partial copy.

54D4
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the position and write.
54D7
LD A,B 78
Copy the high byte of the target record count (register B) into register A to test for a zero count.
54D8
OR C B1
OR register A (high byte) with register C (low byte); the Z flag is set only if the target count in BC is zero.
54D9
RET Z C8
If the Z flag is set (nothing to pre-allocate), RETURN without extending the file.
54DA
DEC BC 0B
Decrement register pair BC to the highest record number (count minus one), the record to be pre-written.
54DB
GOSUB to the resident SYS0 service @POSN at 4442H to position the destination file (its FCB at 59DAH) to record BC, allocating every granule up to that record.
54DE
PUSH DE D5
Save register pair DE (the destination FCB pointer 59DAH) on the stack across the buffer fill.
54DF
LD HL,5B00H 21 00 5B
Point register pair HL at the record buffer base 5B00H as the source of the fill block move.
54E2
LD DE,5B01H 11 01 5B
Point register pair DE at 5B01H, one byte into the buffer, as the destination of the propagating fill.
54E5
LD BC,00FFH 01 FF 00
Load register pair BC with 00FFH (255), the count for filling the rest of the 256-byte record.
54E8
LD (HL),0E5H 36 E5
Store 0E5H into the first buffer byte at 5B00H, the fill value that the block move will propagate through the record.
54EA
LDIR ED B0
Block-move the 0E5H byte forward through the buffer (register pair HL to register pair DE, count register pair BC), filling 5B00H-5BFFH with 0E5H.
54EC
POP DE D1
Restore the destination FCB pointer (register pair DE, 59DAH) from the stack.
54ED
GOSUB to @WRITE at 4439H to write the 0E5H-filled record to the destination file (its FCB at 59DAH) at the positioned record, committing the allocation. The Z flag is returned on success.
54F0
RET Z C8
If the Z flag is set (the pre-extend write succeeded), RETURN to the caller.
54F1
Otherwise JUMP to 5810H to report the write error (typically a full disk) through @ERROR and abort.

54F4H - Character Copy Loop (Device and Byte-Serial Transfers)

Reached when either the source or destination is a * device, so fixed-record block copying cannot be used. It opens both endpoints, shows the progress banner, then transfers one byte at a time from source to destination, echoing to the display when the ECHO option is active and checking for BREAK, until end of file.

54F4
GOSUB to 5803H to point register pair DE at the source FCB (5986H) and register pair HL at the record buffer (5B00H) and open the source for reading.
54F7
GOSUB to 568AH to copy the resolved source specification into the display buffer at 59B6H for the banner.
54FA
LD A,(5359H) 3A 59 53
Load register A with the destination logical record length stored at 5359H, the LRL to open the destination device/file with.
54FD
LD B,A 47
Copy the destination LRL (register A) into register B, the record-length argument for the open helper below.
54FE
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH for the open.
5501
LD HL,5C00H 21 00 5C
Point register pair HL at 5C00H, the single-record buffer the destination will use during the byte transfer.
5504
LD A,20H 3E 20
Load register A with 20H, the fill/mode byte passed to the open helper (a space fill for the destination buffer).
5506
GOSUB to 580CH to create or open the destination file/device (its FCB at 59DAH) with the record length in register B and the 5C00H buffer, jumping to the error path on failure.
5509
GOSUB to 5690H to copy the resolved destination specification into the display buffer at 59CAH for the banner.
550C
GOSUB to 56A1H to display the "Copying: source to destination" (or "Appending:") progress banner.
550F
EX DE,HL EB
Exchange register pairs DE and HL so register pair HL points at the destination FCB base (59DAH) for the bit test.
5510
BIT 7,(HL) CB 7E
Test bit 7 of the destination FCB flag byte at (HL). Bit 7 set marks a disk file; bit 7 clear marks a device. The Z flag reflects the tested bit.
5512
EX DE,HL EB
Exchange register pairs DE and HL back, restoring the working pointers.
5513
If the Z flag is set (the destination is a device), JUMP to 5519H, skipping the disk-only end-of-file flag reset below.
5515
XOR A AF
Set register A to ZERO and clear all flags for the store below.
5516
LD (59E3H),A 32 E3 59
Store zero into the destination FCB+09H byte at 59E3H, clearing the record-position flag so a disk destination starts at its beginning.
5519
LD A,0EH 3E 0E
Load register A with 0EH, the video control code that turns the cursor on before the transfer begins.
551B
GOSUB to the ROM display routine @DSP at 0033H to send the cursor-on control code in register A to the video display.
551E
LD DE,5986H 11 86 59
Main Loop
Point register pair DE at the source FCB at 5986H to fetch the next byte.
5521
LD A,(DE) 1A
Load register A with the source FCB flag byte at 5986H to decide how to read the next byte.
5522
BIT 7,A CB 7F
Test bit 7 of register A (the source flag byte). Bit 7 set marks a disk file (read via a blocking get); bit 7 clear marks a device (poll until a byte arrives). The Z flag reflects the tested bit.
5524
If the Z flag is set (the source is a device), JUMP to 5539H to poll the device for a byte.
5526
The source is a disk file. GOSUB to the ROM/DOS input routine @GET at 0013H to fetch one byte from the source (its DCB/FCB at 59... register pair DE = 5986H) into register A. The Z flag is returned when a byte is available; end of file returns error code 1CH.
5529
If the Z flag is set (a byte was read), JUMP to 554DH to write it to the destination.
552B
CP 1CH FE 1C
Compare the returned code (register A) against 1CH (28 decimal, "end of file"). If it matches, the source is exhausted and the Z flag is set.
552D
If the Z flag is set (end of file), JUMP to 547AH to close the destination and finish.
5530
Any other value in register A is a read error: JUMP to 5810H to report it through @ERROR and abort.
5533
Device-source wait point. GOSUB to 56E9H, which checks SFLAG$ 430FH and KFLAG$ 4423H for a BREAK/pause request; it returns the NZ flag if BREAK was pressed.
5536
If the NZ flag is set (BREAK pressed), JUMP to 547AH to close the destination and stop the copy.
5539
GOSUB to @GET at 0013H to fetch one byte from the source device (its DCB at 5986H, register pair DE) into register A. A device returns register A = 0 with the Z flag set when no byte is ready yet.
553C
OR A B7
Test register A (the byte or zero returned). The Z flag is set when no byte was available.
553D
Loop Start
If the Z flag is set (no byte yet), LOOP BACK to 5533H to check BREAK and poll the device again.
553F
CP 01H FE 01
Compare register A (the received byte) against 01H, the device end-of-transmission marker. If it matches the Z flag is set.
5541
If the Z flag is set (device end of data), JUMP to 547AH to close the destination and finish.
5544
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand cell 5545H. The 0000H shown is the default; the ECHO option patches the high byte to 0FFH so that INC D below sets the Z flag and each transferred byte is echoed to the screen.
5547
INC D 14
Increment register D. With the default operand D becomes 01H (NZ, no echo); with the ECHO patch D rolls 0FFH to 00H, setting the Z flag.
5548
PUSH AF F5
Save register pair AF (the received byte in register A and the echo Z flag) on the stack across the optional echo.
5549
If the Z flag is set (ECHO active), GOSUB to the ROM @DSP routine at 0033H to display the transferred byte in register A at the cursor.
554C
POP AF F1
Restore register pair AF, recovering the received byte in register A for the write below.
554D
LD DE,59DAH 11 DA 59
Point register pair DE at the destination FCB at 59DAH to write the byte.
5550
GOSUB to the ROM/DOS output routine @PUT at 001BH to write the byte in register A to the destination (its DCB/FCB at 59DAH, register pair DE). The Z flag is returned when the byte was accepted.
5553
If the Z flag is set (the byte was written), JUMP to 555CH to check BREAK and continue the loop.
5555
EX DE,HL EB
Exchange register pairs DE and HL so register pair HL points at the destination FCB base (59DAH) for the bit test.
5556
BIT 7,(HL) CB 7E
Test bit 7 of the destination FCB flag byte at (HL). Bit 7 set marks a disk file, where a non-Z @PUT return is a real write error. The Z flag reflects the tested bit.
5558
EX DE,HL EB
Exchange register pairs DE and HL back, restoring the working pointers.
5559
If the NZ flag is set (a disk destination reported a write error), JUMP to 5810H to report it through @ERROR and abort.
555C
GOSUB to 56E9H to check for a BREAK/pause request; it returns the NZ flag if BREAK was pressed.
555F
If the NZ flag is set (BREAK pressed), JUMP to 547AH to close the destination and stop.
5562
Loop End
LOOP BACK to 551EH to transfer the next byte from source to destination.

5564H - Command-Tail Token Copy and Uppercase

Copies a name token from the command line at (HL) into the buffer at (DE), folding lowercase letters to uppercase and stopping at a carriage return, space or open parenthesis. Entry 5564H additionally carriage-return-terminates the copied token; it is used to complete a defaulted destination specification.

5564
GOSUB to 556CH to copy the token at (HL) into the buffer at (DE), leaving register pair DE pointing just past the copied text.
5567
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return, to terminate the copied token.
5569
LD (DE),A 12
Store the carriage return (register A) at (DE), the byte after the copied token, terminating the destination specification.
556A
RET C9
RETURN to the caller with the token copied and terminated.
556B
INC HL 23
Loop Start
Advance the source pointer (register pair HL) past a leading space while skipping whitespace before the token.
556C
LD A,(HL) 7E
Load register A with the current source character at (HL).
556D
CP 0DH FE 0D
Compare register A (the current character) against 0DH (carriage return, the end of the command tail). The Z flag is set at end of line.
556F
RET Z C8
If the Z flag is set (end of line), RETURN with nothing copied.
5570
CP 20H FE 20
Compare register A (the current character) against 20H (ASCII space). The Z flag is set for a leading space to be skipped.
5572
Loop End
If the Z flag is set (a leading space), LOOP BACK to 556BH to skip it and examine the next character.
5574
DEC HL 2B
Step the source pointer (register pair HL) back one, since the copy loop below re-reads the current non-space character.
5575
LD B,20H 06 20
Load register B with 20H (32), the maximum token length in bytes for the copy loop below.
5577
LD A,(HL) 7E
Loop Start
Load register A with the next token character at (HL).
5578
CP 61H FE 61
Compare register A (the character) against 61H (ASCII a). If it is below 61H the CARRY flag is set (not a lowercase letter).
557A
If the CARRY flag is set (below a), JUMP to 5582H to store the character unchanged.
557C
CP 7BH FE 7B
Compare register A (the character) against 7BH (one past ASCII z). If it is 7BH or above the NO CARRY flag is set (not a lowercase letter).
557E
If the NO CARRY flag is set (above z), JUMP to 5582H to store the character unchanged.
5580
RES 5,A CB AF
The character is a to z: clear bit 5 of register A, folding the lowercase letter to uppercase.
5582
LD (DE),A 12
Store the (possibly uppercased) character (register A) into the output buffer at (DE).
5583
CP 0DH FE 0D
Compare register A (the stored character) against 0DH (carriage return). The Z flag is set at end of the token.
5585
RET Z C8
If the Z flag is set (carriage return stored), RETURN, the token is complete.
5586
CP 28H FE 28
Compare register A (the stored character) against 28H (ASCII (, the start of a parameter list). The Z flag is set if the token ended at a parameter list.
5588
RET Z C8
If the Z flag is set (parameter list reached), RETURN, the token is complete.
5589
INC HL 23
Advance the source pointer (register pair HL) to the next token character.
558A
INC DE 13
Advance the output pointer (register pair DE) to the next output position.
558B
Loop End
DECrement register B (the remaining length) and LOOP BACK to 5577H if not zero, copying the next character until 32 have been copied.
558D
RET C9
RETURN once the 32-character limit is reached.

558EH - Destination Filespec Validation

Confirms the destination specification at 59DAH is a usable file name: it rejects an empty destination or one that begins with a digit (reporting "Destination spec required"), then scans the specification for its '/' extension and '.' delimiters, inserting a drive prefix where needed via the helper below.

558E
LD HL,5986H 21 86 59
Point register pair HL at the source specification at 5986H, used as the drive-default reference for the destination.
5591
LD DE,59DAH 11 DA 59
Point register pair DE at the destination specification at 59DAH, the text to validate.
5594
LD A,(DE) 1A
Load register A with the first destination character at 59DAH.
5595
CP 0DH FE 0D
Compare register A (the first destination character) against 0DH (carriage return). The Z flag is set if the destination is empty.
5597
If the Z flag is set (no destination given), JUMP to 582FH to display "Destination spec required" and abort.
559A
CP 30H FE 30
Compare register A (the first character) against 30H (ASCII 0). If it is below 30H the CARRY flag is set (not a digit).
559C
If the CARRY flag is set (first character below 0, a valid name character), JUMP to 55A3H to process the specification.
559E
CP 3AH FE 3A
Compare register A (the first character) against 3AH (one past ASCII 9). If it is below 3AH the CARRY flag is set (the destination begins with a digit, which is illegal).
55A0
If the CARRY flag is set (the destination starts with a digit 0-9), JUMP to 582FH to display "Destination spec required" and abort.
55A3
PUSH DE D5
Save the destination pointer (register pair DE, 59DAH) on the stack across the scans below.
55A4
LD A,(DE) 1A
Reload register A with the first destination character at (DE) for the digit-insert test.
55A5
CP 41H FE 41
Compare register A (the first character) against 41H (ASCII A). If it is below 41H the CARRY flag is set (a digit or punctuation preceding the name).
55A7
If the CARRY flag is set (leading non-letter), GOSUB to 55DEH to shift the drive digit into the correct position within the specification.
55AA
LD B,2FH 06 2F
Load register B with 2FH (ASCII /), the extension delimiter to search for.
55AC
GOSUB to 55B7H to scan the destination specification for the / extension delimiter in register B.
55AF
LD B,2EH 06 2E
Load register B with 2EH (ASCII .), the alternate delimiter to search for.
55B1
GOSUB to 55B7H to scan the destination specification for the . delimiter in register B.
55B4
POP DE D1
Restore the destination pointer (register pair DE, 59DAH) from the stack.
55B5
RET C9
RETURN with the destination specification validated and normalised.

55B6H - Delimiter Scan and Character Insert Helpers

Two cooperating helpers used by the validator above. 55B7H scans the specification for the delimiter character in register B, and 55DEH/55EAH shift characters forward to insert a drive digit at the correct spot so a specification given as name:d becomes the canonical form.

55B6
INC DE 13
Loop Start
Advance the scan pointer (register pair DE) to the next specification character.
55B7
LD A,(DE) 1A
Load register A with the current specification character at (DE).
55B8
CP B B8
Compare register A (the current character) against the delimiter in register B. The Z flag is set when the delimiter is found.
55B9
If the Z flag is set (delimiter found), JUMP to 55C9H to step past it and return.
55BB
CP 41H FE 41
Compare register A (the character) against 41H (ASCII A). If it is 41H or above the NO CARRY flag is set (a letter, keep scanning).
55BD
If the NO CARRY flag is set (a letter), LOOP BACK to 55B6H to scan the next character.
55BF
CP 30H FE 30
Compare register A (the character) against 30H (ASCII 0). If it is below 30H the CARRY flag is set (a terminator or punctuation).
55C1
If the CARRY flag is set (below 0, end of the name field), JUMP to 55CBH to insert the delimiter.
55C3
CP 3AH FE 3A
Compare register A (the character) against 3AH (one past ASCII 9). If it is below 3AH the CARRY flag is set (a digit, keep scanning).
55C5
Loop End
If the CARRY flag is set (a digit), LOOP BACK to 55B6H to scan the next character.
55C7
Otherwise JUMP to 55CBH to insert the delimiter at this position.
55C9
INC DE 13
The delimiter already exists: advance register pair DE past it.
55CA
RET C9
RETURN with register pair DE positioned after the delimiter.
55CB
PUSH HL E5
Save register pair HL (the source reference) on the stack while an insert is performed.
55CC
LD A,(HL) 7E
Loop Start
Load register A with the character at the reference pointer (HL).
55CD
INC HL 23
Advance the reference pointer (register pair HL).
55CE
CP 03H FE 03
Compare register A (the character) against 03H (the ETX specification terminator). The Z flag is set at the end of the string.
55D0
If the Z flag is set (end of string), JUMP to 55DCH to finish.
55D2
CP 0DH FE 0D
Compare register A (the character) against 0DH (carriage return terminator). The Z flag is set at the end of the string.
55D4
If the Z flag is set (end of string), JUMP to 55DCH to finish.
55D6
CP B B8
Compare register A (the character) against the delimiter in register B. The Z flag is set when the delimiter is found ahead.
55D7
Loop End
If the NZ flag is set (not yet the delimiter), LOOP BACK to 55CCH to scan the next character.
55D9
GOSUB to 55EAH to shift the trailing characters and insert the delimiter at this position.
55DC
POP HL E1
Restore register pair HL (the source reference) from the stack.
55DD
RET C9
RETURN to the delimiter scanner.
55DE
LD A,(HL) 7E
Load register A with the character at the reference pointer (HL) to test whether a drive digit must be inserted.
55DF
CP 30H FE 30
Compare register A (the character) against 30H (ASCII 0). If below 30H the CARRY flag is set.
55E1
RET C D8
If the CARRY flag is set (below 0, nothing to insert), RETURN.
55E2
CP 3AH FE 3A
Compare register A (the character) against 3AH (one past ASCII 9). If below 3AH the CARRY flag is set (a digit).
55E4
If the CARRY flag is set (a digit), JUMP to 55E9H to advance past it.
55E6
CP 41H FE 41
Compare register A (the character) against 41H (ASCII A). If below 41H the CARRY flag is set.
55E8
RET C D8
If the CARRY flag is set (punctuation, nothing to insert), RETURN.
55E9
INC HL 23
Advance the reference pointer (register pair HL) past the digit before the insert.
55EA
PUSH HL E5
Save register pair HL on the stack while the tail of the specification is shifted forward.
55EB
LD H,D 62
Copy register D into register H so register pair HL addresses the destination specification (was register pair DE).
55EC
LD L,E 6B
Copy register E into register L, completing HL = the destination pointer for the shift.
55ED
LD C,(HL) 4E
Loop Start
Load register C with the character currently at (HL) so it can be displaced by the inserted character.
55EE
LD (HL),A 77
Store the inserted character (register A) at (HL), overwriting the current position.
55EF
INC HL 23
Advance the destination pointer (register pair HL) to the next position.
55F0
LD A,C 79
Move the displaced character (register C) into register A so it becomes the next character to store.
55F1
CP 03H FE 03
Compare register A (the displaced character) against 03H (the ETX terminator). The Z flag is set at the end of the string.
55F3
If the Z flag is set (end of string reached), JUMP to 55F9H to store the terminator and finish.
55F5
CP 0DH FE 0D
Compare register A (the displaced character) against 0DH (carriage return terminator). The Z flag is set at the end of the string.
55F7
Loop End
If the NZ flag is set (more characters to shift), LOOP BACK to 55EDH to displace the next character.
55F9
LD (HL),A 77
Store the terminator character (register A) at (HL), ending the shifted specification.
55FA
POP HL E1
Restore register pair HL from the stack.
55FB
INC DE 13
Advance register pair DE to the next specification position.
55FC
LOOP BACK to 55DEH to test and insert at the next position.

55FEH - Build Working Filespec and Open File

Copies the specification at (DE) into the working area 59A6H, folding in the extension, appending a ':' drive placeholder (whose position it records for the drive-digit patch), then opens the file with @OPEN. On a successful open it verifies the drive and the file's protection level, refusing (error 25 "file access denied") a file whose access is too restricted to copy. Register A on entry is the open-mode byte; register B is the record length.

55FE
PUSH AF F5
Save register pair AF (register A = the open-mode byte, 20H for the destination or 24H for the source) on the stack while the specification is built.
55FF
PUSH HL E5
Save register pair HL (the record-buffer address) on the stack.
5600
PUSH DE D5
Save register pair DE (the source specification pointer) on the stack.
5601
LD HL,59A6H 21 A6 59
Point register pair HL at 59A6H, the working area where the canonical specification is assembled.
5604
LD A,(DE) 1A
Loop Start
Load register A with the current specification character at (DE).
5605
CP 2FH FE 2F
Compare register A (the character) against 2FH (ASCII /, the extension delimiter). The Z flag is set at the extension.
5607
If the NZ flag is set (not the extension delimiter), JUMP to 5611H to store the character as-is.
5609
INC DE 13
Advance register pair DE to the character after the / to test the extension.
560A
LD A,(DE) 1A
Load register A with the first extension character at (DE).
560B
CP 41H FE 41
Compare register A (the extension character) against 41H (ASCII A). If below 41H the CARRY flag is set (no real extension follows).
560D
If the CARRY flag is set (an empty extension), JUMP to 5611H to store the / anyway.
560F
DEC DE 1B
Step register pair DE back to the / character so it is stored below.
5610
LD A,(DE) 1A
Reload register A with the / character at (DE) to store it.
5611
LD (HL),A 77
Store the character (register A) into the working specification at (HL).
5612
INC HL 23
Advance the working-area pointer (register pair HL).
5613
INC DE 13
Advance the source pointer (register pair DE).
5614
CP 0EH FE 0E
Compare register A (the stored character) against 0EH. If below 0EH the CARRY flag is set (a control terminator ends the name).
5616
If the CARRY flag is set (a terminator was copied), JUMP to 5620H to finish the specification.
5618
CP 3AH FE 3A
Compare register A (the stored character) against 3AH (ASCII :, an explicit drive delimiter). The Z flag is set if the drive was already given.
561A
If the Z flag is set (a : drive delimiter was copied), JUMP to 5620H to finish.
561C
CP 2EH FE 2E
Compare register A (the stored character) against 2EH (ASCII .). The Z flag is set at a period delimiter.
561E
Loop End
If the NZ flag is set (still within the name), LOOP BACK to 5604H to copy the next character.
5620
DEC HL 2B
Step the working-area pointer (register pair HL) back onto the delimiter just stored, so the drive placeholder can replace it.
5621
POP DE D1
Restore the original specification pointer (register pair DE) from the stack.
5622
LD A,(DE) 1A
Load register A with the first character of the original specification at (DE) to test for a device.
5623
CP 2AH FE 2A
Compare register A (the first character) against 2AH (ASCII *). The Z flag is set for a device specification.
5625
If the Z flag is set (a * device, which has no drive digit), JUMP to 562EH to terminate the specification.
5627
LD (HL),3AH 36 3A
Store 3AH (ASCII :) into the working specification at (HL) as the drive delimiter.
5629
INC HL 23
Advance register pair HL to the byte that will hold the drive digit.
562A
LD (5687H),HL 22 87 56
Self-Modifying Code
Store the drive-digit slot address (register pair HL) into the operand cell 5687H, the operand of the LD (nnnn),A instruction at 5686H inside 5679H, so that routine can later poke the actual drive digit into this specification.
562D
INC HL 23
Advance register pair HL past the drive-digit slot to the terminator position.
562E
LD (HL),03H 36 03
Store 03H (the ETX terminator) at (HL), ending the working specification at 59A6H.
5630
POP HL E1
Restore the record-buffer address (register pair HL) from the stack.
5631
POP AF F1
Restore register pair AF, recovering the open-mode byte in register A.
5632
LD (5636H),A 32 36 56
Store the open-mode byte (register A) into the work cell 5636H, where it is re-read below to select the drive and protection checks.
5635
GOSUB to the resident SYS0 service @OPEN at 4424H to open the file described by the working specification at 59A6H (with the record length in register B). The Z flag is returned on a successful open; the NZ flag with an error code in register A otherwise.
5638
PUSH AF F5
Save register pair AF (the @OPEN result flags and any error code) on the stack while the drive digit is patched.
5639
GOSUB to 5679H to write the opened file's actual drive number (FCB+06H) as an ASCII digit into the drive slot of the working specification recorded at 5687H. It returns the Z flag if the file is not a disk file.
563C
If the Z flag is set (not a disk file, so no drive check applies), JUMP to 5651H.
563E
LD A,(5636H) 3A 36 56
Load register A with the open-mode byte saved at 5636H to decide whether the drive is validated.
5641
CP 20H FE 20
Compare register A (the open mode) against 20H (the destination-open mode). The Z flag is set for the destination.
5643
If the NZ flag is set (this is the source open, mode 24H), JUMP to 5651H, skipping the destination drive check.
5645
POP AF F1
Recover the @OPEN result flags (register pair AF) from the stack to test whether the destination already existed.
5646
PUSH AF F5
Re-save the @OPEN result flags (register pair AF) on the stack for the shared restore at 5651H.
5647
If the NZ flag is set (the destination did not previously exist and is being created), JUMP to 5651H, skipping the write-protect check on an existing disk.
5649
GOSUB to the resident SYS0 service @CKDRV at 44B8H to check the destination drive; it sets the CARRY flag if that drive is write-protected or not ready.
564C
LD A,0FH 3E 0F
Load register A with error code 0FH (15 decimal, "write protected disk") in case the drive check failed.
564E
If the CARRY flag is set (the destination disk is write-protected), JUMP to 5810H to report error 0FH through @ERROR and abort.
5651
POP AF F1
Restore the @OPEN result flags (register pair AF) from the stack.
5652
RET NZ C0
If the NZ flag is set (the open did not succeed), RETURN NZ to the caller, which treats it as an open error.
5653
BIT 7,(IX+00H) DD CB 00 7E
The file opened. Test bit 7 of the FCB flag byte at IX+00H (register IX addresses the opened FCB). Bit 7 set marks a disk file whose protection must be checked; the Z flag reflects the tested bit.
5657
If the Z flag is set (not a protected disk file), JUMP to 5677H to return success.
5659
LD A,(IX+01H) DD 7E 01
Load register A with the FCB byte at IX+01H, whose low three bits hold the file's access-protection level.
565C
AND 07H E6 07
Mask register A to its low three bits (07H), isolating the access-protection level (0 = full access through 7 = no access).
565E
LD B,A 47
Copy the isolated protection level (register A) into register B for the comparisons below.
565F
LD A,(5636H) 3A 36 56
Load register A with the open-mode byte at 5636H to choose the protection threshold.
5662
CP 20H FE 20
Compare register A (the open mode) against 20H (the destination-open mode). The Z flag is set for the destination.
5664
LD A,B 78
Copy the protection level (register B) back into register A for the threshold test.
5665
If the Z flag is set (destination), JUMP to 5673H to apply the stricter destination threshold (write access required).
5667
CP 06H FE 06
Source file: compare the protection level (register A) against 06H. If below 06H the CARRY flag is set (read access is permitted).
5669
If the CARRY flag is set (protection under 6, read is allowed), JUMP to 5677H to return success.
566B
Access is too restricted. GOSUB to @CLOSE at 4428H to close the file (its FCB in register IX) that may not be copied.
566E
LD A,19H 3E 19
Load register A with error code 19H (25 decimal, "file access denied").
5670
JUMP to 5810H to report error 19H (file access denied) through @ERROR and abort.
5673
CP 05H FE 05
Destination file: compare the protection level (register A) against 05H. If 05H or above the NO CARRY flag is set (write/rename access is not permitted).
5675
If the NO CARRY flag is set (protection 5 or higher, no write access), JUMP to 566BH to close the file and report access denied.
5677
XOR A AF
Set register A to ZERO and set the Z flag to signal a successful, permitted open.
5678
RET C9
RETURN to the caller with the Z flag set (open succeeded and access is allowed).

5679H - Drive-Digit Patch, Spec Display Copy and Progress Banner

Three display-side helpers. 5679H pokes an opened file's real drive number into the working specification. 568AH and 5690H copy that specification into the source or destination display buffer. 56A1H prints the progress banner "Copying: source to destination" (or "Appending:").

5679
PUSH DE D5
Save register pair DE (the FCB pointer) on the stack.
567A
POP IX DD E1
Restore that pointer into register pair IX, so IX indexes the FCB fields.
567C
LD A,(DE) 1A
Load register A with the FCB flag byte at (DE) to test the file type.
567D
BIT 7,A CB 7F
Test bit 7 of register A (the FCB flag byte). Bit 7 set marks a disk file with a drive number; the Z flag reflects the tested bit.
567F
RET Z C8
If the Z flag is set (a device, no drive digit), RETURN with the Z flag set.
5680
LD A,(IX+06H) DD 7E 06
Load register A with the FCB byte at IX+06H, the opened file's drive number.
5683
LD C,A 4F
Copy the drive number (register A) into register C for the caller.
5684
ADD A,30H C6 30
Add 30H (ASCII 0) to register A, converting the drive number to its ASCII digit.
5686
LD (0000H),A 32 00 00
Self-Modifying Code
Store the ASCII drive digit (register A) into the specification drive slot. The 0000H shown is the listing value; the operand cell 5687H was patched at 562AH with the drive-slot address in the working specification at 59A6H, so the digit lands in the displayed spec.
5689
RET C9
RETURN with register C holding the drive number and the NZ flag set (a disk file).
568A
PUSH HL E5
Save register pair HL on the stack for the display copy.
568B
LD HL,59B6H 21 B6 59
Point register pair HL at 59B6H, the SOURCE display buffer that the banner prints after "Copying:".
568E
JUMP to the shared copy at 5694H with HL pointing at the SOURCE display buffer.
5690
PUSH HL E5
Save register pair HL on the stack for the display copy.
5691
LD HL,59CAH 21 CA 59
Point register pair HL at 59CAH, the DESTINATION display buffer that the banner prints after "to".
5694
PUSH DE D5
Save register pair DE on the stack across the copy.
5695
LD DE,59A6H 11 A6 59
Point register pair DE at 59A6H, the working specification just built, as the copy source.
5698
EX DE,HL EB
Exchange register pairs DE and HL so register pair HL = 59A6H (source spec) and register pair DE = the display buffer (destination).
5699
LD BC,000FH 01 0F 00
Load register pair BC with 000FH (15), the number of specification bytes to copy for display.
569C
LDIR ED B0
Block-move 15 bytes from the working specification at 59A6H (register pair HL) into the display buffer (register pair DE).
569E
POP DE D1
Restore register pair DE from the stack.
569F
POP HL E1
Restore register pair HL from the stack.
56A0
RET C9
RETURN with the specification copied into the chosen display buffer.
56A1
PUSH HL E5
Save register pair HL on the stack across the banner display.
56A2
PUSH DE D5
Save register pair DE on the stack.
56A3
LD HL,583BH 21 3B 58
Self-Modifying Code
Point register pair HL at 583BH, the "Copying: " literal. The address operand at 56A4H is patched to 5845H ("Appending: ") by the APPEND entry, so this call prints the correct verb.
56A6
GOSUB to the resident SYS0 service @DSPLY at 4467H to display the 03H-terminated verb literal at (HL) ("Copying: " or "Appending: ").
56A9
LD HL,59B6H 21 B6 59
Point register pair HL at the SOURCE display buffer at 59B6H.
56AC
GOSUB to @DSPLY at 4467H to display the source specification at (HL).
56AF
LD HL,59C6H 21 C6 59
Point register pair HL at 59C6H, the " to " joiner literal, which is immediately followed in memory by the DESTINATION display buffer at 59CAH.
56B2
GOSUB to @DSPLY at 4467H to display " to " and, because it runs on into the adjacent buffer, the destination specification at 59CAH up to its 03H terminator.
56B5
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return to end the banner line.
56B7
GOSUB to the ROM @DSP routine at 0033H to send the carriage return in register A to the display, moving to a new line.
56BA
POP DE D1
Restore register pair DE from the stack.
56BB
POP HL E1
Restore register pair HL from the stack.
56BC
RET C9
RETURN with the progress banner displayed.

56BDH - Directory Attribute and Date-Field Readers

Two helpers that index the file's directory entry inside the resident sector buffer at 4200H using the directory position in FCB+07H. 56BDH returns the entry's attribute byte; 56CCH copies the entry's date and access fields into the 5A1EH template used to stamp the copied file.

56BD
PUSH DE D5
Save register pair DE (the FCB pointer) on the stack.
56BE
POP IX DD E1
Restore that pointer into register pair IX so IX indexes the FCB.
56C0
LD A,(IX+07H) DD 7E 07
Load register A with the FCB byte at IX+07H, the file's directory-entry position within the directory sector.
56C3
AND 0E0H E6 E0
Mask register A to its high three bits (0E0H), the directory-entry index scaled to a 32-byte entry offset within the sector.
56C5
ADD A,04H C6 04
Add 04H to register A, advancing to offset +04H within the directory entry (the attribute/flag field).
56C7
LD L,A 6F
Copy the computed offset (register A) into register L as the low byte of the directory-entry address.
56C8
LD H,42H 26 42
Load register H with 42H, so register pair HL now addresses the entry inside the resident directory sector buffer at 4200H.
56CA
LD A,(HL) 7E
Load register A with the directory entry's attribute/flag byte at (HL) for the caller.
56CB
RET C9
RETURN with the file's attribute byte in register A.
56CC
PUSH DE D5
Save register pair DE (the FCB pointer) on the stack.
56CD
POP IX DD E1
Restore it into register pair IX so IX indexes the FCB.
56CF
LD A,(IX+07H) DD 7E 07
Load register A with the FCB byte at IX+07H, the file's directory-entry position.
56D2
AND 0E0H E6 E0
Mask register A to its high three bits (0E0H), the directory-entry offset within the sector.
56D4
LD L,A 6F
Copy the offset (register A) into register L as the low byte of the entry address.
56D5
LD H,42H 26 42
Load register H with 42H, so register pair HL addresses the directory entry base within the sector buffer at 4200H.
56D7
LD DE,5A1EH 11 1E 5A
Point register pair DE at 5A1EH, the template that will hold the copied file's date/attribute bytes for stamping the destination.
56DA
LD BC,0003H 01 03 00
Load register pair BC with 0003H, the count for the first field copy (the attribute and date bytes at the entry base).
56DD
LDIR ED B0
Block-move 3 bytes from the directory entry (register pair HL) into the template at 5A1EH (register pair DE).
56DF
LD A,0DH 3E 0D
Load register A with 0DH (13), the offset from the entry base to its access/update field.
56E1
ADD A,L 85
Add the entry-base low byte (register L) to register A, forming the low byte of directory-entry offset +0DH.
56E2
LD L,A 6F
Copy the computed low byte (register A) into register L, so register pair HL now addresses directory-entry byte +0DH.
56E3
LD BC,0004H 01 04 00
Load register pair BC with 0004H, the count for the second field copy.
56E6
LDIR ED B0
Block-move 4 more bytes from directory-entry byte +0DH (register pair HL) into the template continuation (register pair DE), completing the saved date/access fields.
56E8
RET C9
RETURN with the source file's date and access fields captured at 5A1EH.

56E9H - BREAK/Pause Check and Single-Drive Disk-Swap Prompts

56E9H handles the keyboard during a transfer: it honours a PAUSE and reports BREAK. 570CH, 571EH and 5740H are the three disk-swap prompts, each a no-op unless the X single-drive flag at 52D4H is set: they display "Insert SYSTEM / SOURCE / DESTINATION disk" and, for the source and destination, re-read the mounted disk's identity and re-prompt if the wrong disk was inserted.

56E9
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH, whose bit 5 marks that the system is not at LDOS command level.
56EC
AND 20H E6 20
Mask register A to bit 5 (20H), isolating the not-command-level flag.
56EE
XOR 20H EE 20
Exclusive-OR register A with 20H; the Z flag is set when bit 5 was set (not at command level), where keyboard pausing is suppressed.
56F0
RET Z C8
If the Z flag is set (not at command level), RETURN with the Z flag, doing no keyboard check.
56F1
LD A,(4423H) 3A 23 44
Load register A with KFLAG$ at 4423H, whose bit 0 is the BREAK flag and bit 1 the PAUSE flag.
56F4
BIT 0,A CB 47
Test bit 0 of register A (the KFLAG$ BREAK flag). If BREAK was pressed the NZ flag is set.
56F6
RET NZ C0
If the NZ flag is set (BREAK pressed), RETURN NZ so the caller aborts the transfer.
56F7
BIT 1,A CB 4F
Test bit 1 of register A (the KFLAG$ PAUSE flag). If PAUSE is set the NZ flag is set.
56F9
RET Z C8
If the Z flag is set (no PAUSE), RETURN with the Z flag so the transfer continues.
56FA
LD A,(4423H) 3A 23 44
Loop Start
PAUSE is active. Reload register A with KFLAG$ at 4423H to re-test BREAK while paused.
56FD
BIT 0,A CB 47
Test bit 0 of register A (the KFLAG$ BREAK flag). If BREAK was pressed during the pause the NZ flag is set.
56FF
RET NZ C0
If the NZ flag is set (BREAK pressed while paused), RETURN NZ so the caller aborts.
5700
GOSUB to the ROM keyboard-scan routine at 002BH; it returns the pressed key in register A, or 00H if no key is down.
5703
OR A B7
Test register A (the scanned key). The Z flag is set when no key is pressed.
5704
If the Z flag is set (no key yet), LOOP BACK to 56FAH to keep waiting while paused.
5706
CP 60H FE 60
Compare register A (the key) against 60H, the code that continues to hold the pause. The Z flag is set if that key is held.
5708
Loop End
If the Z flag is set (the hold key), LOOP BACK to 56FAH to remain paused.
570A
XOR A AF
Any other key resumes: set register A to ZERO and the Z flag to signal continue.
570B
RET C9
RETURN with the Z flag set so the transfer resumes.
570C
LD A,(52D4H) 3A D4 52
Load register A with the single-drive flag at 52D4H. A zero value means this is not a single-drive copy.
570F
OR A B7
Test register A (the single-drive flag). The Z flag is set for an ordinary multi-drive copy.
5710
RET Z C8
If the Z flag is set (not single-drive), RETURN without prompting.
5711
LD A,00H 3E 00
Self-Modifying Code
Load register A with the current drive number. The 00H shown is the listing value; the immediate operand cell is 5712H, which also holds the copy's drive number written at 5309H, so register A receives that drive number.
5713
OR A B7
Test register A (the drive number). The NZ flag is set for any drive other than drive 0.
5714
RET NZ C0
If the NZ flag is set (not drive 0), RETURN without prompting, since the SYSTEM disk lives in drive 0.
5715
PUSH HL E5
Save register pair HL on the stack across the prompt.
5716
LD HL,58FBH 21 FB 58
Point register pair HL at 58FBH, the "Insert SYSTEM disk " prompt string.
5719
GOSUB to 576EH to display the SYSTEM-disk prompt at (HL) and wait for the operator to reinsert the system disk and press ENTER.
571C
POP HL E1
Restore register pair HL from the stack.
571D
RET C9
RETURN after the SYSTEM-disk prompt.
571E
LD A,(52D4H) 3A D4 52
Load register A with the single-drive flag at 52D4H.
5721
OR A B7
Test register A (the single-drive flag). The Z flag is set for an ordinary copy.
5722
RET Z C8
If the Z flag is set (not single-drive), RETURN without prompting.
5723
PUSH HL E5
Loop Start
Save register pair HL on the stack across the source-disk prompt and verification.
5724
LD HL,5919H 21 19 59
Point register pair HL at 5919H, the "Insert SOURCE disk in drive :n and press " prompt string.
5727
GOSUB to 576EH to display the SOURCE-disk prompt and wait for the operator.
572A
LD A,(5712H) 3A 12 57
Load register A with the copy's drive number saved at 5712H.
572D
LD C,A 4F
Copy the drive number (register A) into register C for the GAT-read helper.
572E
GOSUB to 57EDH to read the mounted disk's GAT sector into the sector buffer at 4200H so its identity can be checked.
5731
LD HL,42CEH 21 CE 42
Point register pair HL at 42CEH, the disk name+date identity of the disk now mounted.
5734
LD DE,59FAH 11 FA 59
Point register pair DE at 59FAH, the saved SOURCE disk identity captured earlier, for comparison.
5737
LD B,12H 06 12
Load register B with 12H (18), the identity length to compare.
5739
GOSUB to 5762H to compare the mounted disk's identity (HL) against the expected SOURCE identity (DE). The Z flag is set only if the correct source disk is mounted.
573C
POP HL E1
Restore register pair HL from the stack.
573D
Loop End
If the NZ flag is set (the wrong disk was inserted), LOOP BACK to 571EH to prompt for the SOURCE disk again.
573F
RET C9
RETURN once the correct SOURCE disk is confirmed.
5740
LD A,(52D4H) 3A D4 52
Load register A with the single-drive flag at 52D4H.
5743
OR A B7
Test register A (the single-drive flag). The Z flag is set for an ordinary copy.
5744
RET Z C8
If the Z flag is set (not single-drive), RETURN without prompting.
5745
PUSH HL E5
Loop Start
Save register pair HL on the stack across the destination-disk prompt and verification.
5746
LD HL,594DH 21 4D 59
Point register pair HL at 594DH, the "Insert DESTINATION disk in drive :n and press " prompt string.
5749
GOSUB to 576EH to display the DESTINATION-disk prompt and wait for the operator.
574C
LD A,(5712H) 3A 12 57
Load register A with the copy's drive number saved at 5712H.
574F
LD C,A 4F
Copy the drive number (register A) into register C for the GAT-read helper.
5750
GOSUB to 57EDH to read the mounted disk's GAT sector into the sector buffer at 4200H.
5753
LD HL,42CEH 21 CE 42
Point register pair HL at 42CEH, the identity of the disk now mounted.
5756
LD DE,5A0CH 11 0C 5A
Point register pair DE at 5A0CH, the saved DESTINATION disk identity, for comparison.
5759
LD B,12H 06 12
Load register B with 12H (18), the identity length to compare.
575B
GOSUB to 5762H to compare the mounted disk's identity (HL) against the expected DESTINATION identity (DE). The Z flag is set only if the correct destination disk is mounted.
575E
POP HL E1
Restore register pair HL from the stack.
575F
Loop End
If the NZ flag is set (the wrong disk was inserted), LOOP BACK to 5740H to prompt for the DESTINATION disk again.
5761
RET C9
RETURN once the correct DESTINATION disk is confirmed.

5762H - Identity Compare, Paged Prompt Wait, KFLAG Clear and Abort

5762H compares B bytes of two disk identities. 576EH displays a swap prompt and flashes it while waiting for a keypress, honouring PAUSE and aborting on BREAK. 57B0H clears the KFLAG$ control bits, and 57B9H reports "Transfer aborted" before aborting to @ABORT.

5762
LD A,(DE) 1A
Loop Start
Load register A with the current byte of the expected identity at (DE).
5763
CP (HL) BE
Compare register A (the expected byte) against the mounted-disk byte at (HL). The NZ flag is set on any mismatch.
5764
RET NZ C0
If the NZ flag is set (identities differ), RETURN NZ to signal the wrong disk.
5765
INC HL 23
Advance the mounted-disk pointer (register pair HL) to the next identity byte.
5766
INC DE 13
Advance the expected-identity pointer (register pair DE) to the next byte.
5767
Loop End
DECrement register B (remaining bytes) and LOOP BACK to 5762H if not zero, comparing the next identity byte.
5769
XOR A AF
All bytes matched: set register A to ZERO and the Z flag to signal the correct disk.
576A
RET C9
RETURN with the Z flag set (identities equal).
576B
GOSUB to 57B0H to clear the KFLAG$ BREAK/PAUSE bits before (re)displaying the prompt.
576E
LD BC,41FDH 01 FD 41
Load register pair BC with 41FDH, the delay count for the ROM timing loop below (a debounce before reading the keyboard).
5771
GOSUB to the ROM delay routine at 0060H, which counts register pair BC down to zero to debounce the keyboard.
5774
LD A,(4423H) 3A 23 44
Load register A with KFLAG$ at 4423H to test the BREAK and PAUSE bits.
5777
AND 05H E6 05
Mask register A to bits 0 and 2 (05H), the BREAK and enable bits.
5779
If the NZ flag is set (a control key is still held), LOOP BACK to 576BH to clear it and wait.
577B
Loop Start
GOSUB to 57B0H to clear the KFLAG$ bits before each display of the flashing prompt.
577E
GOSUB to @DSPLY at 4467H to display the 03H-terminated prompt string at (HL).
5781
LD BC,4000H 01 00 40
Load register pair BC with 4000H, the on-time count for the flashing prompt.
5784
GOSUB to 5794H to count register pair BC down while scanning for a keypress, aborting on BREAK.
5787
LD A,1EH 3E 1E
Load register A with 1EH, the video control code that erases the prompt line to make it flash.
5789
GOSUB to the ROM @DSP routine at 0033H to send the erase control code in register A, blanking the prompt.
578C
LD BC,3333H 01 33 33
Load register pair BC with 3333H, the off-time count for the flashing prompt.
578F
GOSUB to 5794H to count register pair BC down while scanning for a keypress during the off phase.
5792
Loop End
LOOP BACK to 577EH to redisplay and re-flash the prompt until a key is pressed.
5794
LD A,(4423H) 3A 23 44
Loop Start
Load register A with KFLAG$ at 4423H to test BREAK and PAUSE while the timing loop runs.
5797
RRCA 0F
Rotate register A right, moving bit 0 (the BREAK flag) into the CARRY flag.
5798
If the CARRY flag is set (BREAK pressed), JUMP to 57B9H to report "Transfer aborted" and abort the copy.
579A
BIT 1,A CB 4F
Test bit 1 of register A (now the original bit 2 after the rotate, the keypress-detected flag). If a key was seen the NZ flag is set.
579C
If the NZ flag is set (a key has been detected), JUMP to 57A4H to consume it and leave the prompt.
579E
DEC BC 0B
Decrement the flash-phase counter (register pair BC).
579F
LD A,B 78
Copy the high byte of the counter (register B) into register A to test for zero.
57A0
OR C B1
OR register A (high byte) with register C (low byte); the Z flag is set only when the counter reaches zero.
57A1
Loop End
If the NZ flag is set (time remaining), LOOP BACK to 5794H to keep scanning during this flash phase.
57A3
RET C9
RETURN when the flash phase elapses with no key pressed.
57A4
POP AF F1
Discard the caller's return address (register pair AF used as scratch), unwinding one stack level so control leaves the flashing prompt loop entirely once a key is seen.
57A5
Loop Start
GOSUB to the ROM keyboard-scan routine at 002BH to read the pressed key into register A.
57A8
OR A B7
Test register A (the key). The Z flag is set once the key has been released.
57A9
Loop End
If the NZ flag is set (key still held), LOOP BACK to 57A5H to wait for release.
57AB
LD A,1EH 3E 1E
Load register A with 1EH, the video erase control code to clear the prompt line.
57AD
GOSUB to the ROM @DSP routine at 0033H to send the erase code in register A, clearing the prompt before the copy resumes. Execution falls into 57B0H.
57B0
LD A,(4423H) 3A 23 44
Load register A with KFLAG$ at 4423H to clear its control bits.
57B3
AND 0F8H E6 F8
Mask register A with 0F8H, clearing the low three bits (BREAK, PAUSE and PAUSE-enable) while keeping the rest.
57B5
LD (4423H),A 32 23 44
Store the cleaned value (register A) back into KFLAG$ at 4423H, cancelling any pending BREAK/PAUSE.
57B8
RET C9
RETURN with the keyboard flags cleared.
57B9
LD HL,5885H 21 85 58
BREAK was pressed. Point register pair HL at 5885H, the "Transfer aborted" message.
57BC
GOSUB to the resident SYS0 service @LOGOT at 447BH to display the carriage-return-terminated "Transfer aborted" message at (HL).
57BF
GOSUB to 570CH to prompt for the SYSTEM disk (a no-op unless the single-drive flag at 52D4H is set) so the operator can restore it before returning to LDOS.
57C2
JUMP to the resident SYS0 service @ABORT at 4030H to terminate the aborted copy job.

57C5H - Resident Checkpoints, Device Test, Dating Bit, GAT Read and Open Entries

Small utilities used across the overlay: three RST 28H overlay pre-loads issued before a single-drive copy starts swapping diskettes; a test for a device endpoint; the per-drive extended-dating bit test (self-modified into a BIT instruction); the GAT-sector read; and the four entry points that set the open mode before calling the filespec-build-and-open routine. The three pre-loads are SEPARATE two-instruction stubs packed nose to tail, not a sequence: 531FH calls 57C5H, 53C3H calls 57C8H and 5424H calls 57CBH, and because the dispatcher at 4BCDH discards the address the RST pushed, each stub returns to the caller of that stub and needs no RET of its own.

57C5
LD A,84H 3E 84
Load register A with request code 84H. Its low nibble less two selects SYS2/SYS and the code masked with 70H gives sub-function 00H, which SYS2/SYS does not recognise, so the overlay returns at once from the RET at 4E16H. The request does no work; its purpose is to leave SYS2/SYS resident before the operator is asked to change diskettes.
57C7
RST 28H EF
Issue the supervisor call. The dispatcher at 4BCDH loads SYS2/SYS, calls it, and gets an immediate return; because it discarded the address this RST pushed, control passes back to 5322H, the instruction after the CALL that reached this stub. COPY prints its own Insert SOURCE disk prompt elsewhere; this request does not display anything.
57C8
LD A,8AH 3E 8A
Load register A with request code 8AH, which by the same arithmetic selects SYS8/SYS with sub-function 00H. This is the head of a separate stub, reached by the CALL at 53C3H, not a continuation of the two instructions above.
57CA
RST 28H EF
Issue the supervisor call, leaving SYS8/SYS resident and returning to 53C6H, the instruction after the CALL that reached this stub.
57CB
LD A,85H 3E 85
Load register A with request code 85H, which selects SYS3/SYS with sub-function 00H. The head of the third separate stub, reached by the CALL at 5424H.
57CD
RST 28H EF
Issue the supervisor call, leaving SYS3/SYS resident and returning to 5427H. With SYS2/SYS, SYS8/SYS and SYS3/SYS all brought in ahead of time, the file services COPY needs are in memory before the system diskette leaves the drive.
57CE
LD A,(5986H) 3A 86 59
Load register A with the first byte of the source FCB at 5986H to test whether the source is a device.
57D1
CP 2AH FE 2A
Compare register A (the source first byte) against 2AH (ASCII *). The Z flag is set if the source is a device.
57D3
RET Z C8
If the Z flag is set (the source is a device), RETURN with the Z flag.
57D4
LD A,(59DAH) 3A DA 59
Load register A with the first byte of the destination FCB at 59DAH to test the destination.
57D7
CP 2AH FE 2A
Compare register A (the destination first byte) against 2AH (ASCII *). The Z flag is set if the destination is a device.
57D9
RET C9
RETURN with the Z flag set if either endpoint is a device.
57DA
AND 07H E6 07
Mask register A (a drive number on entry) to its low three bits (07H), giving the drive index 0-7.
57DC
LD B,A 47
Copy the drive index (register A) into register B as the loop counter for building the bit mask.
57DD
INC B 04
Increment register B so the loop below runs drive-index-plus-one times.
57DE
LD A,3FH 3E 3F
Load register A with 3FH, the base opcode byte that, after the additions below, becomes a BIT n,A opcode.
57E0
ADD A,08H C6 08
Loop Start
Add 08H to register A. Each 08H step advances the bit-select field of the BIT opcode by one bit position.
57E2
Loop End
DECrement register B and LOOP BACK to 57E0H until the opcode selects the drive's bit; register A ends holding CB-prefix opcode 47H+8n = BIT n,A for drive n.
57E4
LD (57EBH),A 32 EB 57
Self-Modifying Code
Store the constructed opcode (register A) into the operand cell 57EBH, the second byte of the CB-prefixed instruction at 57EAH, turning it into BIT drive,A so it tests this drive's bit.
57E7
LD A,(475DH) 3A 5D 47
Load register A with the SYS2 extended-dating flags at 475DH, one bit per drive marking whether that drive uses extended date/time stamping.
57EA
BIT 0,A CB 00
Self-Modifying Code
Test the drive's bit in register A (the dating flags). The listing shows the unpatched CB 00; at run time the operand at 57EBH was rewritten to BIT drive,A, so the Z flag reflects whether this drive uses extended dating.
57EC
RET C9
RETURN with the Z flag reflecting the drive's extended-dating setting.
57ED
PUSH DE D5
Save register pair DE on the stack across the GAT read.
57EE
PUSH HL E5
Save register pair HL on the stack across the GAT read.
57EF
GOSUB to the resident SYS0 service DIRCYL at 4B65H to fetch the directory cylinder of the drive in register C, the cylinder that holds the GAT.
57F2
LD HL,4200H 21 00 42
Point register pair HL at the resident sector buffer at 4200H, the destination for the GAT sector.
57F5
LD E,L 5D
Copy register L (00H) into register E, selecting sector 0 (the GAT sector) for the read.
57F6
GOSUB to the resident SYS0 service RDSSEC at 4B45H to read sector 0 of the directory cylinder into 4200H. The Z flag is returned on a successful read.
57F9
POP HL E1
Restore register pair HL from the stack.
57FA
POP DE D1
Restore register pair DE from the stack.
57FB
RET Z C8
If the Z flag is set (the GAT read succeeded), RETURN.
57FC
LD A,14H 3E 14
The read failed: load register A with error code 14H (20 decimal, "GAT read error").
57FE
RET C9
RETURN with the NZ flag and error 14H in register A.
57FF
LD A,20H 3E 20
Destination open entry: load register A with open mode 20H (the destination-open mode).
5801
JUMP to 580BH to open the file described by register pair DE with the record length in register B (from the caller's register pair HL).
5803
LD DE,5986H 11 86 59
Source open entry: point register pair DE at the source FCB spec at 5986H.
5806
LD HL,5B00H 21 00 5B
Point register pair HL at the record buffer 5B00H (the low byte, 00H, also becomes the record-length argument).
5809
LD A,24H 3E 24
Load register A with open mode 24H (the source-open mode).
580B
LD B,L 45
Copy register L (the buffer low byte, 00H) into register B as the record-length argument for the open.
580C
GOSUB to 55FEH to build the working specification and open the file (register pair DE = spec, register A = mode, register B = record length). The Z flag is returned on a successful, permitted open.
580F
RET Z C8
If the Z flag is set (the open succeeded), RETURN to the caller. Otherwise execution falls into the error reporter at 5810H.

5810H - Error Reporting and Overlapped Message Selector

The common failure tail. 5810H reports a numeric error code through @ERROR; 5816H is an alternate entry for the fixed "parameter error" code. 581FH-5831H is an overlapped block of LD HL,message instructions: each of the five error entry points lands on a different LD HL, while the interleaved DD prefixes turn the non-selected loads into harmless LD IX instructions, so entering at a given address selects exactly one message before the shared @LOGOT display.

5810
PUSH AF F5
Save register pair AF (the disk error code in register A) on the stack while the SYSTEM-disk prompt is shown.
5811
GOSUB to 570CH to prompt for the SYSTEM disk (a no-op unless the single-drive flag at 52D4H is set) so @ERROR can read its text from the system disk.
5814
POP AF F1
Restore the error code (register pair AF) from the stack.
5815
LD BC,2C3EH 01 3E 2C
Self-Modifying Code
As reached by fall-through this loads register pair BC with 2C3EH (harmless). Entered instead at 5816H, the two bytes 3E 2C read as LD A,2CH, placing error code 2CH (44 decimal, "parameter error") into register A; the JP NZ,5816H parameter-error exits use this entry.
5818
OR 0C0H F6 C0
OR register A (the error code) with 0C0H, setting bits 7 and 6 so @ERROR both displays the message and, per bit 7, returns to the caller after reporting.
581A
GOSUB to the resident SYS0 service @ERROR at 4409H to display the English text for the error code in register A.
581D
JUMP to 5835H to load the error return status and exit the overlay.

The five instructions from 581FH to 5831H form one overlapped message-selector table. Each error exit jumps to a different address within it; the byte landed on begins an LD HL,message instruction, and any DD prefixes ahead of it are consumed as the opcode of a do-nothing LD IX. All paths converge on the @LOGOT display at 5832H.

581F
LD HL,58D1H 21 D1 58
Entered at 581FH: point register pair HL at 58D1H, the "Source and destination disks are the same" message.
5822
LD IX,5897H DD 21 97 58
By fall-through this loads register pair IX with 5897H (unused). Entered at 5823H, the DD prefix is skipped and the bytes 21 97 58 read as LD HL,5897H, selecting the "File spec required" message.
5826
LD IX,58AAH DD 21 AA 58
By fall-through this loads register pair IX with 58AAH (unused). Entered at 5827H, the bytes 21 AA 58 read as LD HL,58AAH, selecting the "Invalid command during processing" message.
582A
LD IX,5851H DD 21 51 58
By fall-through this loads register pair IX with 5851H (unused). Entered at 582BH, the bytes 21 51 58 read as LD HL,5851H, selecting the "Files have different LRLs" message.
582E
LD IX,586BH DD 21 6B 58
By fall-through this loads register pair IX with 586BH (unused). Entered at 582FH, the bytes 21 6B 58 read as LD HL,586BH, selecting the "Destination spec required" message.
5832
GOSUB to the resident SYS0 service @LOGOT at 447BH to display the carriage-return-terminated message selected in register pair HL.
5835
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, the non-zero error status the overlay exit tests to decide between a clean return and an abort.
5838
JUMP to the shared exit at 5489H, which restores the caller stack and returns (or aborts to @ABORT at 4030H if the system is not at LDOS command level).

583BH - Message and Prompt String Data

The overlay's text: the two progress-banner verbs (03H-terminated for @DSPLY), the error and status messages (0DH-terminated for @LOGOT), and the three single-drive disk-swap prompts (framed by video control codes 1DH/1EH, 03H-terminated, with the drive digit at 5938H and 5971H patched at run time).

583B
DEFM "Copying: ",03H 43 6F 70 79 69 6E 67 3A 20 03
The COPY progress-banner verb, displayed via @DSPLY (03H terminator).
5845
DEFM "Appending: ",03H 41 70 70 65 6E 64 69 6E 67 3A 20 03
The APPEND progress-banner verb; the APPEND entry patches 56A4H to point here instead of 583BH.
5851
DEFM "Files have different LRLs",0DH 46 69 6C 65 73 20 68 61 76 65 20 64 69 66 66 65 72 65 6E 74 20 4C 52 4C 73 0D
Error message shown at 582BH when the source and destination logical record lengths are incompatible.
586B
DEFM "Destination spec required",0DH 44 65 73 74 69 6E 61 74 69 6F 6E 20 73 70 65 63 20 72 65 71 75 69 72 65 64 0D
Error message shown at 582FH when no distinct destination file was supplied.
5885
DEFB 1DH : DEFM "Transfer aborted",0DH 1D 54 72 61 6E 73 66 65 72 20 61 62 6F 72 74 65 64 0D
Message shown at 57B9H when BREAK is pressed during a copy; the leading 1DH homes the cursor to the line start.
5897
DEFM "File spec required",0DH 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 0D
Error message shown at 5823H when @FSPEC could not parse a file specification.
58AA
DEFM "Invalid command during <DO> processing",0DH 49 6E 76 61 6C 69 64 20 63 6F 6D 6D 61 6E 64 20 64 75 72 69 6E 67 20 3C 44 4F 3E 20 70 72 6F 63 65 73 73 69 6E 67 0D
Error message shown at 5827H when a single-drive copy is attempted from inside a JCL DO stream.
58D1
DEFM "Source and destination disks are the same",0DH 53 6F 75 72 63 65 20 61 6E 64 20 64 65 73 74 69 6E 61 74 69 6F 6E 20 64 69 73 6B 73 20 61 72 65 20 74 68 65 20 73 61 6D 65 0D
Error message shown at 581FH when the operator failed to swap disks between the SOURCE and DESTINATION prompts.
58FB
DEFB 1DH,1EH : DEFM "Insert SYSTEM disk <ENTER>" : DEFB 1DH,03H 1D 1E 49 6E 73 65 72 74 20 53 59 53 54 45 4D 20 64 69 73 6B 20 3C 45 4E 54 45 52 3E 1D 03
Single-drive prompt (570CH) to reinsert the system disk; 1DH/1EH position and clear the line, 03H terminates for @DSPLY.
5919
DEFB 1DH,1EH : DEFM "Insert SOURCE disk in drive :0 and press <ENTER>" : DEFB 1DH,03H 1D 1E 49 6E 73 65 72 74 20 53 4F 55 52 43 45 20 64 69 73 6B 20 69 6E 20 64 72 69 76 65 20 3A 30 20 61 6E 64 20 70 72 65 73 73 20 3C 45 4E 54 45 52 3E 1D 03
Single-drive prompt (571EH); the drive digit at 5938H is patched with the actual drive number at run time.
594D
DEFB 1DH,1EH : DEFM "Insert DESTINATION disk in drive :0 and press <ENTER>" : DEFB 1DH,03H 1D 1E 49 6E 73 65 72 74 20 44 45 53 54 49 4E 41 54 49 4F 4E 20 64 69 73 6B 20 69 6E 20 64 72 69 76 65 20 3A 30 20 61 6E 64 20 70 72 65 73 73 20 3C 45 4E 54 45 52 3E 1D 03
Single-drive prompt (5740H); the drive digit at 5971H is patched with the actual drive number at run time.

5986H - Work Areas, Buffers and Reserved Cells

The overlay's uninitialised RAM work areas (the two file control blocks, the specification build and display buffers, and the disk-identity and directory-stamp scratch), interrupted only by the initialised four-byte " to " banner joiner at 59C6H. These addresses hold no loaded bytes; the contents shown are established at run time.

Address RangePurpose
5986H-59A5H
32 bytes
Source File Control Block. +00 flags (bit7 = disk file); +03/04 record-buffer pointer (5989H, set before each @READ); +06 drive (598CH); +07 directory position (598DH); +08 EOF byte offset (598EH); +0C/0D ending record number (5992H).
59A6H-59B5H
16 bytes
Working filespec assembly area built by 55FEH as NAME/EXT:d terminated by 03H; the drive-digit slot is recorded at 5687H for the 5679H patch.
59B6H-59C5H
16 bytes
Source specification display buffer, printed by the banner after the verb.
59C6H-59C9H
4 bytes
Initialised " to " banner joiner (loaded data); it runs on into the adjacent destination display buffer so one @DSPLY prints " to <dest>".
59CAH-59D9H
16 bytes
Destination specification display buffer, printed by the banner after " to ".
59DAH-59F9H
32 bytes
Destination File Control Block. +03 record-buffer pointer (59DDH); +06 drive (59E0H); +08 EOF byte offset (59E2H); +09 record-position flag (59E3H); +0C/0D ending record number (59E6H).
59FAH-5A0BH
18 bytes
Saved SOURCE disk identity (name and date), captured from the GAT for the single-drive same-disk guard.
5A0CH-5A1DH
18 bytes
Saved DESTINATION disk identity (name and date).
5A1EH-5A24H
7 bytes
CLONE date/attribute template filled from the source directory entry by 56CCH and stamped into the destination directory record at 5459H/5462H.

5A25H - COPY and APPEND Option Keyword Table

One @PARAM keyword table shared by the two commands. COPY parses it from the top (5A25H), accepting LRL, CLONE and X (and the single-letter abbreviations); APPEND parses the same table from 5A4DH, so it accepts only STRIP and ECHO. Each entry is a six-character space-padded keyword followed by the two-byte address of the self-modified operand cell that receives the value; a 00H byte at 5A6DH terminates.

5A25
DEFM "LRL " 4C 52 4C 20 20 20
Keyword: LRL keyword (COPY): sets the destination logical record length; the value is stored at 5359H (read at 54FAH when opening a device destination).
5A2B
DEFW 5359H 59 53
Address of the operand cell patched with the value for the keyword above.
5A2D
DEFM "L " 4C 20 20 20 20 20
Keyword: L, the single-letter abbreviation of LRL, targeting the same cell 5359H.
5A33
DEFW 5359H 59 53
Address of the operand cell patched with the value for the keyword above.
5A35
DEFM "CLONE " 43 4C 4F 4E 45 20
Keyword: CLONE keyword (COPY): copies the source date and attributes to the destination by making the LD DE operand at 544AH non-zero (cells 544BH/544CH), enabling the directory-field copy at 5451H.
5A3B
DEFW 544BH 4B 54
Address of the operand cell patched with the value for the keyword above.
5A3D
DEFM "C " 43 20 20 20 20 20
Keyword: C, the single-letter abbreviation of CLONE, targeting the same cells 544BH/544CH.
5A43
DEFW 544BH 4B 54
Address of the operand cell patched with the value for the keyword above.
5A45
DEFM "X " 58 20 20 20 20 20
Keyword: X keyword (COPY): the single-drive disk-swap copy; makes the LD DE operand at 52D3H non-zero so 52D4H reads as the single-drive flag.
5A4B
DEFW 52D4H D4 52
Address of the operand cell patched with the value for the keyword above.
5A4D
DEFM "STRIP " 53 54 52 49 50 20
Keyword: STRIP keyword (APPEND, and the first entry APPEND parses): trims the destination's final partial record before appending, via the operand at 5268H (cells 5269H/526AH).
5A53
DEFW 5269H 69 52
Address of the operand cell patched with the value for the keyword above.
5A55
DEFM "S " 53 20 20 20 20 20
Keyword: S, the single-letter abbreviation of STRIP, targeting the same cells 5269H/526AH.
5A5B
DEFW 5269H 69 52
Address of the operand cell patched with the value for the keyword above.
5A5D
DEFM "ECHO " 45 43 48 4F 20 20
Keyword: ECHO keyword (APPEND): echoes each transferred byte to the display by patching the LD DE operand at 5544H (cells 5545H/5546H) so INC D sets the Z flag in the character loop.
5A63
DEFW 5545H 45 55
Address of the operand cell patched with the value for the keyword above.
5A65
DEFM "E " 45 20 20 20 20 20
Keyword: E, the single-letter abbreviation of ECHO, targeting the same cells 5545H/5546H.
5A6B
DEFW 5545H 45 55
Address of the operand cell patched with the value for the keyword above.
5A6D
DEFB 00H 00
Table terminator (a zero keyword byte) ending the option scan for both commands.

Disassembly - Overlay 8 - LIST

5200H - Overlay Entry: Reset Keyboard Flags and Scan the Command Tail for Parameters

Entry of the LIST command overlay (Library A command 8, dispatched by RST 28H code 88H). It saves the caller's stack pointer for the exit, clears the resident keyboard status flags, then scans the command line for the parameter-list open parenthesis so any options can be parsed before the file is opened.

5200
LD (538BH),SP ED 73 8B 53
Self-Modifying Code
Store the caller's stack pointer (register SP, which on entry holds the LDOS command-level stack) into the operand of the LD SP,nnnn instruction at 538AH, so the overlay exit can restore the caller's stack.
5204
GOSUB to the local routine at 5548H to clear the resident keyboard/pause flags in KFLAG$ (4423H) before listing begins; it returns with register A cleared.
5207
PUSH HL E5
Save the command-line pointer (register pair HL, which points at the text following the LIST command name) on the stack while the tail is scanned for a parameter list.
5208
LD A,(HL) 7E
Loop Start
Load register A with the command-line character at (HL) while scanning for the parameter-list open parenthesis.
5209
CP 28H FE 28
Compare register A (the current command-line character) against 28H, the ASCII left parenthesis ( that introduces the parameter list.
520B
If register A equals 28H (Z, a parameter list is present), JUMP to 5214H to parse the parameters.
520D
CP 0EH FE 0E
Compare register A (the current command-line character) against 0EH; command-line text ends with a control byte below 0EH (carriage return 0DH or the end marker 03H).
520F
If register A is below 0EH (CARRY, end of the command line with no parameter list), JUMP to 522FH to parse the filespec.
5211
INC HL 23
INCrement the command-line pointer (register pair HL) to the next character.
5212
LOOP BACK to 5208H to test the next command-line character.

5214H - Parse the Parameter List and Apply the Compressed-Display Toggle

The parameter list is parsed by the resident @PARAM service against the local keyword table at 55C2H. Each supplied value is stored by @PARAM into a self-modified operand cell inside the overlay. This block then resolves the C (compressed hexadecimal display) switch, whose default is on.

5214
LD DE,55C2H 11 C2 55
Point register pair DE at 55C2H, the local @PARAM keyword descriptor table (ASCII8/A8, C, HEX/H, LRL/L, LINE, NUM, N, REC/R, P, TAB/T).
5217
GOSUB to the resident @PARAM service at 4476H to parse the parameter list at (HL) against the table at (DE)=55C2H, storing each supplied value into the self-modified cell named by its table entry.
521A
If @PARAM reported a syntax error (NZ), JUMP to 5583H to issue a parameter error (error code 2CH).
521D
LD HL,0FFFFH 21 FF FF
Load register pair HL with the compressed-hexadecimal-display flag; the assembled default is 0FFFFH (compressed mode on). If the command line contained C=OFF, @PARAM has overwritten the operand at 521EH-521FH with 0000H.
5220
LD A,H 7C
Load register A with the high byte of the compressed-mode flag (register H).
5221
OR L B5
OR in the low byte (register L); register A is non-zero when compressed mode is on and zero when C=OFF was given, and the Z flag is set accordingly.
5222
LD (53F4H),A 32 F4 53
Store the compressed-mode flag byte (register A) into the self-modified per-byte-spacing gate at 53F4H, tested in the hexadecimal read loop.
5225
LD (5412H),A 32 12 54
Store the same compressed-mode flag byte (register A) into the self-modified layout gate at 5412H, tested at 5411H to choose the compressed one-line layout versus the separate two-line layout.
5228
If the flag is zero (Z, C=OFF requested), JUMP to 522FH leaving the separate-format grouping in place.
522A
LD A,03H 3E 03
Compressed mode selected. Load register A with 03H, the byte-group mask for the compressed layout (a gap every 4 bytes).
522C
LD (53FBH),A 32 FB 53
Store 03H (register A) into the self-modified AND mask at 53FBH (the operand of AND 07H at 53FAH), so the compressed formatter groups every 4 bytes instead of the default every 8.

522FH - Parse the Filespec, Apply the Default /TXT Extension and Open the File

The filespec is parsed into a File Control Block, a device specification is rejected, a backup copy of the FCB is taken, the default extension /TXT is applied and the file is opened. If /TXT is not found the original blank-extension specification is restored and the open is retried, matching the documented search order.

522F
POP HL E1
Restore the command-line pointer (register pair HL) saved at 5207H, now positioned at the start of the filespec.
5230
LD A,(HL) 7E
Loop Start
Load register A with the filespec character at (HL) while skipping leading blanks.
5231
INC HL 23
INCrement the filespec pointer (register pair HL).
5232
CP 20H FE 20
Compare register A (the filespec character) against 20H, an ASCII space.
5234
If register A is a space (Z), LOOP BACK to 5230H to skip it.
5236
DEC HL 2B
A non-blank was found. DECrement the pointer (register pair HL) back onto the first filespec character.
5237
LD DE,564CH 11 4C 56
Point register pair DE at 564CH, the File Control Block work area that will receive the parsed file specification.
523A
GOSUB to the resident @FSPEC service at 441CH to parse the filespec at (HL) into the FCB at (DE)=564CH.
523D
If @FSPEC reported an invalid or missing filespec (NZ), JUMP to 558CH to display the File spec required message.
5240
LD A,(DE) 1A
Load register A with the first byte of the built FCB at (DE)=564CH.
5241
CP 2AH FE 2A
Compare that FCB byte (register A) against 2AH, the ASCII asterisk * that marks a device specification.
5243
If the specification names a device (Z), JUMP to 558CH to reject it; LIST accepts only disk files.
5246
PUSH HL E5
Save the command-line pointer (register pair HL) for later reuse.
5247
LD BC,0020H 01 20 00
Load register pair BC with 0020H (32), the length of a File Control Block, as the byte count for the copy that follows.
524A
LD DE,566CH 11 6C 56
Point register pair DE at 566CH, a spare buffer that will hold a backup copy of the parsed FCB.
524D
LD HL,564CH 21 4C 56
Point register pair HL at 564CH, the parsed FCB (copy source).
5250
PUSH HL E5
Save the FCB address (register pair HL)=564CH so it can be recovered as the @OPEN destination after the copy.
5251
LDIR ED B0
Block-copy 32 bytes (register pair BC) from the FCB at (HL)=564CH to the backup at (DE)=566CH, preserving the original specification in case the /TXT open fails.
5253
POP DE D1
Recover the FCB address 564CH into register pair DE for the @FEXT and @OPEN calls.
5254
LD HL,55BFH 21 BF 55
Point register pair HL at 55BFH, the default file extension text TXT.
5257
GOSUB to the resident @FEXT service at 4473H to apply the default extension /TXT to the FCB at (DE) when the filespec supplied no extension.
525A
LD HL,5700H 21 00 57
Point register pair HL at 5700H, the 256-byte file I/O buffer used while the file is open.
525D
LD B,L 45
Load register B with the low byte of HL (00H), passing a logical record length of 0 (=256 bytes) to @OPEN.
525E
GOSUB to the resident @OPEN service at 4424H to open the file described by the FCB at (DE) using the buffer at (HL)=5700H with the LRL in register B.
5261
If the file opened successfully (Z), JUMP to 527EH to set up the record length.
5263
CP 18H FE 18
The open failed. Compare the returned error code (register A) against 18H (error 24, file not in directory).
5265
If the failure was any error other than file-not-found (NZ), JUMP to 5585H to report it through @ERROR.
5268
LD BC,0020H 01 20 00
File not found with /TXT. Load register pair BC with 0020H (32 bytes) to restore the original FCB.
526B
LD DE,564CH 11 4C 56
Point register pair DE at 564CH, the FCB work area (copy destination).
526E
PUSH DE D5
Save the FCB address (register pair DE)=564CH for the retry @OPEN.
526F
LD HL,566CH 21 6C 56
Point register pair HL at 566CH, the backup FCB (copy source, holding the specification with no default extension).
5272
LDIR ED B0
Block-copy 32 bytes (register pair BC) from the backup at (HL)=566CH back to the FCB at (DE)=564CH, restoring the original blank-extension specification.
5274
POP DE D1
Recover the FCB address 564CH into register pair DE.
5275
LD HL,5700H 21 00 57
Point register pair HL at 5700H, the file I/O buffer.
5278
GOSUB to @OPEN at 4424H to retry opening the file with a blank extension.
527B
If the retry also failed (NZ), JUMP to 5585H to report the error through @ERROR.

527EH - Establish the Logical Record Length and the TAB Stop

With the file open, IX is pointed at the FCB. The logical record length is taken from the LRL parameter if given, otherwise from the file's directory entry, and written into the FCB. The TAB stop is defaulted to 8 and range-checked to 1-32.

527E
PUSH DE D5
Save the FCB address (register pair DE)=564CH so it can be reloaded into register pair IX.
527F
POP IX DD E1
Load register pair IX with the FCB address 564CH; IX now indexes the open file's control-block fields.
5281
LD HL,(53B9H) 2A B9 53
Load register pair HL with the requested logical record length from 53B9H; the assembled default is 0FF00H (LRL not specified), otherwise @PARAM stored the LRL value here.
5284
INC L 2C
INCrement register L to test the low byte of the LRL word against the not-specified sentinel.
5285
LD A,H 7C
Load register A with the high byte of the LRL word (register H).
5286
AND L A5
AND register L into register A to test whether the LRL word is still at its unspecified sentinel.
5287
INC A 3C
INCrement register A; a supplied LRL leaves register A non-zero, the sentinel leaves it zero.
5288
If an explicit LRL was supplied (NZ), JUMP to 5298H to store it into the FCB.
528A
LD A,(IX+07H) DD 7E 07
No LRL supplied. Load register A with the FCB byte at IX+07H, which holds the directory-derived record attributes of the open file.
528D
AND 0E0H E6 E0
Mask register A to bits 7-5, the encoded record-length attribute of the directory entry.
528F
ADD A,04H C6 04
Add 04H to register A to index the entry in the resident file-control area that yields the directory record length.
5291
LD L,A 6F
Move the computed index (register A) into register L.
5292
LD H,42H 26 42
Load register H with 42H, forming the pointer HL=42xxH into the resident file-control area holding the record length.
5294
LD A,(HL) 7E
Load register A with the directory logical record length from (HL).
5295
LD (53B9H),A 32 B9 53
Store the directory record length (register A) into the LRL cell at 53B9H for the listing.
5298
LD A,(53B9H) 3A B9 53
Load register A with the effective logical record length from 53B9H (either the supplied LRL or the directory value).
529B
LD (IX+09H),A DD 77 09
Store the record length (register A) into the FCB record-length field at IX+09H so the file is read with the correct record size.
529E
SET 7,(IX+01H) DD CB 01 FE
Set bit 7 of the FCB flag byte at IX+01H to mark the file for the byte-at-a-time, record-spanning access the listing uses.
52A2
LD HL,(5343H) 2A 43 53
Load register pair HL with the requested TAB expansion value from 5343H; @PARAM stores the TAB value here, or leaves the assembled default when TAB was not given.
52A5
LD A,H 7C
Load register A with the high byte of the TAB word (register H).
52A6
AND L A5
AND the low byte (register L) into register A to test the TAB word against its unspecified sentinel.
52A7
INC A 3C
INCrement register A; a zero result marks the unspecified sentinel.
52A8
LD A,L 7D
Load register A with the low byte of the TAB word (register L), the candidate tab-stop value.
52A9
If a TAB value was supplied (NZ), JUMP to 52ADH keeping the supplied value in register A.
52AB
LD A,08H 3E 08
No TAB supplied. Load register A with 08H, the default tab stop (every 8 columns).
52AD
LD (534DH),A 32 4D 53
Store the effective tab stop (register A) into the tab-width operand at 534DH (the operand of LD C,nn at 534CH used during tab expansion).
52B0
DEC A 3D
DECrement register A to range-check the tab stop.
52B1
CP 20H FE 20
Compare register A against 20H (32); a tab stop of 32 or more is out of range.
52B3
If the tab stop is 32 or more (NO CARRY, out of the 1-32 range), JUMP to 5583H to report a parameter error.

52B6H - Select the Output Device and the HEX or ASCII Listing Mode

The P switch chooses the printer or video Device Control Block and forces non-stop mode for the printer. The HEX switch then routes to the hexadecimal listing; otherwise the ASCII paging constants are set up (15 lines per page in this DOS 5 build) and self-modifying patches disable the screen clear used only by the hexadecimal pager.

52B6
LD BC,0000H 01 00 00
Load register pair BC with the P (printer) flag; the assembled default is 0000H (video output), or @PARAM stored a non-zero value when P was given.
52B9
LD A,B 78
Load register A with the high byte of the P flag (register B).
52BA
OR C B1
OR in the low byte (register C); register A is zero for video and non-zero when P was requested, setting the Z flag accordingly.
52BB
LD DE,401DH 11 1D 40
Point register pair DE at 401DH, the resident video Device Control Block (the display device).
52BE
If P was not given (Z, video output), JUMP to 52CCH keeping the video DCB.
52C0
LD (54F6H),BC ED 43 F6 54
Printer output requested. Store the non-zero P flag (register pair BC) into the non-stop flag at 54F6H, forcing non-stop mode for printer listings.
52C4
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return appended at the end of each printed hexadecimal line.
52C6
LD (547EH),A 32 7E 54
Store 0DH (register A) into the cell at 547EH, the trailing character emitted after a printed hexadecimal record line.
52C9
LD DE,4025H 11 25 40
Point register pair DE at 4025H, the resident printer Device Control Block.
52CC
LD (540DH),A 32 0D 54
Store register A into the printer-mode gate at 540DH (00H for video, 0DH for printer); a non-zero value suppresses screen paging.
52CF
LD (54CAH),DE ED 53 CA 54
Store the selected output DCB address (register pair DE) into the self-modified operand at 54CAH used by the character-output routine at 54C9H.
52D3
PUSH DE D5
Save the output DCB address (register pair DE) on the stack for the display routines, which pass it to @MSG.
52D4
LD BC,0000H 01 00 00
Load register pair BC with the HEX-mode flag; the assembled default is 0000H (ASCII listing), or @PARAM stored a non-zero value when HEX/H was given.
52D7
LD A,B 78
Load register A with the high byte of the HEX flag (register B).
52D8
OR C B1
OR in the low byte (register C); register A is non-zero when HEX was requested.
52D9
If HEX mode was requested (NZ), JUMP to 5399H to run the hexadecimal listing.
52DC
LD (54F4H),A 32 F4 54
ASCII mode. Store 00H (register A) into 54F4H, patching the PUSH DE at 54F4H to a NOP so the ASCII pager stays stack-balanced with its disabled screen-clear path.
52DF
LD (551EH),A 32 1E 55
Store 00H (register A) into 551EH, patching the POP AF at 551EH to a NOP to match the disabled PUSH.
52E2
LD A,0FH 3E 0F
Load register A with 0FH (15), the ASCII page length (15 lines per screen in this DOS 5 build).
52E4
LD (54FCH),A 32 FC 54
Store 15 (register A) into the line-countdown operand at 54FCH that triggers a pause when it reaches zero.
52E7
LD (551AH),A 32 1A 55
Store 15 (register A) into the line-count reload operand at 551AH used after each pause in ASCII mode.
52EA
LD A,11H 3E 11
Load register A with 11H, the opcode byte for LD DE,nn.
52EC
LD (5516H),A 32 16 55
Store 11H (register A) over the opcode at 5516H, converting the CALL 01C9H (clear screen) at 5516H into a harmless LD DE,01C9H so ASCII paging does not clear the screen between pages.

52EFH - ASCII Listing: Skip Forward to the Starting LINE

When the LINE parameter asks the listing to start beyond the first line, the file is read a byte at a time and carriage returns are counted until the requested number of lines has been skipped.

52EF
LD BC,0001H 01 01 00
Load register pair BC with the starting LINE number; the assembled default is 0001H (list from the first line), or @PARAM stored the LINE value here.
52F2
DEC BC 0B
DECrement register pair BC to the count of carriage returns that must be skipped to reach the starting line.
52F3
LD A,B 78
Load register A with the high byte of the skip count (register B).
52F4
OR C B1
OR in the low byte (register C) to test whether any lines must be skipped.
52F5
If no lines are to be skipped (Z, LINE=1), JUMP to 5309H to begin the ASCII listing.
52F7
LD DE,564CH 11 4C 56
Point register pair DE at 564CH, the open file's FCB, as input for the byte reader.
52FA
Loop Start
GOSUB to the ROM byte-input routine at 0013H to read the next file byte (FCB in register pair DE) into register A.
52FD
If the read returned an error (NZ), JUMP to 5585H to report it through @ERROR.
5300
CP 0DH FE 0D
Compare the file byte (register A) against 0DH, the ASCII carriage return that ends a line.
5302
If the byte is not a carriage return (NZ), LOOP BACK to 52FAH to keep reading the current line.
5304
DEC BC 0B
A line ended. DECrement the remaining skip count (register pair BC).
5305
LD A,B 78
Load register A with the high byte of the skip count (register B).
5306
OR C B1
OR in the low byte (register C) to test whether more lines remain to be skipped.
5307
If more lines remain (NZ), LOOP BACK to 52FAH to skip the next line.

5309H - ASCII Display Loop: Line Numbering, Tab Expansion and Character Output

The main ASCII loop. At the head of each line the five-digit line number is formatted and, when NUM is active, sent to the output device. Each character is then optionally high-bit stripped (unless ASCII8 was given), tab characters are expanded to the next stop, and the character is displayed. A carriage return returns to the line head; end of file finishes the listing.

5309
LD HL,(52F0H) 2A F0 52
Load register pair HL with the (decremented) LINE value from 52F0H as the initial line-number counter for a NUM listing.
530C
LD DE,55ACH 11 AC 55
Point register pair DE at 55ACH, the five-digit line-number display field.
530F
GOSUB to the decimal formatter at 5559H to render the line number (register pair HL) as five ASCII digits into the field at (DE).
5312
LD DE,564CH 11 4C 56
New Line
Point register pair DE at 564CH, the open file's FCB, to read the first character of the next line.
5315
GOSUB to the ROM byte-input routine at 0013H to read the next file byte (FCB in register pair DE) into register A.
5318
If the read returned end of file or an error (NZ), JUMP to 5377H to finish the listing.
531A
LD (5330H),A 32 30 53
Store the file byte (register A) into the self-modified operand at 5330H so it can be re-fetched (and high-bit stripped unless ASCII8 was given) before display.
531D
LD BC,0000H 01 00 00
Load register pair BC with the NUM flag; the assembled default is 0000H (no line numbers), or @PARAM stored a non-zero value when NUM was given.
5320
LD A,B 78
Load register A with the high byte of the NUM flag (register B).
5321
OR C B1
OR in the low byte (register C); a non-zero result means line numbering is active.
5322
If NUM was not given (Z), JUMP to 532FH to display the character without a line number.
5324
LD HL,55ACH 21 AC 55
NUM active. Point register pair HL at 55ACH, the formatted line-number field.
5327
POP DE D1
Recover the output DCB address into register pair DE (saved at 52D3H).
5328
PUSH DE D5
Re-save the output DCB address (register pair DE) for subsequent lines.
5329
GOSUB to the resident @MSG service at 4479H to send the line-number field at (HL) to the output device whose DCB is in register pair DE.
532C
GOSUB to 5572H to advance the five-digit ASCII line-number counter in the field at 55ACH for the next line.
532F
LD A,00H 3E 00
Reload the current file byte from the self-modified operand at 5330H into register A for display.

Character Processing Loop
Entered at 5331H for the second and later characters of a line (from 5375H), and fallen into at 532FH for the first character. The rotate that follows works with the high-bit test to strip or keep bit 7 of the character.

5331
RLCA 07
Rotate register A left; the character's high bit (bit 7) moves into the carry flag, ahead of the high-bit test that follows.
5332
LD DE,0000H 11 00 00
Load register pair DE from the self-modified operand at 5333H, which holds the ASCII8 flag (0000H unless ASCII8 was given).
5335
INC D 14
INCrement register D to test the high byte of the ASCII8 flag.
5336
DEC D 15
DECrement register D back, setting the Z flag when the ASCII8 flag high byte was zero.
5337
If ASCII8 was given (NZ, keep all eight bits), JUMP to 533CH, landing on the RRCA that restores the rotated character.
5339
SRL A CB 3F
ASCII8 not given. Shift register A right, which (following the earlier RLCA) clears bit 7, stripping the high bit to the X'00'-X'7F' range.

Overlap
The fall-through path executes SRL A at 5339H (stripping the high bit) and then LD E,0FH here at 533BH. When ASCII8 is active, the jump at 5337H (JR NZ,533CH) instead lands on the operand byte 0FH at 533CH, which executes as RRCA and undoes the earlier RLCA at 5331H, keeping all eight bits of the character. The anchor for 533CH resolves to this 533BH row.

533B
LD E,0FH 1E 0F
Load register E with 0FH; register E is a scratch value on the non-ASCII8 path (its operand byte 0FH doubles as the RRCA entered at 533CH on the ASCII8 path).
533D
PUSH AF F5
Save the character and flags (register AF); the saved carry records whether the character's original high bit was set.
533E
CP 09H FE 09
Compare the character (register A) against 09H, the ASCII tab code.
5340
If the character is not a tab (NZ), JUMP to 535DH to display it directly.
5342
LD DE,0008H 11 08 00
The character is a tab. Load register pair DE with 0008H as a scratch working value for tab expansion.
5345
INC E 1C
INCrement register E as part of the scratch tab-width test.
5346
DEC E 1D
DECrement register E, setting the Z flag from the scratch value.
5347
If the scratch test is zero (Z), JUMP to 535DH to emit the tab as a single character rather than expanding it.
5349
LD A,(563BH) 3A 3B 56
Load register A with the current output column from the counter at 563BH.
534C
LD C,08H 0E 08
Load register C with the tab width (self-modified at 534DH; 08H by default, or the TAB value).
534E
SUB C 91
Loop Start
SUBtract the tab width (register C) from the column (register A) to reduce it modulo the tab width.
534F
If the result did not go negative (NO CARRY), LOOP BACK to 534EH to keep subtracting the tab width.
5351
NEG ED 44
NEGate register A so it holds the number of spaces needed to reach the next tab stop.
5353
LD B,A 47
Move the space count (register A) into register B as the loop counter.
5354
LD A,20H 3E 20
Loop Start
Load register A with 20H, an ASCII space, for the tab expansion.
5356
GOSUB to the character-output routine at 54C9H to emit one space.
5359
DECrement register B and LOOP BACK to 5354H until the tab has been expanded to the next stop.
535B
JUMP to 5360H, past the single-character output, once the tab is expanded.
535D
Non-tab character. GOSUB to the character-output routine at 54C9H to emit the character in register A.
5360
LD A,(563BH) 3A 3B 56
Load register A with the current output column from the counter at 563BH.
5363
OR A B7
Test register A; a zero column means the line just wrapped at 64 columns.
5364
If the column is zero (Z, a wrapped full line), GOSUB to the pause/BREAK check at 5525H.
5367
POP AF F1
Restore the character and flags (register AF) saved at 533DH; the carry again reflects the character's original high bit.
5368
If the carry is set (the character's original high bit was set), GOSUB to the pause/BREAK check at 5525H.
536B
CP 0DH FE 0D
Compare the character (register A) against 0DH, an ASCII carriage return.
536D
If the character was a carriage return (Z, end of line), LOOP BACK to 5312H to start the next line.
536F
LD DE,564CH 11 4C 56
Same line continues. Point register pair DE at 564CH, the open file's FCB, for the next character.
5372
GOSUB to the ROM byte-input routine at 0013H to read the next file byte (FCB in register pair DE) into register A.
5375
If the read succeeded (Z), LOOP BACK to 5331H to display this character within the current line.
5377
PUSH AF F5
End of the ASCII listing. Save the terminating status/byte (register AF) returned by the byte reader.
5378
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return, to flush the final partial line.
537A
GOSUB to the character-output routine at 54C9H to emit the closing carriage return.
537D
POP AF F1
Restore the terminating code (register AF).
537E
CP 1CH FE 1C
Compare the terminating code (register A) against 1CH (error 28, end of file).
5380
If end of file (Z), JUMP to 5387H to exit cleanly.
5382
CP 1DH FE 1D
Compare register A against 1DH (error 29, record number out of range, also a normal end).
5384
If the code is neither normal-end value (NZ), JUMP to 5585H to report the error through @ERROR.

5387H - Overlay Exit and Command-Level Check

Common exit. Register pair HL carries the status word (0000H for success, 0FFFFH for an error). The caller's stack is restored from the operand patched at entry. A clean status returns to the RST 28H dispatcher; an error status aborts the job through @ABORT when not at the LDOS command level.

5387
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status returned to the RST 28H dispatcher.
538A
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 538BH, patched at entry (5200H) with the caller's SP; register SP now addresses the LDOS command-level stack.
538D
LD A,H 7C
Load register A with the high byte of the status word (register H).
538E
OR L B5
OR in the low byte (register L); Z means clean completion, non-zero means an error status is being returned.
538F
RET Z C8
If the status is zero (Z, success), RETurn to the RST 28H overlay dispatcher.
5390
LD A,(430FH) 3A 0F 43
Error status. Load register A from the resident system flag byte SFLAG$ at 430FH.
5393
BIT 5,A CB 6F
Test bit 5 of register A, which is set when execution is not at the LDOS command level.
5395
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher, which handles the error.
5396
Not at command level. JUMP to the resident @ABORT vector at 4030H to abort the running job.

5399H - HEX Listing: Position to the Starting Record and Read a 16-Byte Line

The hexadecimal listing. The file is positioned to the REC starting record, then for each record the header aaaa:bb = is built and displayed and up to 16 raw bytes are read into the line buffer, each emitted as two hexadecimal digits with the grouping spacing selected by the C switch.

5399
LD BC,0000H 01 00 00
Load register pair BC with the starting record number for the hexadecimal listing; the assembled default is 0000H (record 0), or @PARAM stored the REC value here.
539C
LD DE,564CH 11 4C 56
Point register pair DE at 564CH, the open file's FCB.
539F
GOSUB to the resident @POSN service at 4442H to position the file (FCB in register pair DE) to record number BC.
53A2
If positioning failed (NZ), JUMP to 5585H to report the error through @ERROR.
53A5
XOR A AF
Main Loop
Clear register A to zero to reset the intra-record byte offset for a new record line.
53A6
LD (53BCH),A 32 BC 53
Store 00H (register A) into the byte-offset counter at 53BCH, the bb field shown in the header.
53A9
LD DE,(539AH) ED 5B 9A 53
Load register pair DE with the current record number from 539AH.
53AD
LD HL,55B4H 21 B4 55
Point register pair HL at 55B4H, the aaaa record-number field of the hexadecimal header template.
53B0
GOSUB to the resident formatter at 4D76H to store the record number (register pair DE) as four hexadecimal ASCII digits at (HL).
53B3
INC DE 13
INCrement the record number (register pair DE) ready for the next record.
53B4
LD (539AH),DE ED 53 9A 53
Store the incremented record number (register pair DE) back at 539AH.
53B8
LD BC,0FF00H 01 00 FF
Load register pair BC with the record length; the low byte (register C) is the logical record length (assembled default 00H = 256, or the LRL value @PARAM stored at 53B9H) and drives the per-record byte count.
53BB
LD A,00H 3E 00
Loop Start
Load register A with the current byte offset from the self-modified operand at 53BCH for the header bb field.
53BD
LD HL,55B9H 21 B9 55
Point register pair HL at 55B9H, the bb offset field of the header template.
53C0
GOSUB to the resident formatter at 4D7BH to store the offset (register A) as two hexadecimal ASCII digits at (HL).
53C3
LD HL,55B4H 21 B4 55
Point register pair HL at 55B4H, the completed aaaa:bb = header line.
53C6
POP DE D1
Recover the output DCB address into register pair DE (saved at 52D3H).
53C7
PUSH DE D5
Re-save the output DCB address (register pair DE).
53C8
GOSUB to the resident @MSG service at 4479H to send the header line at (HL) to the output device (register pair DE).
53CB
LD A,(53BCH) 3A BC 53
Load register A with the current byte offset from 53BCH.
53CE
ADD A,10H C6 10
Add 10H (16) to register A to advance the offset for the next 16-byte line.
53D0
LD (53BCH),A 32 BC 53
Store the advanced offset (register A) back at 53BCH.
53D3
LD B,10H 06 10
Load register B with 10H (16), the number of bytes read and formatted on this line.
53D5
LD HL,563CH 21 3C 56
Point register pair HL at 563CH, the 16-byte line buffer that collects the raw bytes for the ASCII sidebar.
53D8
LD DE,564CH 11 4C 56
Inner Loop
Point register pair DE at 564CH, the open file's FCB, for the next byte read.
53DB
GOSUB to the ROM byte-input routine at 0013H to read the next file byte (FCB in register pair DE) into register A.
53DE
If the byte was read successfully (Z), JUMP to 53EBH to store and format it.
53E0
PUSH AF F5
A non-success status was returned. Save it (register AF).
53E1
CP 1CH FE 1C
Compare the status (register A) against 1CH (error 28, end of file).
53E3
If end of file (Z), JUMP to 53EAH to finish the partial line.
53E5
CP 1DH FE 1D
Compare register A against 1DH (error 29, record number out of range, also a normal end).
53E7
If neither normal-end value (NZ), JUMP to 5585H to report the error through @ERROR.
53EA
POP AF F1
Restore the terminating status (register AF).
53EB
If a non-zero terminating status is present (NZ, end of data), JUMP to 5406H to format the partial line.
53ED
LD (HL),A 77
Store the file byte (register A) into the line buffer at (HL).
53EE
INC HL 23
INCrement the line-buffer pointer (register pair HL).
53EF
GOSUB to 54B8H to output the byte (register A) as two hexadecimal ASCII digits.
53F2
DEC B 05
DECrement the per-line byte count (register B).
53F3
LD A,00H 3E 00
Load register A from the self-modified per-byte-spacing gate at 53F4H (00H requests a space after every byte in the separate format; non-zero suppresses it in the compressed format).
53F5
OR A B7
Test register A to set the Z flag for the spacing decision.
53F6
If the gate is zero (Z, separate format), GOSUB to 54A8H to emit a separating space after the byte.
53F9
LD A,B 78
Load register A with the remaining per-line byte count (register B).
53FA
AND 07H E6 07
AND register A with the group-size mask (07H by default = every 8 bytes; 03H in compressed mode = every 4 bytes; the mask at 53FBH is set at 522CH).
53FC
If at a group boundary (Z), GOSUB to 54A8H to emit an extra separating space.
53FF
DEC C 0D
DECrement the remaining record-length count (register C).
5400
If the whole record has been read (Z), JUMP to 5406H to format the ASCII sidebar.
5402
LD A,B 78
Load register A with the remaining per-line count (register B).
5403
OR A B7
Test register B for zero (the line is full at 16 bytes).
5404
If the line is not yet full (NZ), LOOP BACK to 53D8H to read the next byte.

5406H - HEX Listing: Format the ASCII Sidebar of the Record Line

After the hexadecimal bytes of a line are emitted, the matching ASCII sidebar is laid out. Three layouts are supported: compressed video (the DOS 5 default), separate two-line video (C=OFF), and printer. Each pads the sidebar so the characters align under their hexadecimal columns, showing a period for any non-displayable byte.

5406
PUSH AF F5
Save the terminating status (register AF) from the read loop.
5407
LD A,B 78
Load register A with the count of unfilled byte positions on this line (register B).
5408
CP 10H FE 10
Compare register A against 10H (16); a full 16 unfilled means no bytes were read on this line.
540A
If the line is empty (Z, no bytes), JUMP to 547DH to finish the record without an ASCII sidebar.
540C
LD A,00H 3E 00
Load register A from the self-modified printer-mode gate at 540DH (00H video, 0DH printer).
540E
OR A B7
Test register A for the output-device decision.
540F
If printing (NZ), JUMP to 5457H to lay out the printer-format ASCII sidebar.
5411
LD A,00H 3E 00
Load register A from the self-modified compressed-mode gate at 5412H (non-zero = compressed one-line layout, 00H = separate layout).
5413
OR A B7
Test register A for the layout decision.
5414
If compressed mode is off (Z, separate two-line format), JUMP to 5424H.
5416
PUSH BC C5
Compressed video format. Save the byte counts (register pair BC).
5417
LD A,B 78
Load register A with the unfilled-position count (register B).
5418
RRCA 0F
Rotate register A right (a divide-by-two step).
5419
RRCA 0F
Rotate register A right again (now divided by four).
541A
AND 03H E6 03
Mask register A to the low two bits, giving the number of 4-byte groups missing on a short final line.
541C
ADD A,B 80
Add the unfilled byte count (register B) to register A.
541D
ADD A,B 80
Add register B again, building the total space padding needed to align the ASCII sidebar under the compressed hex columns.
541E
OR A B7
Test register A for zero padding.
541F
If no padding is needed (Z, a full line), JUMP to 5466H to emit the ASCII characters.
5421
INC A 3C
Include one extra separating column (register A).
5422
JUMP to 5462H to emit that many pad spaces before the ASCII sidebar.
5424
LD A,03H 3E 03
Separate video format. Load register A with 03H, an ETX end-marker, to terminate the current hexadecimal line.
5426
GOSUB to the character-output routine at 54C9H to end the hex line (03H forces a paged newline).
5429
PUSH BC C5
Save the byte counts (register pair BC).
542A
LD B,0BH 06 0B
Load register B with 0BH (11), the indent width for the second (ASCII) line so it aligns under the hex.
542C
GOSUB to 5451H to emit register B spaces of indentation.
542F
POP BC C1
Restore the byte counts (register pair BC).
5430
LD A,10H 3E 10
Load register A with 10H (16).
5432
SUB B 90
Subtract the unfilled count (register B) to get the number of bytes actually on the line.
5433
LD B,A 47
Move the bytes-on-line count (register A) into register B as the loop counter.
5434
SUB 07H D6 07
Subtract 07H to compute how many extra group-gap spaces the short line needs.
5436
LD (5449H),A 32 49 54
Store that value (register A) into the self-modified compare operand at 5449H used inside the sidebar loop.
5439
LD HL,563CH 21 3C 56
Point register pair HL at 563CH, the line buffer holding this record line's raw bytes.
543C
LD A,(HL) 7E
Loop Start
Load register A with the next raw byte from the line buffer at (HL).
543D
INC HL 23
INCrement the buffer pointer (register pair HL).
543E
GOSUB to 54ACH to output the byte (register A) as a printable ASCII character (non-printables shown as a period).
5441
GOSUB to 54A8H to emit a separating space.
5444
GOSUB to 54A8H to emit a second separating space, matching the two-column hexadecimal spacing.
5447
LD A,B 78
Load register A with the remaining byte count (register B).
5448
CP 09H FE 09
Compare register A against the self-modified group boundary at 5449H (set at 5436H) to align the mid-line gap.
544A
If at the group boundary (Z), GOSUB to 54A8H to emit the extra alignment space.
544D
DECrement register B and LOOP BACK to 543CH until all bytes on the line have been shown.
544F
JUMP to 547DH to finish the record line.
5451
Loop Start
GOSUB to 54A8H to emit one space.
5454
DECrement register B and LOOP BACK to 5451H to emit register B spaces in total.
5456
RET C9
RETurn to the caller of the space-padding helper.
5457
PUSH BC C5
Printer format. Save the byte counts (register pair BC).
5458
LD A,B 78
Load register A with the unfilled-position count (register B).
5459
RLCA 07
Rotate register A left (a multiply-by-two step).
545A
ADD A,B 80
Add register B, forming three times the unfilled count (three output columns per missing byte).
545B
LD B,A 47
Move the padding count (register A) into register B.
545C
CP 18H FE 18
Compare register A against 18H (24) to detect a full or near-full short line.
545E
CCF 3F
Complement the carry flag for the rounding adjustment that follows.
545F
LD A,03H 3E 03
Load register A with 03H.
5461
ADC A,B 88
Add register B plus the adjusted carry, producing the final printer-sidebar indent (register A).
5462
LD B,A 47
Move the pad count (register A) into register B.
5463
GOSUB to 5451H to emit register B pad spaces before the ASCII sidebar.
5466
POP BC C1
Restore the byte counts (register pair BC).
5467
PUSH BC C5
Re-save the byte counts (register pair BC).
5468
LD C,08H 0E 08
Load register C with 08H, the mid-line group size for the ASCII sidebar spacing.
546A
LD A,10H 3E 10
Load register A with 10H (16).
546C
SUB B 90
Subtract the unfilled count (register B) to get the count of bytes actually present.
546D
LD B,A 47
Move that count (register A) into register B as the loop counter.
546E
LD HL,563CH 21 3C 56
Point register pair HL at 563CH, the raw line buffer.
5471
LD A,(HL) 7E
Loop Start
Load register A with the next raw byte from the line buffer at (HL).
5472
INC HL 23
INCrement the buffer pointer (register pair HL).
5473
GOSUB to 54ACH to output the byte (register A) as a printable ASCII character.
5476
DEC C 0D
DECrement the group counter (register C).
5477
If a group of eight has completed (Z), GOSUB to 54A8H to emit a mid-line gap space.
547A
DECrement register B and LOOP BACK to 5471H until all present bytes are shown.
547C
POP BC C1
Restore the byte counts (register pair BC).

547DH - HEX Listing: Close the Record Line and Advance to the Next Record

The record line is closed, the terminating status is checked, a page-pause test is run, and the loop either continues the current record (if it holds more than sixteen bytes) or advances to the next record.

547D
LD A,03H 3E 03
Load register A with 03H, an ETX end-marker, to terminate the record's output line.
547F
GOSUB to the character-output routine at 54C9H to end the line and run the page-pause check.
5482
POP AF F1
Restore the terminating status (register AF) saved at 5406H.
5483
LD A,1CH 3E 1C
Preset register A to 1CH (the end-of-file code) so the shared finalizer treats a normal end as clean; this load does not disturb the status flags from 5482H.
5485
If the terminating status was non-zero (NZ, end of data), JUMP to 5377H to run the shared clean-exit finalizer.
5488
More records remain. GOSUB to the pause/BREAK check at 5525H between records.
548B
LD A,C 79
Load register A with the remaining record-length count (register C).
548C
OR A B7
Test register C; a non-zero value means the current record holds more than the sixteen bytes just shown.
548D
If the record is not exhausted (NZ), JUMP to 53BBH to output the next 16-byte line of the same record.
5490
LD A,(54F6H) 3A F6 54
Record finished. Load register A from the non-stop flag at 54F6H.
5493
OR A B7
Test register A for the non-stop setting.
5494
If non-stop is off (Z, paged mode), JUMP to 549FH to advance to the next record.
5496
Non-stop mode. GOSUB to 54A8H to emit a trailing space between records.
5499
LD A,(547EH) 3A 7E 54
Load register A from the trailing-character cell at 547EH (0DH when printing).
549C
GOSUB to the character-output routine at 54C9H to emit that trailing character.
549F
LD HL,55B4H 21 B4 55
Point register pair HL at 55B4H, the record-number field of the header template.
54A2
GOSUB to 5573H to advance the four-digit record-number digits at (HL); the header is refreshed from the record counter at the top of the next record loop.
54A5
LOOP BACK to 53A5H to list the next record.

54A8H - Output Helpers: Space, Printable-Character Filter and Hexadecimal Digit

Small shared routines used by both listing modes: emit a single space, convert a raw byte to a printable ASCII character (period for non-printables) and emit it, and print a byte as two hexadecimal ASCII digits using the DAA nibble-conversion method.

54A8
LD A,20H 3E 20
Load register A with 20H, an ASCII space.
54AA
JUMP to the character-output routine at 54C9H to emit the space and run the page-pause check.
54AC
CP 20H FE 20
Printable Character Filter
Compare the raw byte (register A) against 20H (space); bytes below 20H are non-printable control codes.
54AE
If the byte is below 20H (CARRY, a control code), JUMP to 54B4H to substitute a period.
54B0
CP 7FH FE 7F
Compare register A against 7FH; bytes at 7FH and above are non-displayable on the Model I.
54B2
If the byte is below 7FH (CARRY, printable), JUMP to 54B6H to emit it unchanged.
54B4
LD A,2EH 3E 2E
Non-printable byte. Load register A with 2EH, an ASCII period, as the placeholder character.
54B6
JUMP to the character-output routine at 54C9H to emit the character in register A.
54B8
PUSH AF F5
Hexadecimal Byte Output
Save the byte (register AF) whose two hexadecimal digits will be printed.
54B9
RRCA 0F
Rotate register A right to begin moving the high nibble into the low four bits.
54BA
RRCA 0F
Rotate register A right (nibble shift, step 2 of 4).
54BB
RRCA 0F
Rotate register A right (nibble shift, step 3 of 4).
54BC
RRCA 0F
Rotate register A right (nibble shift, step 4 of 4); the high nibble now sits in the low four bits.
54BD
GOSUB to 54C1H to convert and emit the high nibble (register A) as one hexadecimal digit.
54C0
POP AF F1
Restore the original byte (register AF) to emit its low nibble.
54C1
AND 0FH E6 0F
Mask register A to the low nibble, a single hexadecimal digit value 0-15.
54C3
ADD A,90H C6 90
Add 90H to register A, the first step of the standard DAA hexadecimal-digit conversion.
54C5
DAA 27
Decimal-adjust register A, producing the packed intermediate for the digit.
54C6
ADC A,40H CE 40
Add 40H plus carry, the second DAA step, mapping 0-9 to characters 0-9 and 10-15 to A-F.
54C8
DAA 27
Decimal-adjust register A again to complete the ASCII hexadecimal digit; execution falls into the output routine at 54C9H.

54C9H - Character Output with Column Tracking and End-of-Line Paging

The single point through which every displayed character passes. It sends the character to the selected device, tracks the 64-column position, and at end of line runs the page-pause logic: printer output never pauses, non-stop mode never pauses, otherwise the page line counter is decremented and a full page waits for a key.

54C9
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE with the output Device Control Block address from the operand at 54CAH, set at 52CFH to the video DCB (401DH) or printer DCB (4025H).
54CC
PUSH HL E5
Save the caller's register pair HL.
54CD
LD HL,563BH 21 3B 56
Point register pair HL at 563BH, the current output-column counter.
54D0
INC (HL) 34
INCrement the column counter at (HL) for the character about to be output.
54D1
PUSH AF F5
Save the character (register AF) to be output.
54D2
GOSUB to the ROM byte-output routine at 001BH to send the character (register A) to the device whose DCB is in register pair DE.
54D5
LD A,(HL) 7E
Load register A with the updated column counter from (HL).
54D6
AND 3FH E6 3F
Mask the column counter (register A) to 0-63, wrapping at 64 columns.
54D8
LD (HL),A 77
Store the wrapped column counter (register A) back at (HL)=563BH.
54D9
POP AF F1
Restore the output character (register AF).
54DA
CP 03H FE 03
Compare the character (register A) against 03H, an ETX end-of-line marker.
54DC
If it is an end-of-line marker (Z), JUMP to 54E6H to force a new line.
54DE
CP 0AH FE 0A
Compare register A against 0AH, a line feed.
54E0
If a line feed (Z), JUMP to 54E6H to force a new line.
54E2
CP 0DH FE 0D
Compare register A against 0DH, a carriage return.
54E4
If it is not a carriage return (NZ, an ordinary character), JUMP to 54E7H, the 00H operand of the next instruction, executing it as a NOP so the column counter is left as-is.

Overlap
The ordinary-character path at 54E4H (JR NZ,54E7H) jumps into the 00H operand byte of the LD (HL),00H instruction here, executing it as a NOP so the column counter is left unchanged; only a genuine end-of-line character falls into the counter reset at 54E6H. The anchor for 54E7H resolves to this 54E6H row.

54E6
LD (HL),00H 36 00
End of line. Store 00H into the column counter at (HL)=563BH, resetting the column and setting the Z flag.
54E8
INC (HL) 34
INCrement the column counter (to 1) and immediately...
54E9
DEC (HL) 35
...DECrement it back to 0, forcing the Z flag to reflect a completed line while leaving the column at zero.
54EA
POP HL E1
Restore the caller's register pair HL.
54EB
RET NZ C0
If the column counter is non-zero (NZ, mid-line), RETurn to the caller; only a completed line (Z) proceeds to paging.
54EC
LD A,(540DH) 3A 0D 54
End of line reached. Load register A from the printer-mode gate at 540DH (00H video, non-zero printer).
54EF
OR A B7
Test register A.
54F0
RET NZ C0
If output is to the printer (NZ), RETurn without paging; printer listings do not pause.
54F1
LD DE,5520H 11 20 55
Load register pair DE with 5520H, the post-pause continuation routine that emits a carriage return.
54F4
PUSH DE D5
Self-Modifying Code
Push the continuation address (register pair DE); in ASCII mode this PUSH is patched to a NOP at 52DCH, paired with the NOP at 551EH.
54F5
LD DE,0000H 11 00 00
Load register pair DE with the non-stop flag from the operand at 54F6H (0000H = paged, non-zero = non-stop).
54F8
LD A,D 7A
Load register A with the high byte of the non-stop flag (register D).
54F9
OR E B3
OR in the low byte (register E) to test the non-stop flag.
54FA
RET NZ C0
If non-stop mode is active (NZ), RETurn without pausing.
54FB
LD A,10H 3E 10
Self-Modifying Code
Load register A with the current page line-countdown from the operand at 54FCH (initialised to 15 for ASCII, 16 for HEX).
54FD
DEC A 3D
DECrement the line countdown (register A).
54FE
LD (54FCH),A 32 FC 54
Store the decremented countdown (register A) back into the operand at 54FCH.
5501
RET NZ C0
If the page is not yet full (NZ), RETurn to continue listing.
5502
Page full. GOSUB to the ROM keyboard routine at 0049H to wait for and read a key press.
5505
CP 01H FE 01
Compare the key (register A) against 01H, the BREAK key code.
5507
If BREAK was pressed (Z), JUMP to 5592H to abort the listing.
550A
SUB 43H D6 43
Subtract 43H (ASCII C) from the key (register A); a zero result means C was pressed to continue non-stop.
550C
If C was pressed (Z), JUMP to 5512H to switch to non-stop mode.
550E
SUB 20H D6 20
Subtract a further 20H from register A; combined with the prior subtraction this tests for lowercase c (63H).
5510
If neither C nor c was pressed (NZ), JUMP to 5516H to resume paged output for one more page.
5512
LD (54F6H),DE ED 53 F6 54
C pressed. Store register pair DE (non-zero) into the non-stop flag at 54F6H so the rest of the file lists without pausing.
5516
Self-Modifying Code
GOSUB to the ROM clear-line routine at 01C9H for the next page; in ASCII mode the opcode here is patched at 52ECH to LD DE,01C9H, suppressing the clear.
5519
LD A,10H 3E 10
Load register A with 10H (16), the page-length reload value; in ASCII mode the operand at 551AH is patched to 0FH (15) at 52E7H.
551B
LD (54FCH),A 32 FC 54
Store the reload value (register A) into the line-countdown operand at 54FCH for the new page.
551E
POP AF F1
Self-Modifying Code
Discard the pushed continuation address (popped into register pair AF); in ASCII mode this POP is patched to a NOP at 52DFH, paired with the NOP at 54F4H.
551F
RET C9
RETurn to the caller, or in HEX mode to the pushed continuation at 5520H.
5520
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return, to close the paused line.
5522
JUMP to the ROM display routine at 0033H to output the carriage return and return to the listing.

5525H - Pause and BREAK Key Handling and the Keyboard-Flag Reset

Checks the resident keyboard flags for a pause or BREAK request and, while paused, polls the keyboard until released. The tail of this block (entered at 5548H, also called at entry) clears the resident keyboard status flags.

5525
LD A,(430FH) 3A 0F 43
Pause and BREAK Check
Load register A from the resident system flag byte SFLAG$ at 430FH.
5528
AND 20H E6 20
Mask register A to bit 5, which is set when not at the LDOS command level.
552A
XOR 20H EE 20
Toggle bit 5; register A becomes zero only when bit 5 was set (a nested, not-command-level context).
552C
RET Z C8
If not at command level (Z), RETurn without checking for a pause key.
552D
LD A,(4423H) 3A 23 44
Load register A from the resident keyboard flag byte KFLAG$ at 4423H.
5530
BIT 0,A CB 47
Test bit 0 of KFLAG$ (register A), the BREAK-pressed flag.
5532
If BREAK is flagged (NZ), JUMP to 5552H to end the listing.
5534
BIT 1,A CB 4F
Test bit 1 of KFLAG$ (register A), the pause-pressed flag.
5536
RET Z C8
If pause is not flagged (Z), RETurn to continue listing.
5537
LD A,(4423H) 3A 23 44
Loop Start
Paused. Load register A from KFLAG$ at 4423H to re-poll the flags.
553A
BIT 0,A CB 47
Test bit 0 (BREAK) of register A.
553C
If BREAK was pressed during the pause (NZ), JUMP to 5552H to end the listing.
553E
GOSUB to the ROM keyboard-scan routine at 002BH to read any key press into register A.
5541
OR A B7
Test register A for a key press.
5542
If no key yet (Z), LOOP BACK to 5537H to keep waiting.
5544
CP 60H FE 60
Compare the key (register A) against 60H, the code produced while the pause key is held down.
5546
If it is still the pause key (Z), LOOP BACK to 5537H to keep waiting.

Reset Keyboard Flags
This tail is also the routine called at 5204H during entry: it clears the low three status bits of KFLAG$ so a stale BREAK or pause from a previous command does not affect the listing.

5548
LD A,(4423H) 3A 23 44
Load register A from KFLAG$ at 4423H; this is also the entry called at 5204H to reset the flags before listing.
554B
AND 0F8H E6 F8
Clear the low three flag bits (BREAK, pause and related) in register A.
554D
LD (4423H),A 32 23 44
Store the cleared flags (register A) back into KFLAG$ at 4423H.
5550
XOR A AF
Clear register A to zero as a continue/success status.
5551
RET C9
RETurn to resume listing.
5552
LD A,0DH 3E 0D
BREAK path. Load register A with 0DH, a carriage return, to close the current line.
5554
GOSUB to the character-output routine at 54C9H to emit the carriage return.
5557
JUMP to 5592H to abort the listing.

5559H - Five-Digit Decimal Formatter

Renders the value in register pair HL as a right-justified, blank-filled five-digit decimal number into the caller-supplied field, using the resident @DIV service to extract each digit.

5559
LD B,05H 06 05
Five-Digit Decimal Formatter
Load register B with 05H, the width of the decimal field (five digits) to be blank-filled.
555B
LD A,20H 3E 20
Load register A with 20H, an ASCII space.
555D
LD (DE),A 12
Loop Start
Store a space (register A) into the field at (DE).
555E
INC DE 13
INCrement the field pointer (register pair DE).
555F
DECrement register B and LOOP BACK to 555DH until all five positions are blanked.
5561
PUSH DE D5
Save the pointer just past the field (register pair DE).
5562
DEC DE 1B
DECrement register pair DE onto the least-significant digit position.
5563
LD A,0AH 3E 0A
Loop Start
Load register A with 0AH (10), the divisor for extracting the next decimal digit.
5565
GOSUB to the resident @DIV service at 44C4H to divide register pair HL by 10; the remainder (0-9) is returned in register A and the quotient stays in HL.
5568
ADD A,30H C6 30
Add 30H to the remainder (register A) to form an ASCII digit 0-9.
556A
LD (DE),A 12
Store the digit (register A) at (DE).
556B
DEC DE 1B
DECrement the field pointer (register pair DE) to the next-higher digit position.
556C
LD A,H 7C
Load register A with the high byte of the remaining quotient (register H).
556D
OR L B5
OR in the low byte (register L) to test whether the quotient is now zero.
556E
If digits remain (NZ), LOOP BACK to 5563H to extract the next digit.
5570
POP DE D1
Restore the pointer past the field (register pair DE).
5571
RET C9
RETurn with the decimal number right-justified and blank-filled in the field.

5572H - Advance an ASCII Decimal Counter Field

Increments a decimal counter held as ASCII digits in memory, propagating the carry leftward. Entered at 5572H it steps over the five-digit line-number field; entered at 5573H it steps over the four-digit record-number field.

5572
INC HL 23
Advance Decimal Counter
Entered at 5572H for the five-digit line-number field: INCrement register pair HL toward the least-significant digit (four increments in total).
5573
INC HL 23
Entered at 5573H for the four-digit record-number field: INCrement register pair HL (three increments in total).
5574
INC HL 23
INCrement register pair HL toward the least-significant digit.
5575
INC HL 23
INCrement register pair HL onto the least-significant digit of the counter field.
5576
LD A,(HL) 7E
Loop Start
Load register A with the current digit character at (HL).
5577
OR 30H F6 30
Force the character (register A) to at least ASCII 0 in case the position held a blank.
5579
INC A 3C
INCrement the digit (register A) to the next character.
557A
LD (HL),A 77
Store the incremented digit (register A) back at (HL).
557B
SUB 3AH D6 3A
Subtract 3AH (one past ASCII 9) from register A to test for overflow past 9.
557D
RET C D8
If the digit is still 0-9 (CARRY, no overflow), RETurn; the counter is updated.
557E
LD (HL),30H 36 30
Overflow. Store 30H (ASCII 0) at (HL), resetting this digit.
5580
DEC HL 2B
DECrement register pair HL to the next-higher digit position to carry.
5581
LOOP BACK to 5576H to increment the carried digit.

5583H - Error Exits

The error paths. A parameter error is reported through @ERROR; a bad or missing filespec displays the File spec required message through @LOGOT. All paths load the error status and jump to the common exit.

5583
LD A,2CH 3E 2C
Parameter Error
Load register A with 2CH (error code 44, parameter error).
5585
OR 0C0H F6 C0
Set bits 7 and 6 of the error code (register A); bit 7 requests the return-to-caller behaviour and bit 6 the message-only form of the @ERROR display.
5587
GOSUB to the resident @ERROR service at 4409H to display the English text for the error code in register A.
558A
JUMP to 5592H to return the error status to the dispatcher.
558C
LD HL,5598H 21 98 55
File-Spec Error
Point register pair HL at 5598H, the File spec required message text.
558F
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message at (HL).
5592
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero error status for the overlay exit.
5595
JUMP to the overlay exit at 538AH to restore the caller stack and return (or abort if not at command level).

5598H - Data: Message, Display Templates and the Default Extension

The non-executable data at the tail of the overlay: the error message shown for a bad filespec, the line-number and hexadecimal-header display templates that the code fills in and sends to the output device, and the default /TXT extension applied when the filespec omits one.

5598-55AA
DEFM "File spec required!" 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Message displayed by @LOGOT (from 558CH) when the filespec is missing or names a device.
55AB
DEFB 0DH 0D
Carriage return terminating the message for @LOGOT.
55AC-55B0
DEFM " " (5 spaces) 20 20 20 20 20
Five-digit line-number field, blank-filled and overwritten with the decimal line number by the formatter at 5559H when NUM is active.
55B1-55B3
DEFM ". " + ETX 2E 20 03
Trailing period, space and 03H end-marker that follow the line number and terminate the field for @MSG.
55B4-55B7
DEFM " " (4 spaces) 20 20 20 20
Four-digit record-number field aaaa, filled with the record number in hex by 4D76H at 53B0H.
55B8
DEFB ":" 3A
Separator between the record number and the byte offset in the hexadecimal header line.
55B9-55BA
DEFM "XX" 58 58
Two-digit byte-offset field bb, filled with the offset in hex by 4D7BH at 53C0H.
55BB-55BE
DEFM " = " + ETX 20 3D 20 03
Space, equals sign, space and 03H end-marker completing the aaaa:bb = header for @MSG.
55BF-55C1
DEFM "TXT" 54 58 54
Default file extension applied by @FEXT at 5257H when the filespec omits an extension.

55C2H - Data: @PARAM Keyword Descriptor Table

The parameter table consulted by @PARAM at 5217H. Each entry is eight bytes: a six-character space-padded keyword followed by the two-byte (low, high) address of the self-modified operand cell that receives the parsed value. Switch keywords deposit an on/off flag; value keywords deposit a number. A 00H byte terminates the table.

55C2-55C9
DEFM "ASCII8" / DEFW 5333H 41 53 43 49 49 38 33 53
ASCII8 switch. Its flag is stored at 5333H (the LD DE operand at 5332H), which selects whether the high bit of each character is kept rather than stripped.
55CA-55D1
DEFM "A8 " / DEFW 5333H 41 38 20 20 20 20 33 53
Abbreviation A8 for ASCII8; same store cell 5333H.
55D2-55D9
DEFM "C " / DEFW 521EH 43 20 20 20 20 20 1E 52
C (compressed hexadecimal display) switch. Its flag is stored at 521EH (the LD HL operand at 521DH); C=OFF stores 0000H to select the separate two-line hex format.
55DA-55E1
DEFM "HEX " / DEFW 52D5H 48 45 58 20 20 20 D5 52
HEX switch. Its flag is stored at 52D5H (the LD BC operand at 52D4H) and routes the listing to the hexadecimal path at 5399H.
55E2-55E9
DEFM "H " / DEFW 52D5H 48 20 20 20 20 20 D5 52
Abbreviation H for HEX; same store cell 52D5H.
55EA-55F1
DEFM "LRL " / DEFW 53B9H 4C 52 4C 20 20 20 B9 53
LRL (logical record length) value. Stored at 53B9H and used at 5281H to set the record size for the hexadecimal listing.
55F2-55F9
DEFM "L " / DEFW 53B9H 4C 20 20 20 20 20 B9 53
Abbreviation L for LRL; same store cell 53B9H.
55FA-5601
DEFM "LINE " / DEFW 52F0H 4C 49 4E 45 20 20 F0 52
LINE (starting line) value. Stored at 52F0H (the LD BC operand at 52EFH) and used at 52EFH to skip forward that many lines.
5602-5609
DEFM "NUM " / DEFW 531EH 4E 55 4D 20 20 20 1E 53
NUM switch. Its flag is stored at 531EH (the LD BC operand at 531DH) and enables line numbering in ASCII mode.
560A-5611
DEFM "N " / DEFW 54F6H 4E 20 20 20 20 20 F6 54
N (non-stop, the abbreviation of NS) switch. Its flag is stored at 54F6H, the non-stop flag that suppresses page pauses.
5612-5619
DEFM "REC " / DEFW 539AH 52 45 43 20 20 20 9A 53
REC (starting record) value. Stored at 539AH (the LD BC operand at 5399H) and used to position the file for the hexadecimal listing.
561A-5621
DEFM "R " / DEFW 539AH 52 20 20 20 20 20 9A 53
Abbreviation R for REC; same store cell 539AH.
5622-5629
DEFM "P " / DEFW 52B7H 50 20 20 20 20 20 B7 52
P switch. Its flag is stored at 52B7H (the LD BC operand at 52B6H) and directs output to the printer.
562A-5631
DEFM "TAB " / DEFW 5343H 54 41 42 20 20 20 43 53
TAB (tab stop) value. Stored at 5343H and used at 52A2H to set the tab width for ASCII tab expansion.
5632-5639
DEFM "T " / DEFW 5343H 54 20 20 20 20 20 43 53
Abbreviation T for TAB; same store cell 5343H.
563A
DEFB 00H 00
Terminator byte ending the @PARAM keyword table.
563B
DEFB 00H 00
Output column counter (563BH). Incremented in the character-output routine at 54CDH and masked to 0-63 to track the 64-column display position and drive line wrapping; the last byte of the overlay image.

Disassembly - Overlay 9 - RENAME

5200H - RENAME Overlay Entry: Parse filespec1

Entry of the RENAME command overlay (Library A command 9, dispatched by RST 28H code 88H). It saves the caller's stack pointer for the exit and parses the first file specification (the existing file) into the filespec1 buffer with the resident @FSPEC service, rejecting a device specification.

5200
LD (52C2H),SP ED 73 C2 52
Self-Modifying Code
Store the caller's stack pointer (register SP, which on entry holds the LDOS command-level stack) into the operand of the LD SP,nnnn instruction at 52C1H, so the overlay exit can restore the caller's stack.
5204
LD DE,53C4H 11 C4 53
Point register pair DE at 53C4H, the filespec1 buffer that will receive the parsed current file specification.
5207
GOSUB to the resident @FSPEC service at 441CH to parse the filespec at (HL) into the filespec1 buffer at (DE)=53C4H.
520A
If @FSPEC reported an invalid or missing specification (NZ), JUMP to 5354H to display "File spec required!".
520D
LD A,(DE) 1A
Load register A with the first byte of the filespec1 buffer at (DE)=53C4H.
520E
CP 2AH FE 2A
Compare that byte (register A) against 2AH, the ASCII asterisk * that marks a device specification.
5210
If filespec1 names a device (Z), JUMP to 5354H to reject it; this DOS 5 RENAME renames disk files only.

5213H - Parse filespec2 and Apply the Dynamic Defaults

The second specification (the new name) is parsed into the filespec2 buffer. Where filespec2 omits the filename, extension or password, those parts default to filespec1's, matching the manual's dynamic-default rule (for example RENAME TEST/DAT TO REAL yields REAL/DAT). An empty filespec2 raises "Rename it to what?".

5213
LD DE,53A4H 11 A4 53
Point register pair DE at 53A4H, the filespec2 buffer that will receive the new file specification.
5216
GOSUB to the resident @FSPEC service at 441CH to parse the next filespec at (HL) into the filespec2 buffer at (DE)=53A4H.
5219
If @FSPEC parsed filespec2 successfully (Z), JUMP to 5221H.
521B
LD A,(HL) 7E
@FSPEC stopped early. Load register A with the character at (HL) where it stopped.
521C
CP 0DH FE 0D
Compare register A against 0DH, an ASCII carriage return (the end of the command line).
521E
If the stopping character is not a carriage return (NZ), GOSUB to 52D3H to copy the intervening word (for example the optional TO) into the filespec2 buffer.
5221
LD A,(53A4H) 3A A4 53
Load register A with the first byte of the filespec2 buffer at 53A4H.
5224
CP 0EH FE 0E
Compare register A against 0EH; a value below 0EH means the buffer holds no new specification.
5226
If filespec2 is empty (CARRY), JUMP to 5358H to display "Rename it to what?".
5229
LD HL,53C4H 21 C4 53
Point register pair HL at 53C4H, the filespec1 buffer, as the default source for the merge.
522C
LD DE,53A4H 11 A4 53
Point register pair DE at 53A4H, the filespec2 buffer, as the merge destination.
522F
GOSUB to 52F0H to apply the dynamic defaults, filling any filename, extension or password that filespec2 omitted from filespec1.
5232
LD DE,53C4H 11 C4 53
Point register pair DE at 53C4H, the filespec1 buffer, for the open that follows.

5235H - Open filespec1 and Check Access

filespec1 is opened to confirm it exists and to obtain its directory location, and its access level is checked so a protected file cannot be renamed.

5235
GOSUB to the resident @OPEN service at 4424H to open the existing file described by the filespec1 buffer at (DE), confirming it exists and locating its directory entry.
5238
If the open failed (NZ), JUMP to 534DH to report the returned error code through @ERROR.
523B
LD A,(53C5H) 3A C5 53
Load register A with the access-level byte at 53C5H (filespec1 buffer offset 1).
523E
AND 07H E6 07
Mask register A to its low three bits, the access-level field.
5240
CP 03H FE 03
Compare the access level (register A) against 03H; level 3 or higher denotes a protected file that may not be renamed.
5242
LD A,25H 3E 25
Load register A with 25H (error code, illegal access to a protected file) ready for the error path; this load does not disturb the compare result.
5244
If the access level is 3 or higher (NO CARRY, protected), JUMP to 534DH to report the access error through @ERROR.

5247H - Require filespec2 to Match the filespec1 Drive

The drive of filespec2 must equal that of filespec1. The buffer is scanned for a drivespec: if present it is compared, and a mismatch aborts; if absent, filespec1's drive is inserted.

5247
LD HL,53A4H 21 A4 53
Point register pair HL at 53A4H, the filespec2 buffer, to scan for a drive specification.
524A
LD A,(HL) 7E
Loop Start
Load register A with the next filespec2 character at (HL) and advance the pointer.
524B
INC HL 23
INCrement the filespec2 pointer (register pair HL).
524C
CP 0DH FE 0D
Compare register A against 0DH, an ASCII carriage return (end of the specification).
524E
If the end was reached without a drive (Z), JUMP to 5263H to insert filespec1's drive.
5250
CP 03H FE 03
Compare register A against 03H, an ETX end marker.
5252
If the end was reached without a drive (Z), JUMP to 5263H to insert filespec1's drive.
5254
CP 3AH FE 3A
Compare register A against 3AH, the ASCII colon that introduces a drivespec.
5256
If this character is not a colon (NZ), LOOP BACK to 524AH to keep scanning.
5258
LD A,(53CAH) 3A CA 53
A drivespec was found. Load register A with filespec1's drive number from 53CAH (filespec1 buffer offset 6).
525B
XOR (HL) AE
XOR the filespec2 drive digit at (HL) into register A; the low three bits become zero only when the two drives match.
525C
AND 07H E6 07
Mask register A to its low three bits, the drive-number field.
525E
If the drives differ (NZ), JUMP to 534BH to report an illegal-drive error.
5261
The drives match. JUMP to 5272H to continue.
5263
DEC HL 2B
No drivespec in filespec2. DECrement register pair HL back onto the terminator character.
5264
LD (HL),3AH 36 3A
Store 3AH (an ASCII colon) at (HL), starting an inserted drivespec.
5266
INC HL 23
INCrement the filespec2 pointer (register pair HL).
5267
LD A,(53CAH) 3A CA 53
Load register A with filespec1's drive number from 53CAH (filespec1 buffer offset 6).
526A
AND 07H E6 07
Mask register A to its low three bits, the drive number.
526C
ADD A,30H C6 30
Add 30H to register A to form the ASCII drive digit.
526E
LD (HL),A 77
Store the drive digit (register A) at (HL), completing the inserted drivespec.
526F
INC HL 23
INCrement the filespec2 pointer (register pair HL).
5270
LD (HL),0DH 36 0D
Store 0DH (an ASCII carriage return) at (HL) to terminate the filespec2 buffer.

5272H - Reject a Duplicate: filespec2 Must Not Already Exist

filespec2 is opened; it is expected to fail with file-not-found. If it opens successfully the new name already exists and "Duplicate file name!" is issued.

5272
LD A,(51E1H) 3A E1 51
Load register A from 51E1H, the one-byte name-hash cell in the SYS2/SYS work area, which holds the Hash Index Table hash of filespec1 left there by the open at 5235H. The duplicate-check open below replaces it with filespec2's hash, so it is saved here and put back at 5285H.
5275
PUSH AF F5
Save register pair AF, holding filespec1's name-hash byte just read from 51E1H, on the stack across the open.
5276
LD DE,53A4H 11 A4 53
Point register pair DE at 53A4H, the filespec2 buffer, for the duplicate check.
5279
GOSUB to the resident @OPEN service at 4424H to try to open filespec2; success means the new name already exists.
527C
If filespec2 opened successfully (Z, the file exists), JUMP to 535CH to display "Duplicate file name!".
527F
CP 18H FE 18
Compare the open error (register A) against 18H (error 24, file not in directory), the expected result.
5281
If the error was anything other than file-not-found (NZ), JUMP to 534DH to report it through @ERROR.
5284
POP AF F1
Restore register pair AF, recovering filespec1's name-hash byte saved at 5275H before the duplicate-check open.
5285
LD (51E1H),A 32 E1 51
Store filespec1's name-hash byte from register A back into 51E1H, the SYS2/SYS name-hash cell, so that it again describes the file being renamed rather than filespec2. The eleven-byte packed name at 51EAH is deliberately left as the open above set it, holding the NEW name.

5288H - Rewrite the Directory Entry with the New Name

The directory record of filespec1 is read, its eleven-byte name and extension field is overwritten with the new name, and the record is written back. The new name is taken from 51EAH, the packed name work area belonging to SYS2/SYS: the duplicate-check open at 5279H loaded SYS2/SYS at 4E00H and left filespec2's name packed there when it failed to find the file, which is exactly the form the directory field needs.

5288
LD BC,(53CAH) ED 4B CA 53
Load register pair BC from 53CAH: register C = filespec1's drive (offset 6), register B = its directory entry code (offset 7).
528C
PUSH BC C5
Save the drive and directory entry code (register pair BC) for the directory write.
528D
GOSUB to the resident DIRRD service at 4B10H to read filespec1's directory record (register B = entry code, register C = drive).
5290
If the directory read failed (NZ), JUMP to 534DH to report the error through @ERROR.
5293
LD D,H 54
Copy register H into register D, beginning to build a pointer to the directory entry's name field.
5294
LD A,L 7D
Load register A with the low byte of the directory buffer pointer (register L).
5295
ADD A,05H C6 05
Add 05H to register A to index offset 5 of the directory entry, the eleven-byte name and extension field.
5297
LD E,A 5F
Move the low byte (register A) into register E, so register pair DE now points at the name field.
5298
LD HL,51EAH 21 EA 51
Point register pair HL at 51EAH, the eleven-byte packed name and extension work area inside the SYS2/SYS image, which holds filespec2 - the new name - as the duplicate-check open at 5279H left it.
529B
LD BC,000BH 01 0B 00
Load register pair BC with 000BH (11), the length of the name and extension field.
529E
LDIR ED B0
Block-copy 11 bytes (register pair BC) from the new name at (HL)=51EAH into the directory entry name field at (DE), performing the rename.
52A0
POP BC C1
Restore the drive and directory entry code (register pair BC) for the directory write.
52A1
GOSUB to the resident DIRWR service at 4B1FH to write the updated directory record back (register B = entry code, register C = drive).
52A4
If the directory write failed (NZ), JUMP to 534DH to report the error through @ERROR.

52A7H - Update the Hash Index Table

Renaming changes the file's name hash, so its Hash Index Table byte must be changed to match. RENAME does that work itself, using two entry points in the SYS2/SYS image that is still resident beneath this overlay after the duplicate-check open: 51BDH reads the Hash Index Table sector into the shared buffer at 4200H and 51BEH writes it back. The new hash byte in between comes from the filename-hash service, which is reached as RST 28H request code 0D4H through the trampoline at 52D0H.

52A7
GOSUB to 51BDH in the resident SYS2/SYS image, which reads sector 1 of the directory cylinder of the drive in register C, the Hash Index Table, into the shared buffer SBUFF$ at 4200H. It returns register pair HL addressing 4200H with registers B and C untouched, or NZ with error 22 in register A.
52AA
If the helper reported an error (NZ), JUMP to 534DH to report it through @ERROR.
52AD
LD D,H 54
Copy register H, which the read at 52A7H left holding 42H, into register D as the high byte of a pointer into the Hash Index Table image at 4200H.
52AE
LD E,B 58
Copy register B, filespec1's directory entry code, into register E. The Hash Index Table holds one byte per directory record indexed by that code, so register pair DE now addresses this file's hash byte inside the buffer at 4200H.
52AF
PUSH BC C5
Save register pair BC for after the service call.
52B0
LD HL,51EAH 21 EA 51
Point register pair HL at 51EAH, the eleven-byte packed name work area in the SYS2/SYS image holding the new name, which is the input the filename-hash service expects.
52B3
GOSUB to 52D0H to issue RST 28H request code 0D4H, the filename-hash service, which folds the eleven packed name characters at (HL) into the one-byte Hash Index Table hash and returns it in register A.
52B6
POP BC C1
Restore register pair BC saved before the service call.
52B7
LD (DE),A 12
Store the new hash byte from register A at (DE), this file's slot in the Hash Index Table image held in the buffer at 4200H.
52B8
GOSUB to 51BEH in the resident SYS2/SYS image, one byte past the read entry used at 52A7H, which writes the amended Hash Index Table buffer at 4200H back to sector 1 of the directory cylinder with a deleted-data address mark and verifies it, returning NZ with error 23 if the write fails.
52BB
If the helper reported an error (NZ), JUMP to 534DH to report it through @ERROR.

52BEH - Overlay Exit and Command-Level Check

Common exit. Register pair HL carries the status word (0000H success, 0FFFFH error). The caller's stack is restored from the operand patched at entry; a clean status returns to the RST 28H dispatcher, an error aborts through @ABORT when not at the LDOS command level.

52BE
LD HL,0000H 21 00 00
Load register pair HL with 0000H, the success status returned to the RST 28H dispatcher.
52C1
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 52C2H, patched at entry (5200H) with the caller's SP; register SP now addresses the LDOS command-level stack.
52C4
LD A,H 7C
Load register A with the high byte of the status word (register H).
52C5
OR L B5
OR in the low byte (register L); Z means clean completion, non-zero means an error status is being returned.
52C6
RET Z C8
If the status is zero (Z, success), RETurn to the RST 28H overlay dispatcher.
52C7
LD A,(430FH) 3A 0F 43
Error status. Load register A from the resident system flag byte SFLAG$ at 430FH.
52CA
BIT 5,A CB 6F
Test bit 5 of register A, which is set when execution is not at the LDOS command level.
52CC
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher, which handles the error.
52CD
Not at command level. JUMP to the resident @ABORT vector at 4030H to abort the running job.

52D0H - Filename-Hash Service Trampoline (RST 28H Code 0D4H)

A three-byte trampoline that loads the rename-service request code and issues RST 28H. The resident dispatcher discards the RST's own return address, so control resumes at the caller of this routine.

RST 28H Return Convention
The resident RST 28H dispatcher discards the return address the RST instruction pushes, so after the 0D4H service completes control returns to the instruction after CALL 52D0H, not to 52D3H.

52D0
LD A,0D4H 3E D4
Load register A with 0D4H, the request code for the filename-hash service. The supervisor masks it with 70H to sub-function 50H and it is serviced by SYS2/SYS, which is already resident from the opens above.
52D2
RST 28H EF
Issue the supervisor call. The dispatcher hashes the eleven packed name characters addressed by register pair HL, returns the one-byte result in register A and also leaves it in the name-hash cell at 51E1H, then returns to the caller of 52D0H.

52D3H - Helper: Copy a Blank-Delimited Word

Copies the next blank-delimited word from the source at (HL) into the buffer at (DE), folding lowercase letters to uppercase and stopping at a carriage return or an open parenthesis. Used to absorb the optional TO word when @FSPEC could not parse filespec2 directly.

52D3
DEC HL 2B
DECrement register pair HL to re-examine the previous source character.
52D4
LD A,(HL) 7E
Loop Start
Load register A with the source character at (HL).
52D5
INC HL 23
INCrement the source pointer (register pair HL).
52D6
CP 20H FE 20
Compare register A against 20H, an ASCII space.
52D8
If the character is a space (Z), LOOP BACK to 52D4H to skip leading blanks.
52DA
DEC HL 2B
A non-blank was found. DECrement register pair HL back onto it.
52DB
LD B,20H 06 20
Load register B with 20H (32), the maximum length of the word to copy.
52DD
LD A,(HL) 7E
Loop Start
Load register A with the current source character at (HL).
52DE
CP 61H FE 61
Compare register A against 61H, ASCII lowercase a.
52E0
If the character is below lowercase a (CARRY, already uppercase or a symbol), JUMP to 52E4H to store it as-is.
52E2
SUB 20H D6 20
Otherwise SUBtract 20H from register A to fold the lowercase letter to uppercase.
52E4
LD (DE),A 12
Store the character (register A) into the destination at (DE).
52E5
CP 0DH FE 0D
Compare register A against 0DH, an ASCII carriage return.
52E7
RET Z C8
If a carriage return was reached (Z), RETurn; the word is complete.
52E8
CP 28H FE 28
Compare register A against 28H, an ASCII open parenthesis (the start of a parameter list).
52EA
RET Z C8
If an open parenthesis was reached (Z), RETurn; the word is complete.
52EB
INC HL 23
INCrement the source pointer (register pair HL).
52EC
INC DE 13
INCrement the destination pointer (register pair DE).
52ED
DECrement register B and LOOP BACK to 52DDH until the word ends or 32 characters have been copied.
52EF
RET C9
RETurn to the caller of the word-copy helper.

52F0H - Helper: Apply filespec1 Defaults to filespec2

Drives the dynamic-default merge: if filespec2 has no filename it takes filespec1's, and the extension (introduced by /) and password (introduced by .) each default to filespec1's when filespec2 omits them.

52F0
PUSH DE D5
Save the filespec2 destination pointer (register pair DE) for restoration on return.
52F1
LD A,(DE) 1A
Load register A with the first character of filespec2 at (DE).
52F2
CP 41H FE 41
Compare register A against 41H, ASCII A; a first character below A means filespec2 supplied no filename.
52F4
If filespec2 has no filename (CARRY), GOSUB to 532BH to splice in filespec1's filename.
52F7
LD B,2FH 06 2F
Load register B with 2FH, the ASCII slash that introduces the extension field.
52F9
GOSUB to 5304H to default the extension from filespec1 when filespec2 omits a slash.
52FC
LD B,2EH 06 2E
Load register B with 2EH, the ASCII period that introduces the password field.
52FE
GOSUB to 5304H to default the password from filespec1 when filespec2 omits a period.
5301
POP DE D1
Restore the filespec2 destination pointer (register pair DE).
5302
RET C9
RETurn to the caller of the default-merge helper.

5303H - Helper: Scan filespec2 Past a Field Delimiter

Advances through filespec2 while the characters are letters or digits, looking for the delimiter passed in register B; if the delimiter is found it is stepped over, otherwise control passes to the field-locator for filespec1.

5303
INC DE 13
INCrement the filespec2 pointer (register pair DE) to the next character.
5304
LD A,(DE) 1A
Loop Start
Load register A with the current filespec2 character at (DE).
5305
CP B B8
Compare register A against the delimiter in register B (a slash or a period).
5306
If the delimiter is present (Z), JUMP to 5316H to step over it (filespec2 already has this field).
5308
CP 41H FE 41
Compare register A against 41H, ASCII A.
530A
If the character is a letter (NO CARRY, 41H or above), LOOP BACK to 5303H to keep scanning.
530C
CP 30H FE 30
Compare register A against 30H, ASCII 0.
530E
If the character is below 0 (CARRY, end of the specification), JUMP to 5318H; the field is missing from filespec2.
5310
CP 3AH FE 3A
Compare register A against 3AH, one past ASCII 9.
5312
If the character is a digit (CARRY, 30H-39H), LOOP BACK to 5303H to keep scanning.
5314
Otherwise JUMP to 5318H; the delimiter is missing from filespec2 so the default must be applied.
5316
INC DE 13
The delimiter was found. INCrement register pair DE past it.
5317
RET C9
RETurn to the merge driver.

5318H - Helper: Locate the Matching Field in filespec1

Scans filespec1 for the same delimiter (register B); if found, the field is spliced into filespec2 so the default is applied.

5318
PUSH HL E5
Save the filespec1 source pointer (register pair HL).
5319
LD A,(HL) 7E
Loop Start
Load register A with the current filespec1 character at (HL) and advance.
531A
INC HL 23
INCrement the filespec1 pointer (register pair HL).
531B
CP 03H FE 03
Compare register A against 03H, an ETX end marker.
531D
If the end of filespec1 was reached (Z), JUMP to 5329H; there is no field to copy.
531F
CP 0DH FE 0D
Compare register A against 0DH, an ASCII carriage return.
5321
If the end of filespec1 was reached (Z), JUMP to 5329H; there is no field to copy.
5323
CP B B8
Compare register A against the delimiter in register B (a slash or a period).
5324
If this is not the delimiter (NZ), LOOP BACK to 5319H to keep scanning filespec1.
5326
The delimiter was found in filespec1. GOSUB to 5337H to splice that field into filespec2.
5329
POP HL E1
Restore the filespec1 source pointer (register pair HL).
532A
RET C9
RETurn to the merge driver.

532BH - Helper: Splice a filespec1 Field into filespec2

Copies the filename or default field character by character from filespec1 into filespec2, shifting the existing filespec2 characters to make room.

532B
LD A,(HL) 7E
Load register A with the current filespec1 character at (HL).
532C
CP 30H FE 30
Compare register A against 30H, ASCII 0.
532E
RET C D8
If the character is below 0 (CARRY, a delimiter or the end), RETurn; the field is complete.
532F
CP 3AH FE 3A
Compare register A against 3AH, one past ASCII 9.
5331
If the character is a digit (CARRY), JUMP to 5336H to copy it.
5333
CP 41H FE 41
Compare register A against 41H, ASCII A.
5335
RET C D8
If the character is below A (CARRY, a symbol between the digits and letters), RETurn; the field is complete.
5336
INC HL 23
INCrement the filespec1 pointer (register pair HL) past the character being copied.
5337
PUSH HL E5
Save the filespec1 source pointer (register pair HL) while filespec2 is edited.
5338
LD H,D 62
Copy register D into register H, forming the high byte of the filespec2 pointer.
5339
LD L,E 6B
Copy register E into register L, so register pair HL now addresses the current filespec2 position.
533A
LD C,(HL) 4E
Loop Start
Load register C with the filespec2 character at (HL) that is about to be displaced.
533B
LD (HL),A 77
Store the incoming character (register A) at (HL), overwriting that position.
533C
INC HL 23
INCrement the filespec2 pointer (register pair HL).
533D
LD A,C 79
Move the displaced character (register C) into register A to carry it one place along.
533E
CP 03H FE 03
Compare register A against 03H, an ETX end marker.
5340
If the end of filespec2 was reached (Z), JUMP to 5346H to store the terminator.
5342
CP 0DH FE 0D
Compare register A against 0DH, an ASCII carriage return.
5344
If the end was not reached (NZ), LOOP BACK to 533AH to shift the next character along.
5346
LD (HL),A 77
Store the final displaced character (register A) at (HL), completing the insertion.
5347
POP HL E1
Restore the filespec1 source pointer (register pair HL).
5348
INC DE 13
INCrement the filespec2 destination pointer (register pair DE) to the next inserted position.
5349
LOOP BACK to 532BH to copy the next character of the field.

534BH - Error Exits

The error paths. A drive mismatch, an access failure and the various service errors are reported through @ERROR; the three message paths ("File spec required!", "Rename it to what?", "Duplicate file name!") are displayed through @LOGOT. All load the error status and jump to the common exit.

534B
LD A,20H 3E 20
Drive mismatch. Load register A with 20H (error code 32, illegal drive number).
534D
OR 0C0H F6 C0
Set bits 7 and 6 of the error code (register A); bit 7 requests the return-to-caller behaviour and bit 6 the message-only form of the @ERROR display.
534F
GOSUB to the resident @ERROR service at 4409H to display the English text for the error code in register A.
5352
JUMP to 5362H to return the error status to the dispatcher.
5354
LD HL,5368H 21 68 53
Point register pair HL at 5368H, the "File spec required!" message text.

Overlap
By fall-through this loads register pair IX with 537CH (unused). Entered at 5358H (from 5226H) the DD prefix is skipped and the bytes 21 7C 53 read as LD HL,537CH, selecting the "Rename it to what?" message. The anchor for 5358H resolves to this 5357H row.

5357
LD IX,537CH DD 21 7C 53
By fall-through this loads register pair IX with 537CH (unused); entered at 5358H it reads as LD HL,537CH, selecting the "Rename it to what?" message.

Overlap
By fall-through this loads register pair IX with 538FH (unused). Entered at 535CH (from 527CH) the DD prefix is skipped and the bytes 21 8F 53 read as LD HL,538FH, selecting the "Duplicate file name!" message. The anchor for 535CH resolves to this 535BH row.

535B
LD IX,538FH DD 21 8F 53
By fall-through this loads register pair IX with 538FH (unused); entered at 535CH it reads as LD HL,538FH, selecting the "Duplicate file name!" message.
535F
GOSUB to the resident @LOGOT service at 447BH to display the carriage-return-terminated message at (HL).
5362
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero error status for the overlay exit.
5365
JUMP to the overlay exit at 52C1H to restore the caller stack and return (or abort if not at command level).

5368H - Data: RENAME Messages

The three carriage-return-terminated messages displayed through @LOGOT by the error paths. The disassembler renders this region as bogus instructions; it is decoded here straight from the SYS6.SYS binary.

5368-537A
DEFM "File spec required!" 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Displayed by @LOGOT (from 5354H) when a specification is missing or names a device.
537B
DEFB 0DH 0D
Carriage return terminating the message.
537C-538D
DEFM "Rename it to what?" 52 65 6E 61 6D 65 20 69 74 20 74 6F 20 77 68 61 74 3F
Displayed by @LOGOT (from 5358H) when filespec2 is empty.
538E
DEFB 0DH 0D
Carriage return terminating the message.
538F-53A2
DEFM "Duplicate file name!" 44 75 70 6C 69 63 61 74 65 20 66 69 6C 65 20 6E 61 6D 65 21
Displayed by @LOGOT (from 535CH) when the new name already exists.
53A3-53A4
DEFB 0DH,0DH 0D 0D
Two carriage returns terminating the message; the last byte of the overlay image.

Disassembly - Overlay 10 - SYSTEM (status/drives)

5200H - Overlay Entry, @PARAM Option Parse and Section Dispatch

Entry of the SYSTEM command overlay, which reports the system configuration. It saves the caller's stack, parses the keyword options with the resident @PARAM service (DRIVES/D, BYTEIO/B, STATUS/S, plus the N nonstop and P printer modifiers), clears the keyboard flags, and dispatches to whichever of the three display sections were requested.

5200
LD (551AH),SP ED 73 1A 55
Self-Modifying Code
Store the caller's stack pointer (register SP, which on entry holds the LDOS command-level stack) into the operand of the LD SP,nnnn instruction at 5519H, so the overlay exit at 5519H can restore this exact stack.
5204
LD DE,569FH 11 9F 56
Point register pair DE at 569FH, the local @PARAM keyword descriptor table (keywords BYTEIO/B, DRIVES/D, N, P, STATUS/S) that follows the code.
5207
CALL 4476H CD 76 44
GOSUB to the resident @PARAM service at 4476H to scan the command tail and, for each keyword found, patch its associated flag cell; it returns NZ on a syntax error.
520A
JP NZ,559DH C2 9D 55
If @PARAM reported a syntax error (NZ), JUMP to 559DH to issue a parameter error (error code 2CH).
520D
LD HL,(553BH) 2A 3B 55
Load register pair HL with the printer-echo flag word from 553BH (the operand of the LD DE,0000H at 553AH); it is non-zero when the P keyword requested that all output also go to the printer.
5210
LD (554CH),HL 22 4C 55
Store the printer-echo flag (register pair HL) into 554CH, the operand of the LD DE,0000H at 554BH, so the pause routine at 5542H shares the same setting.
5213
CALL 558CH CD 8C 55
GOSUB to the local helper at 558CH to clear the low three bits (BREAK, pause, key-pending) of the resident keyboard flag KFLAG$ at 4423H before display begins.
5216
EI FB
Enable maskable interrupts so the real-time clock keeps running while the report is displayed.
5217
LD HL,0FFFFH 21 FF FF
Self-Modifying Code
Load register pair HL with the DRIVES-option flag from the operand cell at 5218H; @PARAM sets this cell non-zero when the DRIVES (or D) keyword is present, and leaves it 0000H otherwise.
521A
LD A,H 7C
Load register A with register H, the high byte of the DRIVES-option flag just read from 5218H, to test the 16-bit value for zero.
521B
OR L B5
OR register A with register L, the low byte of the DRIVES-option flag from 5218H; register A is now zero only if the whole flag word is 0000H.
521C
JP Z,5365H CA 65 53
If the DRIVES flag is zero (Z, the keyword was not given), JUMP to 5365H to skip the per-drive geometry display.

521FH - DRIVES Option: Per-Drive Loop Head, Drive-Table Check and Disk-Name Field

For each of the eight logical drives, fetches the Drive Code Table (DCT) entry, skips drives that are not configured, reads the disk name from the drive's Granule Allocation Table (GAT) sector (or substitutes No Disk when the drive is not ready), and begins the drive line with the drive number, write-protect indicator and bracketed disk name.

521F
LD C,00H 0E 00
Load register C with 00H, the logical drive number that begins the per-drive scan (drives 0 through 7).
5221
PUSH BC C5
Main Loop
Save register pair BC (register C = the current logical drive number 0-7) on the stack across the GETDCT call and the display work.
5222
XOR A AF
Set register A to zero and clear the flags, ready to seed the drive-status byte at 5270H.
5223
LD (5270H),A 32 70 52
Self-Modifying Code
Store the zero in register A into 5270H, the operand of the LD A,nn at 526FH; this byte accumulates the drive-ready/write-protect status used later at 526FH.
5226
CALL 478FH CD 8F 47
GOSUB to the resident GETDCT service at 478FH, which points register IY at the Drive Code Table (DCT) entry for the logical drive in register C.
5229
LD A,(IY+00H) FD 7E 00
Load register A with the first byte of this drive's DCT entry at IY+00H; an enabled drive begins with 0C3H (a Z80 JP opcode to its driver).
522C
CP 0C3H FE C3
Compare register A (the DCT entry's first byte) against 0C3H, the JP opcode that marks a configured, enabled drive.
522E
JP NZ,535DH C2 5D 53
If register A is not 0C3H (NZ, the drive slot is empty or disabled), JUMP to 535DH to advance to the next drive without printing a line.
5231
CALL 44B8H CD B8 44
GOSUB to the resident @CKDRV service at 44B8H to test whether the drive selected in register C is physically ready; it returns NZ (and the status in register A) when the drive is not ready.
5234
If @CKDRV reported the drive not ready (NZ), JUMP to 5257H to substitute the No Disk placeholder name.
5236
RRA 1F
Rotate register A right through carry; register A holds the @CKDRV status, and this shifts its low ready/protect bit into position for the status byte.
5237
LD (5270H),A 32 70 52
Self-Modifying Code
Store the rotated status (register A) into 5270H, the operand of the LD A,nn at 526FH, so the write-protect indicator built at 526FH reflects this drive's status.
523A
LD HL,4200H 21 00 42
Point register pair HL at 4200H, SBUFF$, the resident shared sector buffer that will receive the drive's Granule Allocation Table (GAT) sector (whose bytes 42D0H-42D7H hold the disk name).
523D
LD D,(IY+09H) FD 56 09
Load register D with the directory cylinder number from this drive's DCT at IY+09H; it selects the track whose GAT sector is read.
5240
LD E,L 5D
Load register E with register L (00H, the low byte of the 4200H buffer address), which also serves as sector number 0 for the read.
5241
CALL 4B45H CD 45 4B
GOSUB to the resident RDSSEC service at 4B45H to read GAT sector 0 of the directory cylinder (register D) into the buffer at 4200H (register pair HL); it returns NZ on a read error.
5244
LD A,14H 3E 14
Load register A with 14H, the LDOS error code for a GAT read error, in case the read just attempted failed.
5246
JP NZ,559FH C2 9F 55
If RDSSEC reported an error (NZ), JUMP to 559FH to report the GAT read error (code 14H) through @ERROR.
5249
LD L,0D8H 2E D8
Load register L with 0D8H so register pair HL addresses 42D8H (the byte just past the 8-character disk name in the GAT buffer).
524B
LD (HL),5DH 36 5D
Store 5DH (the ] character) at (HL) = 42D8H, closing the [diskname] bracket after the 8-character name.
524D
INC L 2C
INCrement register L so register pair HL addresses 42D9H.
524E
LD (HL),20H 36 20
Store 20H (a space) at (HL) = 42D9H, separating the disk name from the fields that follow.
5250
INC L 2C
INCrement register L so register pair HL addresses 42DAH.
5251
LD (HL),03H 36 03
Store 03H (the display terminator) at (HL) = 42DAH so the @DSPLY of the name field stops here.
5253
LD L,0D0H 2E D0
Load register L with 0D0H so register pair HL addresses 42D0H, the start of the disk-name field, ready to display it.
5255
JR 5262H 18 0B
JUMP to 5262H to continue building the drive line with the real disk name in place.
5257
LD HL,55AAH 21 AA 55
Point register pair HL at 55AAH, the 12-byte No Disk template used when the drive is not ready.
525A
LD DE,42D0H 11 D0 42
Point register pair DE at 42D0H, the disk-name field in the buffer, the destination for the template.
525D
LD BC,000CH 01 0C 00
Load register pair BC with 000CH (12), the length of the No Disk template.
5260
LDIR ED B0
Block-copy the 12-byte template from (HL)=55AAH to (DE)=42D0H (register pair BC = count), filling the disk-name field with No Disk], its terminator and a trailing space.
5262
LD A,3AH 3E 3A
Load register A with 3AH, the : character that separates the drive number from the rest of the line.
5264
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the colon (register A) to the screen (and to the printer when the P option is active).
5267
POP BC C1
Restore register pair BC from the stack so register C again holds the current logical drive number.
5268
PUSH BC C5
Re-save register pair BC on the stack, keeping the drive number available for the rest of the line.
5269
LD A,C 79
Load register A with register C, the current logical drive number (0-7).
526A
ADD A,30H C6 30
ADD 30H to register A, converting the drive number to its ASCII digit 0 through 7.
526C
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the drive-number digit (register A).
526F
LD A,00H 3E 00
Self-Modifying Code
Load register A from the operand at 5270H, the drive-ready/write-protect status byte stored at entry by 5223H/5237H.
5271
OR (IY+03H) FD B6 03
OR register A with this drive's DCT flag byte at IY+03H, merging the status bit with the drive's configuration flags to decide the write-protect indicator.
5274
RLCA 07
Rotate register A left; the combined status/flag bit now sitting in the high position moves into the carry flag.
5275
LD A,20H 3E 20
Load register A with 20H (a space), the first character of a blank (not-protected) indicator.
5277
LD B,20H 06 20
Load register B with 20H (a space), the second character of the blank indicator.
5279
If the carry is clear (NO CARRY, the drive is writable), JUMP to 527FH to print the two spaces.
527B
LD A,57H 3E 57
Otherwise load register A with 57H (the W character), the first character of the WP write-protect indicator.
527D
LD B,50H 06 50
Load register B with 50H (the P character), the second character of the WP indicator.
527F
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the first indicator character (register A).
5282
LD A,B 78
Load register A with register B, the second indicator character (space or P).
5283
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the second indicator character (register A).
5286
LD A,20H 3E 20
Load register A with 20H (a space) to separate the indicator from the disk name.
5288
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the space (register A).
528B
LD A,5BH 3E 5B
Load register A with 5BH (the [ character) opening the [diskname] display.
528D
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the opening bracket (register A).
5290
LD HL,42D0H 21 D0 42
Point register pair HL at 42D0H, the disk-name field in the buffer (either the GAT disk name plus ] or the No Disk template).
5293
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the name field at (HL) up to its 03H terminator.

5296H - DRIVES Option: Disk Size, Drive Type, Cylinders, Density, Sides, Step and Settle

Completes the per-drive line from the DCT flag and configuration bytes: the drive size in inches, the Floppy or Rigid type and physical unit number, the cylinder count, and then either the removable/fixed status (rigid) or the density, side count, step rate and head-settle delay (floppy).

5296
BIT 5,(IY+03H) FD CB 03 6E
Test bit 5 of this drive's DCT flag byte at IY+03H, which is set for an 8-inch drive and clear for a 5.25-inch drive.
529A
LD A,35H 3E 35
Load register A with 35H (the 5 character) for a 5.25-inch drive.
529C
If bit 5 was clear (Z, 5.25-inch), JUMP to 52A0H keeping the 5 in register A.
529E
LD A,38H 3E 38
Otherwise load register A with 38H (the 8 character) for an 8-inch drive.
52A0
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the drive-size digit (register A).
52A3
BIT 3,(IY+03H) FD CB 03 5E
Test bit 3 of this drive's DCT flag byte at IY+03H, which is set for a rigid (hard) drive and clear for a floppy drive.
52A7
LD HL,561CH 21 1C 56
Point register pair HL at 561CH, the string " Floppy #", ready to use for a floppy drive.
52AA
If bit 3 was clear (Z, a floppy drive), JUMP to 52AFH keeping the Floppy string in register pair HL.
52AC
LD HL,5627H 21 27 56
Otherwise point register pair HL at 5627H, the string " Rigid #", for a rigid drive.
52AF
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the drive-type string at (HL).
52B2
LD A,(IY+04H) FD 7E 04
Load register A with this drive's DCT configuration byte at IY+04H, whose low nibble holds the physical drive/unit number.
52B5
AND 0FH E6 0F
AND register A with 0FH to isolate the low nibble (the physical drive/unit number 0-15) of the DCT byte.
52B7
ADD A,90H C6 90
ADD 90H to register A, the first step of the classic add-90 / DAA / add-40 / DAA sequence that converts a 0-9 value to its ASCII digit.
52B9
DAA 27
Decimal-adjust register A (DAA) as the second step of the digit conversion.
52BA
ADC A,40H CE 40
ADD 40H to register A with carry (ADC), the third step of the digit conversion.
52BC
DAA 27
Decimal-adjust register A (DAA) again, completing the conversion of the physical unit number to its ASCII character.
52BD
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the physical drive-number character (register A) after the #.
52C0
LD L,(IY+06H) FD 6E 06
Load register L with this drive's highest cylinder number from the DCT at IY+06H.
52C3
LD H,00H 26 00
Load register H with 00H so register pair HL holds the cylinder value as a 16-bit number.
52C5
INC HL 23
INCrement register pair HL so it holds the cylinder count (highest cylinder number plus one).
52C6
BIT 3,(IY+03H) FD CB 03 5E
Test bit 3 of the DCT flag byte at IY+03H (set for a rigid drive) to decide whether the cylinder count must be doubled.
52CA
If bit 3 is clear (Z, a floppy drive), JUMP to 52D3H leaving the cylinder count unchanged.
52CC
BIT 5,(IY+04H) FD CB 04 6E
Test bit 5 of this drive's DCT configuration byte at IY+04H, which marks a double-sided rigid drive whose cylinder count is stored per surface.
52D0
If bit 5 is clear (Z, single surface), JUMP to 52D3H leaving the cylinder count unchanged.
52D2
ADD HL,HL 29
ADD register pair HL to itself, doubling the cylinder count for a double-sided rigid drive.
52D3
LD DE,5637H 11 37 56
Point register pair DE at 5637H, the four-space numeric field inside the " Cyl= " string, the destination for the cylinder count.
52D6
CALL 541BH CD 1B 54
GOSUB to the decimal formatter at 541BH to write the cylinder count (register pair HL) as up to three ASCII digits into the field at (DE).
52D9
LD HL,5632H 21 32 56
Point register pair HL at 5632H, the " Cyl=nnn" string now holding the formatted cylinder count.
52DC
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the " Cyl=" field at (HL).
52DF
BIT 3,(IY+03H) FD CB 03 5E
Test bit 3 of the DCT flag byte at IY+03H again, to branch between the rigid-drive fields and the floppy-drive fields.
52E3
If bit 3 is clear (Z, a floppy drive), JUMP to 52F6H to print the floppy density, side and step fields.
52E5
BIT 2,(IY+03H) FD CB 03 56
Rigid drive. Test bit 2 of the DCT flag byte at IY+03H, which is set for a fixed platter and clear for a removable one.
52E9
LD HL,563CH 21 3C 56
Point register pair HL at 563CH, the string "Removable", ready for a removable rigid drive.
52EC
If bit 2 is clear (Z, removable), JUMP to 52F1H keeping the Removable string in register pair HL.
52EE
LD HL,5646H 21 46 56
Otherwise point register pair HL at 5646H, the string "Fixed", for a fixed rigid drive.
52F1
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the removable/fixed string at (HL).
52F4
JR 535AH 18 64
JUMP to 535AH to finish this drive's line, skipping the floppy-only density, side and step fields.
52F6
BIT 6,(IY+03H) FD CB 03 76
Floppy drive. Test bit 6 of the DCT flag byte at IY+03H, which is set for double density and clear for single density.
52FA
LD A,53H 3E 53
Load register A with 53H (the S character) for single density.
52FC
If bit 6 was clear (Z, single density), JUMP to 5300H keeping the S in register A.
52FE
LD A,44H 3E 44
Otherwise load register A with 44H (the D character) for double density.
5300
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the density letter (register A).
5303
LD HL,564CH 21 4C 56
Point register pair HL at 564CH, the string "den Side=" (the density suffix and the side-count label).
5306
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the "den Side=" string at (HL).
5309
BIT 5,(IY+04H) FD CB 04 6E
Test bit 5 of the DCT configuration byte at IY+04H, which is set for a double-sided drive.
530D
LD A,31H 3E 31
Load register A with 31H (the 1 character), the side count for a single-sided drive.
530F
If bit 5 was clear (Z, single sided), JUMP to 5312H keeping the 1 in register A.
5311
INC A 3C
Otherwise INCrement register A to 32H (the 2 character) for a double-sided drive.
5312
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the side count (register A).
5315
LD HL,5656H 21 56 56
Point register pair HL at 5656H, the string " Step=", the step-rate label.
5318
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the " Step=" label at (HL).
531B
LD A,(IY+03H) FD 7E 03
Load register A with the DCT flag byte at IY+03H, whose stepping-rate bits (bits 0, 1 and 5) select this drive's step rate.
531E
AND 23H E6 23
AND register A with 23H to keep only the stepping-rate bits (bits 0, 1 and 5) of the DCT flag byte.
5320
LD B,A 47
Copy the masked stepping-rate bits (register A) into register B for the reshuffle that follows.
5321
RRCA 0F
Rotate register A right, first of three rotates that move bit 5 down toward the low bits so all three rate bits become adjacent.
5322
RRCA 0F
Rotate register A right, second of the three rotates aligning the stepping-rate bits.
5323
RRCA 0F
Rotate register A right, third of the three rotates aligning the stepping-rate bits.
5324
OR B B0
OR register A with register B (the original masked bits), combining the shifted bit 5 with bits 0 and 1 into a small index.
5325
RLCA 07
Rotate register A left, doubling the index so it steps through the 560CH table two bytes (one entry) at a time.
5326
AND 0EH E6 0E
AND register A with 0EH to keep the even index 0, 2, 4 ... 14 that selects one of the eight two-character step-rate entries.
5328
LD HL,560CH 21 0C 56
Load register pair HL with 560CH, the base of the eight-entry step-rate lookup table.
532B
ADD A,L 85
ADD register L to register A, forming the low byte of the address of the selected two-character step-rate entry.
532C
LD L,A 6F
Copy the computed low byte (register A) into register L.
532D
ADC A,H 8C
ADD register H to register A with carry (ADC), propagating any carry into the high byte of the table address.
532E
SUB L 95
SUBtract register L from register A, leaving in register A the high byte of the entry address.
532F
LD H,A 67
Copy the high byte (register A) into register H so register pair HL now points at the selected step-rate entry in the 560CH table.
5330
LD A,(HL) 7E
Load register A with the first ASCII character of the step-rate entry at (HL).
5331
INC HL 23
INCrement register pair HL to point at the second character of the step-rate entry.
5332
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the first step-rate character (register A).
5335
LD A,(HL) 7E
Load register A with the second ASCII character of the step-rate entry at (HL).
5336
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the second step-rate character (register A).
5339
BIT 5,(IY+03H) FD CB 03 6E
Test bit 5 of the DCT flag byte at IY+03H; when set, no head-settle delay is shown for this drive.
533D
If bit 5 is set (NZ), JUMP to 535AH to finish the line without a settle-delay field.
533F
LD HL,5660H 21 60 56
Point register pair HL at 5660H, the string " Dly=", the head-settle-delay label.
5342
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the " Dly=" label at (HL).
5345
BIT 2,(IY+03H) FD CB 03 56
Test bit 2 of the DCT flag byte at IY+03H, which selects between the two head-settle-delay values.
5349
LD A,20H 3E 20
Load register A with 20H (a space), the first character of the " 1" delay value.
534B
LD B,31H 06 31
Load register B with 31H (the 1 character), the second character of the " 1" delay value.
534D
If bit 2 is clear (Z), JUMP to 5353H keeping the " 1" delay value.
534F
LD A,2EH 3E 2E
Otherwise load register A with 2EH (the . character), the first character of the ".5" delay value.
5351
LD B,35H 06 35
Load register B with 35H (the 5 character), the second character of the ".5" delay value.
5353
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the first delay character (register A).
5356
LD A,B 78
Load register A with register B, the second delay character (1 or 5).
5357
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the second delay character (register A).
535A
CALL 5542H CD 42 55
GOSUB to the new-line helper at 5542H to end this drive's line and apply screen paging.

535DH - DRIVES Option: Advance to the Next Drive

Restores the loop counter, advances to the next logical drive and repeats until all eight have been reported.

535D
POP BC C1
Restore register pair BC from the stack so register C again holds the logical drive number just processed.
535E
INC C 0C
INCrement register C to advance to the next logical drive number.
535F
LD A,C 79
Load register A with register C, the next logical drive number, to test the loop limit.
5360
CP 08H FE 08
Compare register A (the next drive number) against 08H, the count of logical drives.
5362
JP NZ,5221H C2 21 52
If register C has not yet reached 08H (NZ), LOOP BACK to 5221H to process the next drive.

5365H - BYTEIO Option: Resident Device I/O Routing Map

Walks the resident device control block (DCB) tables (the KI/DO/PR table at 4015H and the auxiliary JL/SI/SO table at 43C0H) and, for each active device, prints its name, its input/output direction marker and where its byte I/O is linked, routed or driven from.

5365
LD HL,0FFFFH 21 FF FF
Self-Modifying Code
Load register pair HL with the BYTEIO-option flag from the operand cell at 5366H; @PARAM sets this cell non-zero when the BYTEIO (or B) keyword is present.
5368
LD A,H 7C
Load register A with register H, the high byte of the BYTEIO flag from 5366H, to test the word for zero.
5369
OR L B5
OR register A with register L, the low byte of the BYTEIO flag from 5366H; register A is zero only if the whole flag word is 0000H.
536A
JP Z,545AH CA 5A 54
If the BYTEIO flag is zero (Z, the keyword was not given), JUMP to 545AH to skip the device I/O routing map.
536D
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the first device control block (DCB) in the resident KI/DO/PR device table; each DCB is eight bytes.
5370
LD A,(HL) 7E
Loop Start
Load register A with the type/flag byte at the start of the current DCB at (HL); a value of 00H marks an unused device slot.
5371
OR A B7
OR register A with itself to set the flags according to the DCB type byte (Z when the slot is unused).
5372
If the DCB type byte is zero (Z, an unused slot), JUMP to 53C2H to advance to the next DCB.
5374
LD DE,566EH 11 6E 56
Point register pair DE at 566EH, the RAM work buffer where this device's routing line is assembled.
5377
PUSH HL E5
Save register pair HL (the DCB pointer) on the stack across the name-field build.
5378
CALL 544AH CD 4A 54
GOSUB to the device-name field builder at 544AH, which writes * plus this device's two-character name (DCB bytes +6 and +7) into the buffer at (DE).
537B
POP HL E1
Restore register pair HL from the stack so it again points at the current DCB.
537C
PUSH HL E5
Re-save register pair HL (the DCB pointer) on the stack for the routing test that follows.
537D
BIT 4,(HL) CB 66
Test bit 4 of the DCB type byte at (HL), which is set when this device is linked or routed to another device.
537F
If bit 4 is clear (Z, a simple device), JUMP to 5398H to show its driver address or Nil marker.
5381
INC L 2C
Loop Start
INCrement register L so register pair HL addresses DCB byte +1, the low byte of the linked-device pointer.
5382
LD A,(HL) 7E
Load register A with DCB byte +1 at (HL), the low byte of the address the device is linked/routed to.
5383
INC L 2C
INCrement register L so register pair HL addresses DCB byte +2, the high byte of the linked-device pointer.
5384
LD H,(HL) 66
Load register H with DCB byte +2 at (HL), the high byte of the linked-device address.
5385
LD L,A 6F
Load register L with register A (the saved low byte) so register pair HL now points at the linked device's control block.
5386
BIT 7,(HL) CB 7E
Test bit 7 of the first byte of the linked device's control block at (HL); when set the link target is a routed (Nil) device rather than another named device.
5388
If bit 7 is set (NZ, a routed/Nil target), JUMP to 53D4H to append the Nil routing marker.
538A
PUSH HL E5
Save register pair HL (the linked-device pointer) on the stack.
538B
CALL 53FCH CD FC 53
GOSUB to the direction-marker builder at 53FCH to append the input/output arrow marker (built from the linked device's flag bits) into the buffer at (DE).
538E
CALL 544AH CD 4A 54
GOSUB to the device-name field builder at 544AH to append * plus the linked device's two-character name (its DCB bytes +6 and +7) into the buffer at (DE).
5391
POP HL E1
Restore register pair HL from the stack so it again points at the linked device's control block.
5392
BIT 4,(HL) CB 66
Test bit 4 of the linked device's type byte at (HL) to see whether the link chain continues to a further device.
5394
If bit 4 is set (NZ, the chain continues), LOOP BACK to 5381H to follow the next link.
5396
JR 53B5H 18 1D
JUMP to 53B5H to terminate and display this device's routing line.
5398
CALL 53FCH CD FC 53
Simple (unlinked) device. GOSUB to the direction-marker builder at 53FCH to append the input/output arrow marker for this device into the buffer at (DE).
539B
BIT 3,(HL) CB 5E
Test bit 3 of the DCB type byte at (HL), which is set when the device has an associated driver load address to display.
539D
If bit 3 is set (NZ, the device has no shown address), JUMP to 53F2H to append the Nil marker.
539F
LD A,58H 3E 58
Load register A with 58H (the X character), the first character of the X'nnnn' address form.
53A1
LD (DE),A 12
Store register A (X) at (DE) in the work buffer.
53A2
INC DE 13
INCrement register pair DE to the next buffer position.
53A3
LD A,27H 3E 27
Load register A with 27H (the ' character) opening the hexadecimal address.
53A5
LD (DE),A 12
Store register A (') at (DE) in the work buffer.
53A6
INC DE 13
INCrement register pair DE to the next buffer position.
53A7
INC L 2C
INCrement register L so register pair HL addresses DCB byte +1, the low byte of the driver address.
53A8
LD A,(HL) 7E
Load register A with DCB byte +1 at (HL), the low byte of the driver load address.
53A9
INC L 2C
INCrement register L so register pair HL addresses DCB byte +2, the high byte of the driver address.
53AA
LD H,(HL) 66
Load register H with DCB byte +2 at (HL), the high byte of the driver load address.
53AB
LD L,A 6F
Load register L with register A (the saved low byte) so register pair HL holds the full driver load address.
53AC
EX DE,HL EB
Exchange register pairs DE and HL so register pair HL is the buffer pointer and register pair DE is the driver address, as the hex helper expects.
53AD
CALL 4D76H CD 76 4D
GOSUB to the resident 4D76H service to write register pair DE (the driver load address) as four hexadecimal ASCII digits into the buffer at (HL).
53B0
EX DE,HL EB
Exchange register pairs DE and HL back so register pair DE is again the buffer pointer, advanced past the four hex digits.
53B1
LD A,27H 3E 27
Load register A with 27H (the ' character) closing the hexadecimal address.
53B3
LD (DE),A 12
Store register A (') at (DE) in the work buffer.
53B4
INC DE 13
INCrement register pair DE to the next buffer position.
53B5
LD A,03H 3E 03
Load register A with 03H, the display terminator for the assembled routing line.
53B7
LD (DE),A 12
Store register A (03H) at (DE), terminating the routing line in the work buffer.
53B8
LD HL,566EH 21 6E 56
Point register pair HL at 566EH, the start of the assembled device routing line in the work buffer.
53BB
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the device routing line at (HL).
53BE
CALL 5542H CD 42 55
GOSUB to the new-line helper at 5542H to end the line and apply screen paging.
53C1
POP HL E1
Restore register pair HL from the stack so it again points at the current DCB.
53C2
LD A,L 7D
Load register A with register L, the low byte of the current DCB address, to step to the next DCB.
53C3
ADD A,08H C6 08
ADD 08H to register A, advancing to the next eight-byte DCB in the table.
53C5
LD L,A 6F
Copy the advanced low byte (register A) back into register L so register pair HL points at the next DCB.
53C6
JP C,545AH DA 5A 54
If the address wrapped past the top of the page (CARRY), JUMP to 545AH; the KI/DO/PR table has been fully scanned.
53C9
CP 2DH FE 2D
Compare register A (the low byte of the next DCB address) against 2DH; 402DH is @EXIT, the byte just past the last DCB in the resident table.
53CB
JP NZ,5370H C2 70 53
If the end of the resident DCB table has not been reached (NZ), LOOP BACK to 5370H to examine the next device.
53CE
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device table (the JL/SI/SO device control blocks), to continue the scan there.
53D1
JP 5370H C3 70 53
JUMP to 5370H to walk the auxiliary device table with the same routing display.

53D4H - BYTEIO Option: Routed (Nil) and Linked Device Formatting

Handles the two special routing cases: a device routed to nothing (Nil) or to a disk file (whose name is expanded by @FNAME), and the continuation of a device that is linked to another named device.

53D4
PUSH HL E5
Routed device. Save register pair HL (the linked device's control block pointer) on the stack.
53D5
LD HL,5669H 21 69 56
Point register pair HL at 5669H, the 5-byte " <=> " routing-arrow template.
53D8
LD BC,0005H 01 05 00
Load register pair BC with 0005H, the length of the " <=> " template.
53DB
LDIR ED B0
Block-copy the 5-byte " <=> " arrow from (HL)=5669H to the work buffer at (DE) (register pair BC = count).
53DD
POP HL E1
Restore register pair HL from the stack so it again points at the routed device's control block.
53DE
LD A,L 7D
Load register A with register L, the low byte of the DCB address, to reach the device's directory reference.
53DF
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, where the routed device stores a directory reference (drive in register C, record number in register B).
53E1
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at DCB byte +6.
53E2
LD C,(HL) 4E
Load register C with DCB byte +6 at (HL), the drive number of the routed destination file.
53E3
INC HL 23
INCrement register pair HL to DCB byte +7, the directory record number of the routed destination.
53E4
LD B,(HL) 46
Load register B with DCB byte +7 at (HL), the directory record number of the routed destination file.
53E5
PUSH DE D5
Save register pair DE (the work-buffer pointer) on the stack across the @FNAME call.
53E6
CALL 44BBH CD BB 44
GOSUB to the resident @FNAME service at 44BBH, which builds the destination file's NAME/EXT:d specification (from directory record register B on drive register C) into the buffer at (DE) ending in 03H.
53E9
POP DE D1
Restore register pair DE from the stack so it again points at the work buffer, now advanced setup notwithstanding.
53EA
LD A,(DE) 1A
Loop Start
Load register A with the buffer byte at (DE) while scanning forward for the 03H terminator that @FNAME wrote.
53EB
CP 03H FE 03
Compare register A (the current buffer byte) against 03H, the filespec terminator.
53ED
If register A is the 03H terminator (Z), JUMP to 53B5H to finish and display the routing line.
53EF
INC DE 13
INCrement register pair DE to the next buffer byte.
53F0
JR 53EAH 18 F8
LOOP BACK to 53EAH to keep scanning for the end of the filespec.
53F2
LD HL,5666H 21 66 56
Load register pair HL with 5666H, the 3-byte "Nil" marker for a device routed to nothing.
53F5
LD BC,0003H 01 03 00
Load register pair BC with 0003H, the length of the "Nil" marker.
53F8
LDIR ED B0
Block-copy the 3-byte "Nil" marker from (HL)=5666H to the work buffer at (DE) (register pair BC = count).
53FA
JR 53B5H 18 B9
JUMP to 53B5H to finish and display this device's routing line.

53FCH - Device Direction-Marker Builder

Builds the routing-direction marker for a device from its flag byte: a leading and trailing space around an equals sign, with a less-than sign added for an input device and a greater-than sign for an output device.

53FC
LD A,20H 3E 20
Load register A with 20H (a space), the leading separator of the routing-direction marker being built at (DE).
53FE
LD (DE),A 12
Store register A (the space) at (DE) in the work buffer.
53FF
INC DE 13
INCrement register pair DE to the next buffer position.
5400
BIT 0,(HL) CB 46
Test bit 0 of the device flag byte at (HL), which is set when the device receives input.
5402
If bit 0 is clear (Z, not an input), JUMP to 5406H leaving a space in register A.
5404
LD A,3CH 3E 3C
Otherwise load register A with 3CH (the < character), marking an input device.
5406
LD (DE),A 12
Store register A (space or <) at (DE) in the work buffer.
5407
INC DE 13
INCrement register pair DE to the next buffer position.
5408
LD A,3DH 3E 3D
Load register A with 3DH (the = character), the centre of the routing marker.
540A
LD (DE),A 12
Store register A (=) at (DE) in the work buffer.
540B
INC DE 13
INCrement register pair DE to the next buffer position.
540C
LD A,20H 3E 20
Load register A with 20H (a space), the default for the output side of the marker.
540E
BIT 1,(HL) CB 4E
Test bit 1 of the device flag byte at (HL), which is set when the device produces output.
5410
If bit 1 is clear (Z, not an output), JUMP to 5414H leaving a space in register A.
5412
LD A,3EH 3E 3E
Otherwise load register A with 3EH (the > character), marking an output device.
5414
LD (DE),A 12
Store register A (space or >) at (DE) in the work buffer.
5415
INC DE 13
INCrement register pair DE to the next buffer position.
5416
LD A,20H 3E 20
Load register A with 20H (a space), the trailing separator of the routing marker.
5418
LD (DE),A 12
Store register A (the space) at (DE) in the work buffer.
5419
INC DE 13
INCrement register pair DE to the next buffer position.
541A
RET C9
RETurn to the caller with the routing-direction marker appended to the work buffer.

541BH - Three-Digit Decimal Formatter (Cylinder Count)

Formats a 16-bit value (the cylinder count) as up to three ASCII decimal digits with leading-zero suppression, writing them into a caller-supplied field.

541B
LD A,20H 3E 20
Load register A with 20H (a space), the leading pad for the hundreds digit of the decimal cylinder count.
541D
LD BC,0064H 01 64 00
Load register pair BC with 0064H (100), the divisor for extracting the hundreds digit.
5420
CALL 542FH CD 2F 54
GOSUB to the digit-extraction helper at 542FH to write the hundreds digit of register pair HL into (DE) (with a leading space when it is zero).
5423
LD BC,000AH 01 0A 00
Load register pair BC with 000AH (10), the divisor for extracting the tens digit.
5426
CALL 542FH CD 2F 54
GOSUB to the digit-extraction helper at 542FH to write the tens digit of the remaining value in register pair HL into (DE).
5429
LD A,L 7D
Load register A with register L, the remaining units value (0-9) after the hundreds and tens have been removed.
542A
ADD A,30H C6 30
ADD 30H to register A, converting the units value to its ASCII digit.
542C
LD (DE),A 12
Store the units digit (register A) at (DE) in the numeric field.
542D
INC DE 13
INCrement register pair DE past the units digit.
542E
RET C9
RETurn to the caller with the three-digit decimal value written to the field.

542FH - Decimal Digit-Extraction Helper

Extracts a single decimal digit by repeated subtraction of a power-of-ten divisor, suppressing a leading zero by writing the caller's pad character instead.

542F
PUSH DE D5
Save register pair DE (the field pointer) on the stack while the digit is computed.
5430
LD E,A 5F
Load register E with register A, preserving the space/zero pad character for this digit.
5431
LD D,0FFH 16 FF
Load register D with 0FFH, seeding the digit counter (it is INCremented to 0 on the first pass).
5433
XOR A AF
Set register A to zero and clear the carry, preparing for the repeated subtraction.
5434
INC D 14
Loop Start
INCrement register D, counting how many times the divisor (register pair BC) fits into the value.
5435
SBC HL,BC ED 42
SUBtract register pair BC (the divisor) from register pair HL (the running value) with SBC.
5437
If the subtraction did not go negative (NO CARRY), LOOP BACK to 5434H to subtract again.
5439
ADD HL,BC 09
ADD register pair BC back to register pair HL, undoing the one subtraction that overshot; register pair HL now holds the remainder.
543A
LD A,E 7B
Load register A with register E, the saved pad character for this digit.
543B
LD B,D 42
Load register B with register D, the digit count produced by the loop.
543C
POP DE D1
Restore register pair DE from the stack so it again points at the numeric field.
543D
LD (DE),A 12
Store register A (the pad character) at (DE) as a provisional value in case the digit is a leading zero.
543E
INC B 04
INCrement register B; combined with the DEC that follows this tests whether the digit count is zero without altering it.
543F
DEC B 05
DECrement register B, restoring the digit count and setting the zero flag when the digit is zero.
5440
If the digit count is zero (Z, a suppressed leading zero), JUMP to 5448H leaving the pad character in place.
5442
LD A,B 78
Load register A with register B, the non-zero digit count for this place.
5443
ADD A,30H C6 30
ADD 30H to register A, converting the digit to its ASCII character.
5445
LD (DE),A 12
Store the digit character (register A) at (DE), overwriting the provisional pad.
5446
LD A,30H 3E 30
Load register A with 30H (the 0 character) so any following place shows a real zero rather than a pad space.
5448
INC DE 13
INCrement register pair DE past this digit position.
5449
RET C9
RETurn to the caller with one decimal digit written to the field.

544AH - Device-Name Field Builder

Appends an asterisk followed by a device's two-character name (from DCB bytes +6 and +7) to the work buffer.

544A
LD A,L 7D
Load register A with register L, the low byte of the DCB address, to reach the device name field.
544B
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, the first character of the two-character device name.
544D
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at DCB byte +6.
544E
LD A,2AH 3E 2A
Load register A with 2AH (the * character) that prefixes a device name.
5450
LD (DE),A 12
Store register A (*) at (DE) in the work buffer.
5451
INC DE 13
INCrement register pair DE to the next buffer position.
5452
LD A,(HL) 7E
Load register A with DCB byte +6 at (HL), the first character of the device name.
5453
LD (DE),A 12
Store the first name character (register A) at (DE) in the work buffer.
5454
INC DE 13
INCrement register pair DE to the next buffer position.
5455
INC L 2C
INCrement register L so register pair HL addresses DCB byte +7, the second character of the device name.
5456
LD A,(HL) 7E
Load register A with DCB byte +7 at (HL), the second character of the device name.
5457
LD (DE),A 12
Store the second name character (register A) at (DE) in the work buffer.
5458
INC DE 13
INCrement register pair DE to the next buffer position.
5459
RET C9
RETurn to the caller with * plus the two-character device name appended to the buffer.

545AH - STATUS Option: Installed Filter List and System Speed

Displays the Options line: the smooth-scroll flag, the eight system filters that are installed (decoded from a packed name list against a resident flag byte) and the current CPU speed (Fast or Slow).

545A
LD HL,0FFFFH 21 FF FF
Self-Modifying Code
Load register pair HL with the STATUS-option flag from the operand cell at 545BH; @PARAM sets this cell non-zero when the STATUS (or S) keyword is present.
545D
LD A,H 7C
Load register A with register H, the high byte of the STATUS flag from 545BH, to test the word for zero.
545E
OR L B5
OR register A with register L, the low byte of the STATUS flag from 545BH; register A is zero only if the whole flag word is 0000H.
545F
JP Z,5516H CA 16 55
If the STATUS flag is zero (Z, the keyword was not given), JUMP to 5516H to reach the overlay exit.
5462
LD HL,55BDH 21 BD 55
Point register pair HL at 55BDH, the string "Options:", the header of the installed-filter list.
5465
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the "Options:" header at (HL).
5468
LD BC,08FFH 01 FF 08
Load register pair BC with 08FFH; register B = 08H is the number of filter bits to test and register C = 0FFH seeds the leading-comma suppressor.
546B
LD A,(46FDH) 3A FD 46
Load register A with the resident configuration byte at 46FDH; it is non-zero when the smooth-scroll option is installed.
546E
OR A B7
OR register A with itself to set the flags according to the 46FDH byte (Z when the option is absent).
546F
LD HL,55B5H 21 B5 55
Point register pair HL at 55B5H, the string " Smooth", ready to append when the option is installed.
5472
If the smooth option is absent (Z), JUMP to 5478H to skip the " Smooth" label.
5474
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the " Smooth" label at (HL).
5477
INC C 0C
INCrement register C past 0FFH to 00H, marking that at least one option name has now been printed.
5478
LD HL,55C6H 21 C6 55
Point register pair HL at 55C6H, the packed filter-name word list (Spool, Type, JKL, PR, KI, MiniDOS, KSM, Graphic), whose words each end with a byte having bit 7 set.
547B
LD A,(441FH) 3A 1F 44
Load register A with the resident filter-installed flag byte at 441FH; each of its eight bits marks whether the corresponding filter in the 55C6H list is installed.
547E
PUSH AF F5
Save register AF on the stack, then immediately restore it, aligning the flag byte before the rotate.
547F
POP AF F1
Loop Start
Restore register AF from the stack so register A again holds the (progressively rotated) filter-installed flag byte for the current bit.
5480
RRCA 0F
Rotate register A right, moving the current filter's install bit into the carry flag.
5481
PUSH AF F5
Save register AF on the stack, preserving the remaining install bits across the name-copy.
5482
If the current filter's bit is clear (NO CARRY, not installed), JUMP to 549DH to skip that word in the list.
5484
INC C 0C
The filter is installed. INCrement register C; this sets the zero flag only when register C was 0FFH (no name printed yet), which suppresses a leading comma.
5485
CALL NZ,5533H C4 33 55
If a previous name was already printed (NZ), GOSUB to 5533H to output a comma separator (register A is loaded with 2CH there).
5488
LD A,20H 3E 20
Load register A with 20H (a space) to separate the filter names.
548A
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the space (register A).
548D
LD A,(HL) 7E
Loop Start
Load register A with the current character of the filter name at (HL).
548E
INC HL 23
INCrement register pair HL to the next character of the filter name.
548F
PUSH AF F5
Save register AF on the stack, preserving the raw character (whose bit 7 marks the last letter).
5490
AND 7FH E6 7F
AND register A with 7FH to strip the end-of-word marker (bit 7) so the printable letter remains.
5492
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the filter-name letter (register A).
5495
POP AF F1
Restore register AF from the stack so register A again holds the raw character with its bit-7 marker.
5496
RLCA 07
Rotate register A left, moving the end-of-word marker (bit 7) into the carry flag.
5497
If this was not the last letter (NO CARRY), LOOP BACK to 548DH to print the next character of the name.
5499
DECrement register B and LOOP BACK to 547FH to test the next filter bit until all eight have been handled.
549B
JR 54A4H 18 07
JUMP to 54A4H once every installed filter name has been printed.
549D
LD A,(HL) 7E
Loop Start
Load register A with the current character of the skipped filter name at (HL).
549E
INC HL 23
INCrement register pair HL to the next character of the name being skipped.
549F
RLCA 07
Rotate register A left, moving the end-of-word marker (bit 7) into the carry flag.
54A0
If this was not the last letter (NO CARRY), LOOP BACK to 549DH to skip the next character of the name.
54A2
DECrement register B and LOOP BACK to 547FH to test the next filter bit after skipping this uninstalled name.
54A4
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH, whose bit 3 records the CPU/clock speed.
54A7
BIT 3,A CB 5F
Test bit 3 of register A (the SFLAG$ value from 430FH); it is set for the fast speed and clear for the slow speed.
54A9
LD HL,55E7H 21 E7 55
Point register pair HL at 55E7H, the string " Fast", ready for the fast setting.
54AC
If bit 3 is set (NZ, fast), JUMP to 54B1H keeping the " Fast" string in register pair HL.
54AE
LD HL,55EDH 21 ED 55
Otherwise point register pair HL at 55EDH, the string " Slow", for the slow setting.
54B1
INC C 0C
INCrement register C past 0FFH to 00H, marking that a name has been printed so a comma precedes the speed label.
54B2
CALL NZ,5533H C4 33 55
If a previous name was already printed (NZ), GOSUB to 5533H to output a comma separator (register A is loaded with 2CH there).
54B5
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the speed string (" Fast" or " Slow") at (HL).

54B8H - STATUS Option: Verify Flag and High-Memory Module List

Appends the Verify indicator when disk write-with-verify is enabled, then lists the numbered high-memory system modules that are currently resident.

54B8
POP AF F1
Restore register AF from the stack, balancing the PUSH AF at 547EH that framed the filter loop.
54B9
XOR A AF
Set register A to zero and clear the carry, preparing the verify-flag comparison.
54BA
LD HL,(443AH) 2A 3A 44
Load register pair HL with the current @WRITE service vector value from 443AH; it equals 48E6H when disk write-with-verify is enabled.
54BD
LD DE,48E6H 11 E6 48
Point register pair DE at 48E6H, the resident write-with-verify routine address, for comparison with the @WRITE vector.
54C0
SBC HL,DE ED 52
SUBtract register pair DE from register pair HL with SBC; the result is zero (Z) when the @WRITE vector points at the verify routine.
54C2
LD HL,5696H 21 96 56
Point register pair HL at 5696H, the string ", Verify", ready to display when verification is on.
54C5
CALL Z,5528H CC 28 55
If the @WRITE vector matched the verify routine (Z), GOSUB to the buffer-display helper at 5528H to display ", Verify" at (HL).
54C8
CALL 5542H CD 42 55
GOSUB to the new-line helper at 5542H to end the Options line and apply screen paging.
54CB
LD HL,4BDFH 21 DF 4B
Point register pair HL at 4BDFH, the resident overlay-loader work word that heads the high-memory system-module chain.
54CE
LD E,(HL) 5E
Load register E with the low byte of the module-chain pointer at (HL) = 4BDFH.
54CF
INC HL 23
INCrement register pair HL to the high byte of the module-chain pointer at 4BE0H.
54D0
LD D,(HL) 56
Load register D with the high byte of the module-chain pointer at (HL); register pair DE now holds the address of the first high-memory module descriptor.
54D1
LD HL,4BF5H 21 F5 4B
Point register pair HL at 4BF5H, the resident overlay-loader entry; when the chain pointer equals this address there are no high-memory modules.
54D4
OR A B7
Clear the carry flag before the 16-bit subtraction.
54D5
SBC HL,DE ED 52
SUBtract register pair DE (the module-chain pointer) from register pair HL (4BF5H) with SBC; the result is zero (Z) when no modules are resident.
54D7
JP Z,5516H CA 16 55
If no high-memory modules are resident (Z), JUMP to 5516H to reach the overlay exit.
54DA
LD HL,0FFE1H 21 E1 FF
Load register pair HL with 0FFE1H (minus 31), the offset from a module descriptor back to the start of its 32-byte entry.
54DD
ADD HL,DE 19
ADD register pair DE to register pair HL so register pair HL points at the first module's descriptor entry.
54DE
PUSH HL E5
Save register pair HL (the module-entry pointer) on the stack across the header display.
54DF
LD HL,55F3H 21 F3 55
Point register pair HL at 55F3H, the string "System modules resident:", the header of the module list.
54E2
CALL 5528H CD 28 55
GOSUB to the buffer-display helper at 5528H to display the "System modules resident:" header at (HL).
54E5
POP HL E1
Restore register pair HL from the stack so it again points at the first module entry.
54E6
LD BC,10FFH 01 FF 10
Load register pair BC with 10FFH; register B = 10H is the maximum module count to scan and register C = 0FFH seeds the leading-comma suppressor.
54E9
LD A,(HL) 7E
Loop Start
Load register A with the first byte of the current module entry at (HL); a zero byte marks the end of the module list.
54EA
INC HL 23
INCrement register pair HL past the first byte of the module entry.
54EB
INC HL 23
INCrement register pair HL again to reach the module's identifier byte.
54EC
OR A B7
OR register A with itself to set the flags according to the first module byte (Z at the end of the list).
54ED
If the end of the module list was reached (Z), JUMP to 5511H to finish the loop.
54EF
INC C 0C
INCrement register C; this sets the zero flag only when register C was 0FFH (no module printed yet), suppressing a leading comma.
54F0
CALL NZ,5533H C4 33 55
If a previous module was already printed (NZ), GOSUB to 5533H to output a comma separator (register A is loaded with 2CH there).
54F3
LD A,20H 3E 20
Load register A with 20H (a space) to separate the module numbers.
54F5
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the space (register A).
54F8
LD A,10H 3E 10
Load register A with 10H (16), the base value from which the remaining count in register B is subtracted to derive this module's number.
54FA
SUB B 90
SUBtract register B (the remaining module count) from register A, giving the current module's 1-based ordinal.
54FB
LD D,0FFH 16 FF
Load register D with 0FFH, seeding the tens-digit counter (it is INCremented to 0 on the first pass).
54FD
INC D 14
Loop Start
INCrement register D, counting how many tens are in the module number.
54FE
SUB 0AH D6 0A
SUBtract 0AH (10) from register A, repeatedly removing tens from the module number.
5500
If the value did not go negative (NO CARRY), LOOP BACK to 54FDH to remove another ten.
5502
PUSH AF F5
Save register AF on the stack, preserving the units remainder (register A overshot by ten).
5503
LD A,D 7A
Load register A with register D, the tens digit count.
5504
ADD A,30H C6 30
ADD 30H to register A, converting the tens count to its ASCII digit.
5506
CP 30H FE 30
Compare register A against 30H (the 0 character) to suppress a leading-zero tens digit.
5508
CALL NZ,5535H C4 35 55
If the tens digit is not zero (NZ), GOSUB to the character-output helper at 5535H to print it (register A).
550B
POP AF F1
Restore register AF from the stack so register A again holds the units remainder (overshot by ten).
550C
ADD A,3AH C6 3A
ADD 3AH to register A, adding back ten and 30H at once to convert the units remainder to its ASCII digit.
550E
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to print the units digit (register A).
5511
DECrement register B and LOOP BACK to 54E9H to display the next high-memory module (the loop also ends when the zero terminator is met).
5513
CALL 5542H CD 42 55
GOSUB to the new-line helper at 5542H to end the module list and apply screen paging.

5516H - Overlay Exit and Command-Level Check

Common exit path. Restores the caller's stack and returns to the RST 28H dispatcher on a normal exit, or aborts the job through @ABORT when an error occurred outside the LDOS command level.

5516
LD HL,0000H 21 00 00
Load register pair HL with 0000H; the value being zero signals a normal (non-error) overlay exit to the shared exit code.
5519
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 551AH, patched at entry (5200H) with the caller's SP; register SP now again addresses the LDOS command-level stack.
551C
LD A,H 7C
Load register A with register H, the high byte of the exit code in register pair HL, to test it for zero.
551D
OR L B5
OR register A with register L, the low byte of the exit code; register A is zero on a normal exit and non-zero when an error code is being returned.
551E
RET Z C8
If register pair HL is zero (Z, a normal exit), RETurn to the RST 28H dispatcher.
551F
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context on the error path.
5522
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5524
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher so it can report the error.
5525
JP 4030H C3 30 40
Not at command level. JUMP to the resident @ABORT service at 4030H to abort the running job.

5528H - Buffer-Display and Character-Output Helpers

Local helpers used throughout the overlay: one displays a terminated string on the screen (echoing to the printer when the P option is active) and one prints a single character (also echoed to the printer).

5528
CALL 4467H CD 67 44
GOSUB to the resident @DSPLY service at 4467H to display the 03H-terminated string at register pair HL on the screen.
552B
LD A,(553BH) 3A 3B 55
Load register A with the printer-echo flag from 553BH (the operand of the LD DE,0000H at 553AH); it is non-zero when the P option requested printer output.
552E
OR A B7
OR register A with itself to set the flags according to the printer-echo flag (Z when printing is off).
552F
JP NZ,446AH C2 6A 44
If printer echo is requested (NZ), JUMP to the resident @PRINT service at 446AH to also send the string (register pair HL) to the printer, returning from there.
5532
RET C9
RETurn to the caller when printer echo is off.
5533
LD A,2CH 3E 2C
Load register A with 2CH (the , character); this is the comma-separator entry that falls straight into the character-output helper below.
5535
PUSH AF F5
Save register AF on the stack, preserving the caller's registers across the ROM display call.
5536
CALL 0033H CD 33 00
GOSUB to the ROM display routine at 0033H to print the character in register A at the cursor.
5539
POP AF F1
Restore register AF from the stack so register A again holds the printed character.
553A
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand at 553BH; this word is the printer-echo flag (non-zero when the P option requested printer output), read here to decide whether to echo the character to the printer.
553D
INC E 1C
INCrement register E; combined with the zero test that follows, this is non-zero (so the printer echo happens) whenever the flag word was non-zero.
553E
JP Z,003BH CA 3B 00
If the printer-echo flag was zero (Z), JUMP to the ROM printer routine at 003BH to also print the character (register A), returning from there.
5541
RET C9
RETurn to the caller when printer echo is off.

5542H - New-Line, Pause and BREAK Helpers

Ends a display line and, unless output is suppressed, counts screen lines to pause a full page and to honour the BREAK and pause keys.

5542
LD A,0DH 3E 0D
Load register A with 0DH, a carriage return, to end the current display line.
5544
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to output the carriage return (register A).
5547
LD DE,5569H 11 69 55
Point register pair DE at 5569H, the address of the BREAK/pause handler, pushed next so it runs after the pause bookkeeping.
554A
PUSH DE D5
Save register pair DE (the 5569H handler address) on the stack so the RET below enters it.
554B
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand at 554CH; this word is the pause-suppression flag copied from 553BH at entry (non-zero when printer output or the N nonstop option is active), read here to decide whether screen paging is skipped.
554E
LD A,D 7A
Load register A with register D, the high byte of the pause-suppression flag from 554CH.
554F
OR E B3
OR register A with register E, the low byte of the pause-suppression flag; register A is non-zero when paging is to be suppressed.
5550
RET NZ C0
If paging is suppressed (NZ), RETurn through the pushed 5569H handler without counting the line.
5551
LD A,0EH 3E 0E
Load register A with 0EH (14), the number of display lines per screen page.
5553
DEC A 3D
DECrement register A to test the line counter as it is reloaded below.
5554
LD (5552H),A 32 52 55
Self-Modifying Code
Store the decremented count (register A) into 5552H, the operand of the LD A,0EH at 5551H, so the remaining-lines counter persists between calls.
5557
RET NZ C0
If the page is not yet full (NZ, lines remain), RETurn through the pushed 5569H handler.
5558
CALL 0049H CD 49 00
The screen page is full. GOSUB to the ROM key-wait routine at 0049H to wait for a keypress before scrolling.
555B
CP 01H FE 01
Compare register A (the key returned) against 01H, the BREAK key code.
555D
JP Z,55A4H CA A4 55
If BREAK was pressed (Z), JUMP to 55A4H to abandon the listing.
5560
CALL 01C9H CD C9 01
GOSUB to the ROM clear-screen routine at 01C9H to clear the display for the next page.
5563
LD A,0EH 3E 0E
Load register A with 0EH (14), the full count of lines per page.
5565
LD (5552H),A 32 52 55
Self-Modifying Code
Store the reset count (register A) into 5552H, the operand of the LD A,0EH at 5551H, restarting the lines-per-page counter.
5568
RET C9
RETurn through the pushed 5569H handler after clearing the screen.
5569
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH; its bit 4 records whether output paging (a listing under user control) is active.
556C
AND 10H E6 10
AND register A with 10H to isolate bit 4 (the paging-active flag) of the SFLAG$ value.
556E
XOR 10H EE 10
XOR register A with 10H, inverting bit 4 so the zero flag is set when paging IS active.
5570
RET Z C8
If paging is active (Z), RETurn without polling the keyboard for BREAK or pause.
5571
LD A,(4423H) 3A 23 44
Load register A with the resident keyboard flag byte KFLAG$ at 4423H; its bit 0 marks a pending BREAK and bit 1 a pending pause.
5574
BIT 0,A CB 47
Test bit 0 of register A (the KFLAG$ value from 4423H), the pending-BREAK flag.
5576
If BREAK is pending (NZ), JUMP to 5596H to end the line and abandon the listing.
5578
BIT 1,A CB 4F
Test bit 1 of register A (the KFLAG$ value from 4423H), the pending-pause flag.
557A
RET Z C8
If pause is not pending (Z), RETurn to the caller.
557B
LD A,(4423H) 3A 23 44
Loop Start
Load register A with the resident keyboard flag byte KFLAG$ at 4423H again to re-test BREAK while paused.
557E
BIT 0,A CB 47
Test bit 0 of register A (the KFLAG$ value from 4423H), the pending-BREAK flag.
5580
If BREAK is pending (NZ), JUMP to 5596H to end the line and abandon the listing.
5582
CALL 002BH CD 2B 00
GOSUB to the ROM keyboard-scan routine at 002BH to read a key while paused; register A returns the key (or zero).
5585
OR A B7
OR register A with itself to set the flags according to the key returned (Z when no key was pressed).
5586
If no key was pressed (Z), LOOP BACK to 557BH to keep waiting during the pause.
5588
CP 60H FE 60
Compare register A (the key pressed) against 60H, the code that resumes a paused listing.
558A
If the resume key was pressed (Z), LOOP BACK to 557BH to re-check the flags one final time before continuing.
558C
LD A,(4423H) 3A 23 44
Load register A with the resident keyboard flag byte KFLAG$ at 4423H to clear its control bits.
558F
AND 0F8H E6 F8
AND register A with 0F8H to clear the low three bits (BREAK, pause and key-pending) of the KFLAG$ value.
5591
LD (4423H),A 32 23 44
Store the cleared value (register A) back into KFLAG$ at 4423H.
5594
XOR A AF
Set register A to zero and clear the flags before returning.
5595
RET C9
RETurn to the caller with the keyboard flags cleared.

5596H - BREAK-Line and Parameter-Error Paths

The BREAK termination path and the @PARAM parameter-error path, both of which set the error return before falling into the common exit.

5596
LD A,0DH 3E 0D
BREAK was pressed. Load register A with 0DH, a carriage return, to end the current display line.
5598
CALL 5535H CD 35 55
GOSUB to the character-output helper at 5535H to output the carriage return (register A).
559B
JR 55A4H 18 07
JUMP to 55A4H to set the error return and exit the overlay.
559D
LD A,2CH 3E 2C
Load register A with 2CH (44), the LDOS error code for a parameter error, ready to report a bad @PARAM keyword.
559F
OR 0C0H F6 C0
OR register A with 0C0H, setting bits 6 and 7 so @ERROR returns to the caller (message-only) rather than aborting.
55A1
CALL 4409H CD 09 44
GOSUB to the resident @ERROR service at 4409H to display the error whose code is in register A.
55A4
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero value that flags an error/abort exit to the shared exit code.
55A7
JP 5519H C3 19 55
JUMP to 5519H to restore the caller's stack and exit through the common exit path.

55AAH - Message, Label and Lookup-Table Data

The overlay's string pool: the No Disk placeholder, the Options and drive-geometry labels, the packed filter-name word list, the two-character step-rate lookup table and the device-routing markers. All display strings are terminated by 03H for @DSPLY.

55AA-55B3
DEFM "No Disk] " 4E 6F 20 20 44 69 73 6B 5D 20
No Disk Placeholder
The 12-byte template (through 55B5H) block-copied to the disk-name buffer at 42D0H by 5257H when a drive is not ready; 42D0H-42D7H become the name No Disk, 42D8H the closing bracket.
55B4
DEFB 03H 03
The 03H display terminator of the No Disk name field copied to 42DAH.
55B5-55BB
DEFM " Smooth" 20 53 6D 6F 6F 74 68
The smooth-scroll option label, displayed at 5474H when the resident configuration byte 46FDH is non-zero. Its leading space at 55B5H is also the 12th byte copied by the No Disk template above.
55BC
DEFB 03H 03
The 03H display terminator of the " Smooth" label.
55BD-55C4
DEFM "Options:" 4F 70 74 69 6F 6E 73 3A
The header of the installed-filter list, displayed at 5465H.
55C5
DEFB 03H 03
The 03H display terminator of the "Options:" header.
55C6-55E6
DEFM "Spool Type JKL PR KI MiniDOS KSM Graphic" 53 70 6F 6F EC 54 79 70 E5 4A 4B CC 50 D2 4B C9 4D 69 6E 69 44 4F D3 4B 53 CD 47 72 61 70 68 69 E3
Packed Filter-Name List
Eight system-filter names read at 547BH-5497H, one per bit of the resident flag byte 441FH (bit 0 Spool, bit 1 Type, bit 2 JKL, bit 3 PR, bit 4 KI, bit 5 MiniDOS, bit 6 KSM, bit 7 Graphic). The final character of each name carries bit 7 set as the end-of-word marker; the spaces shown here separate the decoded words only.
55E7-55EB
DEFM " Fast" 20 46 61 73 74
The fast-speed label, displayed at 54B5H when SFLAG$ (430FH) bit 3 is set.
55EC
DEFB 03H 03
The 03H display terminator of the " Fast" label.
55ED-55F1
DEFM " Slow" 20 53 6C 6F 77
The slow-speed label, displayed at 54B5H when SFLAG$ (430FH) bit 3 is clear.
55F2
DEFB 03H 03
The 03H display terminator of the " Slow" label.
55F3-560A
DEFM "System modules resident:" 53 79 73 74 65 6D 20 6D 6F 64 75 6C 65 73 20 72 65 73 69 64 65 6E 74 3A
The header of the high-memory module list, displayed at 54E2H.
560B
DEFB 03H 03
The 03H display terminator of the "System modules resident:" header.
560C-561B
DEFM " 6122040 3 61015" 20 36 31 32 32 30 34 30 20 33 20 36 31 30 31 35
Step-Rate Lookup Table
Eight two-character step-rate values indexed at 5328H by the reshuffled stepping-rate bits of DCT+03H: " 6", "12", "20", "40", " 3", " 6", "10", "15" (milliseconds).
561C
DEFB 22H 22
The inch-mark quote printed after the drive size (for example 5″), preceding the Floppy label.
561D-5625
DEFM " Floppy #" 20 46 6C 6F 70 70 79 20 23
The floppy drive-type label, displayed at 52AFH; the physical unit number is printed after the # by 52BDH.
5626
DEFB 03H 03
The 03H display terminator of the " Floppy #" label.
5627
DEFB 22H 22
The inch-mark quote printed after the drive size, preceding the Rigid label.
5628-5630
DEFM " Rigid #" 20 52 69 67 69 64 20 20 23
The rigid (hard) drive-type label, displayed at 52AFH.
5631
DEFB 03H 03
The 03H display terminator of the " Rigid #" label.
5632-563A
DEFM " Cyl= " 20 43 79 6C 3D 20 20 20 20
The cylinder-count label; the four-space field at 5637H-563AH receives the formatted count from 52D6H.
563B
DEFB 03H 03
The 03H display terminator of the " Cyl=" field.
563C-5644
DEFM "Removable" 52 65 6D 6F 76 61 62 6C 65
The removable-platter label for a rigid drive, displayed at 52F1H.
5645
DEFB 03H 03
The 03H display terminator of the "Removable" label.
5646-564A
DEFM "Fixed" 46 69 78 65 64
The fixed-platter label for a rigid drive, displayed at 52F1H.
564B
DEFB 03H 03
The 03H display terminator of the "Fixed" label.
564C-5654
DEFM "den Side=" 64 65 6E 20 53 69 64 65 3D
The density suffix (following the S or D density letter) and the side-count label, displayed at 5306H.
5655
DEFB 03H 03
The 03H display terminator of the "den Side=" label.
5656-565B
DEFM " Step=" 20 53 74 65 70 3D
The step-rate label, displayed at 5318H before the two-character rate value.
565C
DEFB 03H 03
The 03H display terminator of the " Step=" label.
565D-565E
DEFM "ms" 6D 73
The millisecond unit label present in the string pool.
565F
DEFB 03H 03
The 03H display terminator of the "ms" label.
5660-5664
DEFM " Dly=" 20 44 6C 79 3D
The head-settle-delay label, displayed at 5342H before the delay value.
5665
DEFB 03H 03
The 03H display terminator of the " Dly=" label.
5666-5668
DEFM "Nil" 4E 69 6C
The Nil marker block-copied at 53F8H for a device that drives nothing.
5669-566D
DEFM " <=> " 20 3C 3D 3E 20
The 5-byte routing-arrow marker block-copied at 53DBH for a routed device.

566EH - Work Buffer and @PARAM Keyword Descriptor Table

The RAM work buffer where each drive and device line is assembled (not part of the loaded image), the Verify label, and the @PARAM keyword descriptor table that maps each option keyword to the self-modified flag cell it sets.

566E-5695
(not loaded)
Line Work Buffer
A 40-byte RAM scratch area (not present in the overlay image) into which each device routing line and drive line is built by the code at 5374H and 53B8H before display.
5696-569D
DEFM ", Verify" 2C 20 56 65 72 69 66 79
The write-with-verify indicator, displayed at 54C5H when the resident @WRITE vector 443AH points at the verify routine 48E6H.
569E
DEFB 03H 03
The 03H display terminator of the ", Verify" label.
569F-56A4
DEFM "BYTEIO" 42 59 54 45 49 4F
The BYTEIO keyword. @PARAM stores the following value into the BYTEIO device-map flag cell (operand of the LD HL at 5365H).
56A5-56A6
DEFW 5366H 66 53
Pointer to the BYTEIO device-map flag cell (operand of the LD HL at 5365H) that the BYTEIO keyword sets.
56A7-56AC
DEFM "B " 42 20 20 20 20 20
The B keyword. @PARAM stores the following value into the BYTEIO device-map flag cell (operand of the LD HL at 5365H).
56AD-56AE
DEFW 5366H 66 53
Pointer to the BYTEIO device-map flag cell (operand of the LD HL at 5365H) that the B keyword sets.
56AF-56B4
DEFM "DRIVES" 44 52 49 56 45 53
The DRIVES keyword. @PARAM stores the following value into the DRIVES geometry flag cell (operand of the LD HL at 5217H).
56B5-56B6
DEFW 5218H 18 52
Pointer to the DRIVES geometry flag cell (operand of the LD HL at 5217H) that the DRIVES keyword sets.
56B7-56BC
DEFM "D " 44 20 20 20 20 20
The D keyword. @PARAM stores the following value into the DRIVES geometry flag cell (operand of the LD HL at 5217H).
56BD-56BE
DEFW 5218H 18 52
Pointer to the DRIVES geometry flag cell (operand of the LD HL at 5217H) that the D keyword sets.
56BF-56C4
DEFM "N " 4E 20 20 20 20 20
The N keyword. @PARAM stores the following value into the nonstop/pause-suppression flag cell (operand of the LD DE at 554BH).
56C5-56C6
DEFW 554CH 4C 55
Pointer to the nonstop/pause-suppression flag cell (operand of the LD DE at 554BH) that the N keyword sets.
56C7-56CC
DEFM "P " 50 20 20 20 20 20
The P keyword. @PARAM stores the following value into the printer-echo flag cell (operand of the LD DE at 553AH).
56CD-56CE
DEFW 553BH 3B 55
Pointer to the printer-echo flag cell (operand of the LD DE at 553AH) that the P keyword sets.
56CF-56D4
DEFM "STATUS" 53 54 41 54 55 53
The STATUS keyword. @PARAM stores the following value into the STATUS flag cell (operand of the LD HL at 545AH).
56D5-56D6
DEFW 545BH 5B 54
Pointer to the STATUS flag cell (operand of the LD HL at 545AH) that the STATUS keyword sets.
56D7-56DC
DEFM "S " 53 20 20 20 20 20
The S keyword. @PARAM stores the following value into the STATUS flag cell (operand of the LD HL at 545AH).
56DD-56DE
DEFW 545BH 5B 54
Pointer to the STATUS flag cell (operand of the LD HL at 545AH) that the S keyword sets.
56DF
DEFB 00H 00
Zero byte marking the end of the @PARAM keyword descriptor table.

Disassembly - Overlay 11 - LINK

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.

Disassembly - Overlay 12 - Command Overlay 12

5200H - Overlay Entry: Save Base-Driver Vectors, Parse Options and Argument

Entry of command overlay 12. It saves the caller's stack, captures the resident base-driver addresses of the KI, DO and PR devices into the local reset template, scans the command line for a parameter list, parses the LRL and DATE options with @PARAM, and parses the file or device argument with @FSPEC to choose one of three actions: reset a device, reset system memory, or set a file's directory attributes.

5200
LD (5282H),SP ED 73 82 52
Self-Modifying Code
Store the caller's stack pointer (register SP, holding the LDOS command-level stack on entry) into the operand of the LD SP,nnnn at 5281H, so the overlay exit can restore this stack.
5204
PUSH HL E5
Save register pair HL (the pointer into the command line) on the stack while the base-driver vectors are captured.
5205
LD HL,(43B8H) 2A B8 43
Load register pair HL with the resident base-driver save word for the keyboard device at 43B8H (the address the KI device is reset to).
5208
LD (542EH),HL 22 2E 54
Self-Modifying Code
Store the KI base-driver address (register pair HL) into 542EH, the driver-address field of the local KI reset-template DCB, so the template restores the current base driver.
520B
LD HL,(43BAH) 2A BA 43
Load register pair HL with the resident base-driver save word for the display device at 43BAH.
520E
LD (5436H),HL 22 36 54
Self-Modifying Code
Store the DO base-driver address (register pair HL) into 5436H, the driver-address field of the local DO reset-template DCB.
5211
LD HL,(43BCH) 2A BC 43
Load register pair HL with the resident base-driver save word for the printer device at 43BCH.
5214
LD (543EH),HL 22 3E 54
Self-Modifying Code
Store the PR base-driver address (register pair HL) into 543EH, the driver-address field of the local PR reset-template DCB.
5217
POP HL E1
Restore register pair HL from the stack so it again points at the start of the command line.
5218
PUSH HL E5
Re-save register pair HL (the command-line pointer) on the stack for the filespec parse that follows.
5219
LD A,(HL) 7E
Loop Start
Load register A with the command-line character at (HL) while scanning for a parameter list or the end of the line.
521A
CP 28H FE 28
Compare register A against 28H (the ASCII open parenthesis) that introduces a parameter list.
521C
If register A is an open parenthesis (Z), JUMP to 5225H to parse the parameter list.
521E
CP 0EH FE 0E
Compare register A against 0EH; command-line characters below 0EH mark the end of the argument.
5220
If register A is below 0EH (CARRY, end of the argument), JUMP to 5230H to parse the filespec.
5222
INC HL 23
INCrement register pair HL to the next command-line character.
5223
JR 5219H 18 F4
LOOP BACK to 5219H to test the next character.
5225
LD DE,545DH 11 5D 54
Point register pair DE at 545DH, the local @PARAM keyword descriptor table (LRL/L and DATE/D).
5228
CALL 4476H CD 76 44
GOSUB to the resident @PARAM service at 4476H to parse the parameter list and patch the LRL and DATE operand cells; it returns NZ on a syntax error.
522B
LD A,2CH 3E 2C
Load register A with 2CH (44), the LDOS parameter-error code, in case @PARAM failed.
522D
JP NZ,53DDH C2 DD 53
If @PARAM reported a syntax error (NZ), JUMP to 53DDH to report the parameter error through @ERROR.
5230
POP HL E1
Restore register pair HL from the stack so it again points at the start of the argument.
5231
LD DE,54F6H 11 F6 54
Point register pair DE at 54F6H, the FCB work area (in RAM just past the overlay) that will receive the parsed file or device specification.
5234
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the specification at (HL) into the FCB at (DE); it returns NZ when no valid specification is present.
5237
JP NZ,5290H C2 90 52
If no valid specification was given (NZ, the command has no file or device argument), JUMP to 5290H to reset system memory.
523A
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (the asterisk character) marks a device specification.
523B
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk) that opens a device name.
523D
JP NZ,5374H C2 74 53
If the specification is not a device (NZ, a disk file), JUMP to 5374H to set the file's LRL and DATE attributes.

5240H - Device Reset: Locate the DCB and Restore its Base Template

When the argument names a device, finds its control block, follows any link chain to the base device and closes a routed file, then overwrites the resident DCB with its 8-byte base template and performs the device-specific reset action (clear filters, reinitialize the keyboard, or clear the screen).

5240
LD DE,(54F7H) ED 5B F7 54
Load register pair DE with the two-character device name from 54F7H (FCB bytes +1 and +2): register E = the first name character, register D = the second.
5244
CALL 53F0H CD F0 53
GOSUB to the local find-DCB-by-name helper at 53F0H, which returns register pair HL pointing at the matching device control block (or NZ and error code 08H if the device is unknown).
5247
JP NZ,53DDH C2 DD 53
If the device was not found (NZ), JUMP to 53DDH to report the error through @ERROR.
524A
PUSH HL E5
Save register pair HL (the matching DCB pointer) on the stack across the link-chain walk.
524B
CALL 53C1H CD C1 53
GOSUB to the local helper at 53C1H, which follows the device's link chain to its base DCB and, if that base is a device routed to a disk file, closes the file.
524E
POP HL E1
Restore register pair HL from the stack so it again points at the device's DCB.
524F
LD (HL),08H 36 08
Store 08H into the DCB type byte at (HL), resetting the device to its base (unlinked, unfiltered) type.
5251
LD A,40H 3E 40
Load register A with 40H, the high byte of the resident DCB page, to confirm the DCB lies in the resident device table.
5253
CP H BC
Compare register A (40H) against register H, the high byte of the DCB address.
5254
If the DCB is not in the 40xxH resident page (NZ), JUMP to 527EH to exit without restoring a base template.
5256
DI F3
Disable interrupts while the resident DCB is overwritten with its base template.
5257
LD D,H 54
Copy register H into register D, beginning the transfer of the DCB address into register pair DE.
5258
LD E,L 5D
Copy register L into register E so register pair DE now holds the DCB address (the LDIR destination).
5259
XOR A AF
Set register A to zero and clear the carry for the subtraction that computes the template offset.
525A
LD BC,4015H 01 15 40
Load register pair BC with 4015H, the base address of the resident device table.
525D
SBC HL,BC ED 42
SUBtract register pair BC (4015H) from register pair HL (the DCB address) with SBC, giving the DCB's offset within the table.
525F
LD BC,542DH 01 2D 54
Load register pair BC with 542DH, the base of the local default-DCB template.
5262
ADD HL,BC 09
ADD register pair BC to register pair HL so register pair HL points at this device's 8-byte entry in the local template.
5263
LD BC,0008H 01 08 00
Load register pair BC with 0008H, the size of one DCB.
5266
LDIR ED B0
Block-copy the 8-byte base-DCB template from (HL) to the resident DCB at (DE) (register pair BC = count), restoring the device to its base driver and name.
5268
EI FB
Re-enable interrupts now that the DCB has been restored.
5269
LD A,2DH 3E 2D
Load register A with 2DH; the DCB just past this one ends at low byte 2DH when the reset device is the printer (PR at 4025H).
526B
CP E BB
Compare register A (2DH) against register E, the low byte of the address one past the restored DCB.
526C
CALL Z,5416H CC 16 54
If this was the printer device (Z), GOSUB to 5416H to clear the printer filter bit in the resident flag byte 441FH.
526F
LD A,1DH 3E 1D
Load register A with 1DH; the DCB just past this one ends at low byte 1DH when the reset device is the keyboard (KI at 4015H).
5271
CP E BB
Compare register A (1DH) against register E, the low byte one past the restored DCB.
5272
CALL Z,541CH CC 1C 54
If this was the keyboard device (Z), GOSUB to 541CH to clear the keyboard filters and reinitialize the keyboard.
5275
LD A,25H 3E 25
Load register A with 25H; the DCB just past this one ends at low byte 25H when the reset device is the display (DO at 401DH).
5277
CP E BB
Compare register A (25H) against register E, the low byte one past the restored DCB.
5278
LD HL,542AH 21 2A 54
Point register pair HL at 542AH, the screen home-and-clear control sequence, ready if this was the display device.
527B
CALL Z,4467H CC 67 44
If this was the display device (Z), GOSUB to the resident @DSPLY service at 4467H to send the home-and-clear control sequence at (HL) to the screen.

527EH - Common Exit and Command-Level Check

Shared exit path. Restores the caller's stack and returns to the RST 28H dispatcher on a normal exit, or aborts through @ABORT when an error occurred outside the LDOS command level.

527E
LD HL,0000H 21 00 00
Load register pair HL with 0000H; the value being zero signals a normal (non-error) overlay exit to the shared exit code below.
5281
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 5282H, patched at entry (5200H) with the caller's SP; register SP now again addresses the LDOS command-level stack.
5284
LD A,H 7C
Load register A with register H, the high byte of the exit code in register pair HL, to test it for zero.
5285
OR L B5
OR register A with register L, the low byte of the exit code; register A is zero on a normal exit and non-zero when an error is being returned.
5286
RET Z C8
If register pair HL is zero (Z, a normal exit), RETurn to the RST 28H dispatcher.
5287
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context on the error path.
528A
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
528C
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher so it can report the error.
528D
JP 4030H C3 30 40
Not at command level. JUMP to the resident @ABORT service at 4030H to abort the running job.

5290H - Memory Reset: Command-Level and Background-Task Checks

The no-argument path resets all of system memory. It first refuses the reset unless it is running at the LDOS command level with no active background task, displaying the appropriate message, and clears the keyboard and printer filters.

5290
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH; memory reset is only permitted at the LDOS command level.
5293
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5295
LD A,(402DH) 3A 2D 40
Load register A with the first byte of the resident @EXIT vector at 402DH, the command-level path check.
5298
If bit 5 was clear (Z, at command level), JUMP to 529DH keeping the @EXIT byte in register A.
529A
LD A,(4065H) 3A 65 40
Otherwise load register A with the saved register-snapshot A slot at 4065H for the nested-context test.
529D
CP 0C3H FE C3
Compare register A against 0C3H (a Z80 JP opcode); a JP here means a nested job or intercept is active.
529F
JP Z,53E4H CA E4 53
If register A is 0C3H (Z, a nested context is active), JUMP to 53E4H to refuse with the command-level message.
52A2
LD A,(4758H) 3A 58 47
Load register A with the resident SYS1 status byte at 4758H to test for a background task.
52A5
BIT 1,A CB 4F
Test bit 1 of register A (the 4758H status byte), which is set when a background task (such as the printer spooler) is active.
52A7
JP NZ,53E4H C2 E4 53
If a background task is active (NZ), JUMP to 53E4H to refuse the memory reset (the can't-reset message).
52AA
CALL 5416H CD 16 54
GOSUB to 5416H to clear bit 3 of the resident filter flag byte 441FH as part of the system reset.
52AD
CALL 541CH CD 1C 54
GOSUB to 541CH to clear the keyboard filters (441FH) and reinitialize the keyboard driver.

52B0H - Memory Reset: Reset Every Device and Scan High Memory

Walks both device tables resetting each device to its base and closing any routed files, then scans the high-memory module table and refuses the reset if any module sits in protected memory above HIGH$.

52B0
LD HL,4015H 21 15 40
Point register pair HL at 4015H, the first resident device control block, to walk and reset every device.
52B3
PUSH HL E5
Loop Start
Save register pair HL (the current DCB pointer) on the stack across the link-chain walk.
52B4
CALL 53C1H CD C1 53
GOSUB to the link-chain helper at 53C1H to follow this device to its base DCB and close any file it routes to.
52B7
POP HL E1
Restore register pair HL from the stack so it again points at the current DCB.
52B8
LD A,L 7D
Load register A with register L, the low byte of the current DCB address, to step to the next DCB.
52B9
ADD A,08H C6 08
ADD 08H to register A, advancing to the next eight-byte DCB in the table.
52BB
LD L,A 6F
Copy the advanced low byte (register A) back into register L so register pair HL points at the next DCB.
52BC
If the address wrapped to 00H (Z, the whole page has been scanned), JUMP to 52C7H to check high memory.
52BE
CP 2DH FE 2D
Compare register A (the low byte of the next DCB) against 2DH; 402DH is @EXIT, one past the last device in the KI/DO/PR table.
52C0
If the end of the resident device table has not been reached (NZ), LOOP BACK to 52B3H to reset the next device.
52C2
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device table (JL/SI/SO), to continue resetting there.
52C5
JR 52B3H 18 EC
JUMP to 52B3H to walk and reset the auxiliary device table.
52C7
LD B,0CH 06 0C
Load register B with 0CH (12), the number of high-memory module-table slots to examine.
52C9
LD HL,4500H 21 00 45
Point register pair HL at 4500H, the base of the high-memory module descriptor table.
52CC
LD E,(HL) 5E
Loop Start
Load register E with the low byte of the current module's start address at (HL).
52CD
INC HL 23
INCrement register pair HL to the high byte of the module start address.
52CE
LD D,(HL) 56
Load register D with the high byte of the module start address; register pair DE now holds the module's start address.
52CF
INC HL 23
INCrement register pair HL to the next module-table slot.
52D0
PUSH HL E5
Save register pair HL (the module-table pointer) on the stack across the range check.
52D1
LD HL,(4049H) 2A 49 40
Load register pair HL with HIGH$, the top of the user memory region, from 4049H.
52D4
XOR A AF
Set register A to zero and clear the carry for the comparison.
52D5
SBC HL,DE ED 52
SUBtract register pair DE (the module start) from register pair HL (HIGH$) with SBC; a borrow means the module sits above HIGH$ in protected memory.
52D7
POP HL E1
Restore register pair HL from the stack so it again points at the module table.
52D8
If the module lies above HIGH$ (CARRY, a protected resident module), JUMP to 5331H to refuse the reset (background task message).
52DA
DECrement register B and LOOP BACK to 52CCH to examine the next high-memory module slot.

52DCH - Memory Reset: Restore Resident Vectors, HIGH$ and Default DCBs

Rebuilds the base system: disarms resident hooks and interception routines, empties the high-memory module chain, clears resident work areas, refreshes the drive code tables, restores HIGH$ to the top of memory and reinstalls the default device control blocks.

52DC
LD A,0C9H 3E C9
Load register A with 0C9H, a Z80 RET opcode, to disable a resident interception routine.
52DE
LD (45DAH),A 32 DA 45
Store the RET opcode (register A) at 45DAH, disabling that resident routine.
52E1
LD HL,4876H 21 76 48
Point register pair HL at 4876H, the resident default command handler address.
52E4
LD (4310H),HL 22 10 43
Store 4876H (register pair HL) into the resident unrecognized-command vector at 4310H, restoring its default handler.
52E7
LD HL,4BF5H 21 F5 4B
Point register pair HL at 4BF5H, the overlay-loader entry address that marks an empty high-memory module chain.
52EA
LD (4BDFH),HL 22 DF 4B
Store 4BF5H (register pair HL) into the module-chain head at 4BDFH, emptying the resident high-memory module chain.
52ED
LD HL,4DF0H 21 F0 4D
Point register pair HL at 4DF0H, the first byte of a 14-byte resident work area to be cleared.
52F0
LD DE,4DF1H 11 F1 4D
Point register pair DE at 4DF1H, one byte into the work area, the destination for the fill.
52F3
LD BC,000DH 01 0D 00
Load register pair BC with 000DH (13), the count for the propagate-zero fill.
52F6
LD (HL),00H 36 00
Store 00H at (HL) = 4DF0H, seeding the zero fill of the work area.
52F8
LDIR ED B0
Block-copy the seed zero forward through 4DF0H-4DFDH (register pair BC = count), clearing the 14-byte resident work area.
52FA
LD HL,430FH 21 0F 43
Point register pair HL at the resident system flag byte SFLAG$ at 430FH.
52FD
RES 0,(HL) CB 86
Clear bit 0 of SFLAG$ at (HL) = 430FH, resetting that system state flag.
52FF
LD HL,4BEFH 21 EF 4B
Point register pair HL at 4BEFH, the default value for the RST 28H dispatcher work word.
5302
LD (4BCFH),HL 22 CF 4B
Store 4BEFH (register pair HL) into the dispatcher work word at 4BCFH, restoring its default.
5305
LD A,0C9H 3E C9
Load register A with 0C9H, a Z80 RET opcode, to disarm two resident hooks.
5307
LD (44FDH),A 32 FD 44
Store the RET opcode (register A) at 44FDH, disarming that resident hook.
530A
LD (4303H),A 32 03 43
Store the RET opcode (register A) at 4303H, disarming that resident hook.
530D
LD DE,0002H 11 02 00
Load register pair DE with 0002H, selecting sector 2 for the read that follows.
5310
LD HL,4200H 21 00 42
Point register pair HL at 4200H, SBUFF$, the shared sector buffer for the read.
5313
CALL 4777H CD 77 47
GOSUB to the resident RDSECT primitive at 4777H to read the sector into the buffer at 4200H; it returns NZ on error.
5316
JP NZ,53DDH C2 DD 53
If the read failed (NZ), JUMP to 53DDH to report the error through @ERROR.
5319
LD L,70H 2E 70
Load register L with 70H so register pair HL addresses the source of the drive-table refresh.
531B
LD DE,4700H 11 00 47
Point register pair DE at 4700H, DCT$, the base of the resident drive code tables (the copy destination).
531E
LD BC,0050H 01 50 00
Load register pair BC with 0050H (80), the byte count of the drive-table refresh.
5321
LD A,(442FH) 3A 2F 44
Load register A with the resident configuration byte at 442FH to select which portion of the buffer to copy.
5324
RRCA 0F
Rotate register A right, moving bit 0 of the configuration byte into the carry flag.
5325
If bit 0 was clear (NO CARRY), JUMP to 5329H keeping the source pointer at 4270H (L=70H).
5327
LD L,20H 2E 20
Otherwise load register L with 20H so register pair HL sources the drive-table refresh from 4220H.
5329
LDIR ED B0
Block-copy 80 bytes from the buffer (HL) to the drive code tables at 4700H (register pair BC = count), refreshing the DCT$ contents.
532B
DI F3
Disable interrupts while the resident memory pointers are restored.
532C
LD HL,(4403H) 2A 03 44
Load register pair HL with the resident top-of-memory word from 4403H.
532F
JR 5340H 18 0F
JUMP to 5340H to store this value into HIGH$ (the reset resets HIGH$ to the top of memory).
5331
LD HL,54A9H 21 A9 54
Point register pair HL at 54A9H, the message Can't reset memory, background task(s) exist.
5334
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).
5337
LD A,03H 3E 03
Load register A with 03H, a value used to flag the aborted-reset state.
5339
LD (542AH),A 32 2A 54
Store register A (03H) into the display buffer at 542AH, marking the reset as refused.
533C
DI F3
Disable interrupts while HIGH$ is left unchanged on the refusal path.
533D
LD HL,(4049H) 2A 49 40
Load register pair HL with the current HIGH$ value from 4049H (leaving it unchanged when the reset is refused).
5340
LD (4049H),HL 22 49 40
Store register pair HL into HIGH$ at 4049H (either the top-of-memory value from 5340H reached via 532FH, or the unchanged value on the refusal path).
5343
LD HL,(4020H) 2A 20 40
Load register pair HL with the current video display DCB cursor word from 4020H, to preserve the cursor across the DCB restore.
5346
PUSH HL E5
Save the video cursor word (register pair HL) on the stack.
5347
LD HL,542DH 21 2D 54
Point register pair HL at 542DH, the base of the local default-DCB template (KI, DO and PR entries).
534A
LD DE,4015H 11 15 40
Point register pair DE at 4015H, the resident KI/DO/PR device table, the restore destination.
534D
LD BC,0018H 01 18 00
Load register pair BC with 0018H (24), the size of three 8-byte DCBs.
5350
LDIR ED B0
Block-copy the three base DCBs from (HL) to 4015H (register pair BC = count), restoring KI, DO and PR to their base drivers.
5352
POP HL E1
Restore the saved video cursor word (register pair HL) from the stack.
5353
LD (4020H),HL 22 20 40
Store the video cursor word (register pair HL) back into the display DCB at 4020H, preserving the cursor position.
5356
LD HL,0000H 21 00 00
Load register pair HL with 0000H to clear a resident work word.
5359
LD (43BEH),HL 22 BE 43
Store zero (register pair HL) into the resident work word at 43BEH.
535C
LD HL,5445H 21 45 54
Point register pair HL at 5445H, the base of the local default DCB template for the auxiliary devices (JL, SI, SO).
535F
LD DE,43C0H 11 C0 43
Point register pair DE at 43C0H, the resident auxiliary device table, the restore destination.
5362
LD BC,0018H 01 18 00
Load register pair BC with 0018H (24), the size of three 8-byte DCBs.
5365
LDIR ED B0
Block-copy the three base DCBs from (HL) to 43C0H (register pair BC = count), restoring JL, SI and SO to their base drivers.
5367
LD HL,43D8H 21 D8 43
Point register pair HL at 43D8H, the start of a resident work area to be cleared.
536A
XOR A AF
Set register A to zero for the clear.
536B
LD (HL),A 77
Loop Start
Store zero (register A) at (HL) in the 43D8H work area.
536C
INC L 2C
INCrement register L to the next byte of the work area.
536D
If register L has not wrapped to 00H (NZ), LOOP BACK to 536BH to clear the next byte through the end of the page.
536F
EI FB
Re-enable interrupts now that the resident state has been rebuilt.
5370
CP A BF
Compare register A with itself, setting the zero flag to signal a clean (non-error) completion.
5371
JP 5278H C3 78 52
JUMP to 5278H to reach the common exit with a normal-completion status.

5374H - Disk File: Set the LRL and DATE Directory Attributes

When the argument names a disk file, opens it, checks the update access level, reads its directory entry and applies the requested logical record length and date, then writes the directory record back.

5374
CALL 4424H CD 24 44
Disk file. GOSUB to the resident @OPEN service at 4424H to open the file whose FCB is at (DE); it returns NZ on a failure.
5377
If the open failed (NZ), JUMP to 53DDH to report the error through @ERROR.
5379
PUSH DE D5
Save register pair DE (the FCB address) on the stack to move it into an index register.
537A
POP IX DD E1
Restore it into register IX so register IX points at the opened file's FCB.
537C
LD A,(IX+01H) DD 7E 01
Load register A with FCB byte +1 at IX+01H, whose low three bits hold the file's access level.
537F
AND 07H E6 07
AND register A with 07H to isolate the three-bit access-level field of the FCB.
5381
CP 05H FE 05
Compare the access level (register A) against 05H; a level of 5 or above lacks the update rights this command needs.
5383
LD A,25H 3E 25
Load register A with 25H (37), the LDOS file-access-denied error code, in case the access check fails.
5385
If the access level is 5 or above (NO CARRY, insufficient rights), JUMP to 53DDH to report file access denied.
5387
LD BC,(54FCH) ED 4B FC 54
Load register pair BC with the directory reference from 54FCH (FCB byte +6/+7): register C = drive, register B = directory record number.
538B
CALL 4B10H CD 10 4B
GOSUB to the resident DIRRD service at 4B10H to read the file's directory record (register B, register C) into memory at (HL).
538E
If the directory read failed (NZ), JUMP to 53DDH to report the error through @ERROR.
5390
PUSH HL E5
Save register pair HL (the directory record pointer) on the stack to move it into an index register.
5391
POP IY FD E1
Restore it into register IY so register IY points at the file's directory entry.
5393
LD DE,0FF00H 11 00 FF
Self-Modifying Code
Load register pair DE with the LRL value from the operand at 5394H; @PARAM writes the requested logical record length here, leaving 0FF00H (high byte FFH) when no LRL keyword was given.
5396
INC D 14
INCrement register D; when register D was FFH (no LRL supplied) it becomes 00H and sets the zero flag.
5397
If no LRL was supplied (Z), JUMP to 539CH to leave the record length unchanged.
5399
LD (IY+04H),E FD 73 04
Store register E (the new logical record length) into directory entry byte IY+04H, the file's LRL.
539C
LD DE,0FF00H 11 00 FF
Self-Modifying Code
Load register pair DE with the DATE value from the operand at 539DH; @PARAM writes the requested date here (or 0FFFFH for the keyword alone), leaving 0FF00H when no DATE keyword was given.
539F
LD A,D 7A
Load register A with register D, the high byte of the DATE value.
53A0
INC A 3C
INCrement register A; combined with the OR below this tests whether the DATE value is the unset 0FF00H marker.
53A1
OR E B3
OR register A with register E, the low byte of the DATE value; the result is zero only when no DATE was supplied.
53A2
If no DATE was supplied (Z), JUMP to 53B9H to write the directory record without a date change.
53A4
LD (IY+12H),96H FD 36 12 96
Store 96H into directory entry byte IY+12H, the high byte of the update-password field (9642H is the LDOS hash of a blank password).
53A8
LD (IY+13H),42H FD 36 13 42
Store 42H into directory entry byte IY+13H, the low byte of the update-password field, clearing any password.
53AC
PUSH IX DD E5
Save register pair IX (the FCB pointer) on the stack.
53AE
LD A,D 7A
Load register A with register D, the high byte of the DATE value, for the keyword-alone test.
53AF
AND E A3
AND register A with register E, the low byte of the DATE value.
53B0
INC A 3C
INCrement register A; the zero flag is set when the DATE value was 0FFFFH (the DATE keyword given with no value).
53B1
POP DE D1
Restore register pair DE from the stack so register pair DE again holds the FCB pointer.
53B2
SET 2,(IX+00H) DD CB 00 D6
Set bit 2 of FCB byte IX+00H, marking the file as dated/modified.
53B6
CALL Z,53D9H CC D9 53
If the DATE keyword was given with no value (Z), GOSUB to 53D9H to close the file.
53B9
CALL 4B1FH CD 1F 4B
GOSUB to the resident DIRWR service at 4B1FH to write the updated directory record back to disk; it returns NZ on error.
53BC
If the directory write failed (NZ), JUMP to 53DDH to report the error through @ERROR.
53BE
JP 527EH C3 7E 52
JUMP to 527EH to reach the common exit with a normal-completion status.

53C1H - Link-Chain Walk and Routed-File Close Helper

Follows a device's link chain to its base control block and, if the base routes output to a disk file, copies that file's control block to a work area and closes it.

53C1
BIT 4,(HL) CB 66
Loop Start
Test bit 4 of the DCB type byte at (HL), which is set when this device is linked to another device.
53C3
If bit 4 is clear (Z, the base device), JUMP to 53CCH to check for a file route.
53C5
INC HL 23
INCrement register pair HL to DCB byte +1, the low byte of the linked-device pointer.
53C6
LD A,(HL) 7E
Load register A with DCB byte +1 at (HL), the low byte of the linked-device address.
53C7
INC HL 23
INCrement register pair HL to DCB byte +2, the high byte of the linked-device pointer.
53C8
LD H,(HL) 66
Load register H with DCB byte +2 at (HL), the high byte of the linked-device address.
53C9
LD L,A 6F
Load register L with register A (the saved low byte) so register pair HL points at the linked device's control block.
53CA
JR 53C1H 18 F5
LOOP BACK to 53C1H to follow the link chain to its base device.
53CC
BIT 7,(HL) CB 7E
Test bit 7 of the base DCB type byte at (HL), which is set when the device routes its output to a disk file.
53CE
RET Z C8
If bit 7 is clear (Z, not a file route), RETurn to the caller with nothing to close.
53CF
LD DE,54D6H 11 D6 54
Point register pair DE at 54D6H, the FCB work area (in RAM just past the overlay) that will receive the routed file's control block.
53D2
PUSH DE D5
Save register pair DE (the 54D6H work-area pointer) on the stack.
53D3
LD BC,0020H 01 20 00
Load register pair BC with 0020H (32), the size of a file control block.
53D6
LDIR ED B0
Block-copy the 32-byte FCB of the routed file from (HL) to the work area at (DE) (register pair BC = count).
53D8
POP DE D1
Restore register pair DE from the stack so register pair DE points at the copied FCB at 54D6H.
53D9
CALL 4428H CD 28 44
GOSUB to the resident @CLOSE service at 4428H to close the routed file whose FCB is at (DE); it returns Z on success.
53DC
RET Z C8
If the close succeeded (Z), RETurn to the caller.

53DDH - Error and Command-Level Refusal Paths

The shared @ERROR reporting path and the command-level refusal path that displays the Valid only at LDOS command level message, both ending in the error exit.

53DD
OR 0C0H F6 C0
Error path. OR register A with 0C0H, setting bits 6 and 7 so @ERROR returns to the caller (message-only) rather than aborting.
53DF
CALL 4409H CD 09 44
GOSUB to the resident @ERROR service at 4409H to display the error whose code is in register A.
53E2
JR 53EAH 18 06
JUMP to 53EAH to set the error return and exit.
53E4
LD HL,547EH 21 7E 54
Point register pair HL at 547EH, the message Can't -- Valid only at LDOS command level!.
53E7
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).
53EA
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero value that flags an error/abort exit to the shared exit code.
53ED
JP 5281H C3 81 52
JUMP to 5281H to restore the caller's stack and exit through the common exit path.

53F0H - Find Device Control Block by Name

Searches the resident KI/DO/PR table and the auxiliary JL/SI/SO table for a device control block whose two-character name matches the requested device, returning its address or a device-not-available error.

53F0
LD HL,4015H 21 15 40
Loop Start
Point register pair HL at 4015H, the first resident device control block, to search for the named device.
53F3
PUSH HL E5
Loop Start
Save register pair HL (the current DCB pointer) on the stack across the name comparison.
53F4
LD A,L 7D
Load register A with register L, the low byte of the DCB address, to reach its name field.
53F5
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, the first character of the device name.
53F7
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at DCB byte +6.
53F8
LD A,(HL) 7E
Load register A with DCB byte +6 at (HL), the first character of this device's name.
53F9
INC L 2C
INCrement register L to DCB byte +7, the second name character.
53FA
CP E BB
Compare register A (the first name character) against register E, the first character of the requested device name.
53FB
If the first characters differ (NZ), JUMP to 5404H to advance to the next DCB.
53FD
LD A,(HL) 7E
Load register A with DCB byte +7 at (HL), the second character of this device's name.
53FE
CP D BA
Compare register A (the second name character) against register D, the second character of the requested device name.
53FF
If the second characters differ (NZ), JUMP to 5404H to advance to the next DCB.
5401
POP HL E1
Match found. Restore register pair HL from the stack so it points at the matching DCB.
5402
XOR A AF
Set register A to zero and clear the flags to signal a successful search.
5403
RET C9
RETurn to the caller with register pair HL pointing at the matching device's DCB.
5404
POP AF F1
No match. Restore register AF from the stack (discarding the saved DCB pointer's low byte handling) so register pair HL again holds the DCB pointer.
5405
INC L 2C
INCrement register L, stepping toward the next DCB and testing for a page wrap.
5406
If register L did not wrap to 00H (NZ), JUMP to 540CH to check the end-of-table marker.
5408
LD A,08H 3E 08
The whole page was searched. Load register A with 08H, the LDOS device-not-available error code.
540A
OR A B7
OR register A with itself to set the flags (NZ) so the caller sees the not-found error.
540B
RET C9
RETurn to the caller with the device-not-found status.
540C
LD A,L 7D
Load register A with register L, the low byte of the address reached, to test for the end of the KI/DO/PR table.
540D
CP 2DH FE 2D
Compare register A against 2DH; 402DH (@EXIT) is one past the last device in the resident table.
540F
If the end of the resident table has not been reached (NZ), LOOP BACK to 53F3H to compare the next DCB.
5411
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device table (JL/SI/SO), to continue the search there.
5414
JR 53F3H 18 DD
LOOP BACK to 53F3H to search the auxiliary device table.

5416H - Filter-Flag Reset Helpers

Two small helpers that clear device filter bits in the resident flag byte 441FH and reinitialize the keyboard driver.

5416
LD HL,441FH 21 1F 44
Point register pair HL at the resident filter flag byte 441FH.
5419
RES 3,(HL) CB 9E
Clear bit 3 of the filter flag byte at (HL) = 441FH, removing that device's filter.
541B
RET C9
RETurn to the caller.
541C
LD A,(441FH) 3A 1F 44
Load register A with the resident filter flag byte at 441FH to clear the keyboard filters.
541F
AND 89H E6 89
AND register A with 89H, keeping bits 0, 3 and 7 and clearing the remaining keyboard filter bits.
5421
LD (441FH),A 32 1F 44
Store the cleared filter flags (register A) back into 441FH.
5424
LD A,0AH 3E 0A
Load register A with 0AH, the reinitialize request passed to the resident routine below.
5426
CALL 4413H CD 13 44
GOSUB to the resident routine at 4413H (register A = 0AH) to reinitialize the keyboard device after clearing its filters.
5429
RET C9
RETurn to the caller.

542AH - Control Sequence, Default DCB Templates and @PARAM Table

The screen home-and-clear control sequence, the six 8-byte base device control block templates used to restore KI, DO, PR, JL, SI and SO to their default drivers, and the @PARAM keyword descriptor table for the LRL and DATE options.

542A-542B
DEFB 1CH,1FH 1C 1F
Screen Control Sequence
The home-cursor (1CH) and clear-to-end-of-frame (1FH) video control codes, displayed at 527BH when the display device (DO) is reset. Byte 542AH is also overwritten with 03H at 5339H on the refused-reset path.
542C
DEFB 03H 03
The 03H terminator of the control sequence.
542D
DEFB 01H 01
KI DCB Template
Device type byte of the base keyboard control block copied to 4015H at 5350H.
542E-542F
DEFW 0000H 00 00
KI base-driver address. Patched at 5208H from the resident save word 43B8H before the template is used.
5430-5432
DEFB 00H,00H,00H 00 00 00
KI working storage (initially zero).
5433-5434
DEFM "KI" 4B 49
Keyboard device name.
5435
DEFB 07H 07
DO DCB Template
Device type byte of the base display control block copied to 401DH at 5350H.
5436-5437
DEFW 0000H 00 00
DO base-driver address. Patched at 520EH from the resident save word 43BAH.
5438-543A
DEFB 00H,3CH,00H 00 3C 00
DO working storage; 3CH is the high byte of the video RAM address (3C00H).
543B-543C
DEFM "DO" 44 4F
Display device name.
543D
DEFB 06H 06
PR DCB Template
Device type byte of the base printer control block copied to 4025H at 5350H.
543E-543F
DEFW 0000H 00 00
PR base-driver address. Patched at 5214H from the resident save word 43BCH.
5440-5442
DEFB 42H,00H,00H 42 00 00
PR working storage; 42H is the high byte of the printer buffer address (4200H).
5443-5444
DEFM "PR" 50 52
Printer device name.
5445
DEFB 08H 08
JL DCB Template
Device type byte of the base JL control block copied to 43C0H at 5365H.
5446-544A
DEFB 00H,00H,00H,00H,00H 00 00 00 00 00
JL driver address and working storage (nil).
544B-544C
DEFM "JL" 4A 4C
Job-log device name.
544D
DEFB 08H 08
SI DCB Template
Device type byte of the base SI control block copied to 43C8H at 5365H.
544E-5452
DEFB 00H,00H,00H,00H,00H 00 00 00 00 00
SI driver address and working storage (nil).
5453-5454
DEFM "SI" 53 49
Standard-input device name.
5455
DEFB 08H 08
SO DCB Template
Device type byte of the base SO control block copied to 43D0H at 5365H.
5456-545A
DEFB 00H,00H,00H,00H,00H 00 00 00 00 00
SO driver address and working storage (nil).
545B-545C
DEFM "SO" 53 4F
Standard-output device name.
545D-5462
DEFM "LRL " 4C 52 4C 20 20 20
The LRL keyword. @PARAM stores its value into the LRL operand cell at 5394H (the LD DE operand at 5393H).
5463-5464
DEFW 5394H 94 53
Pointer to the LRL operand cell (5394H) that the LRL keyword sets.
5465-546A
DEFM "L " 4C 20 20 20 20 20
Single-letter abbreviation L for the LRL keyword; same operand cell 5394H.
546B-546C
DEFW 5394H 94 53
Pointer to the LRL operand cell (5394H) that the L keyword sets.
546D-5472
DEFM "DATE " 44 41 54 45 20 20
The DATE keyword. @PARAM stores its value into the DATE operand cell at 539DH (the LD DE operand at 539CH).
5473-5474
DEFW 539DH 9D 53
Pointer to the DATE operand cell (539DH) that the DATE keyword sets.
5475-547A
DEFM "D " 44 20 20 20 20 20
Single-letter abbreviation D for the DATE keyword; same operand cell 539DH.
547B-547C
DEFW 539DH 9D 53
Pointer to the DATE operand cell (539DH) that the D keyword sets.
547D
DEFB 00H 00
Zero byte marking the end of the @PARAM keyword descriptor table.

547EH - Refusal Messages

The two carriage-return-terminated refusal messages displayed through the resident 447BH service.

547E-54A7
DEFM "Can't -- Valid only at LDOS command level!" 43 61 6E 27 74 20 2D 2D 20 56 61 6C 69 64 20 6F 6E 6C 79 20 61 74 20 4C 44 4F 53 20 63 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C 21
Message
Displayed at 53E7H when the command is refused because a nested job or intercept is active or it was not issued at the LDOS command level.
54A8
DEFB 0DH 0D
Carriage return terminating the message above.
54A9-54D4
DEFM "Can't reset memory, background task(s) exist" 43 61 6E 27 74 20 72 65 73 65 74 20 6D 65 6D 6F 72 79 2C 20 62 61 63 6B 67 72 6F 75 6E 64 20 74 61 73 6B 28 73 29 20 65 78 69 73 74
Message
Displayed at 5334H when the memory reset is refused because a background task is running or a resident module occupies protected memory above HIGH$.
54D5
DEFB 0DH 0D
Carriage return terminating the message above.

Disassembly - Overlay 13 - ROUTE

5200H - Overlay Entry: Parse the Source Device and Options

Entry of the ROUTE command overlay, which sends all output of one device to another device or to a disk file. It saves the caller's stack, parses the source device specification with @FSPEC, parses the NIL and REWIND options with @PARAM, records the source device name in the routing-module name, and branches to the NIL handler when NIL was given.

5200
LD (527EH),SP ED 73 7E 52
Self-Modifying Code
Store the caller's stack pointer (register SP, holding the LDOS command-level stack on entry) into the operand of the LD SP,nnnn at 527DH, so the overlay exit can restore this stack.
5204
LD DE,5434H 11 34 54
Point register pair DE at 5434H, the FCB work area (in RAM just past the overlay) that will receive the source device specification.
5207
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the first specification at (HL) into the FCB at (DE); it returns NZ when the specification is malformed.
520A
If the specification is malformed (NZ), JUMP to 5230H, which reports Device spec required.
520C
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (the asterisk character) marks a device specification.
520D
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk) that opens a device name.
520F
If the source is not a device (NZ), JUMP to 5230H to report Device spec required (ROUTE only routes devices).
5211
LD DE,53D1H 11 D1 53
Point register pair DE at 53D1H, the local @PARAM keyword descriptor table (NIL and REWIND/R).
5214
CALL 4476H CD 76 44
GOSUB to the resident @PARAM service at 4476H to parse any NIL or REWIND option on the source; it returns NZ on a syntax error.
5217
JP NZ,5351H C2 51 53
If @PARAM reported a syntax error (NZ), JUMP to 5351H to report a parameter error through @ERROR.
521A
LD DE,(5435H) ED 5B 35 54
Load register pair DE with the two-character source device name from 5435H (FCB bytes +1 and +2).
521E
LD (53F1H),DE ED 53 F1 53
Store the source device name (register pair DE) into 53F1H, the name field of the routing-module name template (making the module name $R plus this device).
5222
LD BC,0000H 01 00 00
Self-Modifying Code
Load register pair BC with the NIL flag from the operand at 5223H; @PARAM sets it non-zero when the NIL keyword was given, leaving 0000H otherwise.
5225
LD A,B 78
Load register A with register B, the high byte of the NIL flag from 5223H, to test the flag for zero.
5226
OR C B1
OR register A with register C, the low byte of the NIL flag; register A is non-zero only when NIL was requested.
5227
JP NZ,531CH C2 1C 53
If NIL was requested (NZ), JUMP to 531CH to route the device to nothing.

522AH - Parse the Destination and Dispatch by Route Type

Parses the destination specification. A device destination is routed device-to-device (rejecting a device routed to itself); a disk-file destination is routed through a high-memory file module.

522A
LD DE,53F4H 11 F4 53
Point register pair DE at 53F4H, the FCB work area (in RAM just past the overlay) that will receive the destination specification.
522D
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the destination specification into the FCB at (DE); it returns NZ when it is missing or malformed.
5230
JP NZ,535EH C2 5E 53
If the destination specification is missing or malformed (NZ), JUMP to 535EH to report Device spec required.
5233
PUSH DE D5
Save register pair DE (the destination FCB pointer) on the stack across the option parse.
5234
LD DE,53D1H 11 D1 53
Point register pair DE at 53D1H, the local @PARAM keyword descriptor table, to parse options on the destination.
5237
CALL 4476H CD 76 44
GOSUB to the resident @PARAM service at 4476H to parse any NIL or REWIND option on the destination.
523A
POP DE D1
Restore register pair DE from the stack so it again points at the destination FCB.
523B
JP NZ,5351H C2 51 53
If @PARAM reported a syntax error (NZ), JUMP to 5351H to report a parameter error through @ERROR.
523E
LD A,(DE) 1A
Load register A with the first destination FCB byte at (DE); a 2AH (the asterisk) marks a device, otherwise it is a disk file.
523F
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
5241
If the destination is not a device (NZ, a disk file), JUMP to 528CH to route the source device to a disk file.
5243
LD DE,(53F5H) ED 5B F5 53
Load register pair DE with the two-character destination device name from 53F5H (FCB bytes +1 and +2).
5247
LD HL,(5435H) 2A 35 54
Load register pair HL with the two-character source device name from 5435H, to compare it with the destination.
524A
SBC HL,DE ED 52
SUBtract register pair DE (the destination name) from register pair HL (the source name) with SBC; the result is zero when the two devices are the same.
524C
JP Z,535EH CA 5E 53
If the source and destination are the same device (Z), JUMP to 535EH to report Device spec required (a device cannot be routed to itself).
524F
CALL 536AH CD 6A 53
GOSUB to the local find-DCB-by-name helper at 536AH to locate the destination device's control block (register pair HL), returning NZ and error 08H if it is unknown.
5252
JP NZ,5353H C2 53 53
If the destination device was not found (NZ), JUMP to 5353H to report the error through @ERROR.

5255H - Install the Route into the Source Device and Exit

Marks the source device as routed, stores the destination address into the source control block link pointer and the destination name into the device-name field the DEVICE command displays, then returns to the dispatcher (or aborts below command level on an error).

5255
PUSH HL E5
Save register pair HL (the destination DCB pointer) on the stack.
5256
CALL 5303H CD 03 53
GOSUB to the local helper at 5303H, which locates and validates the source device's control block (register pair HL) and closes any file it is already routed to.
5259
DI F3
Disable interrupts while the source DCB is relinked.
525A
LD (HL),10H 36 10
Store 10H into the source DCB type byte at (HL), marking the device as routed.
525C
POP BC C1
Restore register pair BC from the stack so register pair BC holds the destination DCB (or high-memory module) address.
525D
PUSH HL E5
Re-save register pair HL (the source DCB pointer) on the stack for the name copy below.
525E
LD A,L 7D
Load register A with register L, the low byte of the source DCB address, to test for the keyboard device.
525F
CP 15H FE 15
Compare register A against 15H; 4015H is the keyboard device (KI), which needs special handling at the command level.
5261
INC L 2C
INCrement register L so register pair HL addresses source DCB byte +1, the low byte of the link pointer.
5262
If the source is not the keyboard (NZ), JUMP to 526EH to store the link pointer directly.
5264
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context.
5267
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5269
If at the command level (Z), JUMP to 526EH to store the link pointer in the keyboard DCB.
526B
LD HL,43BEH 21 BE 43
Otherwise point register pair HL at 43BEH, the resident work word, so a keyboard route made below command level is recorded there instead of in the live DCB.
526E
LD (HL),C 71
Store register C (the low byte of the destination DCB/module address) at (HL), the source DCB link pointer low byte.
526F
INC L 2C
INCrement register L to the link pointer high byte.
5270
LD (HL),B 70
Store register B (the high byte of the destination address) at (HL), completing the source DCB link pointer.
5271
POP HL E1
Restore register pair HL from the stack so it again points at the start of the source DCB.
5272
LD A,L 7D
Load register A with register L, the low byte of the source DCB address, to reach its name field.
5273
ADD A,06H C6 06
ADD 06H to register A so it addresses source DCB byte +6, the first character of the device name.
5275
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at source DCB byte +6.
5276
LD (HL),E 73
Store register E (the first character of the destination name) at (HL), source DCB byte +6.
5277
INC L 2C
INCrement register L to source DCB byte +7.
5278
LD (HL),D 72
Store register D (the second character of the destination name) at (HL), completing the routed-to name shown by the DEVICE command.
5279
EI FB
Re-enable interrupts now that the route is installed.
527A
LD HL,0000H 21 00 00
Load register pair HL with 0000H; the value being zero signals a normal (non-error) overlay exit to the shared exit code below.
527D
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 527EH, patched at entry (5200H) with the caller's SP; register SP now again addresses the LDOS command-level stack.
5280
LD A,H 7C
Load register A with register H, the high byte of the exit code in register pair HL, to test it for zero.
5281
OR L B5
OR register A with register L, the low byte of the exit code; register A is zero on a normal exit and non-zero when an error is being returned.
5282
RET Z C8
If register pair HL is zero (Z, a normal exit), RETurn to the RST 28H dispatcher.
5283
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context on the error path.
5286
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5288
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher so it can report the error.
5289
JP 4030H C3 30 40
Not at command level. JUMP to the resident @ABORT service at 4030H to abort the running job.

528CH - Route to a Disk File: Locate or Allocate the High-Memory Module

Looks up an existing routing module for the device, or checks the command level, opens the destination file (positioning to its end for append unless REWIND was given), reserves memory below HIGH$ and builds the module header and file control block, then links the device to it.

528C
PUSH DE D5
Route to a disk file. Save register pair DE (the destination file's FCB) on the stack.
528D
LD DE,53EFH 11 EF 53
Point register pair DE at 53EFH, the routing-module name ($R plus the source device, terminated by 03H), the lookup key.
5290
CALL 532DH CD 2D 53
GOSUB to the local helper at 532DH, which issues the resident routing-module lookup (RST 28H code BCH) for the name at (DE); it returns Z with register pair HL pointing at the module if this device is already routed to a file.
5293
POP DE D1
Restore register pair DE from the stack so it again points at the destination file's FCB.
5294
If no existing routing module was found (NZ), JUMP to 52A2H to allocate a new one.
5296
INC HL 23
An existing module was found. INCrement register pair HL past the module link field.
5297
INC HL 23
INCrement register pair HL again to the module's buffer-address field.
5298
LD A,(HL) 7E
Load register A with the low byte of the module's buffer address at (HL).
5299
INC HL 23
INCrement register pair HL to the high byte of the buffer address.
529A
LD H,(HL) 66
Load register H with the high byte of the buffer address at (HL).
529B
LD L,A 6F
Load register L with register A (the saved low byte) so register pair HL points at the existing module's buffer.
529C
XOR A AF
Set register A to zero, ready to mark that no new high memory needs to be reserved.
529D
LD (52E5H),A 32 E5 52
Self-Modifying Code
Store zero into 52E5H, the operand of the OR nn at 52E4H, so the HIGH$ reservation below is skipped when reusing an existing module.
52A0
JR 52BFH 18 1D
JUMP to 52BFH to reuse the existing module without reserving more memory.
52A2
LD A,(430FH) 3A 0F 43
Allocate a new module. Load register A with the resident system flag byte SFLAG$ at 430FH; a new high-memory allocation is only allowed at the command level.
52A5
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
52A7
LD A,(402DH) 3A 2D 40
Load register A with the first byte of the resident @EXIT vector at 402DH, the command-level path check.
52AA
If at the command level (Z), JUMP to 52AFH keeping the @EXIT byte in register A.
52AC
LD A,(4065H) 3A 65 40
Otherwise load register A with the saved register-snapshot A slot at 4065H for the nested-context test.
52AF
CP 0C3H FE C3
Compare register A against 0C3H (a Z80 JP opcode); a JP here means a nested job or intercept is active.
52B1
JP Z,535AH CA 5A 53
If register A is 0C3H (Z, a nested context is active), JUMP to 535AH to refuse with the command-level message.
52B4
LD A,(4758H) 3A 58 47
Load register A with the resident SYS1 status byte at 4758H to test for a background task.
52B7
BIT 1,A CB 4F
Test bit 1 of register A (the 4758H status byte), which is set when a background task is active.
52B9
JP NZ,535AH C2 5A 53
If a background task is active (NZ), JUMP to 535AH to refuse the routing (the command-level message).
52BC
LD HL,(4049H) 2A 49 40
Load register pair HL with HIGH$, the top of the user memory region, from 4049H, the base for the new module.
52BF
LD (53ECH),HL 22 EC 53
Store register pair HL into 53ECH, the module buffer-base cell of the header template, recording where the new module begins.
52C2
INC HL 23
INCrement register pair HL to point one byte into the new module region.
52C3
DEC H 25
DECrement register H, adjusting register pair HL to the FCB blocking buffer position within the module.
52C4
PUSH HL E5
Save register pair HL (the module/FCB pointer) on the stack across the file open.
52C5
LD B,00H 06 00
Load register B with 00H, the record length selector passed to @INIT.
52C7
CALL 4420H CD 20 44
GOSUB to the resident @INIT service at 4420H to open the destination file (creating it if it does not exist); it returns NZ on error.
52CA
If the open returned an error (NZ), JUMP to 52D9H to test whether it was a tolerable end-of-file condition.
52CC
LD BC,0000H 01 00 00
Self-Modifying Code
Load register pair BC with the REWIND flag from the operand at 52CDH; @PARAM sets it non-zero when REWIND was requested, leaving 0000H otherwise.
52CF
LD A,B 78
Load register A with register B, the high byte of the REWIND flag from 52CDH.
52D0
AND C A1
AND register A with register C, the low byte of the REWIND flag; combined with the INC below this tests whether REWIND was omitted.
52D1
INC A 3C
INCrement register A; the zero flag is set when the REWIND flag was 0FFFFH.
52D2
CALL NZ,4448H C4 48 44
If REWIND was not requested (NZ), GOSUB to the resident @POSN service at 4448H to position the file at its end so routed data is appended.
52D5
If the file was positioned to the end successfully (Z), JUMP to 52D9H to continue.
52D7
CP 1CH FE 1C
Compare register A against 1CH, the end-of-file code that is expected and tolerated when appending to a new file.
52D9
POP HL E1
Restore register pair HL from the stack so it again points at the module/FCB region.
52DA
JP NZ,5353H C2 53 53
If the open or position failed with a real error (NZ), JUMP to 5353H to report it through @ERROR.
52DD
LD BC,0029H 01 29 00
Load register pair BC with 0029H (41), the combined size of the module header and FCB reserved below HIGH$.
52E0
XOR A AF
Set register A to zero and clear the carry for the subtraction.
52E1
SBC HL,BC ED 42
SUBtract register pair BC (41) from register pair HL (the module base) with SBC, giving the new top-of-memory pointer.
52E3
PUSH HL E5
Save the new memory pointer (register pair HL) on the stack.
52E4
OR 0FFH F6 FF
Self-Modifying Code
OR register A with the operand at 52E5H (0FFH for a new module, patched to 00H at 529DH when reusing an existing one) to decide whether HIGH$ must be lowered.
52E6
If an existing module is being reused (Z, operand was 00H), JUMP to 52ECH to skip lowering HIGH$.
52E8
DEC HL 2B
DECrement register pair HL to leave one guard byte below the module.
52E9
LD (4049H),HL 22 49 40
Store register pair HL into HIGH$ at 4049H, reserving the module's memory above the new top of user memory.
52EC
POP DE D1
Restore the module base (register pair DE) from the stack, the destination for the header copy.
52ED
LD BC,0009H 01 09 00
Load register pair BC with 0009H (9), the length of the routing-module header template.
52F0
PUSH BC C5
Save register pair BC (the header length) on the stack.
52F1
PUSH DE D5
Save register pair DE (the module base) on the stack.
52F2
LD HL,53EAH 21 EA 53
Point register pair HL at 53EAH, the 9-byte routing-module header template.
52F5
LDIR ED B0
Block-copy the 9-byte header from (HL) to the module at (DE) (register pair BC = count), planting the marker, buffer pointer and $R-plus-device name.
52F7
INC HL 23
INCrement register pair HL past the header template's name terminator to reach the destination FCB just parsed.
52F8
LD C,20H 0E 20
Load register C with 20H (32), the size of a file control block.
52FA
LDIR ED B0
Block-copy the 32-byte destination FCB into the module (register pair BC = count) so the module carries the open file.
52FC
POP DE D1
Restore register pair DE from the stack (the module base).
52FD
POP HL E1
Restore register pair HL from the stack (the header length, 0009H).
52FE
ADD HL,DE 19
ADD register pair DE to register pair HL so register pair HL points at the module's FCB, the address the source device links to.
52FF
PUSH HL E5
Save register pair HL (the module FCB pointer) on the stack, to be popped as register pair BC by the shared linking code.
5300
JP 5256H C3 56 52
JUMP to 5256H to link the source device to this high-memory routing module (the same code path as a device-to-device route).

5303H - Locate and Validate the Source Device Helper

Finds the source device's control block (allocating a free slot for a new user device), returning a no-device-space error if none is free, and closes any file the device is already routed to.

5303
LD DE,(5435H) ED 5B 35 54
Load register pair DE with the two-character source device name from 5435H, the device to be routed.
5307
PUSH DE D5
Save register pair DE (the source name) on the stack.
5308
CALL 536AH CD 6A 53
GOSUB to the local find-DCB-by-name helper at 536AH to locate the source device's control block (register pair HL).
530B
LD DE,0000H 11 00 00
Load register pair DE with 0000H, the empty name used to find a free device slot if the source device does not yet exist.
530E
CALL NZ,536AH C4 6A 53
If the source device was not found (NZ), GOSUB to the find-DCB-by-name helper at 536AH again to find a free (unnamed) device slot for it.
5311
LD A,21H 3E 21
Load register A with 21H (33), the LDOS no-device-space-available error code, in case no slot is free.
5313
If no free device slot was found (NZ), JUMP to 5353H to report no device space available.
5315
PUSH HL E5
Save register pair HL (the source DCB pointer) on the stack.
5316
CALL 5334H CD 34 53
GOSUB to the local helper at 5334H to follow the DCB link chain and close any file the device is already routed to.
5319
POP HL E1
Restore register pair HL from the stack so it again points at the source DCB.
531A
POP DE D1
Restore register pair DE from the stack so it again holds the source device name.
531B
RET C9
RETurn to the caller with register pair HL pointing at the validated source DCB.

531CH - NIL Route Helper

Routes the source device to nothing: returns its control block to the base state and restores its own name.

531C
CALL 5303H CD 03 53
NIL route. GOSUB to the local helper at 5303H to locate and validate the source device's control block (register pair HL) and close any file it is routed to.
531F
LD (HL),08H 36 08
Store 08H into the source DCB type byte at (HL), returning the device to its base (nil) state.
5321
LD A,L 7D
Load register A with register L, the low byte of the source DCB address, to reach its name field.
5322
ADD A,06H C6 06
ADD 06H to register A so it addresses source DCB byte +6, the first character of the device name.
5324
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at source DCB byte +6.
5325
DI F3
Disable interrupts while the device name is restored.
5326
CALL 5330H CD 30 53
GOSUB to the local helper at 5330H to store the device's own name (register pair DE) into DCB bytes +6 and +7, clearing any routed-to name.
5329
EI FB
Re-enable interrupts now that the NIL route is installed.
532A
JP 527AH C3 7A 52
JUMP to 527AH to reach the common exit with a normal-completion status.

532DH - Routing-Module Lookup and Byte-Pair Store Helpers

Issues the resident routing-module lookup and a small two-byte store used to write a link pointer or device name into a control block.

532D
LD A,0BCH 3E BC
Load register A with 0BCH, the request code for the resident routing-module lookup service.
532F
RST 28 EF
Issue RST 28H (request code 0BCH) to look up the routing module named at (DE); it returns Z with register pair HL pointing at the module when it exists.
5330
LD (HL),E 73
Store register E at (HL) (a device-name or link byte), the first byte written by this small store helper.
5331
INC L 2C
INCrement register L to the next byte.
5332
LD (HL),D 72
Store register D at (HL), the second byte written by the helper.
5333
RET C9
RETurn to the caller.

5334H - Close a Routed File and the @ERROR Path

Follows a device link chain to its base and closes any disk file it routes to, and provides the shared @ERROR reporting entry.

5334
BIT 4,(HL) CB 66
Loop Start
Test bit 4 of the DCB type byte at (HL), which is set when this device is linked or routed to another device.
5336
If bit 4 is clear (Z, the base device), JUMP to 533FH to check for a file route.
5338
INC HL 23
INCrement register pair HL to DCB byte +1, the low byte of the linked-device pointer.
5339
LD A,(HL) 7E
Load register A with DCB byte +1 at (HL), the low byte of the linked address.
533A
INC HL 23
INCrement register pair HL to DCB byte +2, the high byte of the linked-device pointer.
533B
LD H,(HL) 66
Load register H with DCB byte +2 at (HL), the high byte of the linked address.
533C
LD L,A 6F
Load register L with register A (the saved low byte) so register pair HL points at the linked control block.
533D
JR 5334H 18 F5
LOOP BACK to 5334H to follow the link chain to its base.
533F
BIT 7,(HL) CB 7E
Test bit 7 of the base DCB type byte at (HL), which is set when the device routes its output to a disk file.
5341
RET Z C8
If bit 7 is clear (Z, not a file route), RETurn to the caller with nothing to close.
5342
LD DE,5414H 11 14 54
Point register pair DE at 5414H, the FCB work area (in RAM just past the overlay) that will receive the routed file's control block.
5345
PUSH DE D5
Save register pair DE (the 5414H work-area pointer) on the stack.
5346
LD BC,0020H 01 20 00
Load register pair BC with 0020H (32), the size of a file control block.
5349
LDIR ED B0
Block-copy the 32-byte FCB of the routed file from (HL) to the work area at (DE) (register pair BC = count).
534B
POP DE D1
Restore register pair DE from the stack so it points at the copied FCB at 5414H.
534C
CALL 4428H CD 28 44
GOSUB to the resident @CLOSE service at 4428H to close the previously routed file whose FCB is at (DE); it returns Z on success.
534F
RET Z C8
If the close succeeded (Z), RETurn to the caller.
5350
LD BC,2C3EH 01 3E 2C
Instruction Overlap
On the close-failure fall-through these bytes decode as LD BC,2C3EH, a filler load left in register pair BC. Entered at 5351H from 5217H and 523BH, the same bytes decode as LD A,2CH, loading the parameter-error code 2CH before the shared @ERROR call below.
5353
OR 0C0H F6 C0
Error entry. OR register A with 0C0H, setting bits 6 and 7 so @ERROR returns to the caller (message-only) rather than aborting.
5355
CALL 4409H CD 09 44
GOSUB to the resident @ERROR service at 4409H to display the error whose code is in register A.
5358
JR 5364H 18 0A
JUMP to 5364H to set the error return and exit.

535AH - Refusal and Error-Message Display

Displays the command-level refusal message or the Device spec required message, using a single display call reached through two overlapping instruction entries, then sets the error return.

535A
LD HL,5390H 21 90 53
Refusal path. Point register pair HL at 5390H, the message Can't -- Valid only at LDOS command level!.
535D
LD IX,53BBH DD 21 BB 53
Instruction Overlap
On the fall-through path these bytes decode as LD IX,53BBH (harmless here). Entered at 535EH from 5230H and 524CH, the same bytes (skipping the DD prefix) decode as LD HL,53BBH, pointing register pair HL at the Device spec required! message so the shared display below shows it.
5361
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).
5364
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero value that flags an error/abort exit to the shared exit code.
5367
JP 527DH C3 7D 52
JUMP to 527DH to restore the caller's stack and exit through the common exit path.

536AH - Find Device Control Block by Name

Searches the resident KI/DO/PR table and the auxiliary JL/SI/SO table for a control block whose two-character name matches the requested device.

536A
LD HL,4015H 21 15 40
Loop Start
Point register pair HL at 4015H, the first resident device control block, to search for a device by name.
536D
PUSH HL E5
Loop Start
Save register pair HL (the current DCB pointer) on the stack across the name comparison.
536E
LD A,L 7D
Load register A with register L, the low byte of the DCB address, to reach its name field.
536F
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, the first character of the device name.
5371
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at DCB byte +6.
5372
LD A,(HL) 7E
Load register A with DCB byte +6 at (HL), the first character of this device's name.
5373
INC L 2C
INCrement register L to DCB byte +7, the second name character.
5374
CP E BB
Compare register A (the first name character) against register E, the first character of the requested name.
5375
If the first characters differ (NZ), JUMP to 537EH to advance to the next DCB.
5377
LD A,(HL) 7E
Load register A with DCB byte +7 at (HL), the second character of this device's name.
5378
CP D BA
Compare register A (the second name character) against register D, the second character of the requested name.
5379
If the second characters differ (NZ), JUMP to 537EH to advance to the next DCB.
537B
POP HL E1
Match found. Restore register pair HL from the stack so it points at the matching DCB.
537C
XOR A AF
Set register A to zero and clear the flags to signal a successful search.
537D
RET C9
RETurn to the caller with register pair HL pointing at the matching device's DCB.
537E
POP AF F1
No match. Restore register AF from the stack so register pair HL again holds the DCB pointer.
537F
INC L 2C
INCrement register L, stepping toward the next DCB and testing for a page wrap.
5380
If register L did not wrap to 00H (NZ), JUMP to 5386H to check the end-of-table marker.
5382
LD A,08H 3E 08
The whole page was searched. Load register A with 08H, the LDOS device-not-available error code.
5384
OR A B7
OR register A with itself to set the flags (NZ) so the caller sees the not-found error.
5385
RET C9
RETurn to the caller with the device-not-found status.
5386
LD A,L 7D
Load register A with register L, the low byte of the address reached, to test for the end of the KI/DO/PR table.
5387
CP 2DH FE 2D
Compare register A against 2DH; 402DH (@EXIT) is one past the last device in the resident table.
5389
If the end of the resident table has not been reached (NZ), LOOP BACK to 536DH to compare the next DCB.
538B
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device table (JL/SI/SO), to continue the search there.
538E
JR 536DH 18 DD
LOOP BACK to 536DH to search the auxiliary device table.

5390H - Messages, @PARAM Table and Routing-Module Header Template

The two refusal messages, the @PARAM keyword descriptor table for the NIL and REWIND options, and the 9-byte header template used to build a routing module in high memory.

5390-53B9
DEFM "Can't -- Valid only at LDOS command level!" 43 61 6E 27 74 20 2D 2D 20 56 61 6C 69 64 20 6F 6E 6C 79 20 61 74 20 4C 44 4F 53 20 63 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C 21
Message
Displayed at 5361H (reached at 535AH) when the route is refused because a nested job is active or the command was not issued at the LDOS command level.
53BA
DEFB 0DH 0D
Carriage return terminating the message above.
53BB-53CF
DEFM "Device spec required!" 44 65 76 69 63 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Message
Displayed at 5361H when reached through the overlapping entry at 535EH, when a device specification is missing, malformed or names the same device twice.
53D0
DEFB 0DH 0D
Carriage return terminating the message above.
53D1-53D6
DEFM "NIL " 4E 49 4C 20 20 20
The NIL keyword. @PARAM stores its value into the NIL flag cell at 5223H (the LD BC operand at 5222H).
53D7-53D8
DEFW 5223H 23 52
Pointer to the NIL flag cell (5223H) that the NIL keyword sets.
53D9-53DE
DEFM "REWIND" 52 45 57 49 4E 44
The REWIND keyword. @PARAM stores its value into the REWIND flag cell at 52CDH (the LD BC operand at 52CCH).
53DF-53E0
DEFW 52CDH CD 52
Pointer to the REWIND flag cell (52CDH) that the REWIND keyword sets.
53E1-53E6
DEFM "R " 52 20 20 20 20 20
Single-letter abbreviation R for the REWIND keyword; same flag cell 52CDH.
53E7-53E8
DEFW 52CDH CD 52
Pointer to the REWIND flag cell (52CDH) that the R keyword sets.
53E9
DEFB 00H 00
Zero byte marking the end of the @PARAM keyword descriptor table.
53EA-53EB
DEFB 18H,0FEH 18 FE
Routing-Module Header Template
The high-memory module marker (18H) and link byte, copied to the new module at 52F5H.
53EC-53ED
DEFW 0000H 00 00
Module buffer/start address, patched at 52BFH with the value of HIGH$ (4049H) when the module is placed.
53EE
DEFB 04H 04
Module name length (4 characters).
53EF-53F0
DEFM "$R" 24 52
Routing-module name prefix; the whole name at 53EFH-53F3H is also the lookup key passed to the module-lookup service at 528DH.
53F1-53F2
DEFM "xx" 78 78
Two-character source device name placeholder, patched at 521EH with the routed device so the module name becomes $R plus the device.
53F3
DEFB 03H 03
Terminator of the routing-module name.

Disassembly - Overlay 14 - Device Driver/Filter (ORG 5A00H)

5A00H - Overlay Entry: Command-Level Check, Spec Parse and Driver/Filter Install

Entry of the driver/filter install command overlay (loaded at 5A00H, not 5200H). It refuses to execute unless it is running at the LDOS command level with no active background task, parses the target device and the driver/filter file, applies the DVR or FLT default extension, locates or creates the device, loads the file and transfers control into the loaded module's initialization code.

5A00
OR 0AFH F6 AF
OR register A (the request code passed on entry) with 0AFH, forming the driver/filter mode flag; a zero result selects driver (DVR) mode and a non-zero result selects filter (FLT) mode.
5A02
LD (5A84H),A 32 84 5A
Self-Modifying Code
Store the mode flag (register A) into 5A84H, the operand of the LD A,nn at 5A83H, so the mode is available to the tests at 5A47H and 5A83H.
5A05
LD (5AE1H),SP ED 73 E1 5A
Self-Modifying Code
Store the caller's stack pointer (register SP, the LDOS command-level stack on entry) into the operand of the LD SP,nnnn at 5AE0H, so the error-exit path can restore this stack.
5A09
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH; installing a driver or filter is only permitted at the command level.
5A0C
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5A0E
LD A,(402DH) 3A 2D 40
Load register A with the first byte of the resident @EXIT vector at 402DH, the command-level path check.
5A11
If at the command level (Z), JUMP to 5A16H keeping the @EXIT byte in register A.
5A13
LD A,(4065H) 3A 65 40
Otherwise load register A with the saved register-snapshot A slot at 4065H for the nested-context test.
5A16
CP 0C3H FE C3
Compare register A against 0C3H (a Z80 JP opcode); a JP here means a nested job or intercept is active.
5A18
JP Z,5AD3H CA D3 5A
If register A is 0C3H (Z, a nested context is active), JUMP to 5AD3H to refuse with the command-level message.
5A1B
LD A,(4758H) 3A 58 47
Load register A with the resident SYS1 status byte at 4758H to test for a background task.
5A1E
BIT 1,A CB 4F
Test bit 1 of register A (the 4758H status byte), which is set when a background task is active.
5A20
JP NZ,5AD3H C2 D3 5A
If a background task is active (NZ), JUMP to 5AD3H to refuse with the command-level message.
5A23
SET 3,A CB DF
Set bit 3 of register A (the 4758H status byte), marking this driver/filter install as an active operation.
5A25
LD (4758H),A 32 58 47
Store the updated status (register A) back into the SYS1 status byte at 4758H.
5A28
LD DE,5B44H 11 44 5B
Point register pair DE at 5B44H, the FCB work area (in RAM just past the overlay) that will receive the source device specification.
5A2B
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the device specification at (HL) into the FCB at (DE); it returns NZ when it is malformed.
5A2E
JP NZ,5ACFH C2 CF 5A
If the specification is malformed (NZ), JUMP to 5ACFH to report Device spec required.
5A31
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (the asterisk) marks a device specification.
5A32
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk) that opens a device name.
5A34
JP NZ,5ACFH C2 CF 5A
If the source is not a device (NZ), JUMP to 5ACFH to report Device spec required.
5A37
LD DE,5B64H 11 64 5B
Point register pair DE at 5B64H, the FCB work area that will receive the driver/filter file specification.
5A3A
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the file specification into the FCB at (DE).
5A3D
JP NZ,5AD7H C2 D7 5A
If the file specification is malformed (NZ), JUMP to 5AD7H to report File spec required.
5A40
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); the driver/filter source must be a disk file, not a device.
5A41
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
5A43
JP Z,5AD7H CA D7 5A
If the source is a device (Z, an asterisk), JUMP to 5AD7H to report File spec required (a driver/filter must be a disk file).
5A46
PUSH HL E5
Save register pair HL (the command-line pointer past the file spec) on the stack; it is later handed to the loaded driver.
5A47
LD A,(5A84H) 3A 84 5A
Load register A with the driver/filter mode flag from 5A84H, to choose the default file extension.
5A4A
OR A B7
OR register A with itself to set the flags according to the mode flag (Z in driver mode).
5A4B
LD HL,5A9CH 21 9C 5A
Point register pair HL at 5A9CH, the default extension DVR, for driver mode.
5A4E
If the flag is zero (Z, driver mode), JUMP to 5A53H keeping the DVR extension in register pair HL.
5A50
LD HL,5A9FH 21 9F 5A
Otherwise point register pair HL at 5A9FH, the default extension FLT, for filter mode.
5A53
CALL 4473H CD 73 44
GOSUB to the resident @FEXT service at 4473H to apply the default extension at (HL) to the file specification when none was given.
5A56
LD DE,(5B45H) ED 5B 45 5B
Load register pair DE with the two-character source device name from 5B45H (device FCB bytes +1 and +2).
5A5A
CALL 5AA2H CD A2 5A
GOSUB to the local find-DCB-by-name helper at 5AA2H to locate the source device's control block (register pair HL); it returns Z when found.
5A5D
If the device was found (Z), JUMP to 5A74H to load the driver/filter into it.
5A5F
LD A,(5A84H) 3A 84 5A
Device not found. Load register A with the driver/filter mode flag from 5A84H to decide whether a new device may be created.
5A62
OR A B7
OR register A with itself to set the flags according to the mode flag.
5A63
LD A,08H 3E 08
Load register A with 08H, the LDOS device-not-available error code, in case a filter targets a missing device.
5A65
If the flag is non-zero (NZ, filter mode), JUMP to 5AC8H to report device not available (a filter needs an existing device).
5A67
LD DE,0000H 11 00 00
Driver mode. Load register pair DE with 0000H, the empty name used to find a free (unnamed) device slot.
5A6A
CALL 5AA2H CD A2 5A
GOSUB to the find-DCB-by-name helper at 5AA2H again to find a free device slot for the new driver.
5A6D
If a free slot was found (Z), JUMP to 5A74H to install the driver there.
5A6F
LD A,21H 3E 21
Load register A with 21H (33), the LDOS no-device-space-available error code.
5A71
JP 5AC8H C3 C8 5A
JUMP to 5AC8H to report no device space available.
5A74
PUSH HL E5
Save register pair HL (the target device's DCB pointer) on the stack across the file load.
5A75
LD HL,430FH 21 0F 43
Point register pair HL at the resident system flag byte SFLAG$ at 430FH.
5A78
SET 2,(HL) CB D6
Set bit 2 of SFLAG$ at (HL) = 430FH, marking that a program load is in progress.
5A7A
LD DE,5B64H 11 64 5B
Point register pair DE at 5B64H, the driver/filter file's FCB, for the load.
5A7D
CALL 4430H CD 30 44
GOSUB to the resident @LOAD service at 4430H to load the driver/filter file into memory; it returns NZ on error and, on success, register pair HL holding the file's transfer (initialization) address.
5A80
JP NZ,5AC8H C2 C8 5A
If the load failed (NZ), JUMP to 5AC8H to report the error through @ERROR.
5A83
LD A,00H 3E 00
Self-Modifying Code
Load register A from the operand at 5A84H, the driver/filter mode flag stored at entry.
5A85
OR A B7
OR register A with itself to set the flags according to the mode flag.
5A86
If the flag is non-zero (NZ, filter mode), JUMP to 5A99H to skip naming the device slot.
5A88
POP DE D1
Driver mode. POP the target DCB pointer into register pair DE (peeking the value pushed at 5A74H).
5A89
PUSH DE D5
Re-save the DCB pointer (register pair DE) on the stack, keeping it for the trampoline below.
5A8A
DI F3
Disable interrupts while the new device slot is named.
5A8B
LD A,E 7B
Load register A with register E, the low byte of the DCB address.
5A8C
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, the first character of the device name.
5A8E
LD E,A 5F
Copy the computed low byte (register A) into register E so register pair DE points at DCB byte +6.
5A8F
LD A,(5B45H) 3A 45 5B
Load register A with the first source device name character from 5B45H.
5A92
LD (DE),A 12
Store the first name character (register A) at (DE), DCB byte +6.
5A93
INC E 1C
INCrement register E to DCB byte +7.
5A94
LD A,(5B46H) 3A 46 5B
Load register A with the second source device name character from 5B46H.
5A97
EI FB
Re-enable interrupts now that the device slot has been named.
5A98
LD (DE),A 12
Store the second name character (register A) at (DE), completing the new device's name.
5A99
POP DE D1
POP the target DCB pointer into register pair DE (the value pushed at 5A74H); the loaded driver receives it in register pair DE.
5A9A
EX (SP),HL E3
Exchange register pair HL with the top of the stack, so register pair HL becomes the command-line pointer saved at 5A46H and the stack top becomes the loaded driver's transfer address.
5A9B
RET C9
RETurn into the loaded driver/filter's transfer (initialization) address, entered with register pair DE pointing at the device DCB and register pair HL at the command tail; the driver links itself in and returns to the dispatcher.

5A9CH - Default Extension Strings

The three-character default file extensions applied by @FEXT at 5A53H, chosen by the mode flag: DVR for a device driver, FLT for a filter.

5A9C-5A9E
DEFM "DVR" 44 56 52
Default extension for driver mode, pointed to by register pair HL at 5A4BH.
5A9F-5AA1
DEFM "FLT" 46 4C 54
Default extension for filter mode, pointed to by register pair HL at 5A50H.

5AA2H - Find Device Control Block by Name

Searches the resident KI/DO/PR table and the auxiliary JL/SI/SO table for a control block whose two-character name matches the requested device (or an empty slot when searching with a zero name).

5AA2
LD HL,4015H 21 15 40
Loop Start
Point register pair HL at 4015H, the first resident device control block, to search for a device by name.
5AA5
PUSH HL E5
Loop Start
Save register pair HL (the current DCB pointer) on the stack across the name comparison.
5AA6
LD A,L 7D
Load register A with register L, the low byte of the DCB address, to reach its name field.
5AA7
ADD A,06H C6 06
ADD 06H to register A so it addresses DCB byte +6, the first character of the device name.
5AA9
LD L,A 6F
Copy the computed low byte (register A) into register L so register pair HL points at DCB byte +6.
5AAA
LD A,(HL) 7E
Load register A with DCB byte +6 at (HL), the first character of this device's name.
5AAB
INC L 2C
INCrement register L to DCB byte +7, the second name character.
5AAC
CP E BB
Compare register A (the first name character) against register E, the first character of the requested name (00H when searching for a free slot).
5AAD
If the first characters differ (NZ), JUMP to 5AB6H to advance to the next DCB.
5AAF
LD A,(HL) 7E
Load register A with DCB byte +7 at (HL), the second character of this device's name.
5AB0
CP D BA
Compare register A (the second name character) against register D, the second character of the requested name.
5AB1
If the second characters differ (NZ), JUMP to 5AB6H to advance to the next DCB.
5AB3
POP HL E1
Match found. Restore register pair HL from the stack so it points at the matching DCB.
5AB4
XOR A AF
Set register A to zero and clear the flags to signal a successful search.
5AB5
RET C9
RETurn to the caller with register pair HL pointing at the matching device's DCB.
5AB6
POP AF F1
No match. Restore register AF from the stack so register pair HL again holds the DCB pointer.
5AB7
INC L 2C
INCrement register L, stepping toward the next DCB and testing for a page wrap.
5AB8
If register L did not wrap to 00H (NZ), JUMP to 5ABEH to check the end-of-table marker.
5ABA
LD A,08H 3E 08
The whole page was searched. Load register A with 08H, the LDOS device-not-available error code.
5ABC
OR A B7
OR register A with itself to set the flags (NZ) so the caller sees the not-found status.
5ABD
RET C9
RETurn to the caller with the device-not-found status.
5ABE
LD A,L 7D
Load register A with register L, the low byte of the address reached, to test for the end of the KI/DO/PR table.
5ABF
CP 2DH FE 2D
Compare register A against 2DH; 402DH (@EXIT) is one past the last device in the resident table.
5AC1
If the end of the resident table has not been reached (NZ), LOOP BACK to 5AA5H to compare the next DCB.
5AC3
LD HL,43C0H 21 C0 43
Point register pair HL at 43C0H, the auxiliary device table (JL/SI/SO), to continue the search there.
5AC6
JR 5AA5H 18 DD
LOOP BACK to 5AA5H to search the auxiliary device table.

5AC8H - Error, Overlapping Message Dispatch and Exit

The shared @ERROR path, the three-way message selection reached through two overlapping instructions, and the exit that restores the caller's stack or aborts below command level.

5AC8
OR 0C0H F6 C0
Error path. OR register A with 0C0H, setting bits 6 and 7 so @ERROR returns to the caller (message-only) rather than aborting.
5ACA
CALL 4409H CD 09 44
GOSUB to the resident @ERROR service at 4409H to display the error whose code is in register A.
5ACD
JR 5ADDH 18 0E
JUMP to 5ADDH to set the error return and exit.
5ACF
LD HL,5B03H 21 03 5B
Message dispatch. Point register pair HL at 5B03H, the Device spec required! message (the fall-through selection reached from 5A2EH and 5A34H).
5AD2
LD IX,5B19H DD 21 19 5B
Instruction Overlap
On the fall-through these bytes decode as LD IX,5B19H. Entered at 5AD3H from 5A18H and 5A20H, the same bytes (skipping the DD prefix) decode as LD HL,5B19H, selecting the Can't -- Valid only at LDOS command level! message.
5AD6
LD IX,5AEFH DD 21 EF 5A
Instruction Overlap
On the fall-through these bytes decode as LD IX,5AEFH. Entered at 5AD7H from 5A3DH and 5A43H, the same bytes decode as LD HL,5AEFH, selecting the File spec required! message.
5ADA
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).
5ADD
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero value that flags an error/abort exit to the shared exit code.
5AE0
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 5AE1H, patched at entry (5A05H) with the caller's SP; register SP now again addresses the LDOS command-level stack.
5AE3
LD A,H 7C
Load register A with register H, the high byte of the exit code in register pair HL, to test it for zero.
5AE4
OR L B5
OR register A with register L, the low byte of the exit code; register A is non-zero on the error path.
5AE5
RET Z C8
If register pair HL is zero (Z, a normal exit), RETurn to the RST 28H dispatcher.
5AE6
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context on the error path.
5AE9
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
5AEB
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher so it can report the error.
5AEC
JP 4030H C3 30 40
Not at command level. JUMP to the resident @ABORT service at 4030H to abort the running job.

5AEFH - Refusal Messages

The three carriage-return-terminated messages displayed through the resident 447BH service, selected by the overlapping instructions at 5ACFH-5AD7H.

5AEF-5B01
DEFM "File spec required!" 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Message
Displayed when the driver/filter file specification is missing or names a device (reached through the entry at 5AD7H).
5B02
DEFB 0DH 0D
Carriage return terminating the message above.
5B03-5B17
DEFM "Device spec required!" 44 65 76 69 63 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Message
Displayed when the target device specification is missing or malformed (reached at 5ACFH).
5B18
DEFB 0DH 0D
Carriage return terminating the message above.
5B19-5B42
DEFM "Can't -- Valid only at LDOS command level!" 43 61 6E 27 74 20 2D 2D 20 56 61 6C 69 64 20 6F 6E 6C 79 20 61 74 20 4C 44 4F 53 20 63 6F 6D 6D 61 6E 64 20 6C 65 76 65 6C 21
Message
Displayed when the command is refused because a nested job is active or it was not issued at the LDOS command level (reached through the entry at 5AD3H).
5B43
DEFB 0DH 0D
Carriage return terminating the message above.

Disassembly - Overlay 15 - Single-Drive Command Loader

5200H - Entry Vectors: Run or Load the Command File

Entry of the single-drive command-loader overlay. The main entry runs the program; an alternate entry loads it. Both parse the command line first and, when the load-only X option is given, prompt the user to swap disks.

5200
JP 527CH C3 7C 52
JUMP to 527CH, the main entry that parses the command line and runs or loads the program file.
5203
CALL 5293H CD 93 52
Alternate load entry. GOSUB to the parse routine at 5293H to read the command line, the option and the program filespec.
5206
LD A,(52BDH) 3A BD 52
Self-Modifying Code
Load register A from the X-option flag at 52BDH (the operand of the LD DE at 52BCH); @PARAM sets it non-zero when the X load-only option was given.
5209
OR A B7
OR register A with itself to set the flags according to the X-option flag (Z when the program is to be run).
520A
If the X option was given (NZ, load only), JUMP to 5216H to load the file and prompt for a disk swap.
520C
LD DE,4408H 11 08 44
Point register pair DE at 4408H, the address the loaded program returns to, and push it as the return address.
520F
PUSH DE D5
Save the return address (register pair DE) on the stack so the loaded program returns to 4408H.
5210
LD DE,4480H 11 80 44
Point register pair DE at 4480H, the resident FCB holding the program filespec, for the load.
5213
JP 4430H C3 30 44
JUMP to the resident @LOAD service at 4430H to load the program at (DE); it returns to 4408H.
5216
CALL 52CCH CD CC 52
GOSUB to the load helper at 52CCH to load the program file (setting the loading flag first).
5219
PUSH HL E5
Save register pair HL on the stack across the disk-swap prompt.
521A
LD HL,5316H 21 16 53
Point register pair HL at 5316H, the Insert SYSTEM disk prompt.
521D
CALL 5225H CD 25 52
GOSUB to the flashing-prompt routine at 5225H to display the prompt and wait for the user's key.
5220
POP HL E1
Restore register pair HL from the stack.
5221
RET C9
RETurn to the caller.

5222H - Flashing Disk-Swap Prompt and Keyboard Wait

Displays a disk-swap prompt, flashing it on and off, and waits for the user to press a key (or BREAK to abort), debouncing the keyboard.

5222
CALL 5267H CD 67 52
Loop Start
GOSUB to 5267H to clear the low three control bits of the keyboard flag KFLAG$ (4423H) before waiting.
5225
LD BC,41FDH 01 FD 41
Load register pair BC with 41FDH, the delay count for one debounce interval.
5228
CALL 0060H CD 60 00
GOSUB to the ROM delay routine at 0060H, which counts register pair BC down to zero.
522B
LD A,(4423H) 3A 23 44
Load register A with the keyboard flag byte KFLAG$ at 4423H to test for a pending key or BREAK.
522E
AND 05H E6 05
AND register A with 05H, keeping bit 0 (BREAK) and bit 2 (a pending control key).
5230
If either bit is set (NZ, a key is still pending), LOOP BACK to 5222H to debounce it away first.
5232
CALL 5267H CD 67 52
GOSUB to 5267H to clear the KFLAG$ control bits (4423H) again before the flashing display begins.
5235
CALL 4467H CD 67 44
Loop Start
GOSUB to the resident @DSPLY service at 4467H to display the prompt string at register pair HL (up to its 03H terminator).
5238
LD BC,4000H 01 00 40
Load register pair BC with 4000H, the on-phase delay count for the flashing prompt.
523B
CALL 524BH CD 4B 52
GOSUB to the flash-delay-and-key-check routine at 524BH; it returns on timeout or exits the prompt when a key is pressed.
523E
LD A,1EH 3E 1E
Load register A with 1EH, the erase-to-end-of-line control code, to blank the prompt for the off phase.
5240
CALL 0033H CD 33 00
GOSUB to the ROM display routine at 0033H to send the erase code (register A) to the screen.
5243
LD BC,3333H 01 33 33
Load register pair BC with 3333H, the off-phase delay count.
5246
CALL 524BH CD 4B 52
GOSUB to the flash-delay-and-key-check routine at 524BH for the off phase.
5249
JR 5235H 18 EA
LOOP BACK to 5235H to redisplay the prompt, continuing the flash until a key is pressed.
524B
LD A,(4423H) 3A 23 44
Loop Start
Load register A with the keyboard flag byte KFLAG$ at 4423H to test for BREAK or a pending key.
524E
RRCA 0F
Rotate register A right, moving bit 0 (the BREAK flag) into the carry.
524F
If BREAK is pending (CARRY), JUMP to 5270H to abort the command.
5251
BIT 1,A CB 4F
Test bit 1 of register A (the KFLAG$ value), which is set when a key has been pressed.
5253
If a key was pressed (NZ), JUMP to 525BH to acknowledge it and exit the prompt.
5255
DEC BC 0B
DECrement register pair BC, counting down this delay interval.
5256
LD A,B 78
Load register A with register B, the high byte of the delay counter.
5257
OR C B1
OR register A with register C, the low byte; register A is zero when the delay has elapsed.
5258
If the delay has not elapsed (NZ), LOOP BACK to 524BH to keep waiting.
525A
RET C9
RETurn to the flashing loop when the delay interval ends (no key yet).
525B
POP AF F1
A key was pressed. POP the return address off the stack, discarding one level so control leaves the flashing prompt entirely.
525C
CALL 002BH CD 2B 00
Loop Start
GOSUB to the ROM keyboard-scan routine at 002BH to read the key (register A returns it, or zero once released).
525F
OR A B7
OR register A with itself to test whether a key is still held down.
5260
If a key is still down (NZ), LOOP BACK to 525CH to wait for its release.
5262
LD A,1EH 3E 1E
Load register A with 1EH, the erase-to-end-of-line control code, to clear the prompt.
5264
CALL 0033H CD 33 00
GOSUB to the ROM display routine at 0033H to send the erase code (register A) to the screen.
5267
LD A,(4423H) 3A 23 44
Load register A with the keyboard flag byte KFLAG$ at 4423H to clear its control bits.
526A
AND 0F8H E6 F8
AND register A with 0F8H to clear the low three bits (BREAK, key-pending and pause) of KFLAG$.
526C
LD (4423H),A 32 23 44
Store the cleared value (register A) back into KFLAG$ at 4423H.
526F
RET C9
RETurn to the caller.

5270H - Command-Aborted Path

Displays the Command aborted message and the Insert SYSTEM disk prompt, then aborts through @ABORT.

5270
LD HL,5352H 21 52 53
BREAK abort. Point register pair HL at 5352H, the Command aborted! message.
5273
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).
5276
CALL 5219H CD 19 52
GOSUB to 5219H to display the Insert SYSTEM disk prompt so the user can restore the system disk.
5279
JP 4030H C3 30 40
JUMP to the resident @ABORT service at 4030H to abort the running job.

527CH - Main Entry: Parse then Run or Load

The overlay's primary entry: parses the command line and either runs the program with @RUN or, for the X option, loads it and prompts for the system disk.

527C
CALL 5293H CD 93 52
Main entry. GOSUB to the parse routine at 5293H to read the command line, the option and the program filespec.
527F
LD A,(52BDH) 3A BD 52
Self-Modifying Code
Load register A from the X-option flag at 52BDH (the operand of the LD DE at 52BCH); it is non-zero when the X load-only option was given.
5282
OR A B7
OR register A with itself to set the flags according to the X-option flag (Z when the program is to be run).
5283
LD DE,4480H 11 80 44
Point register pair DE at 4480H, the resident FCB holding the program filespec.
5286
JP Z,4433H CA 33 44
If the X option was not given (Z, run the program), JUMP to the resident @RUN service at 4433H to load and execute the file at (DE).
5289
PUSH HL E5
The X option was given. Save register pair HL on the stack across the load.
528A
LD DE,4480H 11 80 44
Point register pair DE at 4480H, the program FCB, for the load.
528D
CALL 52CCH CD CC 52
GOSUB to the load helper at 52CCH to load the program file.
5290
EX (SP),HL E3
Exchange register pair HL with the top of the stack, restoring the saved register pair HL and leaving the load result available.
5291
JR 5219H 18 86
JUMP to 5219H to display the Insert SYSTEM disk prompt after the load.

5293H - Parse the Command Line, Option and Program Filespec

Saves the stack for exit, parses the X option with @PARAM, skips a leading space, parses the program filespec with @FSPEC into the resident FCB, applies the default CMD extension, and prompts for the source disk when the X option is present.

5293
LD (52F4H),SP ED 73 F4 52
Self-Modifying Code
Store the caller's stack pointer (register SP, the LDOS command-level stack) into the operand of the LD SP,nnnn at 52F3H, so the overlay exit can restore this stack.
5297
LD DE,5364H 11 64 53
Point register pair DE at 5364H, the local @PARAM keyword descriptor table (the X option).
529A
CALL 4476H CD 76 44
GOSUB to the resident @PARAM service at 4476H to parse the X option; it returns NZ on a syntax error.
529D
If @PARAM reported a syntax error (NZ), JUMP to 52E1H to report a parameter error through @ERROR.
529F
LD A,(HL) 7E
Load register A with the command-line character at (HL) to skip a leading blank before the filespec.
52A0
CP 20H FE 20
Compare register A against 20H (a space).
52A2
If the character is not a space (NZ), JUMP to 52A5H leaving register pair HL in place.
52A4
INC HL 23
INCrement register pair HL past the leading space.
52A5
LD DE,4480H 11 80 44
Point register pair DE at 4480H, the resident FCB that will receive the program filespec.
52A8
CALL 441CH CD 1C 44
GOSUB to the resident @FSPEC service at 441CH to parse the filespec at (HL) into the FCB at (DE); it returns NZ when it is missing or malformed.
52AB
If the filespec is missing or malformed (NZ), JUMP to 52EAH to display File spec required.
52AD
LD A,(DE) 1A
Load register A with the first FCB byte at (DE); a 2AH (the asterisk) marks a device, which is not a program file.
52AE
CP 2AH FE 2A
Compare register A against 2AH (the ASCII asterisk).
52B0
If the specification names a device (Z), JUMP to 52EAH to reject it (a program file is required).
52B2
PUSH HL E5
Save register pair HL (the command-line pointer) on the stack.
52B3
LD HL,536DH 21 6D 53
Point register pair HL at 536DH, the default file extension CMD.
52B6
CALL 4473H CD 73 44
GOSUB to the resident @FEXT service at 4473H to apply the default extension CMD to the filespec when none was given.
52B9
CALL 52C9H CD C9 52
GOSUB to 52C9H, which issues the resident RST 28H request code 84H used while preparing the command file.
52BC
LD DE,0000H 11 00 00
Self-Modifying Code
Load register pair DE from the operand at 52BDH; this is the X-option flag (non-zero when the load-only option was given), and it selects whether a source-disk swap is prompted for.
52BF
LD A,D 7A
Load register A with register D, the high byte of the X-option flag.
52C0
OR E B3
OR register A with register E, the low byte of the X-option flag; register A is non-zero when the X option was given.
52C1
LD HL,5334H 21 34 53
Point register pair HL at 5334H, the Insert SOURCE disk prompt.
52C4
CALL NZ,5225H C4 25 52
If the X option was given (NZ), GOSUB to the flashing-prompt routine at 5225H to prompt for the source disk.
52C7
POP HL E1
Restore register pair HL from the stack so it again points at the command line.
52C8
RET C9
RETurn to the caller.

52C9H - Drive Service and File Load Helper

Issues a resident supervisor call, and loads the program file (marking the load in progress) with error reporting.

52C9
LD A,84H 3E 84
Load register A with 84H, a resident supervisor-call request code.
52CB
RST 28 EF
Issue RST 28H (request code 84H), a resident service used in preparing the command file.
52CC
LD DE,4480H 11 80 44
Point register pair DE at 4480H, the program FCB, for the load.
52CF
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH.
52D2
SET 2,A CB D7
Set bit 2 of register A, the flag marking that a program load is in progress.
52D4
LD (430FH),A 32 0F 43
Store the updated flags (register A) back into SFLAG$ at 430FH.
52D7
CALL 4430H CD 30 44
GOSUB to the resident @LOAD service at 4430H to load the program file at (DE); it returns Z on success.
52DA
RET Z C8
If the load succeeded (Z), RETurn to the caller.
52DB
PUSH AF F5
Load failed. Save register AF (the error code) on the stack across the prompt.
52DC
CALL 5219H CD 19 52
GOSUB to 5219H to display the Insert SYSTEM disk prompt.
52DF
POP AF F1
Restore register AF from the stack so register A again holds the load error code.
52E0
LD BC,2C3EH 01 3E 2C
Instruction Overlap
On the load-failure fall-through these bytes decode as LD BC,2C3EH, a filler load (register A already holds the load error code). Entered at 52E1H from 529DH, the same bytes decode as LD A,2CH, the parameter-error code, before the shared @ERROR call at 52E3H.
52E3
OR 0C0H F6 C0
OR register A with 0C0H, setting bits 6 and 7 so @ERROR returns to the caller (message-only) rather than aborting.
52E5
CALL 4409H CD 09 44
GOSUB to the resident @ERROR service at 4409H to display the error whose code is in register A.
52E8
JR 52F0H 18 06
JUMP to 52F0H to set the error return and exit.
52EA
LD HL,5302H 21 02 53
Point register pair HL at 5302H, the File spec required! message.
52ED
CALL 447BH CD 7B 44
GOSUB to the resident 447BH service to display the carriage-return-terminated message at (HL).

52F0H - Overlay Exit

Restores the caller's stack and returns to the RST 28H dispatcher, or aborts through @ABORT when an error occurred outside the command level.

52F0
LD HL,0FFFFH 21 FF FF
Load register pair HL with 0FFFFH, a non-zero value that flags an error/abort exit to the shared exit code.
52F3
LD SP,0000H 31 00 00
Self-Modifying Code
Restore the caller's stack pointer from the operand at 52F4H, patched at 5293H with the caller's SP; register SP now again addresses the LDOS command-level stack.
52F6
LD A,H 7C
Load register A with register H, the high byte of the exit code in register pair HL, to test it for zero.
52F7
OR L B5
OR register A with register L, the low byte of the exit code; register A is non-zero on the error path.
52F8
RET Z C8
If register pair HL is zero (Z, a normal exit), RETurn to the RST 28H dispatcher.
52F9
LD A,(430FH) 3A 0F 43
Load register A with the resident system flag byte SFLAG$ at 430FH to check the execution context on the error path.
52FC
BIT 5,A CB 6F
Test bit 5 of register A (the SFLAG$ value from 430FH), which is set when execution is not at the LDOS command level.
52FE
RET Z C8
If bit 5 is clear (Z, at command level), RETurn to the dispatcher so it can report the error.
52FF
JP 4030H C3 30 40
Not at command level. JUMP to the resident @ABORT service at 4030H to abort the running job.

5302H - Messages, Prompts, @PARAM Table and Extension

The error message, the two flashing disk-swap prompts (framed by video control codes), the Command aborted message, the @PARAM keyword table for the X option and the default CMD extension.

5302-5314
DEFM "File spec required!" 46 69 6C 65 20 73 70 65 63 20 72 65 71 75 69 72 65 64 21
Message
Displayed at 52EDH when the program filespec is missing, malformed or names a device.
5315
DEFB 0DH 0D
Carriage return terminating the message above.
5316-5317
DEFB 1DH,1EH 1D 1E
Video control codes (1DH cursor to start of line, 1EH erase to end of line) that frame the Insert SYSTEM disk prompt.
5318-5331
DEFM "Insert SYSTEM disk <ENTER>" 49 6E 73 65 72 74 20 53 59 53 54 45 4D 20 64 69 73 6B 20 3C 45 4E 54 45 52 3E
Prompt
Displayed by the flashing-prompt routine at 5235H (pointed to at 521AH) asking the user to reinsert the system disk on a single-drive machine.
5332-5333
DEFB 1DH,03H 1D 03
Trailing cursor-to-start control and the 03H display terminator of the SYSTEM prompt.
5334-5335
DEFB 1DH,1EH 1D 1E
Video control codes framing the Insert SOURCE disk prompt.
5336-534F
DEFM "Insert SOURCE disk <ENTER>" 49 6E 73 65 72 74 20 53 4F 55 52 43 45 20 64 69 73 6B 20 3C 45 4E 54 45 52 3E
Prompt
Displayed by the flashing-prompt routine (pointed to at 52C1H) asking the user to insert the source disk when the X option is given.
5350-5351
DEFB 1DH,03H 1D 03
Trailing cursor-to-start control and the 03H display terminator of the SOURCE prompt.
5352
DEFB 1DH 1D
Cursor-to-start-of-line control code preceding the Command aborted message.
5353-5362
DEFM "Command aborted!" 43 6F 6D 6D 61 6E 64 20 61 62 6F 72 74 65 64 21
Message
Displayed at 5273H when the user presses BREAK at a disk-swap prompt.
5363
DEFB 0DH 0D
Carriage return terminating the message above.
5364-5369
DEFM "X " 58 20 20 20 20 20
The X (load-only) keyword. @PARAM stores its value into the flag cell at 52BDH (the LD DE operand at 52BCH).
536A-536B
DEFW 52BDH BD 52
Pointer to the X-option flag cell (52BDH) that the X keyword sets.
536C
DEFB 00H 00
Zero byte marking the end of the @PARAM keyword descriptor table.
536D-536F
DEFM "CMD" 43 4D 44
The default file extension applied by @FEXT at 52B6H when the program filespec has none.