4D00H - SYS6/SYS ENTRY POINT AND COMMAND DISPATCH
SYS6/SYS is the NEWDOS/80 disk utility overlay module, loaded by SYS1 into memory at 4D00H when the user enters the FORMAT, COPY, or APPEND command. Register A contains a command code set by SYS1: 68H for hex dump/compare mode, 28H for APPEND, 48H for COPY/FORMAT. IY is loaded with 4280H (the DOS work area base pointer) and remains set throughout SYS6 execution.
4D00
LD IY,4280H FD 21 80 42
Point Index Register IY to 4280H, the DOS work area base address. IY remains set to this value for the entire duration of SYS6 execution. All (IY+offset) references throughout SYS6 address fields within the DOS work area at 4280H-42FFH.
4D04
LD (IY+08H),08H FD 36 08 00
Store 08H into the DOS work area at (IY+08H) = 4288H. This initializes a command state flag used by SYS0 routines to identify SYS6 as the active overlay. The value 08H signals that SYS6 is loaded and processing a disk utility command.
The command dispatch begins here. Register A still contains the command code passed by SYS1 when it loaded SYS6 into memory. The code checks A against three known command codes and dispatches accordingly.
4D08
CP 68H FE 68
Compare Register A against 68H (ASCII h). If Register A equals 68H, the Z FLAG is set. This tests whether the user invoked the hex dump/compare mode.
4D0A
If the Z FLAG has been set (command code is 68H = hex dump/compare), JUMP to 6F4AH to enter the hex dump/compare handler. This bypasses all COPY/FORMAT/APPEND processing.
4D0D
SET 3,(IY+09H) FD CB 09 DE
Set bit 3 of the DOS work area byte at (IY+09H) = 4289H. This flag bit indicates a non-hex-dump command is being processed (COPY, FORMAT, or APPEND). SYS0 routines check this bit to determine the active command mode.
4D11
CP 28H FE 28
Compare Register A against 28H (ASCII (). If Register A equals 28H, the Z FLAG is set. This tests whether the user invoked the APPEND command.
4D13
If the Z FLAG has been set (command code is 28H = APPEND), JUMP to 65FAH to enter the APPEND command handler.
4D16
CP 48H FE 48
Compare Register A against 48H (ASCII H). If Register A equals 48H, the Z FLAG is set. This tests whether the user invoked the COPY or FORMAT command.
4D18
If the Z FLAG has been set (command code is 48H = COPY/FORMAT), JUMP to 4D1EH to begin COPY/FORMAT initialization.
4D1B
If none of the three valid command codes matched, JUMP unconditionally to 5208H, the error handler, which loads error code 2AH (general error) and reports an invalid command.
4D1EH - COPY/FORMAT COMMAND INITIALIZATION
This section begins the COPY/FORMAT command processing. It first checks whether this is a COPY or FORMAT operation by examining bit 6 of the DOS status byte at 428AH. For FORMAT commands (bit 6 clear), it sets the FORMAT flag and saves the high memory pointer. It then parses the drive number from the command line, stores it as both source and destination drive, and sets up the option parameter blocks.
4D1E
LD A,(428AH) 3A 8A 42
Fetch the DOS command status byte from 428AH into Register A. Bit 6 of this byte distinguishes FORMAT (bit 6 = 0) from COPY (bit 6 = 1). This byte was set by SYS1 before loading SYS6.
4D21
BIT 6,A CB 77
Test bit 6 of Register A without changing it. If bit 6 is 1 (COPY command), the NZ FLAG is set. If bit 6 is 0 (FORMAT command), the Z FLAG is set.
4D23
If the NZ FLAG has been set (bit 6 = 1, meaning this is a COPY command), JUMP forward to 4D32H, skipping the FORMAT-specific initialization at 4D25H-4D31H.
The next block (4D25H-4D31H) executes only for FORMAT commands. It sets the FORMAT mode flag at 5996H and saves the current high memory pointer from (4411H) into the work area at 593CH.
4D25
PUSH HL E5
Save Register Pair HL onto the stack. HL currently points to the command line text (the user's command arguments following the FORMAT keyword).
4D26
LD HL,5996H 21 96 59
Point Register Pair HL to 5996H, the option flags byte 2 in the SYS6 work area. This byte contains mode flags: bit 5 = FORMAT mode, bit 2 = source parsed, bit 3 = destination parsed, among others.
4D29
SET 5,(HL) CB EE
Set bit 5 of the byte at (HL) = 5996H. Bit 5 is the FORMAT mode flag, indicating that SYS6 is processing a FORMAT command rather than a COPY command.
4D2B
LD HL,(4411H) 2A 11 44
Load Register Pair HL with the 16-bit value stored at 4411H, the SYS0 high memory pointer. This is the top of available memory as managed by the DOS. FORMAT needs this to know how much buffer space is available for track formatting.
4D2E
LD (593CH),HL 22 3C 59
Store Register Pair HL (the high memory pointer) into 593CH, the saved high memory limit in the SYS6 work area. This preserves the original value so it can be restored after FORMAT completes. [SELF-MODIFYING DATA] — 593CH is in the work area, written at runtime.
4D31
POP HL E1
Restore Register Pair HL from the stack. HL once again points to the command line text (user's arguments).
Both COPY and FORMAT execution paths converge here at 4D32H. HL points to the command line text. The code now parses the source drive number.
4D32
PUSH HL E5
Save Register Pair HL (command line pointer) onto the stack for later use.
4D33
GOSUB to 6ECAH to parse a drive number from the command line at (HL). This routine expects HL to point to the text; it returns with Register A = drive number (0-3), HL advanced past the parsed text, and the CARRY FLAG set on success or clear on failure.
4D36
If the NO CARRY FLAG has been set (drive number parsing failed — no explicit drive specified), JUMP to 4D98H to handle the no-drive-specified case (default drive or error).
If we reach here, a valid source drive number was parsed. Register A = drive number (0-3). HL points past the parsed drive specifier. The drive number is stored in three locations: the source FCB area, the source drive parameter, and the destination drive parameter (destination defaults to same as source initially).
4D39
POP DE D1
Pop the previously saved command line pointer into Register Pair DE. DE now holds the original command line position (before the drive number was parsed). This is no longer needed since HL has been advanced.
4D3A
LD (5AEBH),A 32 EB 5A
Store the parsed drive number (Register A) into 5AEBH, the source drive number field in the source drive parameter block at 5AE5H. Offset +06H within the parameter block holds the drive number.
4D3D
LD (594CH),A 32 4C 59
Store the parsed drive number (Register A) into 594CH, the source drive number variable in the SYS6 work area. This is the primary source drive reference used throughout the COPY/FORMAT operation.
4D40
LD (5956H),A 32 56 59
Store the parsed drive number (Register A) into 5956H, the destination drive number variable. Initially the destination defaults to the same drive as the source; the user can override this with option parameters.
4D43
PUSH HL E5
Save Register Pair HL (pointing to the remainder of the command line after the drive number) onto the stack.
4D44
LD DE,64A6H 11 A6 64
Point Register Pair DE to 64A6H, the drive geometry data table. This table contains default parameters (track count, sector count, density, etc.) for each drive, used to initialize the source/destination parameter blocks.
4D47
GOSUB to 63A3H to look up the "=" sign in the command line and extract the value after it. This routine scans (HL) for '=' (3DH), and if found, calls 6EE6H to parse the numeric value after it. The result is stored at (DE) = 64A6H. Returns with Z set if '=' was found and parsed, NZ if not.
4D4A
GOSUB to 6FE4H to parse and validate a filespec from the command line. This routine extracts a filename/extension from the text at (HL), validates it, and returns HL pointing past the parsed filespec. On success CARRY is set; on failure CARRY is clear.
4D4D
GOSUB to 6392H to parse a second drive number (the destination drive). This routine calls 6ECAH internally. If a second drive is specified, it stores it at 5B1DH (destination parameter block drive field), 5956H (destination drive variable), and 4DFAH (self-modifying location).
4D50
If the NO CARRY FLAG has been set (no second drive number found), JUMP to 4D8BH to set default values for the operation mode (single-drive COPY or FORMAT) and continue processing.
If we reach here, both source and destination drives were successfully parsed. The code now sets up the command prompt message and begins parsing option keywords.
4D53
GOSUB to 63A0H to look up a destination "=" parameter, similar to the call at 4D47H but for the destination drive's geometry table entry at (DE) = 64A9H.
4D56
EX (SP),HL E3
Exchange HL with the value on top of the stack. HL had the advanced command line pointer; the stack had the previous command line position. After this exchange, HL = previous position and the stack top = advanced position.
4D57
LD HL,6E0BH 21 0B 6E
Point Register Pair HL to 6E0BH, the message string "STARTING DISKETTE COPY". This message will be displayed to the user to indicate the operation is beginning.
4D5A
GOSUB to SYS0 routine at 4467H to display the message string pointed to by HL. This routine outputs characters from (HL) until it encounters a terminator byte (03H or 0DH). The "STARTING DISKETTE COPY" message is shown on screen.
4D5D
POP HL E1
Restore Register Pair HL from the stack. HL now points to the advanced command line position (after both drive numbers and any '=' parameters).
4D5E
GOSUB to 6FB7H to parse optional date/version stamps from the remaining command line text. This routine extracts up to 3 pairs of digits (e.g., month/day/year) and validates them against the source disk's date stamp at 598BH.
4D61
LD B,20H 06 20
Load Register B with 20H (32 decimal). This sets the maximum number of option keywords that can be parsed in the upcoming option parsing loop. The COPY command supports up to 32 option parameters.
4D63
GOSUB to 4EA7H to parse option keywords from the remainder of the command line. This is the main option parsing engine that reads keywords like "CFWO", "ODDPW=", "SPW=", etc., looks them up in the keyword table at 505CH, and sets the corresponding option flags in the work area at 5994H-5997H. Register B = max keywords to parse (32).
After option parsing returns, the code examines the parsed option flags to determine the exact operation mode. The option flags at 5994H-5995H encode which features were requested (verify, old-to-new density, same-drive copy, etc.).
4D66
LD HL,5994H 21 94 59
Point Register Pair HL to 5994H, the first option flags byte in the SYS6 work area. This byte and the next (5995H) contain bit flags set during option parsing.
4D69
LD A,(HL) 7E
Load Register A with the value at (HL) = 5994H, the option flags byte 1. Each bit represents a specific option: bit 0 = verify, bit 1 = source != dest, bit 3 = prompt, bit 4 = old density, bit 5 = new density, bit 6 = special mode, bit 7 = no-prompt mode.
4D6A
AND F9H E6 F9
Mask Register A with F9H (11111001 binary), clearing bits 1 and 2 while preserving all other bits. This isolates the flags other than the source/dest same-drive indicator bits. If the result is zero, only those two bits (or nothing) were set.
4D6C
INC HL 23
INCrement Register Pair HL to point to 5995H, the option flags byte 2.
4D6D
If the NZ FLAG has been set (other option flags besides bits 1-2 were present in byte 1), JUMP to 4D72H to skip the byte 2 check — the presence of any significant options means this is a COPY with options.
4D6F
LD A,(HL) 7E
Load Register A with the value at (HL) = 5995H, the option flags byte 2. This byte contains additional option flags.
4D70
AND 01H E6 01
Mask Register A with 01H, isolating bit 0 of the second option flags byte. Bit 0 of 5995H indicates whether a specific copy sub-mode was requested.
4D72
If the NZ FLAG has been set (at least one significant option flag is active), JUMP to 4D79H to proceed with the copy using the user-specified options.
If we reach here, no significant options were specified. The code sets a default option: bit 6 of 5994H, which enables the standard whole-disk COPY mode (backup mode with no special processing).
4D74
DEC HL 2B
DECrement Register Pair HL back to 5994H (option flags byte 1).
4D75
LD A,(HL) 7E
Load Register A with the current value at (HL) = 5994H, the option flags byte 1.
4D76
OR 40H F6 40
Set bit 6 of Register A by ORing with 40H. Bit 6 of 5994H enables default backup mode (whole-disk sector-by-sector copy with no special file handling).
4D78
LD (HL),A 77
Store the updated option flags (with bit 6 set) back into (HL) = 5994H.
4D79
GOSUB to 5C9FH to initialize copy parameters. This routine reads the source and destination drive geometry from the system tables, sets up sector counts, track counts, interleave tables, density flags, and all the drive-specific parameters needed for the copy operation. It stores results throughout the 59xxH-5BxxH work area.
4D7C
LD HL,59B7H 21 B7 59
Point Register Pair HL to 59B7H, the source drive geometry parameter block in the SYS6 work area. This block contains the source disk's track count, sector count, density, and related geometry values as initialized by the call to 5C9FH.
4D7F
GOSUB to 6713H to validate and configure the destination drive. This routine uses the geometry data at (HL) to check compatibility between source and destination drives, verifies that the destination can accept the data, and configures the FDC parameters accordingly.
4D82
GOSUB to 6710H to validate and configure the source drive, performing similar geometry validation as the previous call but for the source disk parameters.
4D85
GOSUB to 4DF3H to initialize the directory buffer. This routine (at 4DF3H below) calls 6424H to read the GAT/directory from the source disk, then sets up the file tracking data structures used during the copy operation.
4D88
JUMP unconditionally to 6291H to enter the main COPY execution engine. This is where the actual disk-to-disk copy operation begins, reading sectors from the source and writing them to the destination.
4D8BH - SINGLE-DRIVE / NO DESTINATION DEFAULT SETUP
When no destination drive was specified on the command line, this code sets default operation parameters. It configures the mode flags at 5940H-5941H for a single-drive operation (FORMAT or single-disk COPY), then re-parses the command line for additional parameters.
4D8B
LD HL,5940H 21 40 59
Point Register Pair HL to 5940H, the operation mode flags in the SYS6 work area. This two-byte field (5940H-5941H) controls the type of disk operation to perform.
4D8E
LD (HL),06H 36 06
Store 06H into (HL) = 5940H. The value 06H (bits 1 and 2 set) indicates source and destination are the same drive — a single-drive operation where the user will be prompted to swap disks.
4D90
INC HL 23
INCrement Register Pair HL to point to 5941H, the second byte of the operation mode flags.
4D91
LD (HL),01H 36 01
Store 01H into (HL) = 5941H. Bit 0 set indicates that disk swapping will be required during the operation (single-drive mode).
4D93
POP HL E1
Restore Register Pair HL from the stack. HL now points to the command line text (after the source drive number).
4D94
GOSUB to 6EC3H to validate the command line syntax. This routine checks that the text at (HL) is properly terminated (0DH for end of line) and that no stray characters follow the drive number. Calls 4C7EH internally to advance past whitespace.
4D97
PUSH HL E5
Save Register Pair HL (the validated command line pointer) onto the stack. Execution falls through to 4D98H.
4D98H - COMMAND LINE OPTION PREFIX AND PARAMETER COPY
This section handles the optional "$" prefix on the command line (which triggers special copy modes), copies the first 80 bytes of the command line into a parameter buffer, and then proceeds to parse source and destination filespecs for file-by-file copy operations.
4D98
POP HL E1
Restore Register Pair HL from the stack. HL points to the current position in the command line text.
4D99
LD A,(HL) 7E
Load Register A with the character at the current command line position (HL). This is the next character to process.
4D9A
CP 24H FE 24
Compare Register A against 24H (ASCII $). If Register A equals 24H, the Z FLAG is set. The "$" prefix on the command line enables special copy modes (system track copy, extended options).
4D9C
If the NZ FLAG has been set (no "$" prefix found), JUMP to 4DA6H to skip the "$" processing and proceed with normal parameter setup.
A "$" was found on the command line. Set the special mode flag and advance past it.
4D9E
PUSH HL E5
Save Register Pair HL (pointing at the "$" character) onto the stack.
4D9F
LD HL,5940H 21 40 59
Point Register Pair HL to 5940H, the operation mode flags.
4DA2
SET 0,(HL) CB C6
Set bit 0 of (HL) = 5940H. Bit 0 is the "$" special mode flag, enabling system track copy and extended parameter handling during the COPY operation.
4DA4
POP HL E1
Restore Register Pair HL (pointing at "$") from the stack.
4DA5
INC HL 23
INCrement HL to advance past the "$" character to the next character on the command line.
4DA6
LD DE,4D3EH 11 3E 4D
Point Register Pair DE to 4D3EH, which is the return address for the parameter copy. This address is pushed onto the stack so that after the LDIR copy completes and the stack is popped, execution will continue at 4D3EH (which is within the COPY initialization code at 4D3AH+4).
4DA9
PUSH DE D5
Push DE (4D3EH) onto the stack as a return address. The upcoming LDIR will copy 80 bytes, then POP HL and eventual RET will resume at 4D3EH.
4DAA
LD BC,0050H 01 50 00
Load Register Pair BC with 0050H (80 decimal). This is the byte count for the LDIR copy — 80 bytes of the command line will be copied into the parameter buffer.
4DAD
LDIR ED B0
Execute block copy: copy 80 bytes from (HL) to (DE). HL points to the command line text (starting after any "$" prefix); the destination was set earlier. After completion, HL and DE have both advanced by 80 bytes, and BC = 0.
4DAF
POP HL E1
Pop the return address (4D3EH) from the stack into HL. Wait — this pops the value we pushed at 4DA9H into HL. So HL = 4D3EH, which is actually the address within the parameter buffer that was written during the LDIR. The stack manipulation here creates a re-entry point.
4DB0
LD DE,5AE5H 11 E5 5A
Point Register Pair DE to 5AE5H, the source drive parameter block base address in the SYS6 work area. This 50-byte block holds all source disk parameters including drive number, track count, sector count, density, and interleave settings.
4DB3
GOSUB to 4E8DH to parse a filespec from the command line and load the source drive parameters. This routine (at 4E8DH) sets B=20H, pushes DE, and calls the SYS0 filespec parser at 4C7AH, which fills the parameter block at (DE) with the parsed drive, filename, extension, and password.
4DB6
GOSUB to 6FE4H to validate the parsed filespec and advance HL past any trailing delimiters. Returns CARRY set on success.
4DB9
LD A,(HL) 7E
Load Register A with the next character at (HL) on the command line, checking what follows the source filespec.
4DBA
CP 3AH FE 3A
Compare Register A against 3AH (ASCII :). A colon after the source filespec indicates a drive separator introducing the destination drive number.
4DBC
If the Z FLAG has been set (colon found), JUMP to 4DC6H to process the destination drive/file specification.
4DBE
CP 2EH FE 2E
Compare Register A against 2EH (ASCII .). A period after the source filespec indicates a filename extension separator.
4DC0
If the Z FLAG has been set (period found), JUMP to 4DC6H to continue parsing the filespec extension.
4DC2
CP 2FH FE 2F
Compare Register A against 2FH (ASCII /). A slash is used as a password separator in NEWDOS/80 filespecs.
4DC4
If the NZ FLAG has been set (none of ':', '.', or '/' found), JUMP to 4DDEH — the source filespec is complete with no additional components, proceed to destination parsing.
A separator character (':', '.', or '/') was found. The code saves it and searches backward through the source parameter block at 5AE5H to find where this separator belongs, then adjusts the parsed filespec accordingly.
4DC6
LD C,A 4F
Copy the separator character from Register A into Register C for safekeeping. C = the separator (:, ., or /).
4DC7
LD B,00H 06 00
Load Register B with 00H. B will count how many positions we need to back up in the parameter block.
4DC9
LD DE,5AE5H 11 E5 5A
Point Register Pair DE to 5AE5H, the start of the source drive parameter block.
4DCC
LD A,(DE) 1A
[LOOP START] Load Register A with the byte at (DE), scanning through the source parameter block searching for the separator character or the end-of-data marker (03H).
4DCD
CP 03H FE 03
Compare Register A against 03H (ETX, end-of-text marker). If the block terminates before the separator is found, it means the separator belongs to a new field.
4DCF
If the Z FLAG has been set (end-of-block marker 03H found before the separator), JUMP to 4DDEH — no match in the existing data, so the separator starts a new component.
4DD1
CP C B9
Compare the current byte (Register A) against the separator character in Register C.
4DD2
If the Z FLAG has been set (found the separator in the block), JUMP to 4DD8H to begin the backward copy that repositions the command line data.
4DD4
INC DE 13
INCrement DE to advance to the next byte in the source parameter block.
4DD5
INC B 04
INCrement B (position counter) to track how far into the block we've scanned.
4DD6
JUMP back to 4DCCH to continue scanning. [LOOP END]
Found the separator character in the parameter block at position B. Now back up the command line pointer (HL) by B positions and copy the block data back over the command line, effectively re-aligning the parse position.
4DD8
DEC HL 2B
[LOOP START] DECrement HL (command line pointer) by one position.
4DD9
DEC DE 1B
DECrement DE (parameter block pointer) by one position.
4DDA
LD A,(DE) 1A
Load Register A with the byte at (DE) in the parameter block.
4DDB
LD (HL),A 77
Store Register A into (HL), copying the parameter block byte back onto the command line position.
4DDC
DECrement B and loop back to 4DD8H if B is not zero. This copies B bytes backward from the parameter block onto the command line. [LOOP END]
4DDE
GOSUB to 4E8AH to parse the destination filespec. This routine sets DE = 5B17H (destination parameter block), B = 20H, and calls SYS0's filespec parser at 4C7AH.
4DE1
PUSH HL E5
Save Register Pair HL (command line pointer after destination filespec) onto the stack.
4DE2
LD HL,5996H 21 96 59
Point Register Pair HL to 5996H, the option flags byte 2.
4DE5
SET 2,(HL) CB D6
Set bit 2 of 5996H. Bit 2 is the "source filespec parsed" flag, indicating that a source filename (not just a drive number) was specified on the command line.
4DE7
INC HL 23
INCrement HL to point to 5997H, the option flags byte 3.
4DE8
SET 3,(HL) CB DE
Set bit 3 of 5997H. Bit 3 is the "destination filespec parsed" flag.
4DEA
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
4DEB
LD B,08H 06 08
Load Register B with 08H (8 decimal). This limits the option keyword parsing to 8 keywords maximum for file-level copy operations (vs. 32 for disk-level copy).
4DED
GOSUB to 4EA7H to parse option keywords from the remainder of the command line. B = 8 (max keywords for file copy mode).
4DF0
JUMP unconditionally to 6377H to enter the file-level COPY execution path. This handles copying individual files (ILF/XLF mode) rather than whole-disk backup, using the parsed source and destination filespecs.
4DF3H - DIRECTORY BUFFER INITIALIZATION
This subroutine initializes the directory tracking data structures for the COPY operation. It reads the GAT (Granule Allocation Table) from the source disk, then sets up the file entry table with initial values. The routine computes block offsets using the source drive number and a fixed multiplier of 10 (000AH).
4DF3
GOSUB to 6424H to read the GAT (Granule Allocation Table) from the source disk into the sector buffer at 4300H. This routine sets up the buffer parameters and calls SYS0's disk read routine at 4436H. On error, it jumps to 521AH.
4DF6
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (10 decimal). This is the parameter block stride — each drive's geometry entry in the system table is 10 bytes long.
4DF9
LD A,00H 3E 00
Load Register A with 00H. [SELF-MODIFYING CODE] — the 00H operand at address 4DFAH is overwritten at runtime by the code at 4FFBH and 639CH. The stored value is the current drive number being processed (0-3). On first entry, it defaults to 0.
4DFB
RLCA 07
Rotate Register A left 1 bit (multiply by 2). A was the drive number (0-3), now A = drive × 2.
4DFC
RLCA 07
Rotate Register A left again (multiply by 2). A = drive × 4.
4DFD
RLCA 07
Rotate Register A left again. A = drive × 8.
4DFE
RLCA 07
Rotate Register A left again. A = drive × 16. Four RLCA instructions effectively move the drive number into the upper nibble: drive 0 = 00H, drive 1 = 10H, drive 2 = 20H, drive 3 = 30H.
4DFF
ADD A,C 81
ADD Register C (= 0AH = 10) to Register A. The result is (drive × 16) + 10. For drive 0 this gives 0AH, for drive 1 gives 1AH, for drive 2 gives 2AH, for drive 3 gives 3AH. This computes an offset into the system drive parameter table.
4E00
EX DE,HL EB
Exchange DE and HL. DE was pointing to the command line area; HL was pointing to the parameter table. After the exchange, the roles swap.
4E01
LD HL,59C5H 21 C5 59
Point Register Pair HL to 59C5H, the destination for the geometry copy in the SYS6 work area. The drive geometry parameters will be copied here.
4E04
LDIR ED B0
Execute block copy: copy BC (10) bytes from (DE) to (HL). This copies 10 bytes of drive geometry data from the system table into the SYS6 work area at 59C5H. After execution, DE and HL have advanced by 10, BC = 0.
4E06
LD H,D 62
Copy Register D into Register H. After the LDIR, DE points 10 bytes past the source table entry. H = D sets up the high byte of the address for the next copy.
4E07
LD L,A 6F
Copy Register A into Register L. A still contains the computed offset (drive × 16 + 10). HL now points to a second table entry at the computed offset within the same page as DE's high byte.
4E08
LD C,06H 0E 06
Load Register C with 06H (6 decimal). BC already has B=0 from the LDIR, so BC = 0006H. This is the byte count for the next block copy — 6 bytes of additional geometry data.
4E0A
LDIR ED B0
Execute block copy: copy 6 bytes from (HL) to (DE). This copies 6 additional bytes of drive geometry data into the work area following the initial 10 bytes.
4E0C
LD L,C 69
Copy Register C (= 0 after LDIR) into Register L. This sets L = 0.
4E0D
LD B,01H 06 01
Load Register B with 01H. BC = 0001H (1 byte to copy).
4E0F
LD DE,6EB4H 11 B4 6E
Point Register Pair DE to 6EB4H. This is the address of a message string terminator or marker byte that will be appended to the work area.
4E12
LDIR ED B0
Execute block copy: copy 1 byte from (HL) to 6EB4H. This copies a single configuration byte to the message area.
4E14H - DRIVE NUMBER VALIDATION AND FLAG SETUP
This section validates the source and destination drive numbers and builds a drive usage flags word in Register Pair DE. The flags indicate which drives are involved in the operation and whether special handling (such as single-drive swap mode or error conditions) is needed. The flags are stored at 5940H for use throughout the copy operation.
4E14
LD DE,0100H 11 00 01
Load Register Pair DE with 0100H. D = 01 (initial flag: "single source" mode), E = 00 (no destination flags yet). These flags will be built up as the drive numbers are validated.
4E17
LD A,(594CH) 3A 4C 59
Fetch the source drive number (0-3) from 594CH into Register A. This was stored during the initial drive parsing at 4D3DH.
4E1A
OR A B7
OR Register A with itself. This sets the Z FLAG if A = 0 (source is drive 0) or NZ if A is non-zero (source is drive 1, 2, or 3). Register A is unchanged.
4E1B
LD B,A 47
Copy the source drive number from Register A into Register B for later comparison with the destination drive.
4E1C
If the NZ FLAG has been set (source drive is not drive 0), JUMP to 4E22H to skip the drive-0 specific flag setup.
Source drive is drive 0 — set bits in E to indicate drive 0 is the source. Bits 0 and 1 of E are set for drive 0 source.
4E1E
LD A,E 7B
Copy Register E (current flag byte, = 00H) into Register A.
4E1F
OR 03H F6 03
OR Register A with 03H, setting bits 0 and 1. These bits indicate drive 0 is the source drive.
4E21
LD E,A 5F
Store the updated flags back into Register E. E now has bits 0-1 set for drive 0 source.
4E22
LD A,(5956H) 3A 56 59
Fetch the destination drive number (0-3) from 5956H into Register A. This was stored at 4D40H (default = same as source) or may have been updated by option parsing.
4E25
OR A B7
OR Register A with itself to test if the destination drive is drive 0. Sets Z if dest = drive 0.
4E26
If the NZ FLAG has been set (destination drive is not drive 0), JUMP to 4E2CH to skip drive-0-as-destination flag setup.
4E28
SET 0,E CB C3
Set bit 0 of Register E. Bit 0 indicates drive 0 is involved in the operation (as destination).
4E2A
SET 2,E CB D3
Set bit 2 of Register E. Bit 2 indicates drive 0 is the destination drive specifically.
4E2C
CP B B8
Compare the destination drive number (Register A) against the source drive number (Register B). If they are equal, the Z FLAG is set — this means source and destination are the same drive (single-drive mode).
4E2D
If the NZ FLAG has been set (source and destination are different drives), JUMP to 4E3DH to skip single-drive error checking.
Source and destination are the same drive. Set the "same drive" flags and check whether a single-drive copy is permitted based on the DOS status flags at 428AH.
4E2F
LD A,E 7B
Copy Register E (flag byte) into Register A.
4E30
OR 06H F6 06
OR Register A with 06H, setting bits 1 and 2. These bits indicate same-drive operation — both source and destination are on the same physical disk drive.
4E32
LD E,A 5F
Store the updated flags back into Register E.
4E33
LD A,(428AH) 3A 8A 42
Fetch the DOS command status byte from 428AH into Register A. Bit 6 of this byte was checked at 4D21H to distinguish FORMAT from COPY.
4E36
BIT 6,A CB 77
Test bit 6 of Register A. Bit 6 = 1 means COPY command; bit 6 = 0 means FORMAT command.
4E38
LD A,15H 3E 15
Pre-load Register A with error code 15H (21 decimal). This error code means "invalid parameter" — a FORMAT command to the same source and destination drive is not valid (you must format a specific single disk, not copy to yourself).
4E3A
If the NZ FLAG has been set (bit 6 = 1, meaning this is a COPY command with same source and destination), JUMP to 521AH with error code 15H. Single-drive COPY to the same drive is not permitted when bit 6 is set — the user must specify different drives or use a different command mode.
Execution continues here when source != destination, or when single-drive mode is allowed. Now check option flags byte 2 at 5995H to determine if the user requested specific copy sub-modes.
4E3D
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A. Bit 7 controls batch/interactive mode.
4E40
BIT 7,A CB 7F
Test bit 7 of Register A. Bit 7 of 5995H = 1 means batch mode (no operator prompts); bit 7 = 0 means interactive mode.
4E42
If the Z FLAG has been set (bit 7 = 0, interactive mode), JUMP to 4E4DH to skip the batch-mode drive count check.
Batch mode is active (bit 7 set). Verify that only 1 or 2 drives are involved (E < 06H). If E >= 06H in batch mode, it is an error.
4E44
LD A,E 7B
Copy the drive flags from Register E into Register A for testing.
4E45
CP 06H FE 06
Compare Register A (drive flags) against 06H. If A >= 06H, the NO CARRY FLAG is set.
4E47
If the NO CARRY FLAG has been set (drive flags >= 06H, indicating an invalid drive configuration for batch mode), JUMP to 5208H to report a general error (error code 2AH). Batch mode does not support same-drive operations.
4E4A
LD DE,0700H 11 00 07
Load Register Pair DE with 0700H. D = 07 sets additional mode flags for batch operation. E = 00 resets the drive flags since batch mode uses a different flag scheme.
4E4D
LD A,E 7B
Copy the drive flags from Register E into Register A.
4E4E
CP 03H FE 03
Compare Register A against 03H. If E = 03H (both bits 0 and 1 set), the source is drive 0. This check determines whether to display the "SOURCE" prompt message.
4E50
LD B,80H 06 80
Load Register B with 80H. This mask value will be AND-tested against option flags byte 3 at 5997H to check if the "SOURCE" display was suppressed.
4E52
LD HL,5A3CH 21 3C 5A
Point Register Pair HL to 5A3CH, the message string "SOURCE " (terminated by 03H).
4E55
If the Z FLAG has been set (E was 03H, meaning source is drive 0), GOSUB to 4E68H to display the "ARE SYSTEM AND THE SAME DISKETTE?" confirmation prompt for the source drive. This prompts the user to confirm that the system disk and source disk are the same physical diskette.
4E58
LD A,E 7B
Reload the drive flags from Register E into Register A.
4E59
CP 05H FE 05
Compare Register A against 05H. If E = 05H (bits 0 and 2 set), the destination is drive 0. This check determines whether to display the "DESTINATION" prompt.
4E5B
LD B,40H 06 40
Load Register B with 40H. This mask for testing option flags byte 3 at 5997H checks if the "DESTINATION" display was suppressed.
4E5D
LD HL,5A44H 21 44 5A
Point Register Pair HL to 5A44H, the message string "DESTINATION " (terminated by 03H).
4E60
If the Z FLAG has been set (E was 05H, meaning destination is drive 0), GOSUB to 4E68H to display the confirmation prompt for the destination drive.
4E63
LD (5940H),DE ED 53 40 59
Store Register Pair DE (the final operation mode flags) into 5940H. These flags are used throughout the COPY/FORMAT operation to control prompting, drive swapping, and error handling. [SELF-MODIFYING DATA] — 5940H is written at runtime.
4E67
RET C9
Return to the caller (either 4D85H or wherever this subroutine was invoked from).
4E68H - SYSTEM DISK CONFIRMATION PROMPT
This subroutine displays an "ARE SYSTEM AND THE SAME DISKETTE?" prompt when one of the drives involved in the COPY operation is drive 0 (the system disk). It checks whether the prompt should be suppressed based on option flags, displays the appropriate message (SOURCE or DESTINATION), and if the user answers "No", clears the drive flags to cancel that drive's involvement.
4E68
DEC A 3D
DECrement Register A by 1. A was the drive flags value (03H for source or 05H for destination). After DEC, A = 02H or 04H. This adjustment removes the "drive 0 involved" bit to isolate the source/dest indicator.
4E69
OR D B2
OR Register A with Register D (the high byte of the mode flags). This merges the drive indicator with the existing mode flags.
4E6A
LD C,A 4F
Save the merged value into Register C for later restoration if the user confirms.
4E6B
LD A,(5997H) 3A 97 59
Fetch option flags byte 3 from 5997H into Register A.
4E6E
AND B A0
AND Register A with Register B (the suppression mask: 80H for source or 40H for destination). If the result is non-zero, the corresponding prompt was suppressed by a command-line option.
4E6F
RET NZ C0
If the NZ FLAG has been set (the prompt was suppressed by an option flag), RETURN immediately without displaying any message.
4E70
PUSH HL E5
Save Register Pair HL (pointing to "SOURCE " or "DESTINATION " message) onto the stack.
4E71
LD HL,6E22H 21 22 6E
Point Register Pair HL to 6E22H, the message string "ARE SYSTEM AND ".
4E74
GOSUB to SYS0 routine at 4467H to display the "ARE SYSTEM AND " message on screen.
4E77
POP HL E1
Restore Register Pair HL (the "SOURCE " or "DESTINATION " message pointer) from the stack.
4E78
GOSUB to SYS0 routine at 4467H to display "SOURCE " or "DESTINATION ", completing the question "ARE SYSTEM AND SOURCE/DESTINATION ...".
4E7B
LD HL,6E32H 21 32 6E
Point Register Pair HL to 6E32H, the message string "THE SAME DISKETTE?" followed by a 03H terminator.
4E7E
GOSUB to 58DEH to display the "THE SAME DISKETTE?" message and wait for a Y/N response. This routine displays the message string at (HL), then prompts for input and checks for 'Y' or 'N'. Returns Z flag set if user answered 'Y' (yes), NZ if 'N' (no).
4E81
RET Z C8
If the Z FLAG has been set (user answered Yes — system and source/destination ARE the same diskette), RETURN. The drive flags in C/D/E remain as set, confirming the drive configuration.
User answered "No" — the system disk and the source/destination disk are NOT the same. Clear the drive flags to indicate that drive 0 is not involved as source/destination, and set E = 00H to reset.
4E82
LD E,00H 1E 00
Load Register E with 00H, clearing all drive flags. This indicates that drive 0 is NOT the same physical disk as the source or destination — the user will be prompted to insert the correct diskette at the appropriate time.
4E84
LD D,C 51
Copy Register C (the merged mode flags computed at 4E69H-4E6AH) into Register D. This preserves the source/dest indicator while clearing the "drive 0 same" assumption.
4E85
RET C9
Return to the caller with the updated drive/mode flags in DE.
4E86H - FLAG MERGE HELPER
A small helper routine that merges the contents of Registers D and C into Register D by ORing them together. Used to combine operation mode flags.
4E86
LD A,D 7A
Copy Register D into Register A.
4E87
OR C B1
OR Register A with Register C, merging the flag bits from both registers.
4E88
LD D,A 57
Store the merged result back into Register D.
4E89
RET C9
Return to the caller.
4E8AH - FILESPEC PARSER (DESTINATION) / 4E8DH - FILESPEC PARSER (SOURCE)
These two entry points parse filespecs from the command line. The 4E8AH entry sets DE to the destination parameter block at 5B17H, while 4E8DH is the common entry that accepts DE as a parameter. Both call SYS0's filespec parser at 4C7AH to extract drive, filename, extension, and password from the command line text at (HL).
4E8A
LD DE,5B17H 11 17 5B
Point Register Pair DE to 5B17H, the destination drive parameter block. This is the 50-byte block where the parsed destination filespec will be stored. Falls through to the common entry at 4E8DH.
4E8D
LD B,20H 06 20
Load Register B with 20H (32 decimal). This sets the maximum filename length for the filespec parser.
4E8F
PUSH DE D5
Save Register Pair DE (parameter block address) onto the stack for use after the parser returns.
4E90
GOSUB to SYS0 routine at 4C7AH to parse a filespec from the command line at (HL). This routine extracts the drive number, filename (up to 8 characters), extension (up to 3 characters), and optional password, storing them into the parameter block at (DE). HL is advanced past the parsed text. Returns CARRY set on success, CARRY clear on error.
4E93H - FILESPEC PARSER LOOP (CONTINUATION FROM 4E8DH)
This is the body of the filespec parsing loop that began at 4E8DH. After each call to SYS0's filespec parser at 4C7AH, this code checks the result: if parsing succeeded (CARRY set), it copies the next command-line byte into the parameter block and loops back. If parsing ended (CARRY clear), it terminates the block with an ETX marker (03H). If the loop counter expires without a clean end, error 30H is reported.
4E93
If the NO CARRY FLAG has been set (filespec parsing ended — either a clean end-of-input or no more data to parse), JUMP to 4EA0H to write the end-of-block terminator and return.
4E95
LD A,(HL) 7E
Load Register A with the next byte at (HL) on the command line. After a successful filespec parse with CARRY set, HL points to the character following the parsed filespec (a separator or additional text).
4E96
LD (DE),A 12
Store the byte from Register A into (DE), appending this post-filespec character (separator, option text, etc.) into the parameter block.
4E97
INC DE 13
INCrement DE to advance to the next position in the parameter block.
4E98
INC HL 23
INCrement HL to advance to the next character on the command line.
4E99
DECrement B and loop back to 4E90H (the CALL 4C7AH) if B is not zero. This continues calling the filespec parser and copying residual bytes until B iterations are exhausted. [LOOP END] B was loaded with 20H (32) at 4E8DH, so up to 32 parse attempts are made.
If the loop counter B reaches zero without the parser signaling end-of-input, the command line is too long or malformed. Report error 30H (parse overflow).
4E9B
LD A,30H 3E 30
Load Register A with error code 30H (48 decimal). This is the parse overflow error — the command line contained more data than the 32-iteration parse loop could handle.
4E9D
JUMP to 521AH, the main error handler, with error code 30H in Register A.
Normal completion path: the filespec parser returned NC (no more data). Write the end-of-block marker.
4EA0
LD A,03H 3E 03
Load Register A with 03H (ETX, end-of-text). This is the parameter block terminator used throughout NEWDOS/80 to mark the end of parsed data.
4EA2
LD (DE),A 12
Store the 03H terminator into (DE), closing the parameter block.
4EA3
POP DE D1
Restore Register Pair DE from the stack. DE was pushed at 4E8FH and contains the base address of the parameter block (5AE5H for source, 5B17H for destination).
4EA4
RET Z C8
If the Z FLAG has been set (the filespec parser returned NC with Z, meaning a clean end-of-input — the command line ended normally), RETURN to the caller.
4EA5
DEC HL 2B
DECrement HL by one position. The parser returned NC with NZ (a parse error or separator found). Back up HL to point at the character that terminated the parse, so the caller can examine it.
4EA6
RET C9
Return to the caller with HL pointing to the terminating character.
4EA7H - OPTION KEYWORD PARSING ENGINE
This is the main option keyword parsing engine for the COPY command. It is called with B = maximum keywords to parse and HL pointing to the remaining command line text. The engine first checks if the command line has ended (via 6EBFH). If text remains, it jumps to the keyword table search at 4F1DH. If no text remains, it performs a multi-step option compatibility validation, checking that the combination of option flags in 5994H-5997H represents a valid configuration. If any incompatibility is detected, it jumps to error handlers at 4F49H (option conflict) or 5218H (parse error). If valid, the final option flags are stored back to 5994H-5997H.
4EA7
GOSUB to 6EBFH to check if the command line has more text. This routine advances HL past whitespace and tests if the next character is a terminator (0DH or 00H). Returns Z flag set if end-of-line reached, NZ if more text follows. HL is advanced to the next non-whitespace character.
4EAA
If the NZ FLAG has been set (more text found on the command line), JUMP to 4F1DH to enter the keyword table search engine which will match the next keyword against the option table at 505CH.
No more text on the command line — all options have been parsed. Now perform a multi-step compatibility check on the accumulated option flags to ensure they form a valid combination. The four option bytes at 5994H-5997H are loaded into HL (5994H-5995H) and DE (5996H-5997H) for testing.
4EAD
LD HL,5997H 21 97 59
Point Register Pair HL to 5997H, option flags byte 3.
4EB0
LD A,(HL) 7E
Load Register A with the value at (HL) = 5997H, option flags byte 3.
4EB1
AND 0CH E6 0C
Mask Register A with 0CH (00001100 binary), isolating bits 2 and 3. Bit 2 = source filespec parsed, bit 3 = destination filespec parsed. If either is set, a filespec was explicitly given.
4EB3
If the NZ FLAG has been set (at least one filespec was parsed), JUMP to 4ECAH to skip the FORMAT prompt — filespecs imply a COPY, not FORMAT.
No filespecs were parsed. Check if this is a FORMAT operation: if batch mode is NOT set, prompt the user to confirm FORMAT. The prompt message is at 6E45H: "FORMAT DISKETTE?".
4EB5
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A.
4EB8
AND 80H E6 80
Mask with 80H, isolating bit 7 (batch mode flag). If batch mode is active (bit 7 = 1), the result is NZ and the prompt is suppressed.
4EBA
PUSH HL E5
Save Register Pair HL (pointing to 5997H) onto the stack.
4EBB
LD HL,6E45H 21 45 6E
Point Register Pair HL to 6E45H, the message string "FORMAT DISKETTE?".
4EBE
If the Z FLAG has been set (batch mode is NOT active, AND result was 0), GOSUB to 58DEH to display "FORMAT DISKETTE?" and prompt for Y/N. Returns Z if user answered Yes, NZ if No.
4EC1
POP HL E1
Restore Register Pair HL (pointing to 5997H) from the stack.
4EC2
SET 3,(HL) CB DE
Set bit 3 of (HL) = 5997H. Bit 3 = destination filespec parsed flag. Setting this here indicates that the FORMAT destination has been confirmed (either by the user answering Yes, or by batch mode bypassing the prompt).
4EC4
If the Z FLAG has been set (user answered Yes to FORMAT, or batch mode was active and 58DEH was not called leaving Z set from the AND 80H), JUMP to 4ECAH to proceed with option validation.
User answered "No" to FORMAT prompt. Toggle bits 2 and 3 of 5997H using XOR to cancel the FORMAT and switch to COPY mode instead.
4EC6
LD A,(HL) 7E
Load Register A with the current value at (HL) = 5997H.
4EC7
XOR 0CH EE 0C
XOR Register A with 0CH (00001100 binary), toggling bits 2 and 3. This flips the source/destination filespec flags, effectively cancelling the FORMAT and switching to COPY mode.
4EC9
LD (HL),A 77
Store the toggled flags back into (HL) = 5997H.
Now begin the option compatibility validation. Load all four option flag bytes into register pairs: HL = (5994H) = bytes 1-2, DE = (5996H) = bytes 2-3. The code then performs a cascade of AND/BIT tests to verify that the combination of flags is valid.
4ECA
LD DE,(5996H) ED 5B 96 59
Load Register Pair DE with the 16-bit value at 5996H. E = option flags byte 2 (5996H), D = option flags byte 3 (5997H).
4ECE
LD HL,(5994H) 2A 94 59
Load Register Pair HL with the 16-bit value at 5994H. L = option flags byte 1 (5994H), H = option flags byte 2 (5995H).
4ED1
LD A,D 7A
Copy Register D (option flags byte 3 at 5997H) into Register A.
4ED2
AND 02H E6 02
Mask with 02H, isolating bit 1 of 5997H. Bit 1 = dual-density copy mode flag. If set, both old and new density parameters must be configured.
4ED4
If the Z FLAG has been set (dual-density mode is NOT active), JUMP to 4EDAH to skip the dual-density flag setup.
4ED6
LD A,L 7D
Copy Register L (option flags byte 1 at 5994H) into Register A.
4ED7
OR 42H F6 42
OR Register A with 42H (01000010 binary), setting bits 1 and 6. Bit 1 = source != dest, bit 6 = backup mode. When dual-density mode is active, both flags are forced on.
4ED9
LD L,A 6F
Store the updated flags back into Register L (will be written to 5994H later).
Compatibility check cascade begins. Each test checks a specific combination of flags; if incompatible, execution jumps to 4F49H (option conflict error).
4EDA
LD A,E 7B
Copy Register E (option flags byte 2 at 5996H) into Register A.
4EDB
AND 13H E6 13
Mask with 13H (00010011 binary), isolating bits 0, 1, and 4 of 5996H. These bits represent: bit 0 = specific sub-mode, bit 1 = alternate mode, bit 4 = extended mode. If any are set, this combination requires further validation.
4EDD
If the NZ FLAG has been set (at least one of bits 0/1/4 of 5996H is active), JUMP to 4EE2H — a qualifying flag is present, skip the secondary check.
4EDF
LD A,D 7A
Copy Register D (option flags byte 3 at 5997H) into Register A.
4EE0
AND 30H E6 30
Mask with 30H (00110000 binary), isolating bits 4 and 5 of 5997H. These bits represent additional mode qualifiers.
4EE2
If the NZ FLAG has been set (at least one qualifying flag found in either check), JUMP to 4EE7H to test whether the qualifying flags are compatible with the rest.
4EE4
LD A,H 7C
Copy Register H (option flags byte 2 at 5995H) into Register A.
4EE5
AND 08H E6 08
Mask with 08H, isolating bit 3 of 5995H. Bit 3 is an additional mode flag.
4EE7
If the Z FLAG has been set (none of the qualifying flags were active), JUMP to 4EEDH — no special modes active, continue the cascade.
4EE9
BIT 3,E CB 5B
Test bit 3 of Register E (5996H). Bit 3 = destination filespec parsed in 5996H (note: the same bit has different meanings in 5996H vs 5997H). If bit 3 is clear while qualifying flags are set, it is a conflict.
4EEB
If the Z FLAG has been set (bit 3 of 5996H is clear — missing required flag), JUMP to 4F49H to report an option conflict error.
4EED
LD A,H 7C
Copy Register H (option flags byte 2 at 5995H) into Register A.
4EEE
AND 06H E6 06
Mask with 06H (00000110 binary), isolating bits 1 and 2 of 5995H. These bits represent additional copy mode qualifiers.
4EF0
If the Z FLAG has been set (bits 1-2 of 5995H are both clear), JUMP to 4EFAH — no conflict here, skip this sub-check.
4EF2
BIT 2,D CB 52
Test bit 2 of Register D (5997H). Bit 2 = source filespec parsed flag in 5997H.
4EF4
If the NZ FLAG has been set (bit 2 of 5997H is set — source filespec was parsed), JUMP to 4EFAH — this combination is valid.
4EF6
BIT 3,E CB 5B
Test bit 3 of Register E (5996H). Another required-flag check.
4EF8
If the Z FLAG has been set (required flag missing), JUMP to 4F49H for option conflict error.
4EFA
BIT 3,E CB 5B
Test bit 3 of Register E (5996H) again — destination filespec flag in 5996H context.
4EFC
If the Z FLAG has been set (destination not specified in 5996H), JUMP to 4F0CH to bypass the next mutual-exclusion check.
4EFE
BIT 3,D CB 5A
Test bit 3 of Register D (5997H). Check destination filespec flag in 5997H context.
4F00
If the Z FLAG has been set (flag clear in 5997H), JUMP to 4F0CH — not a full conflict.
Both bit 3 of 5996H and bit 3 of 5997H are set. This means both source and destination filespecs are present. In this case, certain other options become invalid — check for them.
4F02
LD A,L 7D
Copy Register L (option flags byte 1 at 5994H) into Register A.
4F03
AND 0DH E6 0D
Mask with 0DH (00001101 binary), isolating bits 0, 2, and 3 of 5994H. These option flags are incompatible with dual-filespec mode.
4F05
If the NZ FLAG has been set (any of the incompatible flags are active), JUMP to 4F49H for option conflict error.
4F07
LD A,H 7C
Copy Register H (option flags byte 2 at 5995H) into Register A.
4F08
AND 36H E6 36
Mask with 36H (00110110 binary), isolating bits 1, 2, 4, and 5 of 5995H. These flags are also incompatible with dual-filespec mode.
4F0A
If the NZ FLAG has been set (any incompatible flags active), JUMP to 4F49H for option conflict error.
4F0C
LD A,H 7C
Copy Register H (option flags byte 2 at 5995H) into Register A.
4F0D
AND 41H E6 41
Mask with 41H (01000001 binary), isolating bits 0 and 6 of 5995H. These bits represent additional mode flags that require a qualifying condition.
4F0F
If the Z FLAG has been set (neither bit 0 nor bit 6 of 5995H is set), JUMP to 4F15H — no qualifying flags to check, store the final flags.
4F11
BIT 3,E CB 5B
Test bit 3 of Register E (5996H). When bits 0 or 6 of 5995H are set, bit 3 of 5996H must also be set to be valid.
4F13
If the Z FLAG has been set (required qualifying bit missing), JUMP to 4F49H for option conflict error.
All compatibility checks passed. Store the validated option flags back to memory.
4F15
LD (5994H),HL 22 94 59
Store Register Pair HL into 5994H. This writes the validated option flags bytes 1 and 2 (L → 5994H, H → 5995H). [SELF-MODIFYING DATA] — 5994H and 5995H are updated with the final validated option configuration.
4F18
LD (5996H),DE ED 53 96 59
Store Register Pair DE into 5996H. This writes the validated option flags bytes 2 and 3 (E → 5996H, D → 5997H). [SELF-MODIFYING DATA] — 5996H and 5997H are updated.
4F1C
RET C9
Return to the caller with the validated option flags stored in the work area.
4F1DH - KEYWORD TABLE SEARCH ENGINE
This routine searches the option keyword table at 505CH for a match against the user's option text pointed to by HL (passed in via DE after the exchange). The table contains encoded entries: each entry starts with ASCII keyword characters, followed by a byte with bit 7 set (marking end of keyword name), then flag and parameter bytes. The routine compares the user's text character-by-character against each table entry. On match, it extracts the option's flag byte, OR-mask value, conflict-check bytes, handler address, and optionally calls the handler. On no match after exhausting the table, it reports a parse error.
4F1D
PUSH BC C5
Save Register Pair BC onto the stack. B = remaining keyword count (loop counter from the main 4EA7H loop).
4F1E
EX DE,HL EB
Exchange DE and HL. Now DE = user's command line text pointer, HL will be set to the keyword table.
4F1F
LD HL,505CH 21 5C 50
Point Register Pair HL to 505CH, the start of the option keyword table. This table contains all recognized COPY/FORMAT option keywords in encoded format.
[OUTER LOOP START] — Try matching the user's text against the current table entry. DE = user text, HL = current table entry.
4F22
PUSH DE D5
Save the user's text pointer (DE) so it can be restored if this table entry doesn't match.
[INNER LOOP START] — Compare characters one by one between user text (DE) and table entry (HL).
4F23
LD A,(DE) 1A
Load Register A with the next character from the user's command line at (DE).
4F24
CP (HL) BE
Compare Register A against the current byte at (HL) in the keyword table entry.
4F25
If the NZ FLAG has been set (characters don't match), JUMP to 4F4CH to check if this is the end of the keyword name (bit 7 set on the current table byte). If so, the keyword matched partially; if not, skip to the next table entry.
4F27
INC DE 13
INCrement DE to advance to the next character in the user's text.
4F28
INC HL 23
INCrement HL to advance to the next byte in the keyword table entry.
4F29
JUMP back to 4F23H to compare the next pair of characters. [INNER LOOP END]
The following code at 4F2BH is the "skip to end of keyword name" loop, used when a match fails mid-keyword. It advances HL through the table entry until finding a byte with bit 7 set (the flag/control byte marking end of keyword name).
4F2B
INC HL 23
[SKIP LOOP START] INCrement HL to advance past the current byte in the keyword table.
4F2C
BIT 7,(HL) CB 7E
Test bit 7 of the byte at (HL). Bit 7 set marks the end of the keyword name / start of the control byte in the table entry.
4F2E
If the Z FLAG has been set (bit 7 is NOT set — still in keyword name), JUMP back to 4F2BH to continue advancing. [SKIP LOOP END]
HL now points to the control byte (bit 7 set). This byte encodes: bits 0-1 = offset into option flags array (5994H+offset), bit 2 = has conflict-check bytes (4 bytes follow), bit 4 = has handler address (2 bytes follow). Extract the control byte and skip past the variable-length fields.
4F30
LD A,(HL) 7E
Load Register A with the control byte at (HL). Bit 7 is set (end-of-name marker). Bits 0-1 = option flags offset, bit 2 = has conflict bytes, bit 4 = has handler address.
4F31
BIT 2,A CB 57
Test bit 2 of Register A. Bit 2 = 1 means this entry has 4 conflict-check bytes following the control byte.
4F33
INC HL 23
INCrement HL past the control byte to the first data byte.
4F34
If the Z FLAG has been set (no conflict-check bytes), JUMP to 4F3AH to skip the 4-byte advance.
4F36
INC HL 23
INCrement HL (skip conflict byte 1).
4F37
INC HL 23
INCrement HL (skip conflict byte 2).
4F38
INC HL 23
INCrement HL (skip conflict byte 3).
4F39
INC HL 23
INCrement HL (skip conflict byte 4).
4F3A
BIT 4,A CB 67
Test bit 4 of Register A (saved control byte). Bit 4 = 1 means this entry has a 2-byte handler address following.
4F3C
If the Z FLAG has been set (no handler address), JUMP to 4F40H to skip the 2-byte advance.
4F3E
INC HL 23
INCrement HL (skip handler address low byte).
4F3F
INC HL 23
INCrement HL (skip handler address high byte).
4F40
POP DE D1
Restore the user's text pointer (DE) from the stack (saved at 4F22H). This resets DE to the start of the user's keyword for the next table entry comparison.
4F41
INC HL 23
INCrement HL past the OR-mask byte to point to the start of the next table entry.
4F42
LD A,(HL) 7E
Load Register A with the first byte of the next table entry.
4F43
OR A B7
OR Register A with itself. If A = 00H, the Z FLAG is set — this is the end-of-table marker (the keyword table is terminated by a 00H byte).
4F44
If the NZ FLAG has been set (not end of table), JUMP back to 4F22H to try matching the user's text against the next table entry. [OUTER LOOP END]
End of keyword table reached without finding a match. Report a parse error.
4F46
JUMP to 5214H to report a parse error (error code 34H). The user's option keyword was not recognized in the table.
4F49H - OPTION CONFLICT / PARSE ERROR DISPATCHERS
Two error dispatch stubs. 4F49H handles option conflict errors (incompatible option combinations); 4F4CH is the "mismatch during keyword comparison" handler that checks if the mismatch occurred at the end of the keyword name.
4F49
JUMP to 5218H to report an option conflict error (error code 2FH). This is reached when incompatible option combinations are detected during validation, or when a required qualifying flag is missing.
The mismatch handler at 4F4CH is reached when comparing user text against a keyword table entry and the characters don't match. It checks if the current table byte has bit 7 set (end-of-keyword marker). If so, the keyword matched up to this point and the mismatch is at the boundary — this could be a valid match (the user's text ended where the keyword name ends). If bit 7 is not set, the match truly failed and we need to skip to the end of this table entry.
4F4C
BIT 7,(HL) CB 7E
Test bit 7 of the byte at (HL) in the keyword table. Bit 7 set means this is the control byte at the end of the keyword name.
4F4E
If the Z FLAG has been set (bit 7 NOT set — still inside the keyword name, not at the end), JUMP to 4F2BH to skip to the end of this keyword entry and try the next one.
Bit 7 IS set — the mismatch occurred at the control byte boundary. This means the user's text matched all the keyword name characters, and the current byte is the control byte. This is a successful keyword match! Pop the saved text pointer (which was the start position) and process the matched keyword.
4F50
POP AF F1
Pop the saved user text pointer from the stack (pushed at 4F22H) into AF. We discard it since DE has already been advanced past the matched keyword characters.
4F51
LD A,B 78
Copy Register B (the remaining keyword count from the outer 4EA7H loop) into Register A.
4F52
AND (HL) A6
AND Register A with the byte at (HL), the control byte. This tests whether the remaining count qualifies for this keyword — certain keywords are only valid when specific bits are set in B (the original count value passed to 4EA7H: 20H for disk copy, 08H for file copy).
4F53
If the Z FLAG has been set (the keyword is not valid for the current command mode), JUMP to 4F49H for option conflict error.
Keyword is valid for the current mode. Extract the control byte and OR-mask, then set the corresponding option flag bits.
4F55
LD B,(HL) 46
Load Register B with the control byte at (HL). B now contains the full control byte: bits 0-1 = offset, bit 2 = has conflict bytes, bit 4 = has handler, bit 7 = end marker.
4F56
INC HL 23
INCrement HL to point to the OR-mask byte.
4F57
LD C,(HL) 4E
Load Register C with the OR-mask byte. This byte will be OR'ed into the appropriate option flags byte to activate this option.
4F58
INC HL 23
INCrement HL past the OR-mask to the next field (conflict bytes or handler address).
4F59
PUSH DE D5
Save Register Pair DE (the advanced user text pointer) onto the stack.
4F5A
LD A,B 78
Copy the control byte from Register B into Register A.
4F5B
AND 03H E6 03
Mask with 03H, isolating bits 0-1. This gives the offset into the option flags array: 0 = 5994H, 1 = 5995H, 2 = 5996H, 3 = 5997H.
4F5D
LD E,A 5F
Copy the offset into Register E.
4F5E
LD D,00H 16 00
Load Register D with 00H. DE = the offset (0-3) as a 16-bit value.
4F60
PUSH HL E5
Save Register Pair HL (current table position) onto the stack.
4F61
LD HL,5994H 21 94 59
Point Register Pair HL to 5994H, the base of the option flags array.
4F64
PUSH HL E5
Save the base address (5994H) onto the stack for later use.
4F65
ADD HL,DE 19
ADD the offset (DE) to HL. HL now points to the specific option flags byte: 5994H + offset.
4F66
LD A,(HL) 7E
Load Register A with the current value of the target option flags byte.
4F67
OR C B1
OR Register A with the OR-mask in Register C. This sets the option flag bits for the matched keyword.
4F68
LD (HL),A 77
Store the updated option flags back into the target byte.
4F69
POP DE D1
Restore the base address (5994H) into DE.
4F6A
POP HL E1
Restore the keyword table position into HL.
4F6B
BIT 2,B CB 50
Test bit 2 of Register B (the control byte). Bit 2 = 1 means this entry has 4 conflict-check bytes.
4F6D
If the Z FLAG has been set (no conflict-check bytes), JUMP to 4F7AH to skip the conflict check and proceed to the handler address.
Conflict-check: the next 4 bytes in the table are AND-masks tested against the 4 option flag bytes (5994H-5997H). If any AND produces a non-zero result, the new option conflicts with an existing one.
4F6F
LD C,04H 0E 04
Load Register C with 04H (4 bytes to check).
4F71
LD A,(DE) 1A
[LOOP START] Load Register A with the current option flags byte at (DE) (starting at 5994H).
4F72
AND (HL) A6
AND Register A with the conflict-check mask at (HL). If the result is non-zero, the newly-set option conflicts with an already-active option.
4F73
INC DE 13
INCrement DE to the next option flags byte.
4F74
INC HL 23
INCrement HL to the next conflict-check mask byte.
4F75
If the NZ FLAG has been set (conflict detected — option flag AND conflict mask is non-zero), JUMP to 4F49H for option conflict error.
4F77
DEC C 0D
DECrement C (byte counter).
4F78
If C is not zero, JUMP back to 4F71H to check the next byte. [LOOP END]
No conflicts found. HL now points past the conflict bytes. The next 2 bytes are the handler address (if bit 4 of the control byte is set).
4F7A
LD E,(HL) 5E
Load Register E with the low byte of the handler address at (HL).
4F7B
INC HL 23
INCrement HL to point to the high byte.
4F7C
LD D,(HL) 56
Load Register D with the high byte of the handler address. DE now contains the handler routine address for this option keyword.
4F7D
LD (4F85H),DE ED 53 85 4F
Store DE (the handler address) into 4F85H. [SELF-MODIFYING CODE] — this writes the handler address into the operand of the CALL NZ instruction at 4F84H. The next instruction will conditionally call this address.
4F81
POP HL E1
Restore the user's text pointer from the stack (saved at 4F59H). HL now points to the command line text following the matched keyword.
4F82
BIT 4,B CB 60
Test bit 4 of Register B (the control byte). Bit 4 = 1 means this option has a handler routine that needs to be called to process the option's value parameter.
4F84
If the NZ FLAG has been set (bit 4 = 1, handler exists), CALL the address at 4F85H-4F86H. [SELF-MODIFYING CODE] — the 0000H operand was overwritten at 4F7DH with the actual handler address. This calls the option's value parser/handler routine (e.g., 4F8BH for name/password, 4F9EH for stepping rate, 4FC3H for numeric values, etc.).
4F87
POP BC C1
Restore Register Pair BC from the stack (saved at 4F1DH). B = remaining keyword count.
4F88
JUMP back to 4EA7H to parse the next option keyword. The main parsing loop continues until no more text remains on the command line.
4F8BH - NAME/PASSWORD PARSING HANDLERS
Three entry points that parse name/password strings from the command line into specific work area buffers. Each sets DE to the destination buffer and falls through to the common parser at 4F98H. The buffers are: 5970H (diskette name, 8 bytes), 5968H (diskette password, 8 bytes), and 5983H (alternate name/date field).
4F8B
LD DE,5970H 11 70 59
Point Register Pair DE to 5970H, the diskette name buffer (8 bytes) in the SYS6 work area. This is where the NDN= (New Destination Name) option value will be stored.
4F8E
JUMP to 4F98H (the common name/password parser).
4F90
LD DE,5968H 11 68 59
Point Register Pair DE to 5968H, the diskette password buffer (8 bytes). This is where the ODPDN= (Old Disk Password/Name) or PDN= option value will be stored.
4F93
JUMP to 4F98H (the common parser).
4F95
LD DE,5983H 11 83 59
Point Register Pair DE to 5983H, the alternate name/date buffer. This is where the SN= (Source diskette Name=) option value will be stored.
4F98
GOSUB to 6F8EH to parse a name/password string from the command line at (HL) into the buffer at (DE). This routine copies up to 8 characters until a delimiter is found, padding with spaces if needed. Returns Z if parsing failed (empty or invalid), NZ on success.
4F9B
If the Z FLAG has been set (name parsing failed — empty or invalid string), JUMP to 4F49H for option conflict error. A name/password option requires a non-empty value.
4F9D
RET C9
Return to the keyword table search engine at 4F87H (via the self-modifying CALL at 4F84H).
4F9EH - STEPPING RATE HANDLER
Handler for the SPW= (Stepping Pulse Width) option. Parses a single digit (2-6) from the command line, converts it to a stepping rate code (2+offset), and stores it in the drive geometry table at 64AFH.
4F9E
LD A,(HL) 7E
Load Register A with the next character from the command line at (HL). This should be a digit representing the stepping rate parameter.
4F9F
SUB 32H D6 32
SUBtract 32H (ASCII 2) from Register A. This converts the characters '2' through '6' to values 0-4. Values below '2' or above '6' will produce out-of-range results.
4FA1
CP 05H FE 05
Compare Register A against 05H. If A >= 5 (the original character was not in the range '2'-'6'), the NO CARRY FLAG is set.
4FA3
INC HL 23
INCrement HL to advance past the parsed digit character.
4FA4
If the NO CARRY FLAG has been set (value out of range — not a valid stepping rate), JUMP to 4FCBH which dispatches to the option conflict error at 4F49H.
4FA6
ADD 02H C6 02
ADD 02H to Register A, converting the 0-4 range back to 2-6. This is the actual stepping rate code stored in the drive geometry table.
4FA8
LD (64AFH),A 32 AF 64
Store the stepping rate code into 64AFH, the stepping pulse width field in the drive geometry data table. [SELF-MODIFYING DATA] — 64AFH is within the drive geometry table area.
4FAB
RET C9
Return to the keyword table search engine.
4FACH - COMMAND LINE FILESPEC BUFFER HANDLER
Handler for the CFWO (Copy File With Options) keyword. This routine copies the remaining command line text into the DOS command buffer at 4480H, parsing it as a series of filespecs. It pre-fills the buffer with 0DH (end-of-line markers), then repeatedly calls the filespec parser.
4FAC
LD DE,4480H 11 80 44
Point Register Pair DE to 4480H, the DOS command line buffer. This is the system's primary command input buffer used by SYS0.
4FAF
LD B,20H 06 20
Load Register B with 20H (32 decimal). This is the maximum number of iterations for the parse loop.
4FB1
LD A,0DH 3E 0D
[LOOP START] Load Register A with 0DH (carriage return / end-of-line marker).
4FB3
LD (DE),A 12
Store 0DH into (DE), pre-filling the buffer position with an end-of-line marker.
4FB4
GOSUB to SYS0 routine at 4C7AH to parse the next filespec from the command line at (HL) into the buffer at (DE).
4FB7
RET Z C8
If the Z FLAG has been set (clean end-of-input), RETURN — all filespecs have been parsed into the buffer.
4FB8
DEC HL 2B
DECrement HL. [SELF-MODIFYING DATA] — address 4FB8H is written by 60ADH at runtime. The DEC HL backs up to the terminating character.
4FB9
RET NC D0
If the NO CARRY FLAG has been set (parse error), RETURN with the error indication.
4FBA
INC HL 23
INCrement HL past the terminating character.
4FBB
LD A,(HL) 7E
Load Register A with the next character at (HL).
4FBC
LD (DE),A 12
Copy the character into the buffer at (DE).
4FBD
INC DE 13
INCrement DE to advance in the buffer.
4FBE
INC HL 23
INCrement HL to advance on the command line.
4FBF
DECrement B and loop back to 4FB1H if not zero. [LOOP END]
4FC1
If the loop counter expired (32 iterations), JUMP to 4FCBH for option conflict error (too many filespecs).
4FC3H - NUMERIC PARAMETER HANDLERS
A group of small handler routines for numeric option parameters. Each calls 6EE6H or 6EE1H to parse a numeric value from the command line, then stores the result into a specific location in the drive geometry or FDC configuration tables. The error exit at 4FCBH catches invalid values.
4FC3
GOSUB to 6EE6H to parse a decimal number from the command line at (HL). Returns the value in Register A. HL is advanced past the digits.
4FC6
LD (64ACH),A 32 AC 64
Store the parsed value into 64ACH, the head settle time field in the drive geometry data table. [SELF-MODIFYING DATA]
4FC9
OR A B7
OR Register A with itself. Tests if the parsed value is zero (which may be invalid for certain parameters).
4FCA
RET NZ C0
If the NZ FLAG has been set (value is non-zero, valid), RETURN to the keyword search engine.
4FCB
If the value was zero or out of range, JUMP to 4F49H for option conflict error.
4FCE
GOSUB to 6EE1H to parse a numeric value (similar to 6EE6H but with slightly different range handling). Returns value in Register A.
4FD1
LD (68ADH),A 32 AD 68
Store the parsed value into 68ADH, the FDC motor-on delay parameter. [SELF-MODIFYING DATA] — this writes into the FDC operation area, modifying a timing value used during format/copy operations.
4FD4
JUMP to 4FC9H to validate (non-zero check) and return.
4FD6
GOSUB to 6EE1H to parse another numeric parameter value.
4FD9
LD (68AEH),A 32 AE 68
Store the parsed value into 68AEH, the FDC head-load delay parameter. [SELF-MODIFYING DATA] — modifies a timing byte in the FDC operation area.
4FDC
RET C9
Return to the keyword search engine.
4FDDH - BUFFER ADDRESS OPTION HANDLERS
Three option handler routines that parse hex addresses from the command line (via 5025H) and store them as 16-bit buffer pointers in the SYS6 work area. These support the OPFST= (Output First Sector), PFTC= (Post-Format Track Count), and similar buffer/address options.
4FDD
GOSUB to 5025H to parse a hex address value from the command line. This routine parses up to 8 hex characters, computing a checksum/encryption, and returns the 16-bit result in DE. See 5025H for details.
4FE0
LD (5978H),DE ED 53 78 59
Store the parsed address into 5978H, the output buffer start address in the SYS6 work area. [SELF-MODIFYING DATA]
4FE4
RET C9
Return to the keyword search engine.
4FE5
GOSUB to 5025H to parse a hex address value from the command line.
4FE8
LD (5981H),DE ED 53 81 59
Store the parsed address into 5981H, the secondary buffer address. [SELF-MODIFYING DATA]
4FEC
RET C9
Return to the keyword search engine.
4FED
GOSUB to 5025H to parse a hex address value from the command line.
4FF0
LD (597AH),DE ED 53 7A 59
Store the parsed address into 597AH, the third buffer address. [SELF-MODIFYING DATA]
4FF4
RET C9
Return to the keyword search engine.
4FF5H - DRIVE NUMBER PARAMETER HANDLERS
Two entry points for parsing drive numbers (0-9) from option parameters. Both call the common routine at 5002H which parses a digit, validates it is 0-9, and stores it at a handler-specific address. 4FF5H stores into 63D6H (copy tracking) and also writes the drive number into the self-modifying location at 4DFAH; 4FFFH stores into 63CAH.
4FF5
LD DE,63D6H 11 D6 63
Point Register Pair DE to 63D6H, a drive tracking byte in the copy operation area.
4FF8
GOSUB to 5002H to parse a single digit and store it at (DE) = 63D6H.
4FFB
LD (4DFAH),A 32 FA 4D
Store the parsed drive number into 4DFAH. [SELF-MODIFYING CODE] — this overwrites the operand of the LD A,00H instruction at 4DF9H, so subsequent calls to 4DF3H will use this drive number instead of the default 0.
4FFE
RET C9
Return to the keyword search engine.
4FFF
LD DE,63CAH 11 CA 63
Point Register Pair DE to 63CAH, another drive tracking byte.
5002
PUSH DE D5
Save Register Pair DE (target address) onto the stack.
5003
GOSUB to 6EE6H to parse a decimal number from the command line. Returns value in Register A.
5006
CP 0AH FE 0A
Compare Register A against 0AH (10 decimal). Valid drive numbers are 0-9. If A >= 10, the NO CARRY FLAG is set.
5008
If the NO CARRY FLAG has been set (drive number >= 10, invalid), JUMP to 4FCBH for option conflict error.
500A
POP DE D1
Restore Register Pair DE (target address) from the stack.
500B
LD (DE),A 12
Store the validated drive number into (DE).
500C
RET C9
Return to the caller.
500DH - HEX CODE PARSER (3-DIGIT)
Parses up to 3 hexadecimal characters from the command line and copies them into the buffer at 624CH. Used for the hex identification code options. Validates that each character is a valid hex digit (0-9 or A-Z).
500D
LD DE,624CH 11 4C 62
Point Register Pair DE to 624CH, the hex code buffer where up to 3 hex characters will be stored.
5010
LD B,03H 06 03
Load Register B with 03H (3 characters maximum).
5012
LD A,(HL) 7E
[LOOP START] Load Register A with the next character from the command line at (HL).
5013
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A. This converts '0'-'9' to 0-9.
5015
CP 0AH FE 0A
Compare Register A against 0AH. If A < 10, the CARRY FLAG is set — the character was a digit '0'-'9'.
5017
If the CARRY FLAG has been set (valid digit), JUMP to 501EH to store it.
5019
SUB 11H D6 11
SUBtract 11H from Register A. After the previous SUB 30H, the value for 'A' would be 11H; subtracting 11H makes it 0. This converts 'A'-'Z' to 0-25.
501B
CP 1AH FE 1A
Compare Register A against 1AH (26). If A >= 26, the character is not a valid letter.
501D
RET NC D0
If the NO CARRY FLAG has been set (not a valid hex/alpha character), RETURN — parsing stops at the first non-hex character. The caller interprets partial results.
501E
LD A,(HL) 7E
Reload the original character from (HL) — we need the raw ASCII value, not the converted number.
501F
LD (DE),A 12
Store the raw ASCII hex character into the buffer at (DE).
5020
INC DE 13
INCrement DE to advance in the buffer.
5021
INC HL 23
INCrement HL to advance on the command line.
5022
DECrement B and loop back to 5012H if not zero. [LOOP END] Up to 3 hex characters are copied.
5024
RET C9
Return after parsing all 3 characters (or when a non-hex character was encountered).
5025H - CHECKSUM/ENCRYPTION COMPUTATION
This routine parses a name string from the command line (via 6F8EH) and computes a 16-bit checksum/encryption value from it using a CRC-like polynomial algorithm. The input is the 8-character name at 5960H; the output is a 16-bit value in DE that serves as a disk verification code. The algorithm processes each character through bit rotations and XOR operations to produce a pseudo-random hash. It also overwrites the name buffer with spaces (20H) after processing each character.
5025
LD DE,5960H 11 60 59
Point Register Pair DE to 5960H, the name/input buffer where the parsed name string will be stored (8 bytes).
5028
GOSUB to 6F8EH to parse a name string from the command line at (HL) into the buffer at 5960H. Up to 8 characters are extracted and padded with spaces.
502B
PUSH HL E5
Save Register Pair HL (command line pointer after the parsed name) onto the stack.
502C
EX DE,HL EB
Exchange DE and HL. HL now points past the 8-byte name buffer (DE was advanced by 6F8EH). HL = 5968H (just past the buffer end).
502D
LD DE,FFFFH 11 FF FF
Load Register Pair DE with FFFFH. This initializes the 16-bit checksum accumulator to all 1s (a common CRC seed value).
5030
LD B,08H 06 08
Load Register B with 08H (8 iterations — one per character in the name buffer).
[OUTER LOOP START] Process one character per iteration, computing the checksum from right to left through the buffer (HL decrements).
5032
PUSH BC C5
Save Register Pair BC (loop counter) onto the stack.
5033
LD A,E 7B
Copy the low byte of the checksum (Register E) into Register A.
5034
AND 07H E6 07
Mask with 07H, isolating the lowest 3 bits of E. Save this as a partial value in C.
5036
LD C,A 4F
Copy the low 3 bits into Register C.
5037
LD A,E 7B
Reload the low checksum byte into Register A.
5038
RLCA 07
Rotate A left (multiply by 2, bit 7 wraps to bit 0).
5039
RLCA 07
Rotate A left again (A = original E × 4, with high bits wrapped).
503A
RLCA 07
Rotate A left again (A = original E × 8, with wrapped bits).
503B
XOR C A9
XOR Register A with C (the low 3 bits of original E). This creates the first polynomial term.
503C
RLCA 07
Rotate A left one more time.
503D
LD C,A 4F
Save the intermediate result into C.
503E
AND F0H E6 F0
Mask with F0H, isolating the upper nibble.
5040
LD B,A 47
Save the upper nibble into B.
5041
LD A,C 79
Reload the intermediate from C.
5042
RLCA 07
Rotate A left.
5043
AND 1FH E6 1F
Mask with 1FH, isolating the lower 5 bits.
5045
XOR B A8
XOR with B (upper nibble), combining the polynomial terms.
5046
XOR D AA
XOR with D (high byte of checksum). This folds the computed value into the high checksum byte.
5047
LD E,A 5F
Store the result as the new low byte of the checksum (E). The old low byte becomes the new high byte in a swap-like operation.
5048
LD A,C 79
Reload the intermediate from C.
5049
AND 0FH E6 0F
Mask with 0FH, isolating the lower nibble.
504B
LD B,A 47
Save the lower nibble into B.
504C
LD A,C 79
Reload intermediate from C.
5050
RLCA 07
Rotate left (4 total rotations = shift by 4 = swap nibbles).
5051
XOR B A8
XOR with B (lower nibble of intermediate). Final polynomial term.
5052
POP BC C1
Restore Register Pair BC (loop counter).
5053
DEC HL 2B
DECrement HL to point to the previous character in the name buffer (processing right to left).
5054
XOR (HL) AE
XOR Register A with the character at (HL). This incorporates the current character into the checksum computation.
5055
LD D,A 57
Store the result as the new high byte of the checksum (D).
5056
LD (HL),20H 36 20
Store 20H (ASCII space) into (HL), overwriting the character in the name buffer with a space. This clears the buffer as it is processed.
5058
DECrement B and loop back to 5032H if not zero. [OUTER LOOP END] Processes all 8 characters.
505A
POP HL E1
Restore Register Pair HL (command line pointer) from the stack.
505B
RET C9
Return with the 16-bit checksum in DE. The name buffer at 5960H has been cleared to spaces.
505CH - OPTION KEYWORD TABLE (DATA — 298 BYTES)
This is the encoded option keyword table for the COPY and FORMAT commands. The table contains 32 encoded keyword entries used by the option parser engine at 4F1DH to match command-line options, set flags, check for conflicts, and dispatch to handler routines. The table covers all options for the COPY command (6 formats), FORMAT command, and related operations.
Each entry consists of: (1) ASCII keyword characters, (2) a control byte with bit 7 set marking end-of-name, (3) an OR-mask byte, (4) optionally 4 conflict-check bytes, and (5) optionally a 2-byte handler address. The table is terminated by a 00H byte at 5185H.
Control byte encoding:
Bits 0-1: Index into option flags array (0=5994H, 1=5995H, 2=5996H, 3=5997H)
Bit 2: If set, 4 conflict-check bytes follow the OR-mask
Bit 4: If set, 2-byte handler address (lo/hi) follows
Bits 5-6: Mode qualifier — AND'd with the command mode register B to validate applicability:
Mode 1 = COPY-only options
Mode 2 = FORMAT-only options
Mode 3 = options valid for both COPY and FORMAT
Conflict checking: When the 4 conflict bytes are present, each is AND'd against the corresponding flags byte (5994H-5997H). If any result is non-zero, the option conflicts with a previously-set option and error 2FH is raised via 4F49H → 5218H.
Entry #1 — "CFWO" (COPY only): Check File With Operator
505C
DEFM "CFWO" 43 46 57 4F
ASCII keyword string "CFWO" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5060
DEFB A1H A1
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 clear = no conflict check; bits 0-1 = 01b (target flags byte at 5995H).
5061
DEFB 40H 40
OR-mask: this value is OR'd into the flags byte at 5995H when the "CFWO" option is matched. Sets bit 6 of 5995H.
Entry #2 — "DDGA=" (COPY and FORMAT): Destination diskette Directory Granule Allocation=gc1
5062
DEFM "DDGA=" 44 44 47 41 3D
ASCII keyword string "DDGA=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5067
DEFB F5H F5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
5068
DEFB 02H 02
OR-mask: this value is OR'd into the flags byte at 5995H when the "DDGA=" option is matched. Sets bit 1 of 5995H.
5069
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
506A
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
506B
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
506C
DEFB 0AH 0A
Conflict mask vs 5997H: AND'd with (5997H). If bit 3, bit 1 of 5997H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
506D
DEFW 4F9EH 9E 4F
Handler address: 4F9EH (lo/hi). When "DDGA=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse numeric value for granule allocation.
Entry #3 — "ODPW=" (COPY only): Old Destination diskette Password=password2
506F
DEFM "ODPW=" 4F 44 50 57 3D
ASCII keyword string "ODPW=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5074
DEFB B5H B5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
5075
DEFB 01H 01
OR-mask: this value is OR'd into the flags byte at 5995H when the "ODPW=" option is matched. Sets bit 0 of 5995H.
5076
DEFB C0H C0
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 6 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5077
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5078
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5079
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
507A
DEFW 4FEDH ED 4F
Handler address: 4FEDH (lo/hi). When "ODPW=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse password string into buffer.
Entry #4 — "NDPW=" (COPY only): New Destination Password
507C
DEFM "NDPW=" 4E 44 50 57 3D
ASCII keyword string "NDPW=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5081
DEFB B5H B5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
5082
DEFB 20H 20
OR-mask: this value is OR'd into the flags byte at 5995H when the "NDPW=" option is matched. Sets bit 5 of 5995H.
5083
DEFB 02H 02
Conflict mask vs 5994H: AND'd with (5994H). If bit 1 of 5994H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5084
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5085
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5086
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
5087
DEFW 4FE5H E5 4F
Handler address: 4FE5H (lo/hi). When "NDPW=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse password string into buffer.
Entry #5 — "DDSL=" (COPY and FORMAT): Destination diskette Directory Starting Lump=ln1
5089
DEFM "DDSL=" 44 44 53 4C 3D
ASCII keyword string "DDSL=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
508E
DEFB F5H F5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
508F
DEFB 04H 04
OR-mask: this value is OR'd into the flags byte at 5995H when the "DDSL=" option is matched. Sets bit 2 of 5995H.
5090
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
5091
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5092
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5093
DEFB 0AH 0A
Conflict mask vs 5997H: AND'd with (5997H). If bit 3, bit 1 of 5997H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5094
DEFW 4FC3H C3 4F
Handler address: 4FC3H (lo/hi). When "DDSL=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse decimal number for starting logical sector.
Entry #6 — "SPDN=" (COPY only): Source PDrive Number=dn3
5096
DEFM "SPDN=" 53 50 44 4E 3D
ASCII keyword string "SPDN=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
509B
DEFB BBH BB
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 11b (target flags byte at 5997H).
509C
DEFB 80H 80
OR-mask: this value is OR'd into the flags byte at 5997H when the "SPDN=" option is matched. Sets bit 7 of 5997H.
509D
DEFW 4FFFH FF 4F
Handler address: 4FFFH (lo/hi). When "SPDN=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse drive number 0-9, store at 63CAH.
Entry #7 — "DPDN=" (COPY and FORMAT): Destination PDrive Number=dn4
509F
DEFM "DPDN=" 44 50 44 4E 3D
ASCII keyword string "DPDN=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50A4
DEFB FBH FB
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 11b (target flags byte at 5997H).
50A5
DEFB 40H 40
OR-mask: this value is OR'd into the flags byte at 5997H when the "DPDN=" option is matched. Sets bit 6 of 5997H.
50A6
DEFW 4FF5H F5 4F
Handler address: 4FF5H (lo/hi). When "DPDN=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse drive number 0-9, store at 63D6H and 4DFAH.
Entry #8 — "PFST=" (FORMAT only): undocumented FORMAT-only option — buffer address parameter
50A8
DEFM "PFST=" 50 46 53 54 3D
ASCII keyword string "PFST=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50AD
DEFB D7H D7
Control byte: bit 7 set = end of keyword name; bits 5-6 = 10b (mode 2: FORMAT only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 11b (target flags byte at 5997H).
50AE
DEFB 02H 02
OR-mask: this value is OR'd into the flags byte at 5997H when the "PFST=" option is matched. Sets bit 1 of 5997H.
50AF
DEFB B9H B9
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 5, bit 4, bit 3, bit 0 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50B0
DEFB 86H 86
Conflict mask vs 5995H: AND'd with (5995H). If bit 7, bit 2, bit 1 of 5995H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50B1
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50B2
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
50B3
DEFW 4FD6H D6 4F
Handler address: 4FD6H (lo/hi). When "PFST=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse numeric value for buffer address.
Entry #9 — "PFTC=" (FORMAT only): undocumented FORMAT-only option — secondary buffer address parameter
50B5
DEFM "PFTC=" 50 46 54 43 3D
ASCII keyword string "PFTC=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50BA
DEFB D3H D3
Control byte: bit 7 set = end of keyword name; bits 5-6 = 10b (mode 2: FORMAT only); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 11b (target flags byte at 5997H).
50BB
DEFB 01H 01
OR-mask: this value is OR'd into the flags byte at 5997H when the "PFTC=" option is matched. Sets bit 0 of 5997H.
50BC
DEFW 4FCEH CE 4F
Handler address: 4FCEH (lo/hi). When "PFTC=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse numeric value for buffer address.
Entry #10 — "NDN=" (COPY only): New Destination Name=name2
50BE
DEFM "NDN=" 4E 44 4E 3D
ASCII keyword string "NDN=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50C2
DEFB B4H B4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
50C3
DEFB 04H 04
OR-mask: this value is OR'd into the flags byte at 5994H when the "NDN=" option is matched. Sets bit 2 of 5994H.
50C4
DEFB 0AH 0A
Conflict mask vs 5994H: AND'd with (5994H). If bit 3, bit 1 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50C5
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
50C6
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50C7
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
50C8
DEFW 4F95H 95 4F
Handler address: 4F95H (lo/hi). When "NDN=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse name string via 6F8EH into buffer at 5970H.
Entry #11 — "ODN=" (COPY and FORMAT): Old Destination Name=name1
50CA
DEFM "ODN=" 4F 44 4E 3D
ASCII keyword string "ODN=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50CE
DEFB F4H F4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
50CF
DEFB 10H 10
OR-mask: this value is OR'd into the flags byte at 5994H when the "ODN=" option is matched. Sets bit 4 of 5994H.
50D0
DEFB C0H C0
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 6 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50D1
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
50D2
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50D3
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50D4
DEFW 4F8BH 8B 4F
Handler address: 4F8BH (lo/hi). When "ODN=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse name string via 6F8EH into buffer at 5983H.
Entry #12 — "DDND" (COPY and FORMAT): Display Destination old Name and Date
50D6
DEFM "DDND" 44 44 4E 44
ASCII keyword string "DDND" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50DA
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
50DB
DEFB 20H 20
OR-mask: this value is OR'd into the flags byte at 5994H when the "DDND" option is matched. Sets bit 5 of 5994H.
50DC
DEFB C0H C0
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 6 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50DD
DEFB 80H 80
Conflict mask vs 5995H: AND'd with (5995H). If bit 7 of 5995H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50DE
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50DF
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #13 — "NDMW" (COPY and FORMAT): No Diskette Mount Waits
50E0
DEFM "NDMW" 4E 44 4D 57
ASCII keyword string "NDMW" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50E4
DEFB E5H E5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
50E5
DEFB 80H 80
OR-mask: this value is OR'd into the flags byte at 5995H when the "NDMW" option is matched. Sets bit 7 of 5995H.
50E6
DEFB 20H 20
Conflict mask vs 5994H: AND'd with (5994H). If bit 5 of 5994H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50E7
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
50E8
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50E9
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
Entry #14 — "SPW=" (COPY only): Source Password=nnnnnnn
50EA
DEFM "SPW=" 53 50 57 3D
ASCII keyword string "SPW=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50EE
DEFB B2H B2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
50EF
DEFB 40H 40
OR-mask: this value is OR'd into the flags byte at 5996H when the "SPW=" option is matched. Sets bit 6 of 5996H.
50F0
DEFW 4FDDH DD 4F
Handler address: 4FDDH (lo/hi). When "SPW=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse stepping rate digit (2-6), store at 64AFH.
Entry #15 — "NFMT" (COPY only): No ForMaT — suppresses formatting of the destination disk before copy
50F2
DEFM "NFMT" 4E 46 4D 54
ASCII keyword string "NFMT" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
50F6
DEFB A7H A7
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 11b (target flags byte at 5997H).
50F7
DEFB 08H 08
OR-mask: this value is OR'd into the flags byte at 5997H when the "NFMT" option is matched. Sets bit 3 of 5997H.
50F8
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
50F9
DEFB 06H 06
Conflict mask vs 5995H: AND'd with (5995H). If bit 2, bit 1 of 5995H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
50FA
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
50FB
DEFB 04H 04
Conflict mask vs 5997H: AND'd with (5997H). If bit 2 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #16 — "XLF=" (COPY only): eXclude List File — filespec of a file listing names to exclude from copy
50FC
DEFM "XLF=" 58 4C 46 3D
ASCII keyword string "XLF=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5100
DEFB B7H B7
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 11b (target flags byte at 5997H).
5101
DEFB 20H 20
OR-mask: this value is OR'd into the flags byte at 5997H when the "XLF=" option is matched. Sets bit 5 of 5997H.
5102
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
5103
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5104
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5105
DEFB 10H 10
Conflict mask vs 5997H: AND'd with (5997H). If bit 4 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5106
DEFW 4FACH AC 4F
Handler address: 4FACH (lo/hi). When "XLF=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse filespec, copy into DOS buffer at 4480H.
Entry #17 — "ILF=" (COPY only): Include List File — filespec of a file listing names to include in copy
5108
DEFM "ILF=" 49 4C 46 3D
ASCII keyword string "ILF=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
510C
DEFB B7H B7
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 11b (target flags byte at 5997H).
510D
DEFB 10H 10
OR-mask: this value is OR'd into the flags byte at 5997H when the "ILF=" option is matched. Sets bit 4 of 5997H.
510E
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
510F
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5110
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5111
DEFB 20H 20
Conflict mask vs 5997H: AND'd with (5997H). If bit 5 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5112
DEFW 4FACH AC 4F
Handler address: 4FACH (lo/hi). When "ILF=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse filespec, copy into DOS buffer at 4480H.
Entry #18 — "KDN" (COPY and FORMAT): Keep Destination diskette Name
5114
DEFM "KDN" 4B 44 4E
ASCII keyword string "KDN" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5117
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
5118
DEFB 08H 08
OR-mask: this value is OR'd into the flags byte at 5994H when the "KDN" option is matched. Sets bit 3 of 5994H.
5119
DEFB C6H C6
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 6, bit 2, bit 1 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
511A
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
511B
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
511C
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #19 — "SN=" (COPY only): Source diskette Name=name3
511D
DEFM "SN=" 53 4E 3D
ASCII keyword string "SN=" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5120
DEFB B2H B2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
5121
DEFB 80H 80
OR-mask: this value is OR'd into the flags byte at 5996H when the "SN=" option is matched. Sets bit 7 of 5996H.
5122
DEFW 4F90H 90 4F
Handler address: 4F90H (lo/hi). When "SN=" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse name string via 6F8EH into buffer at 5968H.
Entry #20 — "KDD" (COPY and FORMAT): Keep Destination diskette Date
5124
DEFM "KDD" 4B 44 44
ASCII keyword string "KDD" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5127
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
5128
DEFB 01H 01
OR-mask: this value is OR'd into the flags byte at 5994H when the "KDD" option is matched. Sets bit 0 of 5994H.
5129
DEFB C2H C2
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 6, bit 1 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
512A
DEFB 10H 10
Conflict mask vs 5995H: AND'd with (5995H). If bit 4 of 5995H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
512B
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
512C
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #21 — "USD" (COPY only): Use Source Date
512D
DEFM "USD" 55 53 44
ASCII keyword string "USD" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5130
DEFB A5H A5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
5131
DEFB 10H 10
OR-mask: this value is OR'd into the flags byte at 5995H when the "USD" option is matched. Sets bit 4 of 5995H.
5132
DEFB 03H 03
Conflict mask vs 5994H: AND'd with (5994H). If bit 1, bit 0 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5133
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
5134
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5135
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
Entry #22 — "BDU" (COPY and FORMAT): Bypass destination Directory Update
5136
DEFM "BDU" 42 44 55
ASCII keyword string "BDU" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5139
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
513A
DEFB 02H 02
OR-mask: this value is OR'd into the flags byte at 5994H when the "BDU" option is matched. Sets bit 1 of 5994H.
513B
DEFB 0CH 0C
Conflict mask vs 5994H: AND'd with (5994H). If bit 3, bit 2 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
513C
DEFB 30H 30
Conflict mask vs 5995H: AND'd with (5995H). If bit 5, bit 4 of 5995H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
513D
DEFB 08H 08
Conflict mask vs 5996H: AND'd with (5996H). If bit 3 of 5996H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
513E
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
Entry #23 — "UBB" (COPY only): Use Big Buffer
513F
DEFM "UBB" 55 42 42
ASCII keyword string "UBB" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5142
DEFB A2H A2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
5143
DEFB 20H 20
OR-mask: this value is OR'd into the flags byte at 5996H when the "UBB" option is matched. Sets bit 5 of 5996H.
Entry #24 — "CBF" (COPY only): Copy By File — activates file-by-file copy mode (COPY format 6)
5144
DEFM "CBF" 43 42 46
ASCII keyword string "CBF" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5147
DEFB A6H A6
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 10b (target flags byte at 5996H).
5148
DEFB 08H 08
OR-mask: this value is OR'd into the flags byte at 5996H when the "CBF" option is matched. Sets bit 3 of 5996H.
5149
DEFB 02H 02
Conflict mask vs 5994H: AND'd with (5994H). If bit 1 of 5994H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
514A
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
514B
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
514C
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
Entry #25 — "UPD" (COPY only): Copy only updated files
514D
DEFM "UPD" 55 50 44
ASCII keyword string "UPD" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5150
DEFB A2H A2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
5151
DEFB 01H 01
OR-mask: this value is OR'd into the flags byte at 5996H when the "UPD" option is matched. Sets bit 0 of 5996H.
Entry #26 — "USR" (COPY only): Copy User Files. Only user files are copied; system and invisible files are excluded
5152
DEFM "USR" 55 53 52
ASCII keyword string "USR" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5155
DEFB A2H A2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
5156
DEFB 10H 10
OR-mask: this value is OR'd into the flags byte at 5996H when the "USR" option is matched. Sets bit 4 of 5996H.
Entry #27 — "DFO" (COPY only): Destination Files Only (Only files already existing on the both the destination and the source diskette are copied
5157
DEFM "DFO" 44 46 4F
ASCII keyword string "DFO" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
515A
DEFB A5H A5
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 01b (target flags byte at 5995H).
515B
DEFB 08H 08
OR-mask: this value is OR'd into the flags byte at 5995H when the "DFO" option is matched. Sets bit 3 of 5995H.
515C
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
515D
DEFB 00H 00
Conflict mask vs 5995H: 00H — no conflict check against this flags byte (AND result is always zero).
515E
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
515F
DEFB 04H 04
Conflict mask vs 5997H: AND'd with (5997H). If bit 2 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #28 — "RWF" (FORMAT only): RaW Format. If RWF is specified, all errors are ignored and each track is formatted once, whether or not the format actually takes
5160
DEFM "RWF" 52 57 46
ASCII keyword string "RWF" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5163
DEFB C6H C6
Control byte: bit 7 set = end of keyword name; bits 5-6 = 10b (mode 2: FORMAT only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 10b (target flags byte at 5996H).
5164
DEFB 80H 80
OR-mask: this value is OR'd into the flags byte at 5996H when the "RWF" option is matched. Sets bit 7 of 5996H.
5165
DEFB 09H 09
Conflict mask vs 5994H: AND'd with (5994H). If bit 3, bit 0 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5166
DEFB 06H 06
Conflict mask vs 5995H: AND'd with (5995H). If bit 2, bit 1 of 5995H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5167
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5168
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #29 — "FMT" (COPY only): ForMaT — formats destination disk before copy (mutually exclusive with NFMT)
5169
DEFM "FMT" 46 4D 54
ASCII keyword string "FMT" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
516C
DEFB A7H A7
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 11b (target flags byte at 5997H).
516D
DEFB 04H 04
OR-mask: this value is OR'd into the flags byte at 5997H when the "FMT" option is matched. Sets bit 2 of 5997H.
516E
DEFB 00H 00
Conflict mask vs 5994H: 00H — no conflict check against this flags byte (AND result is always zero).
516F
DEFB 08H 08
Conflict mask vs 5995H: AND'd with (5995H). If bit 3 of 5995H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5170
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5171
DEFB 08H 08
Conflict mask vs 5997H: AND'd with (5997H). If bit 3 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
Entry #30 — "/" (COPY only): file extension prefix — followed by 3-character extension to filter files (e.g., /BAS)
5172
DEFM "/" 2F
ASCII keyword string "/" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5173
DEFB B2H B2
Control byte: bit 7 set = end of keyword name; bits 5-6 = 01b (mode 1: COPY only); bit 4 set = 2-byte handler address follows; bit 2 clear = no conflict check; bits 0-1 = 10b (target flags byte at 5996H).
5174
DEFB 02H 02
OR-mask: this value is OR'd into the flags byte at 5996H when the "/" option is matched. Sets bit 1 of 5996H.
5175
DEFW 500DH 0D 50
Handler address: 500DH (lo/hi). When "/" is matched, this address is stored into the self-modifying CALL operand at 4F85H, then the handler is called to parse 3-character hex/extension code into buffer at 624CH.
Entry #31 — "Y" (COPY and FORMAT): Yes — suppress source disk swap prompt, enable whole-disk backup mode
5177
DEFM "Y" 59
ASCII keyword string "Y" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
5178
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
5179
DEFB 40H 40
OR-mask: this value is OR'd into the flags byte at 5994H when the "Y" option is matched. Sets bit 6 of 5994H.
517A
DEFB B9H B9
Conflict mask vs 5994H: AND'd with (5994H). If bit 7, bit 5, bit 4, bit 3, bit 0 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
517B
DEFB 01H 01
Conflict mask vs 5995H: AND'd with (5995H). If bit 0 of 5995H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
517C
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
517D
DEFB 00H 00
Conflict mask vs 5997H: 00H — no conflict check against this flags byte (AND result is always zero).
Entry #32 — "N" (COPY and FORMAT): No — suppress destination disk swap prompt, enable no-prompt mode
517E
DEFM "N" 4E
ASCII keyword string "N" — the option parser at 4F1DH compares command-line text against these characters one by one. Each byte has bit 7 clear, indicating it is part of the keyword name.
517F
DEFB E4H E4
Control byte: bit 7 set = end of keyword name; bits 5-6 = 11b (mode 3: COPY and FORMAT); bit 4 clear = no handler (flag-only option); bit 2 set = 4 conflict-check bytes follow; bits 0-1 = 00b (target flags byte at 5994H).
5180
DEFB 80H 80
OR-mask: this value is OR'd into the flags byte at 5994H when the "N" option is matched. Sets bit 7 of 5994H.
5181
DEFB 79H 79
Conflict mask vs 5994H: AND'd with (5994H). If bit 6, bit 5, bit 4, bit 3, bit 0 of 5994H are already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5182
DEFB 01H 01
Conflict mask vs 5995H: AND'd with (5995H). If bit 0 of 5995H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5183
DEFB 00H 00
Conflict mask vs 5996H: 00H — no conflict check against this flags byte (AND result is always zero).
5184
DEFB 02H 02
Conflict mask vs 5997H: AND'd with (5997H). If bit 1 of 5997H is already set, the result is non-zero and error 2FH (option conflict) is raised via 5218H.
5185
DEFB 00H 00
End-of-table marker. The keyword parser at 4F1DH stops scanning when it encounters this 00H byte.
5200H - ERROR DISPATCH ENTRY POINTS AND MAIN ERROR HANDLER
Multiple entry points load specific NEWDOS/80 error codes into Register A, then fall through or jump to the main error handler at 521AH. The main handler at 521AH is the single most-referenced routine in SYS6, with 25 CALL references and 6 JP references throughout the module. It outputs a carriage return, sets up the SYS0 error handler return address on the stack, optionally flushes drive parameter blocks, clears the non-hex command flag in the DOS work area, and returns with the error code in Register A so the SYS0 error dispatcher at 4409H can process it.
Entry points and their error codes:
| 5200H | Error 20H (space/buffer error) |
| 5204H | Error 3CH (disk geometry mismatch) |
| 5208H | Error 2AH (general error — referenced from the entry dispatcher at 4D00H) |
| 520CH | Error 2CH (directory full) |
| 5210H | Command line termination check (returns if at end, else error 34H) |
| 5214H | Error 34H (parse error) |
| 5218H | Error 2FH (option conflict — referenced from option parser at 4F49H) |
Each error dispatch stub loads a specific error code into Register A, then jumps (or falls through) to the common error handler at 521AH. This eliminates the need for callers throughout SYS6 to set up their own error codes — they simply CALL or JP to the appropriate stub address.
5200
LD A,20H 3E 20
Load Register A with error code 20H (space/buffer allocation error). This entry is used when there is insufficient memory for disk buffers.
5202
JUMP unconditionally to the main error handler at 521AH to process error code 20H.
5204
LD A,3CH 3E 3C
Load Register A with error code 3CH (disk geometry mismatch error — 60 decimal). This entry is used when source and destination disk parameters are incompatible.
5206
JUMP unconditionally to the main error handler at 521AH to process error code 3CH.
5208
LD A,2AH 3E 2A
Load Register A with error code 2AH (general error — 42 decimal). This is the default error entry referenced by the command dispatch table at 4D00H when the command code in Register A does not match FORMAT, COPY, APPEND, or HEX DUMP.
520A
JUMP unconditionally to the main error handler at 521AH to process error code 2AH.
520C
LD A,2CH 3E 2C
Load Register A with error code 2CH (directory full — 44 decimal). This entry is used when the destination disk directory has no free entries for a file being copied.
520E
JUMP unconditionally to the main error handler at 521AH to process error code 2CH.
The next entry point (5210H) is different from the others — it first checks whether the command line has ended normally before treating the situation as an error. If the byte at (HL) is a carriage return (0DH), the command line has been fully parsed and the routine returns normally. Otherwise, there is unexpected text remaining on the command line, so it falls through to the parse error entry at 5214H.
5210
LD A,(HL) 7E
Fetch the current byte from the command line buffer pointed to by Register Pair HL (which holds the current parse position in the user's command text).
5211
CP 0DH FE 0D
Compare Register A against 0DH (ASCII carriage return, the command line terminator). If Register A equals 0DH, the Z FLAG is set, meaning the command line has been completely parsed. If Register A does not equal 0DH, the NZ FLAG is set, meaning unexpected text remains.
5213
RET Z C8
If the Z FLAG has been set (command line byte is 0DH, end of line), RETURN to the caller. The command line has been fully consumed — no error.
5214
LD A,34H 3E 34
Load Register A with error code 34H (parse error — 52 decimal). Execution reaches here if the command line contains unexpected text after all options have been processed.
5216
JUMP unconditionally to the main error handler at 521AH to process error code 34H.
5218
LD A,2FH 3E 2F
Load Register A with error code 2FH (option conflict — 47 decimal). This entry is used by the option keyword parser at 4F49H when two incompatible options are specified on the same command line (e.g., conflicting copy modes).
[MAIN ERROR HANDLER] — All error dispatch stubs above converge here. This is the central error exit for the entire SYS6 module. The routine: (1) outputs a carriage return to clean up the display, (2) pushes the SYS0 error handler address (4409H) and the error code onto the stack, (3) calls the alternate drive parameter setup at 5582H to point to the third drive block, (4) checks whether drive parameter blocks need flushing, (5) clears the non-hex command flag at (IY+09H), and (6) returns — which pops the error code and then "returns" to the SYS0 error handler at 4409H via the stacked address.
521A
PUSH AF F5
Save Register A (containing the error code) and the Flags register onto the stack. The error code must be preserved across the upcoming subroutine calls.
521B
GOSUB to 5881H to display a carriage return (CR). This moves the cursor to the beginning of the next line, ensuring any error message that follows appears cleanly on a new line.
521E
POP AF F1
Restore Register A (the error code) and Flags from the stack.
521F
LD HL,4409H 21 09 44
Point Register Pair HL to 4409H, the SYS0 error handler entry point. This address will be placed on the stack so that when this routine eventually executes RET, control transfers to the SYS0 error dispatcher rather than to the original caller.
5222
PUSH HL E5
Push the SYS0 error handler address (4409H) onto the stack. This becomes the return address that RET at 523BH will pop, redirecting execution to SYS0's error handler.
5223
PUSH AF F5
Push Register A (the error code) and Flags onto the stack again. The stack now has, from top: error code/flags, then 4409H. The error code will be popped at 523AH, and the RET at 523BH will pop 4409H.
5224
GOSUB to 5582H to set up the drive parameter pointer. This routine points HL to the alternate drive parameter block at 5942H, preparing the system for the drive flush check that follows.
5227
LD A,(593BH) 3A 3B 59
Fetch the value from work area variable at 593BH (disk operation state flags) into Register A. Bit 7 of this byte indicates whether drive parameter blocks have been initialized and need flushing before the error exit.
522A
BIT 7,A CB 7F
Test bit 7 of Register A (the 593BH flags byte). If bit 7 is set (1), drive parameter blocks have been initialized and need to be flushed. If bit 7 is clear (0), no flush is needed. The Z FLAG is set if bit 7 is 0; the NZ FLAG is set if bit 7 is 1.
522C
If the Z FLAG has been set (bit 7 of 593BH is clear — drive blocks not initialized), JUMP to 5235H to skip the flush operation and proceed directly to clearing the DOS flag and returning.
Bit 7 of 593BH is set, meaning drive parameter blocks were initialized during the FORMAT/COPY operation. They must be flushed (written back to the disk controller state) before exiting, even on an error path, to avoid leaving the drives in an inconsistent state.
522E
LD B,05H 06 05
Load Register B with 05H (5 decimal). This is the retry count passed to the drive flush routine at 5646H — if flushing fails, it will be retried up to 5 times.
5230
GOSUB to 5646H to flush all three drive parameter blocks back to the disk controller. Register B contains the retry count (5). On return, the Z FLAG indicates success (all blocks flushed) and NZ FLAG indicates at least one flush operation failed after all retries.
5233
If the NZ FLAG has been set (drive flush failed even after 5 retries), JUMP to 523CH to handle the flush failure — this path displays a "DISKETTE/GAT OVERFLOW" warning before continuing with the error exit.
Drive parameter blocks flushed successfully (or were not initialized). Clear the non-hex command flag and return with the error code.
5235
LD HL,4289H 21 89 42
Point Register Pair HL to 4289H, which is the DOS work area flags byte at (IY+09H). IY is set to 4280H throughout SYS6, so IY+09H = 4289H. This byte contains various DOS command state flags.
5238
RES 3,(HL) CB 9E
Clear bit 3 of the byte at 4289H (IY+09H). Bit 3 is the "non-hex command in progress" flag. Clearing it tells the DOS that the SYS6 command (FORMAT, COPY, or APPEND) has completed (even if with an error), restoring normal DOS command processing state.
523A
POP AF F1
Restore Register A (the error code) from the stack. The error code was pushed at 5223H and is now needed by the SYS0 error handler.
523B
RET C9
RETURN — but the return address on the stack is 4409H (pushed at 5222H), not the original caller. This effectively performs a JP 4409H, transferring control to the SYS0 error handler with the error code in Register A. SYS0 will display the appropriate error message and return to the DOS command prompt.
[DRIVE FLUSH FAILURE HANDLER] — Execution reaches here from 5233H when the drive parameter block flush at 5646H failed after 5 retries. This is a secondary error condition layered on top of the original error. The handler issues a DOS SVC call (RST 18H with function 46H) to perform a system-level disk close, displays the "DISKETTE/GAT OVERFLOW" warning message, then loops back to 5222H to continue the normal error exit sequence (which will ultimately transfer to SYS0 at 4409H).
523C
PUSH AF F5
Save Register A (the original error code) onto the stack. It must be preserved because the flush failure handling below will destroy Register A.
523D
LD A,46H 3E 46
Load Register A with 46H (70 decimal), the SVC function code for "close all files / disk reset." This prepares for the RST 18H system call that follows.
523F
RST 18H DF
Execute RST 18H (NEWDOS/80 Supervisor Call). With Register A = 46H, this performs a system-level close of all open files and resets disk state. This is a safety measure to prevent data corruption after the flush failure — any partially-written drive state is abandoned.
5240
LD HL,5AC2H 21 C2 5A
Point Register Pair HL to the message string at 5AC2H, which contains the ASCII text "DISKETTE/GAT OVERFLOW" followed by a 0DH (carriage return) terminator.
5243
GOSUB to 5881H to display a carriage return. This ensures the warning message appears on a fresh line.
5246
GOSUB to the SYS0 message display routine at 4467H. Register Pair HL points to the string at 5AC2H. The routine displays each character starting at (HL) until it encounters a 03H or 0DH terminator. This outputs "DISKETTE/GAT OVERFLOW" to the screen as a warning to the operator.
5249
LD HL,4030H 21 30 40
Point Register Pair HL to 4030H, the SYS0 DOS re-entry point. This replaces the previously-pushed 4409H on the stack. After a flush failure with the "DISKETTE/GAT OVERFLOW" warning, the error exit redirects to 4030H (a clean DOS restart) rather than the normal 4409H error handler, because the disk state is now unreliable.
524C
JUMP back to 5222H to push the new return address (4030H) onto the stack and continue through the standard error exit sequence. The original 4409H push from the first pass is still on the stack below; this second pass through 5222H pushes 4030H on top. When the two-level RET sequence executes, 4030H will be the effective destination, performing a full DOS restart.
524EH - DIRECTORY BUFFER RELOCATION AND TRACK-PER-PASS CALCULATION
This routine performs two critical setup tasks for FORMAT/COPY operations. First, it relocates the directory entry buffer from its default position to a new base at 5D16H by copying its contents, freeing space for track data buffers. Second, it calculates how many disk tracks can be processed in a single pass given the available memory between the buffer end pointer (5D14H) and the saved high memory limit (593CH). Each track requires 0102H (258) bytes of buffer space — the routine divides available memory by this track size to determine the per-pass track count, then stores the result via self-modifying code into the comparison operand at 531AH. Finally, it initializes the source drive parameters and jumps into the main track processing loop at 5316H with the track counter initialized to zero.
This routine is called after all command-line options have been parsed and validated. The directory buffer pointers at 5D12H (base) and 5D14H (end) track directory entries read from the source disk. The routine must relocate this buffer data to the fixed base at 5D16H, then calculate how many track buffers fit in the remaining memory above the directory data.
524E
LD HL,(5D14H) 2A 14 5D
Load Register Pair HL with the 16-bit value stored at 5D14H, the directory buffer end pointer. This marks the end of directory entry data currently in the buffer.
5251
LD DE,(5D12H) ED 5B 12 5D
Load Register Pair DE with the 16-bit value stored at 5D12H, the directory buffer base pointer. DE now holds the start address of the directory data.
5255
OR A B7
Clear the CARRY FLAG by ORing Register A with itself. This prepares for the 16-bit subtraction that follows — SBC always subtracts the carry, so it must be cleared first.
5256
SBC HL,DE ED 52
Subtract Register Pair DE (buffer base from 5D12H) from Register Pair HL (buffer end from 5D14H). The result in HL is the number of bytes of directory data currently in the buffer.
5258
LD B,H 44
Copy the high byte of the directory data byte count from Register H into Register B.
5259
LD C,L 4D
Copy the low byte of the directory data byte count from Register L into Register C. Register Pair BC now holds the total number of bytes to relocate.
525A
PUSH DE D5
Save Register Pair DE (the old buffer base address from 5D12H) onto the stack. This will be used as the LDIR source address.
525B
LD HL,5D16H 21 16 5D
Point Register Pair HL to 5D16H, the fixed starting address for the relocated directory buffer. All directory data will be copied to start from this address.
525E
LD (5D12H),HL 22 12 5D
Store the new buffer base address (5D16H) into the directory buffer base pointer at 5D12H, resetting it to the fixed base.
5261
PUSH HL E5
Save Register Pair HL (the new base address 5D16H) onto the stack for later use.
5262
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now contains 5D16H (the LDIR destination), and HL will receive the old base from the stack for use as the LDIR source.
5263
LDIR ED B0
Block copy BC bytes from the old buffer location at (HL) to the new location at (DE). This relocates all directory entry data to the fixed base at 5D16H. After completion, DE points past the end of the copied data.
5265
LD (5D14H),DE ED 53 14 5D
Store Register Pair DE (the address past the end of the relocated directory data) into the buffer end pointer at 5D14H. This updates the end pointer to reflect the new data position.
5269
GOSUB to 5578H to set up the source drive parameter pointer. This routine loads HL with 594CH (the source drive number location) and initializes the source drive parameter block at 5AE5H.
526C
POP HL E1
Restore Register Pair HL from the stack (the new directory buffer base 5D16H, pushed at 5261H).
526D
GOSUB to 56A6H to validate the directory buffer contents. On return, the Z FLAG indicates the buffer is empty (no directory entries) and the NZ FLAG indicates valid entries are present.
5270
If the Z FLAG has been set (directory buffer is empty — no files to process), JUMP to 552DH to skip the copy operation entirely and proceed to the completion handler.
Directory entries are present and valid. Display the "COPYING" status message to the operator, then calculate how many tracks can be buffered in the available memory space above the directory data.
5273
LD HL,627BH 21 7B 62
Point Register Pair HL to the message string at 627BH, which contains the ASCII text "COPYING" followed by a 03H terminator.
5276
GOSUB to 587EH to display the message string "COPYING" to the screen, informing the operator that the file copy operation is beginning.
5279
LD HL,(593CH) 2A 3C 59
Load Register Pair HL with the 16-bit value stored at 593CH, the saved high memory limit. This is the highest address SYS6 can use for buffer space, established during FORMAT initialization.
527C
LD DE,(5D14H) ED 5B 14 5D
Load Register Pair DE with the 16-bit value stored at 5D14H, the directory buffer end pointer. The memory from this address up to the high memory limit is free for track data buffers.
5280
OR A B7
Clear the CARRY FLAG by ORing Register A with itself, preparing for the 16-bit subtraction.
5281
SBC HL,DE ED 52
Subtract Register Pair DE (buffer end pointer) from Register Pair HL (high memory limit). The result in HL is the total bytes of free memory available for track data buffers.
5283
LD DE,0102H 11 02 01
Load Register Pair DE with 0102H (258 decimal). This is the size of one track buffer entry: 256 bytes for sector data plus 2 bytes for the track/sector identification header.
[LOOP START] — Division-by-subtraction loop: divide available memory (HL) by the track buffer size (DE = 0102H / 258 bytes). Register A counts the number of complete buffers that fit. The counter starts at FFH and is pre-incremented, so the first real count is 00H.
5286
LD A,FFH 3E FF
Load Register A with FFH (255). This initializes the track counter to one less than zero because the INC A at 5288H executes before each subtraction attempt, so the first real iteration starts at 00H.
5288
INC A 3C
INCrement Register A by 1. On the first iteration A goes from FFH to 00H; on subsequent iterations it counts 01H, 02H, 03H, etc. — each count representing one additional track buffer that fits in memory.
5289
OR A B7
Clear the CARRY FLAG by ORing Register A with itself. This ensures the upcoming SBC HL,DE performs a clean subtraction without residual carry.
528A
SBC HL,DE ED 52
Subtract Register Pair DE (0102H — one track buffer size) from Register Pair HL (remaining free memory). If HL >= DE, another buffer fits and the NO CARRY FLAG is set. If HL < DE, insufficient room remains and the CARRY FLAG is set.
528C
If the NO CARRY FLAG has been set (enough memory remains for another track buffer), JUMP back to 5288H to increment the counter and subtract another buffer size. [LOOP END] — The loop exits when CARRY is set, meaning no more complete buffers fit.
The division loop has completed. Register A now holds the number of complete track buffers that fit in the available memory. This value is written into the instruction stream via self-modifying code to control the main copy loop's per-pass track limit.
528E
LD (531AH),A 32 1A 53
Store Register A (the calculated tracks-per-pass count) into address 531AH. [SELF-MODIFYING CODE] — Address 531AH is the operand byte of the CP 0AH instruction at 5319H. By overwriting this byte, the comparison dynamically becomes CP [tracks-per-pass], so the main copy loop at 5319H will process exactly the number of tracks that fit in the available buffer space before needing to flush and reload.
5291
LD HL,594CH 21 4C 59
Point Register Pair HL to 594CH, the source drive number storage location. This prepares for the drive parameter initialization call.
5294
GOSUB to 5538H to initialize drive parameters for the source drive. This reads the drive number from (594CH) and configures the source drive parameter block at 5AE5H with the appropriate geometry and timing values for that drive.
5297
XOR A AF
Set Register A to ZERO and clear all flags. This initializes the track counter to zero — the copy operation will begin with track 0.
5298
LD HL,(5D14H) 2A 14 5D
Load Register Pair HL with the 16-bit value stored at 5D14H, the directory buffer end pointer. This address marks the start of the track data buffer area — all memory from here to the high memory limit is used for track I/O buffers.
529B
JUMP forward to 5316H to enter the main track processing loop. Register A = 0 (initial track counter) and HL = track buffer start address. At 5316H, the counter is stored into the self-modifying operand at 5314H and compared against the per-pass limit at 5319H (which was just set at 528EH).
529DH - SOURCE TRACK READ LOOP (READ TRACKS INTO BUFFER)
This is the inner loop that reads tracks from the source disk into the track data buffer. For each track, it: (1) advances HL past the 2-byte header to set the data buffer address at 5AE8H, (2) calls the disk read routine at 57C8H, (3) handles read errors with retry or skip logic, (4) stores a marker byte (FFH) and the error/success status in the header, (5) optionally patches boot sector data for small-track-count disks, and (6) increments the track counter via self-modifying code at 5314H until it reaches the per-pass limit stored at 531AH. When the limit is reached, the routine calls the track write-back routine at 5324H then loops back to 5291H for the next pass.
[MAIN TRACK READ LOOP START] — Each iteration reads one track from the source disk. Register Pair HL points to the current position in the track data buffer. The first 2 bytes of each buffer slot are a header (FFH marker + status byte), followed by 256 bytes of sector data. The loop runs until the track counter (at self-modifying location 5314H) reaches the per-pass limit (at self-modifying location 531AH).
529D
PUSH HL E5
Save Register Pair HL (the current track buffer pointer) onto the stack. HL points to the 2-byte header position for this track's buffer slot. It will be restored at 52D0H to write the header bytes.
529E
INC HL 23
INCrement Register Pair HL by 1 to advance past the first header byte.
529F
INC HL 23
INCrement Register Pair HL by 1 again. HL now points 2 bytes past the header — to the beginning of the 256-byte sector data area for this track.
52A0
LD (5AE8H),HL 22 E8 5A
Store Register Pair HL (the sector data buffer address) into 5AE8H, which is offset +03H within the source drive parameter block at 5AE5H. This tells the disk read routine where to place the sector data it reads from the source disk.
52A3
LD A,80H 3E 80
Load Register A with 80H (128 decimal), the "read sector" operation code for the disk I/O control byte at 57EBH.
52A5
LD (57EBH),A 32 EB 57
Store Register A (80H) into 57EBH, the disk operation type control byte. This configures the disk I/O routine at 57C8H to perform a sector read on the next call.
52A8
GOSUB to 57C8H to execute the disk read operation. The routine reads one sector from the source disk into the buffer at (5AE8H). On return: Z FLAG = success, NZ FLAG = error with error code in Register A.
52AB
If the Z FLAG has been set (sector read completed successfully), JUMP to 52CFH to set A=0 (success status) and store the track header.
The sector read returned an error. Check the error code to determine whether to retry, skip, or treat as end-of-data.
52AD
CP 06H FE 06
Compare Register A (the error code) against 06H (end-of-file/end-of-data). If A = 06H, the Z FLAG is set — a normal condition indicating no more data on this track.
52AF
If the Z FLAG has been set (error code is 06H — end of data), JUMP to 52D0H to store the end-of-data status (06H) in the track header.
52B1
CP 1CH FE 1C
Compare Register A against 1CH (position error — before start of file).
52B3
If the Z FLAG has been set (position error 1CH), JUMP to 52B9H to check whether drive reconfiguration can resolve it.
52B5
CP 1DH FE 1D
Compare Register A against 1DH (position error — past end of file).
52B7
If the NZ FLAG has been set (error is not 06H, not 1CH, and not 1DH — a genuine disk read error), JUMP to 52CAH to display the error and offer a retry.
Error code is 1CH or 1DH (position errors). These may indicate the track is beyond the formatted area. Check option flags to determine handling.
52B9
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, used as a parameter for the drive reconfiguration call at 56A2H.
52BC
LD A,(5996H) 3A 96 59
Fetch the value from 5996H (option flags byte 2 — mode flags) into Register A. Bit 3 indicates whether a destination filespec was parsed.
52BF
AND 08H E6 08
Mask Register A with 08H to isolate bit 3 (destination filespec parsed flag).
52C1
If the NZ FLAG has been set (destination filespec was parsed — file-level copy mode), GOSUB to 56A2H to attempt drive reconfiguration. On return, Z FLAG = succeeded, NZ FLAG = failed.
52C4
If the Z FLAG has been set (no destination filespec, or reconfiguration succeeded), JUMP to 549CH to exit the track read loop and proceed to the write phase.
52C7
POP HL E1
Restore Register Pair HL from the stack (track buffer header pointer, pushed at 529DH).
52C8
JUMP back to 529DH to retry reading this track with potentially reconfigured drive parameters.
Genuine disk read error. Display the error to the operator and offer a retry.
52CA
GOSUB to 585AH to display the error code and prompt the operator. On return, Z FLAG = operator declined retry (skip), NZ FLAG = operator chose to retry.
52CD
If the NZ FLAG has been set (operator chose to retry), JUMP back to 52A8H to attempt the disk read again.
Read succeeded (from 52ABH) or operator chose to skip (from 52CDH). Store the 2-byte track header: FFH marker + status byte.
52CF
XOR A AF
Set Register A to ZERO (success status code). Reached when the sector read succeeded. A=00H means "track read OK."
52D0
POP HL E1
Restore Register Pair HL from the stack (the track buffer header pointer, pushed at 529DH). HL points to the first byte of this track's 2-byte header.
52D1
LD (HL),FFH 36 FF
Store FFH as the first header byte at (HL). This marker flags the buffer slot as "contains track data."
52D3
INC HL 23
INCrement Register Pair HL by 1 to advance to the second header byte.
52D4
LD (HL),A 77
Store Register A (status code: 00H=success, 06H=end-of-data, or other error code) as the second header byte.
52D5
INC HL 23
INCrement Register Pair HL by 1 to advance past the header to the 256-byte data area.
52D6
GOSUB to 571BH to advance the internal track/sector pointers for the source disk, positioning it for the next track read.
52D9
PUSH HL E5
Save Register Pair HL (pointing past this track's data area — the next buffer slot) onto the stack.
52DA
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the sector data address for this track, needed by the boot sector patch logic below.
Check whether this track's data needs boot sector patching. All of these conditions must be true: (1) no file-level copy flags in 5996H bits 2-3, (2) source and destination are the same drive (5994H bit 1 clear), (3) source disk has a small track count (1-3), and (4) for 3-track disks, the boot sector must contain the NEWDOS/80 signature byte A5H at offset EFH.
52DB
LD A,(5996H) 3A 96 59
Fetch the value from 5996H (option flags byte 2 — mode flags) into Register A.
52DE
AND 0CH E6 0C
Mask Register A with 0CH to isolate bits 2-3 (source filespec parsed, destination filespec parsed). If either is set, this is a file-level copy.
52E0
If the NZ FLAG has been set (file-level copy mode), JUMP to 5311H to skip boot sector patching.
52E2
LD A,(5994H) 3A 94 59
Fetch the value from 5994H (option flags byte 1) into Register A.
52E5
BIT 1,A CB 4F
Test bit 1 of Register A (the "source != dest" indicator). Z FLAG is set if bit 1 is 0 (same drive); NZ FLAG if bit 1 is 1 (different drives).
52E7
If the NZ FLAG has been set (different drives), JUMP to 5311H to skip boot sector patching.
52E9
LD HL,(5AEFH) 2A EF 5A
Load Register Pair HL with the 16-bit value at 5AEFH, the total track count from the source drive parameter block (offset +0AH from base 5AE5H).
52EC
DEC HL 2B
DECrement Register Pair HL by 1 to convert track count to zero-based maximum (e.g., 1 track becomes 0).
52ED
LD A,H 7C
Copy the high byte of (track count - 1) from Register H into Register A.
52EE
OR A B7
Test whether Register A (high byte) is zero. If non-zero, the disk has 256+ tracks.
52EF
If the NZ FLAG has been set (256+ tracks), JUMP to 5311H to skip patching.
52F1
LD A,L 7D
Copy the low byte of (track count - 1) from Register L into Register A. For 1 track: A=00H; 2 tracks: A=01H; 3 tracks: A=02H.
52F2
CP 02H FE 02
Compare Register A against 02H. If A < 02H (1-2 tracks), CARRY FLAG set. If A = 02H (3 tracks), Z FLAG set. If A > 02H, neither flag set.
52F4
If the NO CARRY FLAG has been set (3+ tracks), JUMP to 52FEH to check for the 3-track special case.
Source disk has 1 or 2 tracks. Apply the boot sector configuration template from 64BAH.
52F6
LD HL,64BAH 21 BA 64
Point Register Pair HL to 64BAH, a boot sector configuration template in the drive geometry data table. This template contains default drive parameters for the destination disk.
52F9
GOSUB to 5C80H to apply the boot sector template from (HL) into the track data buffer at (DE), overwriting the boot sector's drive parameter area.
52FC
JUMP to 530FH to execute the LDIR that performs the data copy, then continue to the track counter increment.
Source disk has 3+ tracks. Check for the special case of exactly 3 tracks with NEWDOS/80 signature.
52FE
If the NZ FLAG has been set (more than 3 tracks), JUMP to 5311H to skip boot sector patching entirely.
5300
LD HL,00EFH 21 EF 00
Load Register Pair HL with 00EFH (239 decimal), the offset within sector data to the boot sector signature byte.
5303
ADD HL,DE 19
ADD Register Pair DE (sector data buffer base) to HL (signature offset). HL now points to the byte at offset EFH within the sector data — the NEWDOS/80 boot sector signature location.
5304
LD A,(HL) 7E
Fetch the byte at the boot sector signature location into Register A.
5305
CP A5H FE A5
Compare Register A against A5H, the NEWDOS/80 boot sector signature byte. Z FLAG set if valid signature; NZ FLAG if not.
5307
If the NZ FLAG has been set (no A5H signature — not a NEWDOS/80 boot sector), JUMP to 5311H to skip patching.
Valid NEWDOS/80 boot sector on a 3-track disk. Copy 16 bytes of drive configuration data from 6EB4H into the boot sector data buffer.
5309
LD HL,6EB4H 21 B4 6E
Point Register Pair HL to 6EB4H, a 16-byte drive configuration data block in the SYS6 data area.
530C
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16 decimal), the number of configuration bytes to copy.
530F
LDIR ED B0
Block copy BC bytes from (HL) into (DE). For the 3-track path: copies 16 bytes of drive configuration from 6EB4H. For the 1-2 track path (from 52FCH): copies boot template data from 64BAH.
Boot sector patching complete (or skipped). Restore the buffer pointer, advance past this track's data, increment the self-modifying track counter, and check whether this pass is complete.
5311
POP HL E1
Restore Register Pair HL from the stack (next buffer slot address, pushed at 52D9H).
5312
INC H 24
INCrement the high byte of Register Pair HL by 1, advancing HL by 256 bytes past the sector data area to the start of the next track buffer slot.
5313
LD A,00H 3E 00
Load Register A with the value at 5314H. [SELF-MODIFYING CODE] — The operand byte 00H at 5314H is overwritten by the instruction at 5316H on each loop iteration. The actual value loaded is the current track counter, not the literal 00H.
5315
INC A 3C
INCrement Register A by 1 to advance the track counter.
5316
LD (5314H),A 32 14 53
Store Register A (updated track counter) into 5314H. [SELF-MODIFYING CODE] — This writes the new counter value into the operand of the LD A,00H at 5313H, so the next iteration loads the current count.
5319
CP 0AH FE 0A
Compare Register A (track counter) against the per-pass limit. [SELF-MODIFYING CODE] — The operand 0AH at 531AH was overwritten at 528EH with the calculated tracks-per-pass value. If A < limit, CARRY FLAG set (more tracks to read); if A >= limit, NO CARRY FLAG set (pass complete).
531B
If the CARRY FLAG has been set (track counter < per-pass limit), JUMP back to 529DH to read the next track. [MAIN TRACK READ LOOP END]
The per-pass limit has been reached — all buffer slots are full. Call the write-back routine to flush buffered tracks to the destination disk, then loop back to 5291H for the next batch.
531E
GOSUB to 5324H to write all buffered track data to the destination disk. This routine switches to the destination drive, writes each buffered track, then returns.
5321
JUMP back to 5291H to reinitialize source drive parameters and begin reading the next batch of tracks.
5324H - DESTINATION TRACK WRITE-BACK ROUTINE
This routine writes buffered track data from memory to the destination disk. It is called from 531EH after the source track read loop fills all available buffer slots, and also recursively from 534DH when a destination track mismatch requires mid-write re-initialization. The routine: (1) selects the destination drive via 5535H, (2) checks if any tracks were actually read (track counter at 5314H), (3) initializes the buffer pointer (544FH) and sector counter (5401H), (4) examines option flags to handle destination filespec mode vs. whole-disk mode, (5) for each sector in the buffer, calls the disk write routine 57CEH, (6) handles write errors with retry/skip logic, (7) optionally patches the boot sector via 546DH, and (8) decrements the track counter at 5314H until all buffered tracks are written. At the end, 53FBH flushes any remaining sectors and resets the disk I/O control byte to write mode (20H) for the next pass.
[DESTINATION WRITE-BACK ENTRY] — Called after the source track read loop at 529DH fills the track buffer. Register state on entry: the track buffer is filled from 5D14H upward, with each 258-byte slot containing FFH + status + 256 data bytes. The track counter at self-modifying location 5314H holds the number of tracks read in this pass. The destination drive parameter block is at 5B17H.
5324
GOSUB to 5535H to select the destination drive. This routine points HL to 5956H (destination drive number), calls 5585H to configure drive parameters, loads IX from the drive parameter block pointer, checks bit 7 of the parameter block status byte, and if bit 7 is clear, allocates the drive via SYS0 calls at 4420H/4424H.
5327
LD A,(5314H) 3A 14 53
Fetch Register A with the current track counter from self-modifying location 5314H. This value was set during the source read loop and represents how many tracks were successfully read into the buffer during this pass. [SELF-MODIFYING CODE TARGET] — the operand at 5314H is written by the source read loop at 5316H (increment) and decremented at 53F5H (write loop).
532A
OR A B7
OR Register A with itself to set flags. If A is zero, the Z FLAG is set, meaning no tracks were read and there is nothing to write.
532B
RET Z C8
If the Z FLAG has been set (track counter is zero — no tracks buffered), RETurn immediately. There is nothing to write to the destination disk.
At least one track was read. Initialize the buffer scan pointer and save the destination sector count for this pass.
532C
LD HL,(5D14H) 2A 14 5D
Load Register Pair HL with the directory buffer end pointer from 5D14H. This is the starting address of the track data buffer area — immediately after the directory buffer. All buffered track data begins here.
532F
LD (544FH),HL 22 4F 54
Store Register Pair HL (track buffer start address) to self-modifying location 544FH. This is the buffer position pointer used by the post-write sector flush routine at 53FBH to walk through the buffer sequentially. [SELF-MODIFYING CODE TARGET] — 544FH is also updated at 5454H as the routine advances through buffer slots.
5332
LD DE,(5B21H) ED 5B 21 5B
Load Register Pair DE with the destination sector count from 5B21H. This is a field in the destination drive parameter block (5B17H + 0AH offset) that tracks how many sectors remain to be written on the current destination track.
5336
LD (5401H),DE ED 53 01 54
Store Register Pair DE (destination sector count) to self-modifying location 5401H. This saves the initial sector count so it can be restored later by the flush routine at 5400H. [SELF-MODIFYING CODE TARGET] — 5401H is read back at 5400H.
533A
XOR A AF
Set Register A to ZERO and clear all flags. A = 00H.
533B
LD (53ECH),A 32 EC 53
Store zero to self-modifying location 53ECH. This is the destination file write counter — it is cleared at the start of each write pass and incremented at 53EEH after each successful sector write. [SELF-MODIFYING CODE TARGET] — 53ECH is also read at 53FBH to check if any sectors were actually written.
[WRITE LOOP START] — The main loop that writes one sector per iteration. HL (saved on stack) points to the current position in the track buffer.
533E
PUSH HL E5
Save Register Pair HL onto the stack. HL points to the current buffer slot being written. It will be restored at 53D5H after the sector is processed.
533F
LD A,(5996H) 3A 96 59
Fetch Register A with option flags byte 2 from 5996H. Bit 2 = source filespec parsed; bit 3 = destination filespec parsed. These flags determine whether this is a whole-disk copy or a file-level copy with specific source/destination filespecs.
5342
AND 0CH E6 0C
Mask Register A with 0CH (binary 00001100) to isolate bits 2 and 3. If both bits are zero, neither source nor destination filespec was parsed, meaning this is a whole-disk (track-level) copy.
5344
If the Z FLAG has been set (bits 2 and 3 both clear — no filespecs, whole-disk mode), JUMP to 53D5H to skip file-level sector matching and proceed directly to writing the current buffer slot.
File-level copy mode: at least one filespec was parsed. Check if a destination filespec was provided (bit 3) or only a source filespec (bit 2).
5347
AND 08H E6 08
Mask Register A with 08H to isolate bit 3 (destination filespec parsed). If bit 3 is clear, only a source filespec was provided.
5349
If the Z FLAG has been set (bit 3 is clear — no destination filespec), JUMP to 5360H to handle source-only filespec mode, which tracks sector counts rather than matching file data.
Destination filespec was parsed (bit 3 set). Compare the track number in the current buffer slot against the destination drive's current track position to detect track boundary crossings.
534B
LD A,(HL) 7E
Load Register A with the byte at (HL). HL points to the current track buffer slot. The first data byte in the 256-byte sector data area encodes track information that identifies which track this sector belongs to.
534C
CP (IX+07H) DD BE 07
Compare Register A against the byte at IX+07H. IX points to the destination drive parameter block at 5B17H, so IX+07H = 5B1EH, which holds the current destination track number. If the buffer slot's track number matches the destination's current track, the sector belongs to the track currently being written.
534F
If the Z FLAG has been set (track numbers match — sector belongs to current destination track), JUMP to 5360H to continue with normal sector count checking.
Track mismatch: the buffer slot contains data for a different track than the one currently being written on the destination. Flush the current write state and reconfigure the destination drive for the new track.
5351
PUSH AF F5
Save Register A and flags onto the stack. A holds the new track number from the buffer slot. The flags preserve the comparison result.
5352
GOSUB to 53FBH to flush any sectors already written in this pass. 53FBH checks if the write counter (53ECH) is nonzero, and if so, resets the sector counter, switches the I/O mode to write (20H), and performs the actual write operations.
5355
POP AF F1
Restore Register A and flags from the stack. A still holds the new track number.
5356
LD IX,5B17H DD 21 17 5B
Point Index Register IX to 5B17H, the base of the destination drive parameter block. This re-establishes IX for the drive parameter update call that follows.
535A
GOSUB to 56B9H to update the destination drive parameters for the new track. This routine reconfigures the destination drive parameter block (pointed to by IX = 5B17H) with the new track number and sector information.
535D
POP HL E1
Restore Register Pair HL from the stack. This is the buffer pointer that was saved at 533EH. The stack has been unwound: the PUSH at 533EH is balanced by this POP.
535E
JUMP back to 532FH to re-store the buffer position pointer and re-enter the write loop with the destination drive now configured for the new track.
5360H - DESTINATION SECTOR COUNT CHECK AND WRITE DISPATCH
Entered from 5349H (no destination filespec) or 534FH (track match). Checks whether the destination sector count has been exhausted. If sectors remain, falls through to 53D5H to write the current buffer slot. If the sector count is zero, this is the start of a new destination track — it initializes write tracking, performs the disk write via 57CEH, handles errors, and manages the write success flag at 53D7H.
5360
LD HL,(5B21H) 2A 21 5B
Load Register Pair HL with the destination sector count from 5B21H. This field in the destination drive parameter block tracks how many sectors remain to be written on the current destination track.
5363
LD A,H 7C
Load Register A with Register H (high byte of sector count).
5364
OR L B5
OR Register A with Register L. This tests whether HL is zero (both bytes zero). If the sector count is nonzero, there are more sectors to write on this track.
5365
If the NZ FLAG has been set (sector count is nonzero — more sectors remain on this destination track), JUMP to 53D5H to proceed directly with writing the current buffer slot.
Sector count is zero: this is the beginning of a new destination track. Initialize the write success flag and load the source/destination track parameters to configure the write.
5367
XOR A AF
Set Register A to ZERO and clear all flags. A = 00H.
5368
LD (53D7H),A 32 D7 53
Store zero to self-modifying location 53D7H. This is the destination write success flag — 00H means no successful writes yet for this track, FFH (set at 53CEH) means at least one sector was written successfully. [SELF-MODIFYING CODE TARGET] — 53D7H is written here (cleared) and at 53CEH (set to FFH).
536B
LD A,(5996H) 3A 96 59
Fetch Register A with option flags byte 2 from 5996H to re-check bit 3 (destination filespec parsed).
536E
BIT 3,A CB 5F
Test bit 3 of Register A. If bit 3 is set, a destination filespec was parsed and the code should use destination drive parameters. If clear, use source drive parameters.
5370
PUSH HL E5
Save Register Pair HL onto the stack. HL is zero (from the sector count check above). This saved value will be restored at 53D1H to update the sector count.
5371
LD HL,(5AF1H) 2A F1 5A
Load Register Pair HL with the 16-bit value at 5AF1H. This is a field in the source drive parameter block (5AE5H + 0CH offset) that holds the source track's total sector count.
5374
LD A,(5AEDH) 3A ED 5A
Fetch Register A with the byte at 5AEDH. This is a field in the source drive parameter block (5AE5H + 08H offset) that holds a track-related parameter (sector starting position or offset).
5377
If the Z FLAG has been set (bit 3 of 5996H was clear — no destination filespec, use source parameters), JUMP to 537FH to proceed with the source drive values loaded above.
Destination filespec was parsed: override with destination drive parameters instead of source parameters.
5379
LD HL,(5B23H) 2A 23 5B
Load Register Pair HL with the 16-bit value at 5B23H. This is a field in the destination drive parameter block (5B17H + 0CH offset) that holds the destination track's total sector count, overriding the source value.
537C
LD A,(5B1FH) 3A 1F 5B
Fetch Register A with the byte at 5B1FH. This is a field in the destination drive parameter block (5B17H + 08H offset) that holds the destination's track-related parameter, overriding the source value.
At this point: HL = total sector count for the active track (source or destination), A = sector offset/starting position. Adjust A and test for track validity.
537F
OR A B7
OR Register A with itself to set flags. Tests whether the sector offset is zero.
5380
If the NZ FLAG has been set (sector offset is nonzero), JUMP to 5383H to skip the adjustment. A nonzero offset means the count is already correct.
5382
DEC HL 2B
DECrement Register Pair HL by 1. When the sector offset (A) is zero, the total sector count needs to be reduced by one because the count includes sector zero which has already been accounted for.
5383
LD A,H 7C
Load Register A with Register H (high byte of adjusted sector count).
5384
AND L A5
AND Register A with Register L. This checks if both H and L are FFH (i.e., HL = FFFFH). If A = FFH after AND, both bytes are FFH.
5385
INC A 3C
INCrement Register A by 1. If A was FFH (from H AND L both being FFH), incrementing wraps to 00H and sets the Z FLAG. This detects HL = FFFFH, which is an invalid sector count (signals an uninitialized or error state).
5386
If the Z FLAG has been set (HL was FFFFH — invalid track with no writable sectors), JUMP to 53D1H to skip writing this track and restore the sector count.
The sector count is valid. Store it as the new destination sector count and perform the actual disk write operation.
5388
LD (5B21H),HL 22 21 5B
Store Register Pair HL (the adjusted sector count) to 5B21H, the destination sector count field in the destination drive parameter block.
538B
LD HL,428BH 21 8B 42
Point Register Pair HL to 428BH, the DOS flags byte at IY+0BH. This byte controls various DOS state flags during disk operations.
538E
SET 1,(HL) CB CE
SET bit 1 of the byte at (HL) = 428BH. Bit 1 of (IY+0BH) signals that a drive write operation is in progress. This flag is checked by the DOS interrupt handler to prevent re-entrant disk access.
5390
GOSUB to 57CEH to perform the disk write operation. 57CEH loads DE from IX (destination parameter block at 5B17H) and jumps to 5CEDH, the disk write engine. Returns Z FLAG set on success, NZ FLAG set on error with error code in A.
5393
RES 1,(HL) CB 8E
RESET bit 1 of the byte at (HL) = 428BH. Clear the drive-write-in-progress flag now that the write operation has completed (whether successfully or with an error).
5395
If the Z FLAG has been set (write succeeded), JUMP to 53D1H to update the sector count and continue to the next buffer slot.
[WRITE ERROR HANDLING] — The disk write at 57CEH failed. Register A holds the error code. Decide whether to display an error message and allow retry, or abort.
5397
PUSH AF F5
Save Register A (error code) and flags onto the stack.
5398
LD HL,5995H 21 95 59
Point Register Pair HL to 5995H, option flags byte 2.
539B
BIT 7,(HL) CB 7E
Test bit 7 of the byte at (HL) = 5995H. Bit 7 is the batch mode flag — when set, the operator should not be prompted for retry decisions; errors are handled automatically.
539D
If the NZ FLAG has been set (batch mode is active), JUMP to 53ADH to display the error without a retry prompt and abort via 521EH.
Interactive mode: check for specific recoverable errors before prompting the user.
539F
LD HL,5996H 21 96 59
Point Register Pair HL to 5996H, option flags byte 2 (mode flags).
53A2
BIT 2,(HL) CB 56
Test bit 2 of the byte at (HL) = 5996H. Bit 2 is the source filespec parsed flag. If set, this is a file-level copy (not whole-disk), which means certain write errors should be treated as fatal.
53A4
If the NZ FLAG has been set (file-level copy mode), JUMP to 521EH (main error handler alternate entry) to abort with the error code. File-level copies cannot safely skip sectors because the file structure depends on every sector being written correctly.
Whole-disk copy in interactive mode. Check if the error is a recoverable position error (1AH class).
53A7
SUB 1AH D6 1A
SUBtract 1AH from Register A (still on stack, but the POP AF at 5355H already restored it — the PUSH AF at 5397H saved the error code). Wait — examining the stack: A was pushed at 5397H and has not been popped. The SUB operates on the current A which is the result of BIT 2,(HL) — this is the error code that was preserved through the BIT test because BIT does not modify A. A = error_code - 1AH. Error codes 1CH (position before start) and 1DH (position past EOF) become 02H and 03H. Other errors will have different values.
53A9
CP 02H FE 02
Compare Register A against 02H. If A < 02H, the CARRY FLAG is set (original error was 1AH or 1BH). If A = 02H (original error 1CH, position before start) or A = 03H (original error 1DH, position past EOF), no carry.
53AB
If the CARRY FLAG has been set (error code was less than 1CH — not a position error), JUMP to 53B3H to attempt recovery by reconfiguring the drive and retrying.
The error code was 1CH or 1DH (or higher): these are non-recoverable in batch-free mode. Display the error and jump to the error handler.
53AD
GOSUB to 5868H to display the error message. 5868H is an error display variant that formats and outputs the error code without prompting for retry.
53B0
JUMP to 521EH (main error handler alternate entry) to abort the operation. The error handler will flush drives and return control to the DOS command processor.
[RECOVERABLE ERROR PATH] — Error code was below 1CH. Attempt to reconfigure the destination drive and retry the write.
53B3
GOSUB to 56DDH to reconfigure the destination drive. This routine calls 48F0H (a SYS0 drive reconfiguration function) to reset the drive state after the error.
53B6
INC HL 23
INCrement Register Pair HL by 1. HL was set inside 56DDH and now points into the drive parameter block. Advance past the first field.
53B7
INC HL 23
INCrement Register Pair HL by 1. Advance to the next field.
53B8
INC HL 23
INCrement Register Pair HL by 1. HL now points to a status/error count field within the drive parameter block (three bytes past the return value from 56DDH).
53B9
XOR A AF
Set Register A to ZERO and clear all flags. A = 00H.
53BA
LD (HL),A 77
Store zero to (HL). Clear the error count or status field at the current position in the drive parameter block.
53BB
LD DE,0011H 11 11 00
Load Register Pair DE with the offset value 0011H (17 decimal). This offset jumps to another field deeper in the drive parameter block.
53BE
ADD HL,DE 19
ADD Register Pair DE (0011H) to Register Pair HL. HL now points 17 bytes further into the drive parameter block, targeting a sector tracking or position field.
53BF
LD (HL),A 77
Store zero to (HL). Clear the sector tracking field.
53C0
INC HL 23
INCrement Register Pair HL by 1 to point to the next byte of a 16-bit field.
53C1
LD (HL),A 77
Store zero to (HL). Clear the second byte of the 16-bit sector tracking field. Together, 53BFH-53C1H zero a 16-bit counter to reset the drive's write position.
53C2
GOSUB to 5711H to advance the destination track/sector pointers. This updates the drive parameter block to point to the next sector to write, accounting for the error recovery.
53C5
POP HL E1
Restore Register Pair HL from the stack. This pops the error code saved by PUSH AF at 5397H (the low byte HL gets is the flags, which are discarded by the H register — but actually POP HL pops the value pushed by PUSH AF, which is A in H and F in L). Wait — examining the stack more carefully: PUSH AF at 5397H saved AF. This POP HL retrieves that value, with H = the error code and L = the saved flags. This effectively discards the error code by consuming the stack entry.
53C6
LD HL,5AD8H 21 D8 5A
Point Register Pair HL to 5AD8H, the message string "DISK FULL - " (terminated by 03H). This message will be displayed to warn the operator that the write error was treated as a disk-full condition.
53C9
GOSUB to 586FH to display the message string at (HL). 586FH calls 4467H (the DOS message display routine) to output "DISK FULL - " to the screen.
53CC
LD A,FFH 3E FF
Load Register A with FFH (255 decimal). This is the success flag value, indicating that at least one sector was written for this track before the error occurred.
53CE
LD (53D7H),A 32 D7 53
Store FFH to self-modifying location 53D7H. Set the destination write success flag to FFH, marking that this track had at least one successful write. [SELF-MODIFYING CODE TARGET] — 53D7H is read at 53D6H/53D8H to decide whether error reporting is needed.
[WRITE LOOP CONVERGENCE POINT] — All paths (write success, write error recovery, invalid track skip) converge here. Restore the sector count, check the write success flag, and advance to the next buffer slot.
53D1
POP HL E1
Restore Register Pair HL from the stack. This retrieves the zero value pushed at 5370H — representing the updated destination sector count.
53D2
LD (5B21H),HL 22 21 5B
Store Register Pair HL to 5B21H, updating the destination sector count. After a successful write or error skip, this restores the sector count to reflect the remaining sectors.
53D5
POP HL E1
Restore Register Pair HL from the stack. This retrieves the buffer pointer saved by PUSH HL at 533EH, pointing to the current position in the track data buffer.
53D6
LD A,00H 3E 00
Load Register A with the value at self-modifying location 53D7H (the operand of this LD A,nn instruction). This is the destination write success flag: 00H = no successful writes yet, FFH = at least one sector written. [SELF-MODIFYING CODE] — the operand byte at 53D7H is modified by 5368H (cleared to 00H) and 53CEH (set to FFH).
53D8
OR A B7
OR Register A with itself to set flags. Tests the write success flag.
53D9
If the Z FLAG has been set (write success flag is 00H — no writes completed for this track), JUMP to 53DFH to skip error display since there is nothing to report.
At least one sector was written (success flag FFH). Display the error/status and decrement the flag.
53DB
GOSUB to 585EH to display an error/status message. 585EH is an error display variant that increments the drive parameter block error counter at IX+0AH before displaying.
53DE
DEC A 3D
DECrement Register A by 1. A was the return value from 585EH. If A was 01H (indicating the display completed and the operator chose to continue), DEC makes it 00H and sets the Z FLAG.
53DF
If the Z FLAG has been set (either no writes were done, or the operator chose to continue after error display), GOSUB to 546DH to write the sector with boot sector patching and verification.
Advance the buffer pointer and track counter for the next iteration.
53E2
INC HL 23
INCrement Register Pair HL by 1. Advance past the last byte of the current sector data in the track buffer.
53E3
If the Z FLAG has been set (from the CALL Z,546DH path — write succeeded or was skipped cleanly), JUMP to 53E6H to skip storing A into the buffer.
53E5
LD (HL),A 77
Store Register A to (HL). Write the status/error code into the buffer at the current position, marking this slot with the result of the write attempt.
53E6
INC HL 23
INCrement Register Pair HL by 1.
53E7
INC H 24
INCrement Register H by 1. This adds 256 to HL, effectively advancing past the 256-byte sector data area of the current buffer slot. Combined with the earlier INC HL instructions, HL now points to the start of the next 258-byte buffer slot.
53E8
GOSUB to 571BH to advance the source track/sector pointers. This updates the drive tracking to reflect that the current sector has been processed.
53EB
LD A,00H 3E 00
Load Register A with the value at self-modifying location 53ECH (the operand of this LD A,nn instruction). This is the destination file write counter — incremented each time a sector is successfully written in this pass. [SELF-MODIFYING CODE] — the operand byte at 53ECH is modified by 533BH (cleared to 00H) and 53EEH (incremented).
53ED
INC A 3C
INCrement Register A by 1. Advance the write counter by one.
53EE
LD (53ECH),A 32 EC 53
Store the incremented counter back to self-modifying location 53ECH. [SELF-MODIFYING CODE TARGET] — updates the operand of the LD A instruction at 53EBH.
53F1
LD A,(5314H) 3A 14 53
Fetch Register A with the track counter from self-modifying location 5314H. This is the number of tracks remaining to be written from the buffer.
53F4
DEC A 3D
DECrement Register A by 1. Reduce the remaining track count by one.
53F5
LD (5314H),A 32 14 53
Store the decremented track counter back to self-modifying location 5314H. [SELF-MODIFYING CODE TARGET] — updates the counter for the next iteration or the loop exit test.
53F8
If the NZ FLAG has been set (track counter is not yet zero — more tracks remain), JUMP back to 533EH to process the next buffer slot. [WRITE LOOP END]
53FBH - POST-WRITE SECTOR FLUSH ROUTINE
Called from 5352H when a track mismatch is detected during file-level copy, and as the fall-through path when the write loop at 533EH-53F8H completes all buffered tracks. Checks whether any sectors were actually written during this pass (via the write counter at 53ECH). If sectors were written, resets the destination sector count, switches the disk I/O mode to write (20H), and calls the sector write engine to flush all pending data to the destination disk. This routine also handles end-of-data detection (status 06H), data verification against the directory template, and write error retry logic.
[FLUSH ENTRY] — Check whether any sectors were written during this write pass. If the write counter is zero, there is nothing to flush.
53FB
LD A,(53ECH) 3A EC 53
Fetch Register A with the destination file write counter from self-modifying location 53ECH. This counter was cleared at 533BH and incremented at 53EEH for each sector written. [SELF-MODIFYING CODE] — reads the operand modified by 533BH/53EEH.
53FE
OR A B7
OR Register A with itself to set flags. Tests whether the write counter is zero.
53FF
RET Z C8
If the Z FLAG has been set (write counter is zero — no sectors were written this pass), RETurn immediately. Nothing to flush.
At least one sector was written. Reset the destination sector count and switch to write mode for the flush operation.
5400
LD HL,0000H 21 00 00
Load Register Pair HL with the value at self-modifying location 5401H (the 16-bit operand of this LD HL,nnnn instruction). This is the saved destination sector count stored at 5336H before the write loop began. [SELF-MODIFYING CODE] — the operand at 5401H-5402H was written by the LD (5401H),DE instruction at 5336H.
5403
LD (5B21H),HL 22 21 5B
Store Register Pair HL to 5B21H, restoring the destination sector count to its value at the start of the write pass. This rewinds the sector counter so the flush can re-write sectors in sequence.
5406
LD HL,(5D10H) 2A 10 5D
Load Register Pair HL with the directory template pointer from 5D10H. This points to the read-only directory reference data used for comparing against written sector content.
5409
LD (5B1AH),HL 22 1A 5B
Store Register Pair HL to 5B1AH, a field in the destination drive parameter block. This sets the destination's reference pointer to the directory template for verification during the flush.
540C
LD A,20H 3E 20
Load Register A with 20H. This is the Write Sector operation code for the disk I/O control byte.
540E
LD (57EBH),A 32 EB 57
Store 20H to 57EBH, the disk operation type control byte. Switches the disk I/O mode from read (80H) to write (20H). Subsequent calls to the disk I/O routine at 57C8H will perform write operations. [SELF-MODIFYING CODE TARGET] — 57EBH controls the disk I/O direction.
[FLUSH LOOP START] — Walk through the track buffer slot by slot. For each slot, check the status byte to decide whether to write, skip, or handle an error.
5411
LD HL,(544FH) 2A 4F 54
Load Register Pair HL with the buffer position pointer from self-modifying location 544FH. This tracks the current position within the track data buffer, advancing by 258 bytes (one slot) each iteration. [SELF-MODIFYING CODE] — reads the operand modified by 532FH/5454H.
5414
INC HL 23
INCrement Register Pair HL by 1. Advance past the FFH marker byte to point to the status byte of this buffer slot.
5415
LD A,(HL) 7E
Load Register A with the status byte at (HL). Status codes: 00H = read success, 06H = end-of-data, other = error code from failed read.
5416
INC A 3C
INCrement Register A by 1. If status was FFH (buffer slot unused/invalid), INC wraps to 00H and sets the Z FLAG. For valid status codes (00H-06H), the result is nonzero.
5417
If the Z FLAG has been set (status was FFH — invalid/unused slot), GOSUB to 585EH to display an error. This should not normally occur; an FFH status indicates buffer corruption or an uninitialized slot.
541A
If the Z FLAG has been set (585EH returned Z — operator chose to skip), JUMP to 544EH to advance past this slot without writing.
Status is valid. Attempt the disk write operation.
541C
GOSUB to 57C8H to perform the disk sector I/O operation. Since 57EBH was set to 20H (write) at 540EH, this writes the sector data from the current buffer slot to the destination disk. Returns Z FLAG on success, NZ FLAG on error with error code in A.
541F
If the NZ FLAG has been set (write failed — A has error code), JUMP to 5422H to check the error code. Skip the XOR A that clears A on success.
5421
XOR A AF
Set Register A to ZERO. Write succeeded, so clear A to use as a success status code (00H).
5422
If the Z FLAG has been set (write succeeded, A = 00H), JUMP to 5428H to compare the result against the buffer's original status.
5424
CP 06H FE 06
Compare Register A (write error code) against 06H. Error code 06H means end-of-data — a normal condition during copy when the source had fewer sectors than the destination expects.
5426
If the NZ FLAG has been set (error code is NOT 06H — a real write error), JUMP to 5430H to display the error and prompt for retry.
Write result is either success (A=00H) or end-of-data (A=06H). Compare against the buffer slot's original read status to verify consistency.
5428
CP (HL) BE
Compare Register A (write result: 00H or 06H) against the byte at (HL), which is the original read status byte in the buffer slot. If they match, the write result is consistent with what was read.
5429
If the Z FLAG has been set (write status matches read status — consistent), JUMP to 5440H to verify the sector data against the directory template.
Status mismatch: the write result differs from the original read status. This is unexpected. Decrement the sector counter and display a warning.
542B
GOSUB to 5492H to decrement the destination sector count at 5B21H. This accounts for the mismatched sector by reducing the expected write count.
542E
LD A,31H 3E 31
Load Register A with error code 31H. This is a NEWDOS/80 error code indicating a sector status mismatch during copy verification.
5430
DEC HL 2B
DECrement Register Pair HL by 1. Step back from the status byte to point to the FFH marker byte at the start of this buffer slot. This positions HL for the error display routine which expects the pointer at the slot header.
5431
GOSUB to 585AH to display the error and prompt the operator for retry. 585AH returns Z FLAG if the operator chose to skip (continue), NZ FLAG if retry is requested.
5434
If the Z FLAG has been set (operator chose to skip this sector), JUMP to 544EH to advance to the next buffer slot.
Operator chose to retry. Attempt to write the sector with verification via 546DH.
5436
GOSUB to 546DH to write the sector with boot sector patching and verification. 546DH examines the status byte, optionally patches boot sector data, sets I/O mode to write-with-verify (40H), writes via 57CEH, and retries on error.
5439
If the NZ FLAG has been set (write with verify failed and operator chose to skip), JUMP to 544EH to advance to the next buffer slot.
543B
GOSUB to 5492H to decrement the destination sector count at 5B21H. The verified write succeeded, so adjust the sector count to reflect one fewer sector remaining.
543E
JUMP back to 5406H to reload the directory template pointer and continue the flush loop with the next sector. [FLUSH LOOP CONTINUE]
Data verification: compare the written sector against the directory template to ensure data integrity.
5440
LD B,00H 06 00
Load Register B with 00H (256 decimal due to DJNZ behavior — when B = 0, DJNZ loops 256 times). This sets up a byte-by-byte comparison loop of 256 bytes (one full sector).
5442
LD DE,(5D10H) ED 5B 10 5D
Load Register Pair DE with the directory template pointer from 5D10H. DE points to the reference data that the written sector should match.
[VERIFY LOOP START] — Compare each byte of the written sector data (at HL+1..HL+256) against the directory template (at DE).
5446
INC HL 23
INCrement Register Pair HL by 1. Advance to the next byte of sector data in the buffer.
5447
LD A,(DE) 1A
Load Register A with the byte at (DE), the current byte from the directory template.
5448
CP (HL) BE
Compare Register A (template byte) against the byte at (HL) (written sector byte). If they match, the Z FLAG is set.
5449
INC DE 13
INCrement Register Pair DE by 1. Advance to the next template byte.
544A
If the NZ FLAG has been set (bytes do not match — verification failure), JUMP to 5461H to handle the directory data mismatch.
544C
DECrement Register B and loop back to 5446H if B is not zero. Continue comparing bytes until all 256 have been verified. [VERIFY LOOP END]
All 256 bytes match the template. The sector was written and verified successfully. Advance to the next buffer slot.
544E
LD HL,0000H 21 00 00
Load Register Pair HL with the value at self-modifying location 544FH (the 16-bit operand of this LD HL,nnnn instruction). This is the current buffer position pointer. [SELF-MODIFYING CODE] — the operand at 544FH-5450H is modified by 532FH (initialized) and 5454H (advanced each iteration).
5451
INC HL 23
INCrement Register Pair HL by 1.
5452
INC HL 23
INCrement Register Pair HL by 1. HL now points 2 bytes past the start of the current buffer slot (past the FFH marker + status byte, to the start of sector data).
5453
INC H 24
INCrement Register H by 1. This adds 256 to HL, advancing past the 256-byte sector data area. HL now points to the start of the next 258-byte buffer slot.
5454
LD (544FH),HL 22 4F 54
Store Register Pair HL (address of next buffer slot) to self-modifying location 544FH. [SELF-MODIFYING CODE TARGET] — advances the buffer position pointer for the next iteration.
5457
GOSUB to 571BH to advance the source track/sector pointers, updating the drive tracking to reflect that this sector has been processed.
545A
LD HL,53ECH 21 EC 53
Point Register Pair HL to 53ECH, the address of the destination file write counter.
545D
DEC (HL) 35
DECrement the byte at (HL) = 53ECH by 1. Reduce the write counter. When it reaches zero, all sectors written in this pass have been flushed.
545E
If the NZ FLAG has been set (write counter is not yet zero — more sectors to flush), JUMP back to 5406H to reload the directory template and process the next buffer slot. [FLUSH LOOP END]
5460
RET C9
RETurn to caller. All sectors have been flushed to the destination disk.
5461H - DIRECTORY DATA MISMATCH HANDLER
Entered from 544AH when a byte comparison between the written sector and the directory template fails during post-write verification. Decrements the destination sector count, displays a "sector mismatch" error (code 3AH), and depending on the operator's response, either skips the sector or retries by re-entering the flush loop.
5461
GOSUB to 5492H to decrement the destination sector count at 5B21H. The mismatch means this sector's data does not match the expected template, so reduce the count.
5464
LD A,3AH 3E 3A
Load Register A with error code 3AH. This is a NEWDOS/80 error code indicating a directory data mismatch during copy verification.
5466
GOSUB to 585AH to display the error and prompt the operator. Returns Z FLAG if skip, NZ FLAG if retry.
5469
If the Z FLAG has been set (operator chose to skip), JUMP to 544EH to advance to the next buffer slot.
546B
JUMP back to 5406H to reload the directory template pointer and retry the write for this sector. [RETRY PATH]
546DH - WRITE SECTOR WITH BOOT PATCH AND VERIFY
Called from 53DFH (conditional on Z FLAG) and 5436H (retry path) to write a single sector to the destination disk with optional boot sector patching and write-with-verify mode. The routine: (1) checks the status byte for end-of-data (06H) and sets bit 0 of IX+00H to signal the caller, (2) calls 5C8EH to configure the destination drive's buffer pointer, (3) sets the I/O mode to write-with-verify (40H), (4) writes via 57CEH, and (5) retries on error with operator prompting. Returns Z FLAG on success, NZ FLAG on unrecoverable failure.
546D
PUSH HL E5
Save Register Pair HL onto the stack. HL points to the current buffer slot header (FFH marker byte). It will be restored at 5488H after the write attempt.
546E
INC HL 23
INCrement Register Pair HL by 1 to advance to the status byte of this buffer slot.
546F
LD A,(HL) 7E
Load Register A with the status byte at (HL). Status code 06H = end-of-data.
5470
CP 06H FE 06
Compare Register A against 06H (end-of-data marker). If A equals 06H, the Z FLAG is set.
5472
INC HL 23
INCrement Register Pair HL by 1. HL now points to the start of the 256-byte sector data within the buffer slot.
5473
If the NZ FLAG has been set (status is NOT 06H — not end-of-data), JUMP to 5479H to skip the end-of-data flag setting and proceed directly to the write.
Status is 06H (end-of-data). Set bit 0 of IX+00H to signal the caller that end-of-data was encountered during this write.
5475
SET 0,(IX+00H) DD CB 00 C6
SET bit 0 of the byte at IX+00H. IX points to the destination drive parameter block at 5B17H, so IX+00H = 5B17H. Setting bit 0 of the parameter block's status byte signals that end-of-data was reached, which the caller uses to determine whether to stop writing additional tracks.
5479
GOSUB to 5C8EH to configure the destination drive's buffer pointer. 5C8EH stores HL to 5B1AH (destination reference pointer) and sets bit 6 of IX+01H to mark the buffer as valid.
547C
LD A,40H 3E 40
Load Register A with 40H. This is the write-with-verify operation code for the disk I/O control byte — it writes the sector and then reads it back to verify the data was written correctly.
547E
LD (57EBH),A 32 EB 57
Store 40H to 57EBH, the disk operation type control byte. Switches the disk I/O mode to write-with-verify. [SELF-MODIFYING CODE TARGET] — 57EBH is set to 80H for read, 20H for write, and 40H for write-with-verify.
5481
GOSUB to 57CEH to perform the disk write-with-verify operation. 57CEH loads DE from IX (5B17H) and jumps to 5CEDH. Returns Z FLAG on success, NZ FLAG on error with error code in A.
5484
RES 0,(IX+00H) DD CB 00 86
RESET bit 0 of the byte at IX+00H = 5B17H. Clear the end-of-data flag that was potentially set at 5475H. The flag served its purpose during the write; clearing it prevents false detection in subsequent operations.
5488
POP HL E1
Restore Register Pair HL from the stack. HL points back to the buffer slot header (FFH marker), as saved at 546DH.
5489
RET Z C8
If the Z FLAG has been set (write-with-verify succeeded), RETurn to caller with Z FLAG set indicating success.
Write-with-verify failed. Display the error and prompt for retry.
548A
GOSUB to 585AH to display the error and prompt the operator for retry. Returns Z FLAG if skip, NZ FLAG if retry.
548D
If the NZ FLAG has been set (operator chose to retry), JUMP back to 546DH to re-attempt the entire write-with-verify sequence. [RETRY LOOP]
Operator chose to skip. Set NZ FLAG to signal failure to the caller.
548F
OR FFH F6 FF
OR Register A with FFH. This forces A to FFH and clears the Z FLAG (sets NZ), signaling to the caller that this sector write was abandoned.
5491
RET C9
RETurn to caller with NZ FLAG set, indicating the write was skipped/abandoned.
5492H - DECREMENT DESTINATION SECTOR COUNT
Utility subroutine that decrements the 16-bit destination sector count at 5B21H. Called from 542BH (status mismatch), 543BH (post-verified write), and 5461H (directory mismatch) to account for sectors that have been processed (whether successfully or with errors).
5492
PUSH HL E5
Save Register Pair HL onto the stack. Preserve the caller's HL value.
5493
LD HL,(5B21H) 2A 21 5B
Load Register Pair HL with the current destination sector count from 5B21H.
5496
DEC HL 2B
DECrement Register Pair HL by 1. Reduce the destination sector count by one.
5497
LD (5B21H),HL 22 21 5B
Store the decremented sector count back to 5B21H.
549A
POP HL E1
Restore Register Pair HL from the stack. Return HL to its original value.
549B
RET C9
RETurn to caller.
549CH — Post-Copy Completion: Write-Back and Option Dispatch
After the main COPY track-read loop at 529DH has finished reading all source tracks (the track counter has reached the total track count and execution falls through the loop), this code performs final write-back of any remaining buffered tracks to the destination disk, then dispatches to post-copy operations based on which option flags are active. The stack contains the return address pushed before the copy loop began.
POP HL E1
Restore Register Pair HL from the stack. This retrieves the return address that was pushed before the main track-read loop began, cleaning up the stack frame.
549D
GOSUB to 5324H (destination track write-back routine) to flush any remaining buffered tracks to the destination disk. This ensures all data read during the final pass is written to the destination before post-copy processing begins.
54A0
LD A,(5996H) 3A 96 59
Fetch option flags byte 3 from 5996H into Register A. This byte controls mode flags including: bit 2 = source filespec parsed, bit 3 = destination filespec parsed, bit 5 = FORMAT mode flag.
54A3
BIT 3,A CB 5F
Test bit 3 of the option flags byte (destination filespec parsed flag). If bit 3 is set, a destination filespec was provided on the command line, indicating a file-level copy operation rather than a whole-disk copy.
If the NZ FLAG has been set (bit 3 is set — destination filespec was parsed), JUMP to 552DH to handle file-level post-copy operations (writing the updated directory and GAT).
54A8
BIT 2,A CB 57
Test bit 2 of the option flags byte (source filespec parsed flag). If bit 2 is set, a source filespec was provided, indicating a selective copy operation.
54AA
If the Z FLAG has been set (bit 2 is clear — no source filespec parsed), JUMP to 54D4H. This means neither source nor destination filespec was given, so this is a whole-disk copy — jump to the option table re-entry point.
Reaching here means: bit 3 was clear (no destination filespec) BUT bit 2 was set (source filespec was parsed). This is a source-only selective copy. The code below writes the updated GAT and directory back to the destination disk.
54AC
LD A,05H 3E 05
Load Register A with 05H — this is a SYS0 function code that selects the operation to set up the destination drive for a GAT/directory write-back.
54AE
GOSUB to 568DH to set up the specified drive (function 05H = destination drive) for a disk operation. This routine calls the common drive setup at 5582H and returns Z if the drive is not configured, NZ if ready.
54B1
GOSUB to 5535H to set up the destination drive parameter block. This routine loads the destination drive number from 5956H, initializes the drive parameter block at 5B17H, and configures IX to point to the destination block.
54B4
LD HL,(5AF1H) 2A F1 5A
Load Register Pair HL with the 16-bit value stored at 5AF1H — this is the source drive's track count or position field (offset +0CH from source parameter block base 5AE5H).
54B7
LD (5B23H),HL 22 23 5B
Store Register Pair HL (source track/position data) to 5B23H — this is the destination parameter field 2 (offset +0CH from destination block base 5B17H). This copies the source drive's position information to the destination drive's parameter block so the write will target the correct location.
54BA
LD A,(5AEDH) 3A ED 5A
Fetch the value at 5AEDH into Register A — this is the source drive parameter byte at offset +08H from source block base 5AE5H.
54BD
LD (5B1FH),A 32 1F 5B
Store Register A to 5B1FH — the destination parameter field at offset +08H from destination block base 5B17H. This copies the source drive's operating parameter to the destination.
54C0
LD DE,5B17H 11 17 5B
Point Register Pair DE to 5B17H — the destination drive parameter block base. DE is passed to the SYS0 disk write routine to identify which drive and parameters to use.
54C3
GOSUB to 4428H — a SYS0 disk write routine that writes the GAT/directory sector(s) back to the destination disk using the parameter block pointed to by DE (5B17H). Returns Z on success, NZ on error with error code in A.
54C6
LD HL,4288H 21 88 42
Point Register Pair HL to 4288H — the active overlay ID byte (IY+08H). This byte identifies which SYS overlay is currently loaded.
54C9
LD (HL),05H 36 05
Store 05H to (HL) at 4288H, setting the active overlay ID to 05H. This updates the DOS state to reflect that the SYS6 post-copy phase is the current operation context.
54CB
If the NZ FLAG has been set (the disk write at 4428H returned an error), JUMP to 521AH (the main error handler) to report the write failure and let the user retry or abort.
54CE
LD HL,402DH 21 2D 40
Point Register Pair HL to 402DH — this is the SYS0 normal completion return address. This address is used as a "clean exit" destination after successful post-copy operations.
JUMP to 5222H to perform final cleanup. That routine uses HL as the return address to exit cleanly through the DOS re-entry point at 402DH, completing the copy operation successfully.
54D4H — Whole-Disk Copy: Return to Option Processing or Post-Copy GAT/Directory Write
This section handles the post-copy path for whole-disk copy operations (no filespec on either source or destination). It either jumps back to the option processing loop for additional commands, or falls through from the file-level path to write the updated GAT and directory to the destination.
JUMP to 502CH to return to the main option processing loop. For a whole-disk copy with no filespecs, all tracks have been copied directly — no directory manipulation is needed. The option processor handles any remaining post-copy options.
54D7H — Post-Copy GAT/Directory Update for Destination Disk
This code runs after a file-level COPY operation (jumped to from 552DH after the directory is written). It updates the destination disk's GAT (Granule Allocation Table) to reflect the copied files. The code reads option flags to determine which disk name and date fields to copy or update, then writes the modified GAT sector back to the destination.
LD DE,(59C1H) ED 5B C1 59
Load Register Pair DE with the 16-bit value at 59C1H — this is a pointer into the destination drive's geometry/configuration data in the work area.
54DB
GOSUB to 5784H — a utility routine. The 3 NOP bytes at 5784H suggest this is a patched or placeholder entry point. The actual routine handles post-copy initialization.
54DE
LD BC,(5994H) ED 4B 94 59
Load Register Pair BC with the option flags word at 5994H-5995H. Register C = option flags byte 1 (5994H), Register B = option flags byte 2 (5995H). These control what post-copy actions to take.
54E2
BIT 1,C CB 49
Test bit 1 of Register C (option flags byte 1 at 5994H). Bit 1 indicates source != destination mode.
54E4
If the NZ FLAG has been set (bit 1 is set — source and destination are different disks), JUMP to 552DH to write the destination directory directly without modifying disk name/date fields.
54E6
GOSUB to 56F9H to initialize the drive for the GAT update operation. This routine performs XOR A (clears A) then calls SYS0 routine 48AFH to select and configure the drive.
54E9
BIT 5,B CB 68
Test bit 5 of Register B (option flags byte 2 at 5995H). Bit 5 controls whether the FORMAT mode flag is active, which determines whether to update the disk date/version stamp.
54EB
If the Z FLAG has been set (bit 5 is clear — FORMAT mode is NOT active), JUMP to 54F3H to skip the date stamp copy and proceed directly to the disk name copy logic.
54ED
LD HL,(5981H) 2A 81 59
Load Register Pair HL with the 16-bit value at 5981H — this is the date/version stamp value stored in the SYS6 work area (parsed from the command line or defaulted during initialization).
54F0
LD (43CEH),HL 22 CE 43
Store the date/version stamp (Register Pair HL) to 43CEH — this is a DOS work area location where the GAT sector's date field is maintained. Writing here updates the in-memory GAT image before it is flushed to disk.
Now determine which disk name to copy into the GAT based on option flags. If the KDN or KDD option flags are set (bits 2-3 of 5994H), the source disk name is copied. Otherwise, the new disk name (if provided) is used.
LD A,C 79
Copy Register C (option flags byte 1 from 5994H) into Register A for bit testing.
54F4
AND 0CH E6 0C
MASK Register A with 0CH (0000 1100), isolating bits 2 and 3. Bit 2 = KDD (Keep Destination Diskname), bit 3 = KDN (Keep Disk Name). If either is set, the disk name from the source should be preserved.
54F6
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16 decimal) — this is the byte count for the LDIR copy. The GAT disk name field is 16 bytes long.
54F9
LD DE,43D0H 11 D0 43
Point Register Pair DE to 43D0H — this is the disk name field within the in-memory GAT image in the DOS work area. This is the destination for the name copy.
54FC
LD HL,5983H 21 83 59
Point Register Pair HL to 5983H — this is the source disk name buffer in the SYS6 work area (16 bytes). This name was read from the source disk's GAT during initialization.
54FF
If the NZ FLAG has been set (from the AND 0CH test at 54F4H — KDN or KDD flags are active), JUMP to 5508H to copy the full 16-byte source disk name to the GAT.
Neither KDN nor KDD is set, so use the new disk name (if provided) instead of the source name. The new name buffer is at 598BH and is only 8 bytes long, stored into a different offset in the GAT.
5501
LD HL,598BH 21 8B 59
Point Register Pair HL to 598BH — the new disk name buffer in the SYS6 work area (8 bytes). This was set by the NDN= option handler at 4F95H if a new name was specified on the command line.
5504
LD E,D8H 1E D8
Load Register E with D8H, changing DE from 43D0H to 43D8H. This shifts the destination pointer 8 bytes forward within the GAT name field, targeting the second half of the 16-byte name area. The new name is shorter (8 bytes) and goes into the latter portion.
5506
LD C,08H 0E 08
Load Register C with 08H (8 decimal), reducing the LDIR byte count from 16 to 8. Only 8 bytes of new disk name will be copied.
LDIR ED B0
Block copy BC bytes from (HL) to (DE). Copies the disk name (either 16 bytes of source name from 5983H to 43D0H, or 8 bytes of new name from 598BH to 43D8H) into the in-memory GAT image.
550AH — GAT Free Space Adjustment and Directory Write-Back
After the disk name has been updated in the GAT image, this code compares the source and destination disk sizes to determine if free space needs to be adjusted (zeroed out in the GAT for tracks that don't exist on a smaller destination disk). It then writes the updated GAT/directory to the destination.
LD HL,(59D1H) 2A D1 59
Load Register Pair HL with the 16-bit value at 59D1H — this is the source disk's total track count (or total granule/sector count, depending on the field offset).
550D
LD DE,(59C3H) ED 5B C3 59
Load Register Pair DE with the 16-bit value at 59C3H — this is the destination disk's total track count (or equivalent size metric).
5511
OR A B7
Clear the CARRY FLAG to prepare for a clean 16-bit subtraction.
5512
SBC HL,DE ED 52
SUBtract DE (destination size) from HL (source size) with borrow. Result in HL = (source size - destination size). If source > destination, result is positive. If source <= destination, CARRY is set or result is zero.
5514
EX DE,HL EB
Exchange DE and HL. Now DE = (source size - destination size), HL still available for use.
5515
If the CARRY FLAG has been set (source disk is smaller than destination — source size < destination size), JUMP to 5528H to skip the GAT free space adjustment since the destination has more capacity.
5517
If the Z FLAG has been set (source and destination are the same size), JUMP to 5528H to skip the adjustment — no tracks need to be zeroed.
Source disk is larger than destination. DE contains the number of extra tracks/granules. The code below zeros out the GAT entries for tracks that don't exist on the smaller destination disk.
5519
LD HL,(59C3H) 2A C3 59
Reload Register Pair HL with 59C3H — the destination disk's total track count. This serves as the starting position in the GAT for the entries that need to be zeroed (the first track beyond the destination's capacity).
551C
LD A,(59BCH) 3A BC 59
Fetch the value at 59BCH into Register A — this is a GAT configuration parameter (sectors per granule or similar multiplier) used to calculate the correct byte offset within the GAT for the given track number.
551F
GOSUB to 4C59H — a SYS0 utility routine that calculates a GAT byte/bit offset from the track number in HL and multiplier in A. Returns the computed position for GAT manipulation.
5522
LD H,43H 26 43
Set the high byte of Register Pair HL to 43H. Combined with the low byte returned from 4C59H, this forms the absolute address within the in-memory GAT image at 4300H. The GAT resides at page 43xxH in the DOS work area.
5524
LD C,A 4F
Copy Register A (the bit position or sub-byte offset returned from 4C59H) into Register C for use by the bit-clearing routine.
5525
GOSUB to 5762H to zero out GAT bits for the excess tracks. This routine clears DE number of granule allocation bits starting at position HL/C, marking those tracks as unused on the destination disk.
GOSUB to 48C4H — a SYS0 routine that writes the modified GAT sector back to the disk. Returns Z on success, NZ on error.
552B
If the NZ FLAG has been set (GAT write failed), JUMP back to 54CBH which stores the overlay ID and then jumps to the error handler at 521AH.
552DH — Write Destination Directory and Exit
This is the common exit path for file-level copy operations. It writes the updated directory sector to the destination disk, then falls through to the clean exit at 54CEH. Reached from 54A5H (destination filespec path), 54E4H (source != dest path), and 552BH (after GAT write success).
LD HL,5A1FH 21 1F 5A
Point Register Pair HL to 5A1FH — this is the directory data buffer in the SYS6 work area containing the updated directory sector image to be written to the destination disk.
5530
GOSUB to 4467H — a SYS0 routine that writes the directory sector from the buffer pointed to by HL to the disk. Returns Z on success, NZ on error.
5533
JUMP to 54CEH to load HL with 402DH (the DOS clean exit address) and jump to 5222H for final cleanup. The copy operation is complete.
5535H — Set Up Destination Drive Parameter Block
SUBROUTINE to initialize the destination drive for a disk operation. Loads the destination drive number from 5956H, calls the common drive setup routine at 5585H, then extracts the PDRIVE table pointer from the drive configuration block and loads IX with the parameter block address at 5AE5H. Called from 54B1H (post-copy GAT write) and other locations that need the destination drive configured.
LD HL,5956H 21 56 59
Point Register Pair HL to 5956H — the destination drive number storage location in the SYS6 work area. The value 0-3 stored here identifies which physical drive is the destination.
5538
GOSUB to 5585H (common drive setup routine) to store HL as the current drive pointer at 593EH, initialize the drive access, and verify the drive is configured. Returns with HL pointing to the drive parameter area.
553B
INC HL 23
INCrement HL by 1, advancing past the drive number byte to the first field of the drive configuration block.
553C
INC HL 23
INCrement HL by 1, advancing to the second field.
553D
LD E,(HL) 5E
Load Register E with the low byte of the PDRIVE table pointer stored at the current position in the drive configuration block.
553E
INC HL 23
INCrement HL to the next byte.
553F
LD D,(HL) 56
Load Register D with the high byte of the PDRIVE table pointer. Register Pair DE now holds the complete 16-bit address of the drive's PDRIVE entry.
5540
PUSH DE D5
Save the PDRIVE table pointer (Register Pair DE) onto the stack temporarily.
5541
POP IX DD E1
Restore the value into Register Pair IX. IX now points to the PDRIVE table entry for the destination drive. Using PUSH DE / POP IX is the standard Z80 idiom for transferring DE to IX (there is no direct LD IX,DE instruction).
5543
LD A,(DE) 1A
Fetch the first byte of the PDRIVE entry pointed to by DE into Register A. This is the drive status/configuration byte — bit 7 indicates whether the drive is configured.
5544
BIT 7,A CB 7F
Test bit 7 of the PDRIVE status byte. Bit 7 = 1 means the drive is configured and ready; bit 7 = 0 means the drive is not configured.
5546
RET NZ C0
If the NZ FLAG has been set (bit 7 is set — drive IS configured), RETurn to the caller. The destination drive is ready for use, IX points to its PDRIVE entry, and the NZ flag signals success.
5547
LD B,00H 06 00
Clear Register B to 00H. B is used as a retry/status counter for the drive initialization attempt that follows.
5549
LD A,17H 3E 17
Load Register A with 17H — this is a SYS0 function code for drive initialization or reconfiguration.
554B
CP E BB
Compare Register A (17H) against Register E (low byte of PDRIVE pointer). This check determines whether the PDRIVE pointer references a specific table position. If E = 17H, the drive is at the standard first table entry position.
554C
If the Z FLAG has been set (E = 17H — standard PDRIVE entry), JUMP to 5556H to use the alternate initialization path via SYS0 routine 4420H.
554E
GOSUB to 4424H — a SYS0 routine that initializes the drive using function code A and parameter block DE. Returns Z on success, NZ on failure with error code in A.
5551
If the Z FLAG has been set (initialization succeeded), JUMP to 5570H to save the drive number and return.
5553
Initialization failed — JUMP to 521AH (the main error handler) with the error code from 4424H still in Register A.
GOSUB to 4420H — a SYS0 routine that initializes the drive using the alternate entry point for standard PDRIVE positions. Returns Z on success, NZ on failure.
5559
If the NZ FLAG has been set (initialization failed), JUMP to 5553H to invoke the error handler at 521AH.
555B
LD DE,(5AEBH) ED 5B EB 5A
Load Register Pair DE with the 16-bit value at 5AEBH — the source drive number field at offset +06H from the source parameter block base 5AE5H.
555F
LD HL,(5B1DH) 2A 1D 5B
Load Register Pair HL with the 16-bit value at 5B1DH — the destination drive number field at offset +06H from the destination parameter block base 5B17H.
5562
RST 18H DF
Execute RST 18H — a fast compare routine that compares HL against DE. Sets Z if HL = DE (source and destination are the same drive), NZ if different.
5563
If the NZ FLAG has been set (source and destination are different drives), JUMP to 5570H to save the drive number and return normally.
Source and destination are the SAME drive. This is a same-disk copy operation, which requires special handling — display a warning message to the operator.
5565
LD HL,5A24H 21 24 5A
Point Register Pair HL to 5A24H — a message string in the SYS6 work area. This is the "same diskette" warning message displayed when source and destination are the same physical drive.
5568
LD A,(5940H) 3A 40 59
Fetch the operation status byte 1 from 5940H into Register A. This byte tracks operation mode flags including bit 0 = "$" mode, bit 1 = source=dest flag, bit 2 = dest=drive 0.
556B
CP 06H FE 06
Compare Register A against 06H. This checks if a specific combination of mode flags is active (bits 1 and 2 both set = source=dest AND dest=drive 0).
556D
If the CARRY FLAG has been set (A < 06H — the mode flag combination does not match), JUMP to 5243H to handle the same-disk warning display and prompt the user for confirmation.
LD HL,(593EH) 2A 3E 59
Load Register Pair HL with the current drive parameter pointer from 593EH. This points to the drive number storage location (5956H for destination, 594CH for source, or 5942H for primary).
5573
LD A,(IX+06H) DD 7E 06
Fetch the drive number byte from offset +06H in the PDRIVE table entry pointed to by IX. This is the physical drive number (0-3) assigned to this PDRIVE entry.
5576
LD (HL),A 77
Store the drive number (Register A) to the location pointed to by HL (the current drive parameter pointer at 593EH). This updates the SYS6 work area with the correct physical drive number for future operations.
5577
RET C9
RETurn to the caller. The destination drive is now fully configured with IX pointing to its PDRIVE entry and the drive number saved in the work area.
5578H — Drive Setup Entry Points (Source, Destination, Primary)
Three entry points that all converge on the common drive setup routine at 5585H. Each loads HL with the address of the appropriate drive number storage location, then falls through or jumps to 5585H. These are called throughout SYS6 to switch between source, destination, and primary drives.
LD HL,594CH 21 4C 59
Point Register Pair HL to 594CH — the source drive number storage location. This entry point is used when the source drive needs to be selected.
557B
JUMP to 5585H (common drive setup) to initialize and select the source drive.
LD HL,5956H 21 56 59
Point Register Pair HL to 5956H — the destination drive number storage location. This entry point is used when the destination drive needs to be selected.
5580
JUMP to 5585H (common drive setup) to initialize and select the destination drive.
LD HL,5942H 21 42 59
Point Register Pair HL to 5942H — the primary drive number storage location. This entry point is used for operations that need the primary (default) drive.
5585H — Common Drive Setup: Select, Initialize, and Configure PDRIVE Access
SUBROUTINE that serves as the central drive initialization routine for SYS6. Called from 5535H, 5578H, 557DH, 5582H, and 5690H. HL points to the drive number storage location on entry. The routine stores the drive pointer at 593EH, checks if the drive is already initialized, selects it via SYS0, and processes a linked list of drive parameter blocks to swap PDRIVE table entries in and out of the DOS configuration area.
LD (593EH),HL 22 3E 59
Store Register Pair HL to 593EH — save the current drive parameter pointer so other routines can reference which drive is active. HL points to either 594CH (source), 5956H (dest), or 5942H (primary).
5588
LD A,FFH 3E FF
Load Register A with FFH.
558A
LD (48D5H),A 32 D5 48
Store FFH to 48D5H — this is a drive cache invalidation flag in the SYS0 work area. Writing FFH forces the DOS to re-read drive parameters from the PDRIVE table rather than using cached values. This ensures the correct drive configuration is loaded after a drive switch.
558D
LD A,(HL) 7E
Fetch the drive number (0-3 or FFH if unconfigured) from the location pointed to by HL into Register A.
558E
INC A 3C
INCrement Register A by 1. This is a test for FFH: if the drive number was FFH (unconfigured), incrementing produces 00H and sets the Z FLAG.
558F
RET Z C8
If the Z FLAG has been set (drive number was FFH — drive is not configured), RETurn immediately to the caller with Z set to signal that no drive is available.
5590
PUSH HL E5
Save the drive number pointer (Register Pair HL) onto the stack for later use.
5591
PUSH DE D5
Save Register Pair DE onto the stack.
5592
PUSH BC C5
Save Register Pair BC onto the stack.
5593
LD A,(593BH) 3A 3B 59
Fetch the disk operation state flags from 593BH into Register A. Bit 7 indicates whether the drive parameter blocks have been initialized.
5596
BIT 7,A CB 7F
Test bit 7 of the state flags. Bit 7 = 1 means the drive parameter blocks are already set up and need to be swapped via the linked list; bit 7 = 0 means first-time initialization.
5598
LD B,00H 06 00
Clear Register B to 00H. B is used as a status indicator passed to the drive parameter block swap routine at 5658H.
559A
If the NZ FLAG has been set (bit 7 was set — parameter blocks already initialized), GOSUB to 5658H to swap the current PDRIVE entries. This routine exchanges the active drive's parameters between the SYS6 work area and the DOS PDRIVE table, ensuring the correct drive geometry is loaded for the next operation.
Now read the drive configuration block to get the SYS0 drive code and PDRIVE pointer for the selected drive.
559D
LD C,(HL) 4E
Load Register C with the drive number (0-3) from the location pointed to by HL. C holds the physical drive number for the SYS0 call.
559E
INC HL 23
INCrement HL to advance past the drive number to the next field in the drive configuration block.
559F
LD B,(HL) 46
Load Register B with the drive flags/status byte from the drive configuration block. This byte contains flags that control how the drive is accessed (bit 0 = select path, bit 1 = parameter direction, bit 2 = error suppress).
55A0
LD DE,0007H 11 07 00
Load Register Pair DE with 0007H (7 decimal) — this is the offset from the current position to the PDRIVE table pointer within the drive configuration block.
55A3
ADD HL,DE 19
ADD DE (7) to HL, advancing HL to the PDRIVE table pointer field within the drive configuration block.
55A4
LD E,(HL) 5E
Load Register E with the low byte of the PDRIVE table pointer.
55A5
INC HL 23
INCrement HL to the high byte of the PDRIVE pointer.
55A6
LD D,(HL) 56
Load Register D with the high byte of the PDRIVE table pointer. Register Pair DE now holds the complete address of the drive's PDRIVE entry in the SYS6 work area.
55A7
LD HL,5940H 21 40 59
Point Register Pair HL to 5940H — the operation status byte 1 in the SYS6 work area.
55AA
LD A,(HL) 7E
Fetch the operation status byte 1 from 5940H into Register A.
55AB
AND B A0
AND Register A with Register B (drive flags). This tests whether specific mode flags in 5940H match the drive's required flags. The result is used as a condition check — if non-zero, the drive needs special handling.
55AC
LD A,(HL) 7E
Re-fetch the operation status byte 1 from 5940H into Register A (the AND at 55ABH destroyed the original value).
55AD
INC HL 23
INCrement HL to 5941H — the operation status byte 2 (disk swapping flags).
55AE
If the Z FLAG has been set (from the AND at 55ABH — mode flags do NOT match), JUMP to 55B5H to skip the disk-swap flag update.
Mode flags matched — this drive requires disk swapping. Clear the swap-needed flag in 5941H by masking off the relevant bits.
55B0
XOR B A8
XOR Register A with Register B. This toggles the bits in A that are set in B (the drive flags), creating a mask that has the drive's flag bits inverted.
55B1
XOR FFH EE FF
XOR Register A with FFH, complementing all bits. Combined with the previous XOR, this creates a mask where ONLY the drive's flag bits are set — all other bits are clear.
55B3
AND (HL) A6
AND the mask in Register A with the value at (HL) = 5941H (operation status byte 2). This clears the drive-specific swap flag bits while preserving all other flags in 5941H.
55B4
LD (HL),A 77
Store the updated value back to 5941H, completing the flag clear operation.
LD A,C 79
Copy Register C (the physical drive number, 0-3) into Register A for the SYS0 drive select call.
55B6
GOSUB to 4723H — a SYS0 routine that selects the drive specified in Register A (0-3). This configures the FDC and drive select latch (port F4H) for the specified drive. Returns Z on success, NZ on error.
55B9
If the NZ FLAG has been set (drive select failed), JUMP to 521AH (main error handler) with the error code from 4723H.
55BC
PUSH HL E5
Save Register Pair HL (pointing to 5941H) onto the stack.
55BD
LD A,(HL) 7E
Fetch the value at 5941H (operation status byte 2 — disk swap flags) into Register A.
55BE
AND B A0
AND Register A with Register B (drive flags). Tests whether the disk swap flag for this drive is still set after the earlier clear operation.
55BF
If the NZ FLAG has been set (swap flag is still set — disk swapping is required for this drive), JUMP to 55ECH to skip the prompt and go directly to writing the PDRIVE entry.
55C1H — Disk Swap Prompt: Ask Operator to Insert Correct Diskette
When a disk swap is needed (source and destination are the same physical drive, or a multi-disk operation), this code displays a prompt message asking the operator to insert the correct diskette, waits for a keypress to confirm, then clears the message. This is a loop — if the drive validation at the end fails, execution returns here to re-prompt.
LD HL,59EEH 21 EE 59
Point Register Pair HL to 59EEH — the first part of the disk swap prompt message in the SYS6 work area (e.g., "INSERT ").
55C4
GOSUB to 4467H — a SYS0 routine that displays the null-terminated string pointed to by HL on the screen.
55C7
LD H,D 62
Copy Register D into Register H. After the display call, DE points past the first message string. Setting H = D preserves the high byte of the current pointer.
55C8
LD L,E 6B
Copy Register E into Register L. Now HL = DE, pointing to the second part of the prompt message (e.g., "SOURCE" or "DESTINATION" followed by " DISKETTE...").
55C9
GOSUB to 4467H to display the second part of the disk swap prompt message.
55CC
LD A,C 79
Copy Register C (the physical drive number, 0-3) into Register A.
55CD
ADD 30H C6 30
ADD 30H (ASCII '0') to Register A, converting the binary drive number (0-3) to its ASCII digit character ('0'-'3').
55CF
LD (5A1DH),A 32 1D 5A
Store the ASCII drive digit to 5A1DH — this is a position within a message string template where the drive number is embedded (e.g., "... DRIVE X"). Patching this byte customizes the message for the active drive.
55D2
LD HL,5A02H 21 02 5A
Point Register Pair HL to 5A02H — the third part of the prompt message (e.g., " THEN PRESS <ENTER>").
55D5
GOSUB to 4467H to display the final part of the disk swap prompt message.
55D8
PUSH BC C5
Save Register Pair BC (C = drive number, B = drive flags) onto the stack before calling the keyboard input routine.
55D9
LD BC,8000H 01 00 80
Load Register Pair BC with 8000H — this is a parameter for the keyboard wait routine. The 80H in B indicates "wait for ENTER key only" mode.
55DC
PUSH DE D5
Save Register Pair DE (PDRIVE table pointer) onto the stack.
55DD
GOSUB to 4C92H — a SYS0 routine that waits for keyboard input. With BC = 8000H, this waits for the operator to press ENTER to confirm the disk has been swapped.
55E0
POP DE D1
Restore Register Pair DE (PDRIVE table pointer) from the stack.
55E1
POP BC C1
Restore Register Pair BC (C = drive number, B = drive flags) from the stack.
GOSUB to 572BH — a routine that checks for the BREAK key and reads a character. Returns the character code in Register A.
55E5
CP 0DH FE 0D
Compare Register A against 0DH (ASCII carriage return / ENTER key). If A = 0DH, the operator pressed ENTER to confirm the disk swap.
55E7
If the NZ FLAG has been set (key pressed was NOT ENTER), JUMP back to 55E2H to read another key. [ENTER KEY WAIT LOOP]
55E9
GOSUB to 5881H — the clear message routine that erases the prompt from the screen, preparing for the next operation or re-prompt.
55ECH — Write PDRIVE Entry and Validate Drive Configuration
After the disk swap (or if no swap was needed), this code writes the PDRIVE table entry from the SYS6 work area to the DOS configuration area, then validates that the drive is properly configured. If validation fails, it loops back to the disk swap prompt at 55C1H.
LD A,C 79
Copy Register C (physical drive number, 0-3) into Register A for the SYS0 PDRIVE write call.
55ED
GOSUB to 4791H — a SYS0 routine that writes the PDRIVE table entry for drive number A. The entry data is taken from the SYS6 work area's copy of the drive parameters. Returns Z on success, NZ if the drive configuration failed validation.
55F0
If the NZ FLAG has been set (PDRIVE write or validation failed), JUMP back to 55C1H to re-display the disk swap prompt and try again. The operator may have inserted the wrong diskette.
55F2
POP HL E1
Restore Register Pair HL from the stack (pointing to 5941H, the operation status byte 2).
55F3
LD A,(HL) 7E
Fetch the operation status byte 2 from 5941H into Register A.
55F4
OR B B0
OR Register A with Register B (drive flags). This SETS the disk swap flag bits for this drive, marking that the swap has been completed and this drive's diskette is now inserted.
55F5
LD (HL),A 77
Store the updated status byte back to 5941H.
55F6
LD HL,5B57H 21 57 5B
Point Register Pair HL to 5B57H — this is the start of the drive parameter linked list in the SYS6 work area. The linked list connects the drive configuration blocks for all drives used in the current operation.
55F9
JUMP to 563BH to enter the linked list traversal loop that processes all drive parameter blocks.
55FBH — Linked List Traversal: Process Drive Parameter Block Entry
This code processes each entry in the drive parameter linked list. Each entry describes a drive whose PDRIVE table parameters need to be swapped between the SYS6 work area and the active DOS configuration. The loop checks the overlay ID, verifies the drive mode, and either swaps the parameters or reports an error.
PUSH HL E5
Save the current linked list pointer (Register Pair HL) onto the stack for later advancement to the next entry.
55FC
If the Z FLAG has been set (from the CP 02H at 563EH — entry type is less than 02H, meaning it's a basic parameter block), JUMP to 560DH to process it without overlay validation.
55FE
LD A,(4288H) 3A 88 42
Fetch the active overlay ID from 4288H (IY+08H) into Register A. This identifies which SYS module is currently loaded.
5601
CP C B9
Compare the active overlay ID (Register A) against Register C (the entry's required overlay ID). If they match, the correct overlay is loaded for this parameter block.
5602
If the Z FLAG has been set (overlay ID matches), JUMP to 560DH to process the parameter block.
5604
BIT 5,(HL) CB 6E
Test bit 5 of the byte at (HL) — a flag within the linked list entry that indicates whether this entry can be processed by a different overlay (cross-overlay access permitted).
5606
If the Z FLAG has been set (bit 5 is clear — cross-overlay access is NOT permitted), JUMP to 5637H to skip this entry and advance to the next one in the linked list.
5608
LD A,33H 3E 33
Load Register A with 33H — this is an error code indicating "overlay mismatch" or "wrong module loaded" error.
560A
JUMP to 521AH (main error handler) with error code 33H to report that the required overlay is not loaded and cross-overlay access was attempted on a restricted entry.
LD A,(4282H) 3A 82 42
Fetch the DOS mode byte from 4282H (IY+02H) into Register A. This byte contains flags that describe the current DOS operating mode.
5610
XOR (HL) AE
XOR Register A with the byte at (HL) — the linked list entry's mode flags. XOR highlights which bits differ between the DOS mode and the entry's expected mode.
5611
AND 20H E6 20
MASK with 20H (bit 5 only). This isolates the FORMAT mode bit — checking whether the DOS is in FORMAT mode while the entry expects non-FORMAT mode, or vice versa.
5613
If the Z FLAG has been set (bit 5 matches — mode is compatible), JUMP to 5637H to skip the swap for this entry (the parameters are already in the correct state).
Mode mismatch detected — the drive parameters need to be swapped between the SYS6 work area and the DOS PDRIVE table. The entry contains swap instructions: a byte count and source/destination pointers.
5615
XOR (HL) AE
XOR Register A (the isolated mode difference) with (HL) again. This effectively toggles bit 5 in the entry's mode flags, marking that the swap has been performed.
5616
LD (HL),A 77
Store the updated mode flags back to the linked list entry, recording that this entry's swap state has been toggled.
5617
INC HL 23
INCrement HL to the next byte in the linked list entry — the low byte of the swap data pointer.
5618
LD A,(HL) 7E
Fetch the low byte of the swap data pointer into Register A.
5619
INC HL 23
INCrement HL to the high byte of the swap data pointer.
561A
LD H,(HL) 66
Load Register H with the high byte of the swap pointer.
561B
LD L,A 6F
Load Register L with the low byte (saved in A). HL now points to the swap data block — a block of bytes that should be exchanged with the DOS PDRIVE table.
561C
JUMP to 562FH to enter the swap block processing loop.
561EH — Swap Block Processing: Exchange PDRIVE Parameters
This code processes a swap block — a data structure that describes pairs of memory locations whose contents need to be exchanged. Each swap block entry contains a byte count followed by source and destination pointers. The routine swaps the bytes between the two locations, effectively switching the PDRIVE parameters between the SYS6 work area and the active DOS configuration.
LD A,(HL) 7E
Fetch the byte count for the current swap block entry from (HL) into Register A. This tells how many bytes need to be exchanged between the two memory locations.
561F
OR A B7
Test Register A (byte count) by ORing it with itself. Sets Z if the count is zero (end of swap block), NZ if there are bytes to swap.
5620
LD B,A 47
Copy the byte count into Register B for use as a loop counter in the DJNZ swap loop.
5621
INC HL 23
INCrement HL past the byte count to the first pointer in the swap block entry.
5622
EX DE,HL EB
Exchange DE and HL. DE now points into the swap block; HL is free for use as the destination pointer.
5623
If the Z FLAG has been set (byte count was zero — end of swap block), JUMP to 562FH to read the next entry's pointer or terminate.
5625
EX DE,HL EB
Exchange DE and HL back. HL now points to the first source address in the swap block entry.
[BYTE SWAP LOOP START] — Exchange B bytes between (HL) and (DE).
LD C,(HL) 4E
Load Register C with the byte at (HL) — save the source byte temporarily.
5627
LD A,(DE) 1A
Load Register A with the byte at (DE) — fetch the destination byte.
5628
LD (HL),A 77
Store the destination byte (Register A) to (HL) — overwrite the source location with the destination's value.
5629
LD A,C 79
Copy Register C (the saved source byte) into Register A.
562A
LD (DE),A 12
Store the source byte (Register A) to (DE) — overwrite the destination location with the source's original value. The two bytes have now been exchanged.
562B
INC HL 23
INCrement HL to the next source byte.
562C
INC DE 13
INCrement DE to the next destination byte.
562D
DECrement Register B (byte count) and loop back to 5626H if not zero. [BYTE SWAP LOOP END]
LD E,(HL) 5E
Load Register E with the low byte of the next entry pointer from the current position in the swap block.
5630
INC HL 23
INCrement HL to the high byte of the next entry pointer.
5631
LD D,(HL) 56
Load Register D with the high byte. DE now holds the pointer to the next swap block entry.
5632
INC HL 23
INCrement HL past the pointer, positioning it at the start of the next entry's data.
5633
LD A,D 7A
Copy Register D (high byte of next pointer) into Register A for the zero test.
5634
OR E B3
OR Register A with Register E. If both bytes are zero, the next pointer is 0000H — end of swap block chain.
5635
If the NZ FLAG has been set (next pointer is not 0000H — more swap entries exist), JUMP back to 561EH to process the next swap block entry. [SWAP BLOCK CHAIN LOOP]
5637H — Advance to Next Linked List Entry and Loop Control
After processing (or skipping) a linked list entry, this code advances to the next entry and checks whether there are more entries to process. The loop continues until all entries have been handled, then returns to the caller.
POP HL E1
Restore the linked list pointer (Register Pair HL) from the stack (saved at 55FBH), pointing back to the start of the current entry.
5638
INC HL 23
INCrement HL by 1, advancing past the first byte of the entry.
5639
INC HL 23
INCrement HL by 1, advancing past the second byte.
563A
INC HL 23
INCrement HL by 1, advancing past the third byte. HL now points to the entry type/control byte of the next linked list entry (each entry in the linked list is a fixed 4-byte header with variable-length data).
LD A,(HL) 7E
Fetch the entry type/control byte of the next linked list entry into Register A. This byte determines the entry type: values < 02H indicate basic parameter blocks, 02H+ indicate overlay-specific entries.
563C
CP 02H FE 02
Compare Register A against 02H. If A < 02H, the CARRY FLAG is set — this is a basic entry or end-of-list marker. If A >= 02H, NO CARRY — this is an overlay-specific entry requiring overlay validation.
563E
LD C,A 4F
Copy the entry type byte into Register C for later use as the overlay ID comparison value.
563F
INC HL 23
INCrement HL past the control byte to the entry's data/flags byte.
5640
If the NO CARRY FLAG has been set (entry type >= 02H — more entries to process), JUMP back to 55FBH to process the next linked list entry. [LINKED LIST TRAVERSAL LOOP]
Entry type was < 02H — end of linked list reached. Restore registers and return.
5642
POP BC C1
Restore Register Pair BC from the stack.
5643
POP DE D1
Restore Register Pair DE from the stack.
5644
POP HL E1
Restore Register Pair HL from the stack.
5645
RET C9
RETurn to the caller. All linked list entries have been processed, PDRIVE parameters have been swapped as needed, and the selected drive is fully configured for the next disk operation.
5646H - FLUSH ALL DRIVE BUFFERS
Iterates through all three drive parameter block base addresses (primary at 5942H, source at 594CH, destination at 5956H), each 10 bytes apart. For each drive that has a valid drive number (not FFH), calls the PDRIVE parameter swap routine at 5658H to flush that drive's cached data back to disk. This is the main cleanup routine called from 5230H before returning to DOS.
5646
LD HL,5942H 21 42 59
Point Register Pair HL to 5942H, the primary drive parameter block base address. This is the first of three 10-byte drive parameter blocks (primary=5942H, source=594CH, destination=5956H).
5649
LD C,03H 0E 03
Load Register C with 03H (decimal 3) as the loop counter — three drive parameter blocks to process.
[LOOP START] — Process each of the three drive parameter blocks. The first byte of each block holds the drive number (00H-03H), or FFH if the block is unused/unconfigured.
564B
LD A,(HL) 7E
Fetch the drive number byte from the current parameter block. For block at 5942H this is the primary drive number, at 594CH the source drive, at 5956H the destination drive. FFH means no drive assigned.
564C
INC A 3C
INCrement Register A by 1. If the drive number was FFH (unassigned), this wraps to 00H and sets the Z FLAG. Any valid drive number (00H-03H) will produce a non-zero result.
564D
If the NZ FLAG is set (drive number was not FFH, meaning a valid drive is assigned), GOSUB to 5658H to perform the PDRIVE parameter swap and flush for this drive. Register A still holds the original drive number (loaded at 564BH) since 5658H re-reads it from (HL).
5650
LD DE,000AH 11 0A 00
Load Register Pair DE with 000AH (decimal 10). Each drive parameter block is 10 bytes long.
5653
ADD HL,DE 19
ADD DE (10) to HL to advance to the next drive parameter block. First iteration: 5942H+0AH=594CH (source). Second: 594CH+0AH=5956H (destination). Third: 5956H+0AH=5960H (past the end, but the loop exits).
5654
DEC C 0D
DECrement Register C (loop counter) by 1.
5655
If the NZ FLAG is set (counter has not reached zero), JUMP back to 564BH to process the next drive parameter block. [LOOP END]
5657
RET C9
RETurn to caller. All three drive parameter blocks have been checked and any active drives have been flushed.
5658H - PDRIVE PARAMETER SWAP AND FLUSH
Selects the drive indicated by the first byte of the parameter block at (HL), then copies 10 bytes of drive geometry data either TO or FROM the DOS PDRIVE table at (42B9H). The direction of the copy is controlled by bit 1 of Register B as returned by 4723H: bit 1 set = copy FROM the SYS6 block TO the PDRIVE table; bit 1 clear = copy FROM the PDRIVE table TO the SYS6 block. After copying, deselects the drive. On error, jumps to the error handler at 521AH unless bit 2 of B is set (suppressed error mode).
5658
LD A,(HL) 7E
Fetch the drive number (00H-03H) from the first byte of the current drive parameter block pointed to by HL.
5659
PUSH HL E5
Save Register Pair HL (pointer to drive parameter block) onto the stack.
565A
PUSH DE D5
Save Register Pair DE onto the stack (preserved across the call).
565B
GOSUB to SYS0 routine at 4723H to select the drive specified in Register A. Returns: Z FLAG set on success, NZ on failure. Register B contains status/mode flags (bit 0: drive active state; bit 1: copy direction for PDRIVE; bit 2: error suppression flag).
565E
If the NZ FLAG is set (drive select failed), JUMP to 5684H for error handling.
5660
LD DE,0004H 11 04 00
Load Register Pair DE with 0004H. Default offset into the parameter block is +4 (the drive geometry data starts at byte 4 of the 10-byte block).
5663
BIT 0,B CB 40
Test bit 0 of Register B (returned from 4723H). Bit 0 set indicates the drive is in an alternate state requiring offset adjustment.
5665
If the Z FLAG is set (bit 0 clear, normal state), JUMP to 5669H to skip the offset adjustment.
5667
INC DE 13
INCrement DE to 0005H.
5668
INC DE 13
INCrement DE to 0006H. The alternate offset is +6 instead of +4.
5669
ADD HL,DE 19
ADD offset DE (either 4 or 6) to HL (parameter block base) to point HL at the drive geometry data within the SYS6 parameter block.
566A
LD E,(HL) 5E
Fetch the low byte of the PDRIVE table entry pointer stored at (HL+offset).
566B
INC HL 23
Advance HL to the next byte.
566C
LD D,(HL) 56
Fetch the high byte of the PDRIVE table entry pointer. DE now points to the SYS6 copy of the PDRIVE data for this drive.
566D
LD HL,(42B9H) 2A B9 42
Fetch the PDRIVE table base pointer from (IY+39H). This is the address of the active DOS PDRIVE table in the system work area.
5670
BIT 1,B CB 48
Test bit 1 of Register B (from 4723H). Bit 1 controls the copy direction: set = copy FROM SYS6 block (DE) TO PDRIVE table (HL); clear = copy FROM PDRIVE table (HL) TO SYS6 block (DE).
5672
If the NZ FLAG is set (bit 1 set, copy SYS6→PDRIVE), JUMP to 5675H. Source=DE (SYS6 block), Destination=HL (PDRIVE table). LDIR copies from (HL) to (DE), so we need DE=PDRIVE, HL=SYS6 — the current registers are already correct for this direction.
5674
EX DE,HL EB
EXchange DE and HL. For bit 1 clear (copy PDRIVE→SYS6): swap so HL=PDRIVE table (source) and DE=SYS6 block (destination) for the LDIR copy.
5675
PUSH BC C5
Save Register Pair BC (B=status flags, C=loop counter from 5646H) onto the stack before the block copy.
5676
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (decimal 10). Copy exactly 10 bytes of PDRIVE drive geometry data.
5679
LDIR ED B0
Block copy 10 bytes from (HL) to (DE), decrementing BC after each byte. This transfers the drive geometry parameters between the SYS6 work area copy and the active DOS PDRIVE table.
567B
POP BC C1
Restore Register Pair BC (B=status flags, C=loop counter).
567C
GOSUB to SYS0 routine at 4720H to deselect the drive. Returns Z FLAG on success, NZ on failure.
567F
If the NZ FLAG is set (drive deselect failed), JUMP to 5684H for error handling.
[SUCCESS PATH] — Drive was selected, PDRIVE data was copied, and drive was deselected successfully.
5681
POP DE D1
Restore Register Pair DE from the stack (saved at 565AH).
5682
POP HL E1
Restore Register Pair HL from the stack (saved at 5659H). HL again points to the drive parameter block base.
5683
RET C9
RETurn to caller (5646H flush loop or other callers). The PDRIVE swap completed successfully.
[ERROR PATH] — Drive select or deselect failed. Check whether error reporting is suppressed.
5684
BIT 2,B CB 50
Test bit 2 of Register B (from 4723H). Bit 2 set means errors are suppressed (silent failure mode).
5686
If the NZ FLAG is set (bit 2 set, errors suppressed), JUMP to 5681H to clean up the stack and return without reporting the error.
5688
JUMP to the SYS6 main error handler at 521AH. Register A contains the error code from the failed drive operation.
568BH - DRIVE SETUP DISPATCHER
Entry point for drive setup operations controlled by the function code in Register A. Saves the function code, calls 5582H to set up the primary drive parameter block, then dispatches based on whether the function code is zero or non-zero. Non-zero codes trigger a SYS0 error dispatch via RST 28H with E0H OR'd into the code. Also compares the source directory buffer end pointer (5D14H) against the current position using RST 18H.
568B
LD A,04H 3E 04
Load Register A with 04H. This is an alternate entry point that preloads function code 04H before falling into 568DH.
568D
LD C,FFH 0E FF
Load Register C with FFH. This is passed to 5582H as the drive setup parameter (FFH = use default configuration).
568F
PUSH AF F5
Save Register A (function code, either 04H from 568BH or a caller-supplied value) onto the stack.
5690
GOSUB to 5582H to set up the primary drive parameter block (loads HL=5942H and falls into 5585H, the common drive setup routine with PDRIVE linked list swap).
5693
POP AF F1
Restore Register A (function code) from the stack.
5694
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is 00H (no special function), NZ if non-zero.
5695
RET Z C8
If the Z FLAG is set (function code is 00H), RETurn to caller. No additional action needed — the drive setup is complete.
5696
OR E0H F6 E0
OR Register A with E0H to set the upper 3 bits. This converts the function code (e.g., 04H) into a SYS0 dispatch code (e.g., E4H). The E0H prefix signals a system operation class to RST 28H.
5698
RST 28H EF
Execute RST 28H with the dispatch code in Register A (e.g., E4H). This is the SYS0 system call interface — it dispatches to the appropriate handler based on the code in A.
After the RST 28H dispatch returns, the following code performs a pointer comparison to check whether source directory data is still valid.
5699
INC HL 23
INCrement Register Pair HL by 1. Advances the pointer (context depends on caller — used by 56A2H as part of a scan loop).
569A
INC HL 23
INCrement HL again (advance by 2 total).
569B
INC HL 23
INCrement HL again (advance by 3 total). HL now points 3 bytes past its entry value.
569C
LD DE,(5D14H) ED 5B 14 5D
Fetch the directory buffer end pointer from 5D14H into Register Pair DE. This is the current end-of-directory-data address, marking where the track buffer area begins.
56A0
RST 18H DF
Execute RST 18H to compare HL against DE. RST 18H performs a 16-bit unsigned compare: sets Z FLAG if HL==DE, CARRY if HL<DE, NO CARRY if HL>=DE.
56A1
RET C9
RETurn to caller with the flags set from the RST 18H comparison. Z means HL reached the directory buffer end; CARRY means HL is still within the buffer.
56A2H - DRIVE CONFIGURATION SCAN AND SOURCE SETUP
Scans through drive configuration entries looking for one with bit 5 set (FORMAT mode flag), then uses the found entry to initialize the source drive parameter block at IX=5AE5H. Calls the option keyword table parser at 4E21H and the filespec validator at 4F2EH to process drive-specific options.
56A2
GOSUB to 5699H to advance HL by 3 and compare against the directory buffer end at 5D14H. Returns Z if HL has reached the end of the buffer.
56A5
RET Z C8
If the Z FLAG is set (HL reached the directory buffer end), RETurn to caller. No more entries to scan.
56A6
BIT 5,(HL) CB 6E
Test bit 5 of the byte at (HL). Bit 5 is the FORMAT mode flag within the drive configuration entry. If set, this entry is relevant to the current operation.
56A8
If the Z FLAG is set (bit 5 clear, not a FORMAT mode entry), JUMP back to 56A2H to advance HL and check the next entry. [LOOP]
Found an entry with bit 5 set. Save its address and extract the drive configuration parameters.
56AA
LD (52BAH),HL 22 BA 52
Store the address of the found configuration entry into 52BAH. This saves the pointer for later reference by the track read/write routines.
56AD
INC HL 23
Advance HL to the next byte of the configuration entry (offset +1: drive number field).
56AE
LD C,(HL) 4E
Fetch the drive number from offset +1 of the entry into Register C.
56AF
INC HL 23
Advance HL to offset +2 of the configuration entry (parameter byte).
56B0
LD A,(HL) 7E
Fetch the parameter byte from offset +2 into Register A.
56B1
LD (52D2H),A 32 D2 52
Store the parameter byte to 52D2H for use by the track read/write routines.
56B4
LD IX,5AE5H DD 21 E5 5A
Point Index Register IX to 5AE5H, the source drive parameter block base. Subsequent operations will use IX-indexed addressing to fill in this block.
56B8
LD A,C 79
Copy the drive number from Register C to Register A.
56B9
LD (4F56H),A 32 56 4F
Store the drive number to 4F56H, the temporary drive number storage used during option parsing.
56BC
GOSUB to 56F4H to initialize the drive hardware via SYS0 routine 48DBH. Register A contains the drive number.
56BF
XOR A AF
Set Register A to 00H and clear all flags.
56C0
LD (4F5EH),A 32 5E 4F
Store 00H to 4F5EH, clearing the drive parse initialization flag. This prepares the parser for a fresh option processing pass.
56C3
INC HL 23
Advance HL to offset +3 of the configuration entry, pointing to the option string data that follows.
56C4
GOSUB to 4E21H, the option keyword table parser. HL points to the option string. The parser processes option keywords and sets the appropriate flags in 5994H-5997H.
56C7
EX DE,HL EB
EXchange DE and HL. After the parser returns, HL held the updated position; now DE has it and HL is free.
56C8
LD A,E 7B
Copy the low byte of the parse position from Register E to Register A.
56C9
ADD 10H C6 10
ADD 10H to Register A. This adjusts the parse position offset by 16 bytes, advancing past a fixed-size data area in the configuration entry.
56CB
LD E,A 5F
Store the adjusted low byte back into Register E. DE now points to the adjusted filespec position.
56CC
GOSUB to 4F2EH to validate the parsed filespec and store it. Returns Z FLAG if validation succeeded, NZ if it failed.
56CF
If the NZ FLAG is set (filespec validation failed), JUMP to 56FEH which jumps to the error handler at 521AH.
56D1
OR FFH F6 FF
OR Register A with FFH, setting A to FFH and setting the NZ FLAG. This signals a successful scan result (non-zero = entry found and configured).
56D3
RET C9
RETurn to caller with NZ FLAG set and A=FFH indicating the drive configuration entry was found and successfully processed.
56D4H - TRACK SEEK DISPATCH
Converts a track number in Register A to a 16-bit value in HL, fetches the DOS position byte from (IY+04H), and jumps to SYS0 routine 4C39H to perform a track seek via the PDRIVE table.
56D4
LD L,A 6F
Copy the track number from Register A to Register L.
56D5
LD H,00H 26 00
Set Register H to 00H. HL now holds the track number as a 16-bit value (00:track).
56D7
LD A,(IY+04H) FD 7E 04
Fetch the DOS position control byte from (IY+04H) = 4284H. This byte controls the seek mode and head positioning parameters for the FDC.
56DA
JUMP to SYS0 routine at 4C39H to execute the track seek. HL=track number, A=position control byte. This routine handles the FDC seek command and waits for completion.
56DDH - DRIVE UTILITY CALL (48F0H WRAPPER)
Calls the SYS0 drive utility routine at 48F0H, then falls through to the common error check at 56FDH.
56DD
GOSUB to SYS0 routine at 48F0H, a drive utility function. Returns Z FLAG on success, NZ on failure with error code in A.
56E0
JUMP unconditionally to 56FDH to check the return status and either return or jump to the error handler.
56E2H - TRACK SEEK WITH CACHE VALIDATION
Performs a track seek via SYS0 routine 48D4H, but first checks whether the drive cache invalidation flag at 570EH (self-modifying code) needs to be updated. If the new track's adjusted value differs from the cached value, calls 570DH to flush the GAT and reset the cache before seeking.
56E2
PUSH AF F5
Save Register A (contains the track/parameter byte for the seek) onto the stack.
56E3
AND 1FH E6 1F
AND Register A with 1FH to mask off the upper 3 bits, isolating the track number (bits 0-4, range 0-31).
56E5
INC A 3C
INCrement A by 1.
56E6
INC A 3C
INCrement A by 1 again. A now holds (track AND 1FH) + 2. This adjusted value is the cache comparison key.
56E7
LD HL,570EH 21 0E 57
Point Register Pair HL to 570EH, the location of the [SELF-MODIFYING CODE] cache comparison byte. This byte holds the previously cached track key value.
56EA
CP (HL) BE
Compare Register A (new track key) against the cached value at (570EH). If they match (Z FLAG), no cache flush is needed.
56EB
If the NZ FLAG is set (new track key differs from cached value), GOSUB to 570DH to flush the GAT sector to disk and reset the cache flag to FFH.
56EE
POP AF F1
Restore Register A (original track/parameter byte) from the stack.
56EF
GOSUB to SYS0 routine at 48D4H to perform the track seek with head configuration. A contains the seek parameters.
56F2
JUMP unconditionally to 56FDH for error checking.
56F4H - DRIVE INITIALIZATION (48DBH WRAPPER)
Calls the SYS0 drive initialization utility at 48DBH with the current drive parameters, then falls through to the common error check.
56F4
GOSUB to SYS0 routine at 48DBH for drive initialization. Sets up the FDC and drive controller for the specified drive.
56F7
JUMP unconditionally to 56FDH for error checking.
56F9H - DRIVE INITIALIZATION WITH BASIC INIT (48AFH WRAPPER)
Clears Register A to 00H (basic initialization mode) and calls SYS0 routine 48AFH, then falls through to the common error check.
56F9
XOR A AF
Set Register A to 00H and clear all flags. A=00H selects basic initialization mode for the drive init routine.
56FA
GOSUB to SYS0 routine at 48AFH for drive initialization with A=0 (basic init mode).
56FDH - COMMON DRIVE OPERATION ERROR CHECK
Shared return point for all drive utility wrappers (56DDH, 56E2H, 56F4H, 56F9H, 5701H). If the Z FLAG is set (success), returns to caller. If NZ (error), jumps to the main error handler at 521AH.
56FD
RET Z C8
If the Z FLAG is set (operation succeeded), RETurn to caller.
56FE
JUMP to the SYS6 main error handler at 521AH. Register A holds the error code from the failed operation.
5701H - DRIVE UTILITY CALL (48C7H WRAPPER)
Calls SYS0 drive utility routine 48C7H and jumps to the common error check at 56FDH.
5701
GOSUB to SYS0 routine at 48C7H, a drive utility function.
5704
JUMP unconditionally to 56FDH for error checking.
5706H - SAVE DRIVE CACHE FLAG
Copies the current drive cache invalidation flag from 48D5H into the self-modifying code location at 570EH for later comparison by the track seek routine at 56E2H.
5706
LD A,(48D5H) 3A D5 48
Fetch the drive cache invalidation flag from 48D5H into Register A. This byte tracks whether the drive cache is valid (specific value) or needs refresh (FFH).
5709
LD (570EH),A 32 0E 57
Store the cache flag value to 570EH. [SELF-MODIFYING CODE] — this overwrites the operand byte of the instruction at 570DH/570EH, so the track seek routine at 56E2H can compare against the current cached track.
570C
RET C9
RETurn to caller.
570DH - FLUSH GAT AND RESET CACHE
Called when the track seek routine at 56E2H detects that the target track differs from the cached track. Writes the GAT sector to disk via 48C4H and resets the cache comparison byte to FFH (invalidated). The first two bytes at 570DH-570EH contain a self-modifying instruction whose operand is the cached track key.
570D
LD A,FFH 3E FF
Load Register A with FFH. The second byte (at 570EH) is [SELF-MODIFYING CODE] — it is overwritten by 5706H and 5713H with the cached track key or FFH.
570F
INC A 3C
INCrement Register A by 1. If A was FFH (cache invalidated), this wraps to 00H and sets Z FLAG. If A held a valid cached track key, it becomes non-zero (NZ).
5710
RET Z C8
If the Z FLAG is set (cache was already invalidated with FFH), RETurn without flushing. No GAT write needed.
5711
LD A,FFH 3E FF
Load Register A with FFH to reset the cache flag.
5713
LD (570EH),A 32 0E 57
Store FFH to 570EH, invalidating the cached track key. [SELF-MODIFYING CODE]
5716
GOSUB to SYS0 routine at 48C4H to write the GAT sector to disk. This flushes any modified GAT data before the track seek changes the active track.
5719
JUMP to 56FDH for common error checking. If 48C4H succeeded (Z), returns; if failed (NZ), jumps to error handler.
571BH - ACTIVITY INDICATOR TOGGLE
Toggles an asterisk (*) character at screen position 3C3FH (top-right corner of the video RAM, column 63 of row 0) as a visual activity indicator. If the current character is an asterisk, replaces it with a space; if anything else, writes an asterisk. This provides feedback to the user that the copy/format operation is actively running.
571B
LD A,(3C3FH) 3A 3F 3C
Fetch the character currently displayed at video RAM address 3C3FH (row 0, column 63 — the top-right corner of the screen).
571E
CP 2AH FE 2A
Compare Register A against 2AH (ASCII *). If the current character is an asterisk, the Z FLAG is set.
5720
LD A,2AH 3E 2A
Load Register A with 2AH (ASCII *). Prepare to write an asterisk (this will be used if the current character was NOT an asterisk).
5722
If the NZ FLAG is set (current character was not an asterisk), JUMP to 5726H to write the asterisk.
5724
LD A,20H 3E 20
Load Register A with 20H (ASCII space). The current character was already an asterisk, so replace it with a space to create the blinking toggle effect.
5726
LD (3C3FH),A 32 3F 3C
Store Register A (either * or space) to video RAM at 3C3FH, updating the activity indicator on screen.
5729
JUMP unconditionally to 5733H to check the BREAK key and batch mode before returning.
572BH - CHECK FOR BREAK KEY AND READ CHARACTER
Reads a character from the keyboard via ROM routine 002BH, then calls SYS0 keyboard processing at 4548H for BREAK key detection. Falls through to the batch mode and BREAK key scan logic at 5733H. This routine is used by interactive prompts (e.g., the menu response scanner at 58E4H).
572B
PUSH DE D5
Save Register Pair DE onto the stack.
572C
GOSUB to ROM routine at 002BH to wait for a keypress and return the character in Register A.
572F
GOSUB to SYS0 routine at 4548H for keyboard processing and BREAK key detection.
5732
POP DE D1
Restore Register Pair DE from the stack.
5733H - BATCH MODE AND BREAK KEY SCAN
Checks whether the operation is in batch mode (5995H bit 7). If not in batch mode, directly scans the keyboard hardware at 3840H for the BREAK key combination. The BREAK key on the TRS-80 Model III requires SHIFT+@ to be held simultaneously. This routine detects the key combo and, if BREAK is pressed while SHIFT is also held, reports error 39H (BREAK key abort) to the error handler.
5733
PUSH AF F5
Save Register A (the character or status from previous operations) onto the stack.
5734
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A. Bit 7 is the batch mode flag (no operator prompts).
5737
BIT 7,A CB 7F
Test bit 7 of Register A. If set, the operation is running in batch mode and BREAK key checking is skipped.
5739
If the NZ FLAG is set (batch mode active), JUMP to 574FH to skip the BREAK key check and return.
573B
LD A,(3840H) 3A 40 38
Read keyboard row 6 from memory-mapped address 3840H. This row contains: ENTER (bit 0), CLEAR (bit 1), BREAK (bit 2), UP (bit 3), DOWN (bit 4), LEFT (bit 5), RIGHT (bit 6), SPACE (bit 7). Active LOW — a pressed key reads as 0.
573E
AND 48H E6 48
AND Register A with 48H (binary 01001000), isolating bit 3 (UP arrow) and bit 6 (RIGHT arrow). These bits being ZERO indicates specific keys are pressed. The test checks for the BREAK key combination detection pattern.
5740
If the Z FLAG is set (both tested bits are 0, meaning neither UP nor RIGHT is pressed in the expected pattern), JUMP to 574FH — BREAK is not being pressed, so return normally.
BREAK key combination detected. Now wait for either SHIFT or another key to confirm the break request versus just a momentary keypress.
5742
LD A,(3840H) 3A 40 38
Read keyboard row 6 again from 3840H. [LOOP START]
5745
AND 09H E6 09
AND Register A with 09H (binary 00001001), isolating bit 0 (ENTER) and bit 3 (UP arrow). This tests whether the user has released the BREAK combination or pressed ENTER.
5747
If the Z FLAG is set (both bits still 0, keys still held), JUMP back to 5742H to keep waiting. [LOOP END]
5749
RRCA 0F
Rotate Register A Right through Carry. Bit 0 (ENTER key state) shifts into the CARRY FLAG. If ENTER was pressed (bit 0 = 1), CARRY is set. If only UP was released (bit 3 = 1, bit 0 = 0), CARRY is clear.
574A
LD A,39H 3E 39
Load Register A with 39H, the error code for BREAK key abort.
574C
If the NO CARRY FLAG is set (ENTER was not pressed, meaning the user confirmed BREAK by releasing without ENTER), JUMP to the error handler at 521AH with error code 39H (BREAK abort). If CARRY is set (ENTER pressed), fall through to return — the user chose to continue.
574F
POP AF F1
Restore Register A from the stack (the original character/status saved at 5733H).
5750
RET C9
RETurn to caller. BREAK was not pressed, or the user cancelled the break by pressing ENTER.
5751H - GAT BIT CLEAR EXIT CHECK
Exit routine for the GAT bit zeroing loop at 5762H. Checks whether the track count in L has reached 60H (decimal 96, the maximum track number for standard disks). Also validates against the destination disk's total track count at 59C6H. If either limit is reached or exceeded, returns to the caller that invoked the GAT zeroing loop (popping 3 register pairs to unwind the stack).
5751
LD A,L 7D
Copy the current GAT bit position (track counter low byte) from Register L to Register A.
5752
CP 60H FE 60
Compare Register A against 60H (decimal 96). If L >= 60H, the NO CARRY FLAG is set — the position has reached or passed the maximum track number for a 96-track disk.
5754
POP BC C1
Restore Register Pair BC from the stack (saved by 5762H).
5755
POP DE D1
Restore Register Pair DE from the stack (saved by 5762H). DE holds the remaining sector count to zero.
5756
POP HL E1
Restore Register Pair HL from the stack (saved by 5762H).
5757
RET NC D0
If the NO CARRY FLAG is set (L >= 60H, maximum track reached), RETurn to the original caller of the GAT zeroing loop. All excess tracks have been cleared.
5758
LD A,(59C6H) 3A C6 59
Fetch the destination disk total track count from 59C6H into Register A. This is the actual number of tracks on the destination disk.
575B
CP 61H FE 61
Compare Register A against 61H (decimal 97). If the destination has fewer than 97 tracks, CARRY is set.
575D
RET NC D0
If the NO CARRY FLAG is set (destination has 97+ tracks), RETurn. Extended disk — no GAT clearing needed beyond 96 tracks as the GAT format handles it differently.
575E
LD A,L 7D
Copy the current position from Register L back to Register A.
575F
ADD 60H C6 60
ADD 60H to Register A. This wraps the track counter into the upper half of the GAT byte (tracks 96-191 are mapped starting at bit offset 60H in the extended GAT).
5761
LD L,A 6F
Store the adjusted position back into Register L. Fall through to 5762H to continue zeroing GAT bits in the upper track range.
5762H - ZERO OUT GAT BITS FOR EXCESS TRACKS
Clears individual bits in the GAT (Granule Allocation Table) for tracks that exceed the destination disk's capacity. When copying from a larger disk to a smaller one, the source GAT may have bits set for tracks that don't exist on the destination. This routine walks through the GAT byte-by-byte, clearing one bit at a time for each excess track, using a rotating bitmask. Register DE holds the count of tracks to clear, HL points to the current GAT byte, and C tracks the bit position within the current byte.
5762
PUSH HL E5
Save Register Pair HL (GAT byte pointer) onto the stack.
5763
PUSH DE D5
Save Register Pair DE (remaining tracks to clear count) onto the stack.
5764
PUSH BC C5
Save Register Pair BC (B=scratch, C=current bit position within GAT byte) onto the stack.
5765
LD A,L 7D
Copy the low byte of the GAT pointer from Register L to Register A. This represents the GAT byte offset plus the bit position encoding.
5766
CP C0H FE C0
Compare Register A against C0H (decimal 192). If L >= C0H, the position has exceeded the GAT boundary.
5768
If the NO CARRY FLAG is set (L >= C0H, past GAT boundary), GOSUB to 5240H for boundary check / error handling.
576B
INC C 0C
INCrement Register C (bit position counter) by 1.
576C
LD B,C 41
Copy Register C to Register B. B will be the DJNZ loop counter for rotating the bitmask.
576D
LD A,7FH 3E 7F
Load Register A with 7FH (binary 01111111). This is the starting bitmask with bit 7 clear — it will be rotated left B times to position the clear bit at the target position.
[INNER LOOP START] — Rotate the bitmask left to align the zero bit with the target bit position.
576F
RLCA 07
Rotate Register A Left Circular. The zero bit in the mask shifts left by one position each iteration.
5770
DECrement B and loop back to 576FH if not zero. After B rotations, the zero bit in A is at bit position (C). [INNER LOOP END]
5772
AND (HL) A6
AND Register A (bitmask with one zero bit) with the GAT byte at (HL). This clears exactly one bit — the bit corresponding to the excess track — while preserving all other bits.
5773
LD (HL),A 77
Store the modified GAT byte back to (HL). The excess track's bit is now cleared.
5774
DEC DE 1B
DECrement Register Pair DE (remaining tracks to clear) by 1.
5775
LD A,D 7A
Copy the high byte of DE to Register A.
5776
OR E B3
OR Register A with Register E. If DE has reached 0000H, the Z FLAG is set — all excess tracks have been cleared.
5777
If the Z FLAG is set (DE=0, all tracks cleared), JUMP to 5751H to exit the loop and unwind the stack.
5779
LD A,(59CAH) 3A CA 59
Fetch the sectors-per-GAT-byte value from 59CAH into Register A. This is the number of granules (and thus bits) per GAT byte for the current disk geometry.
577C
CP C B9
Compare Register A (sectors per GAT byte) against Register C (current bit position). If C has reached the maximum bit position for this GAT byte, they are equal (Z FLAG).
577D
If the NZ FLAG is set (more bits remain in this GAT byte), JUMP back to 576BH to process the next bit. [OUTER LOOP continues]
577F
LD C,00H 0E 00
Reset Register C to 00H. Starting from bit position 0 of the next GAT byte.
5781
INC L 2C
INCrement Register L to advance HL to the next GAT byte.
5782
JUMP back to 5765H to continue the boundary check and bit clearing loop for the next GAT byte. [OUTER LOOP END]
5784H - POST-COPY INITIALIZATION PLACEHOLDER
Six NOP instructions occupying addresses 5784H-5789H. This is placeholder/reserved space that can be patched at runtime or in a future version. The code was identified in the continuation notes as "3 NOPs" but the disassembly shows six consecutive NOP bytes. Execution falls straight through to 578AH.
5784
NOP 00
No OPeration. Placeholder byte 1 of 6.
5785
NOP 00
No OPeration. Placeholder byte 2 of 6.
5786
NOP 00
No OPeration. Placeholder byte 3 of 6.
5787
NOP 00
No OPeration. Placeholder byte 4 of 6.
5788
NOP 00
No OPeration. Placeholder byte 5 of 6.
5789
NOP 00
No OPeration. Placeholder byte 6 of 6. Falls through to 578AH.
578AH - DESTINATION WRITE SETUP AND SECTOR COUNT LOOP
Initializes the destination drive for writing by storing the write-sector command code (20H) to 57EBH (the disk operation type control byte), saving the sector count from DE to 5B21H, and setting the destination buffer pointer at 5B1AH to 4300H. Then compares the total destination disk capacity (from 59CFH) against the sector count. If the destination has enough room, displays the "COPYING" message and enters a read-sector loop that reads sectors via 57C8H (which calls SYS0 4436H), handles errors via 585AH, toggles the activity indicator, and decrements the sector count until HL reaches 0000H.
578A
LD A,20H 3E 20
Load Register A with 20H. This is the disk operation type code for "write sector" mode.
578C
LD (57EBH),A 32 EB 57
Store 20H to 57EBH, the disk operation type control byte. [SELF-MODIFYING CODE] — 57EBH is the operand of the LD B,00H instruction at 57EAH; writing 20H here changes it to LD B,20H, which signals write mode to the status display routine at 57DAH.
578F
LD (5B21H),DE ED 53 21 5B
Store Register Pair DE to 5B21H, the destination sector count / progress field. DE holds the number of sectors to be written to the destination disk.
5793
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H. This is the DOS work area buffer address used as the destination write buffer base.
5796
LD (5B1AH),HL 22 1A 5B
Store 4300H to 5B1AH, the destination related pointer within the destination drive parameter block. This sets the buffer address for the write operation.
5799
LD HL,(59CFH) 2A CF 59
Fetch the total destination disk capacity (sector count) from 59CFH into Register Pair HL.
579C
OR A B7
Clear the CARRY FLAG (OR A with itself). Prepares for the 16-bit subtraction that follows.
579D
SBC HL,DE ED 52
SUBtract DE (requested sector count) from HL (total capacity) with borrow. If DE > HL, the result is negative and the CARRY FLAG is set — the destination disk is too small.
579F
RET C D8
If the CARRY FLAG is set (destination disk does not have enough room for the requested sectors), RETurn to caller with CARRY indicating failure.
57A0
RET Z C8
If the Z FLAG is set (destination capacity exactly equals the requested sector count), RETurn to caller with Z FLAG. Exact fit — no excess sectors to process.
Destination disk has MORE capacity than needed. HL holds the excess (capacity - requested). Display the "COPYING" message and begin the read-sector loop.
57A1
PUSH HL E5
Save Register Pair HL (excess sector count) onto the stack.
57A2
LD HL,5A79H 21 79 5A
Point Register Pair HL to 5A79H, the address of a status/label message string (e.g., "COPYING" or similar destination label).
57A5
GOSUB to 587EH to display the string at (HL) via 4467H followed by a carriage return.
57A8
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH. This sentinel value indicates "not yet started" or "no position set" for the destination parameter field.
57AB
LD (5B23H),HL 22 23 5B
Store FFFFH to 5B23H, the destination parameter field 2 (offset +0CH). Initializes the position tracker to the "unset" sentinel.
57AE
SET 1,(IX+00H) DD CB 00 CE
SET bit 1 of (IX+00H). IX points to the source drive parameter block at 5AE5H; bit 1 of byte 0 marks the block as active/in-use for the write operation.
57B2
POP HL E1
Restore Register Pair HL (excess sector count saved at 57A1H). HL is now the loop counter — the number of additional sectors to read from the source.
[MAIN READ-SECTOR LOOP START] — Read one sector at a time from the source drive, handle errors, toggle the activity indicator, and decrement the counter until HL reaches 0.
57B3
GOSUB to 57C8H to read a sector from the source drive. 57C8H copies IX to DE and calls SYS0 routine 4436H. Returns Z FLAG on success (A=00H) or NZ with error code in A.
57B6
If the Z FLAG is set (read succeeded with A=00H), JUMP to 57BAH to skip the end-of-data check.
57B8
CP 06H FE 06
Compare Register A against 06H (end-of-data code). If the read returned error code 06H, this is a normal end-of-file condition, not a true error.
57BA
If the NZ FLAG is set (read returned an error other than 00H success or 06H end-of-data), GOSUB to 585AH to display the error status, increment the track count, and return Z (continue) or NZ (abort).
57BD
If the NZ FLAG is set (585AH indicated the error is non-recoverable or track was incremented and we should retry), JUMP back to 57B3H to read the next sector.
57BF
DEC HL 2B
DECrement Register Pair HL (remaining sector count) by 1.
57C0
GOSUB to 571BH to toggle the activity indicator asterisk at the top-right corner of the screen (3C3FH) and check for BREAK key.
57C3
LD A,H 7C
Copy the high byte of the remaining count from Register H to Register A.
57C4
OR L B5
OR Register A with Register L. If HL=0000H (all sectors have been read), the Z FLAG is set.
57C5
If the NZ FLAG is set (more sectors remain), JUMP back to 57B3H to read the next sector. [MAIN READ-SECTOR LOOP END]
57C7
RET C9
RETurn to caller. All requested sectors have been read successfully.
57C8H - READ SECTOR VIA SYS0 (IX→DE, CALL 4436H)
Copies the source drive parameter block pointer from IX to DE, then jumps to SYS0 routine 4436H to read a sector. This is a thin wrapper that converts the IX-based parameter passing convention to the DE-based convention expected by SYS0.
57C8
PUSH IX DD E5
Save Index Register IX (source drive parameter block pointer at 5AE5H) onto the stack.
57CA
POP DE D1
Restore the value into Register Pair DE. DE now holds the same address as IX (5AE5H). This is the standard IX→DE transfer idiom.
57CB
JUMP to SYS0 routine at 4436H to read a sector. DE points to the drive parameter block. Returns Z on success, NZ with error code in A.
57CEH - SECTOR OPERATION VIA SYS0 (IX→DE, CALL 5CEDH)
Copies IX to DE and jumps to the SYS6 internal routine at 5CEDH for a sector-level disk operation.
57CE
PUSH IX DD E5
Save Index Register IX onto the stack.
57D0
POP DE D1
Restore the value into Register Pair DE (IX→DE transfer).
57D1
JUMP to SYS6 internal routine at 5CEDH for a sector-level disk operation. DE points to the parameter block.
57D4H - WRITE SECTOR VIA SYS0 (IX→DE, CALL 443CH)
Copies IX to DE and jumps to SYS0 routine 443CH to write a sector to disk.
57D4
PUSH IX DD E5
Save Index Register IX onto the stack.
57D6
POP DE D1
Restore the value into Register Pair DE (IX→DE transfer).
57D7
JUMP to SYS0 routine at 443CH to write a sector to disk. DE points to the drive parameter block.
57DAH - FORMAT/COPY STATUS DISPLAY
Displays a multi-line status message showing the current FORMAT or COPY operation progress. Saves all registers, outputs a carriage return, displays the operation label from 59D3H (e.g., "FORMAT" or "COPY"), then selects a mode-specific label based on bits 5 and 6 of Register B (loaded from the self-modifying byte at 57EBH). Displays the track count (either destination from 5B21H or source from 5AEFH depending on bit 7 of B), a separator string, and the formatted decimal sector count via 5909H. Then checks if a source filespec was parsed (5996H bit 2) and either returns via 521EH or displays the source disk label and restores the drive configuration.
57DA
PUSH HL E5
Save Register Pair HL onto the stack.
57DB
PUSH DE D5
Save Register Pair DE onto the stack.
57DC
PUSH BC C5
Save Register Pair BC onto the stack.
57DD
PUSH AF F5
Save Register A and flags onto the stack.
57DE
GOSUB to 5881H to output a carriage return character (0DH) to the screen. This moves the cursor to the start of the next line.
57E1
LD HL,59D3H 21 D3 59
Point Register Pair HL to 59D3H, the operation label message string (e.g., "FORMAT " or "COPY ").
57E4
GOSUB to SYS0 routine at 4467H to display the null-terminated string at (HL).
57E7
LD HL,5A67H 21 67 5A
Point Register Pair HL to 5A67H, the default mode label message (first of three possible mode labels).
57EA
LD B,00H 06 00
Load Register B with 00H. [SELF-MODIFYING CODE] — the operand byte at 57EBH is overwritten by 578AH (with 20H for write mode), 529DH and others to control which status labels are displayed. The value in B selects the display mode: bit 5 = FORMAT label, bit 6 = COPY label, bit 7 = source track count.
57EC
BIT 6,B CB 70
Test bit 6 of Register B (from 57EBH). Bit 6 set selects the COPY mode label at 5A70H.
57EE
If the Z FLAG is set (bit 6 clear, not COPY mode), JUMP to 57F3H to check for FORMAT mode.
57F0
LD HL,5A70H 21 70 5A
Point Register Pair HL to 5A70H, the COPY mode label message string.
57F3
BIT 5,B CB 68
Test bit 5 of Register B. Bit 5 set selects the FORMAT mode label at 5A79H.
57F5
If the Z FLAG is set (bit 5 clear, not FORMAT mode), JUMP to 57FAH to display whichever label HL currently points to.
57F7
LD HL,5A79H 21 79 5A
Point Register Pair HL to 5A79H, the FORMAT mode label message string.
57FA
GOSUB to SYS0 routine at 4467H to display the selected mode label string.
57FD
LD HL,5A44H 21 44 5A
Point Register Pair HL to 5A44H, the default track count label string (e.g., " TRACK ").
5800
LD DE,(5B21H) ED 5B 21 5B
Fetch the destination sector count from 5B21H into Register Pair DE. This is the default count to display.
5804
BIT 7,B CB 78
Test bit 7 of Register B. Bit 7 set means display the source track count instead of the destination count.
5806
If the Z FLAG is set (bit 7 clear, use destination count), JUMP to 580FH.
5808
LD HL,5A3CH 21 3C 5A
Point Register Pair HL to 5A3CH, the source track count label string.
580B
LD DE,(5AEFH) ED 5B EF 5A
Fetch the source track count from 5AEFH (offset +0AH of the source parameter block at 5AE5H) into Register Pair DE.
580F
GOSUB to SYS0 routine at 4467H to display the track label string.
5812
LD HL,5A5FH 21 5F 5A
Point Register Pair HL to 5A5FH, a separator or suffix string displayed after the track label.
5815
GOSUB to SYS0 routine at 4467H to display the separator string.
5818
GOSUB to 5909H to format and display the sector count in DE as a decimal number.
581B
GOSUB to 5881H to output a carriage return.
Status line complete. Now check whether a source filespec was parsed. If so, return via the alternate exit at 521EH. Otherwise, display the source disk label and restore the drive configuration.
581E
LD A,(5996H) 3A 96 59
Fetch option flags byte 3 from 5996H into Register A. Bit 2 indicates whether a source filespec was parsed.
5821
BIT 2,A CB 57
Test bit 2 of Register A. If set, a source filespec was parsed and the status display should exit via the alternate path.
5823
If the NZ FLAG is set (source filespec was parsed), JUMP to 521EH to exit through the alternate cleanup/return path.
5826
GOSUB to 5868H to conditionally display the source disk label. 5868H checks 5869H for a non-zero flag and displays the drive info message from 59E0H if set.
5829
POP BC C1
Restore Register Pair BC from the stack (originally saved at 57DCH). Note: AF was pushed last at 57DDH but is NOT popped here — the previous POP is consumed as part of the drive restoration sequence below.
Restore the drive configuration that was active before the status display. This ensures the correct drive is selected for the next disk operation.
582A
LD HL,(593EH) 2A 3E 59
Fetch the current drive parameter pointer from 593EH into Register Pair HL. This points to whichever drive parameter block (5942H/594CH/5956H) was active before the display routine was called.
582D
LD A,(4288H) 3A 88 42
Fetch the active overlay ID from (IY+08H) = 4288H into Register A. This is 08H for SYS6.
5830
LD C,A 4F
Copy the overlay ID from Register A to Register C for use by 568DH.
5831
PUSH HL E5
Save Register Pair HL (drive parameter pointer) onto the stack.
5832
PUSH BC C5
Save Register Pair BC (B=status, C=overlay ID) onto the stack.
5833
GOSUB to 5582H to set up the primary drive parameter block (loads HL=5942H, falls into 5585H for PDRIVE swap).
5836
LD A,B 78
Copy Register B (status flags from 5582H) to Register A.
5837
GOSUB to 584AH to check the batch mode flag and dispatch the error handler if needed. A contains the status code.
583A
POP BC C1
Restore Register Pair BC (B=status, C=overlay ID).
583B
POP DE D1
Restore the saved drive parameter pointer into Register Pair DE (was HL, saved at 5831H).
583C
PUSH AF F5
Save Register A (return status from 584AH) onto the stack.
583D
LD A,C 79
Copy the overlay ID from Register C to Register A.
583E
GOSUB to 568DH, the drive setup dispatcher. Register A holds the overlay ID as the function code, C=FFH is set within 568DH.
5841
EX DE,HL EB
EXchange DE and HL. HL now holds the saved drive parameter pointer.
5842
GOSUB to 5585H, the common drive setup routine with PDRIVE swap. HL points to the drive parameter block to restore.
5845
POP AF F1
Restore Register A (return status saved at 583CH).
5846
POP BC C1
Restore Register Pair BC (originally saved at 57DCH).
5847
POP DE D1
Restore Register Pair DE (originally saved at 57DBH).
5848
POP HL E1
Restore Register Pair HL (originally saved at 57DAH).
5849
RET C9
RETurn to caller. All registers restored, drive configuration reset to its previous state.
584AH - BATCH MODE ABORT CHECK
Checks the batch mode flag (5995H bit 7). If batch mode is active, jumps to the error handler at 521AH — batch mode cannot tolerate interactive prompts. If not in batch mode, OR's C0H into Register A and calls the SYS0 error handler entry at 4409H, then jumps to the post-prompt continuation at 58C8H.
584A
LD HL,5995H 21 95 59
Point Register Pair HL to 5995H, option flags byte 2.
584D
BIT 7,(HL) CB 7E
Test bit 7 of (5995H). Bit 7 is the batch mode flag.
584F
If the NZ FLAG is set (batch mode active), JUMP to the error handler at 521AH. In batch mode, any condition requiring operator interaction is treated as a fatal error.
5852
OR C0H F6 C0
OR Register A with C0H, setting bits 6 and 7 of the status code. This converts the status into a SYS0 error handler dispatch code.
5854
GOSUB to SYS0 error handler entry at 4409H with the dispatch code in A. This displays the error message and may prompt the user for action.
5857
JUMP to 58C8H to continue with the post-prompt operator confirmation logic.
585AH - READ ERROR WITH TRACK INCREMENT
Called when a sector read returns an error (not 00H and not 06H). Displays the error status via 57DAH. If the display routine indicates the user chose to continue (returns NZ), increments the source track count at (IX+0AH)/(IX+0BH) as a 16-bit value, clears A to return Z FLAG (signal to retry), and returns.
585A
GOSUB to 57DAH to display the FORMAT/COPY status message showing the current operation state and error information.
585D
RET NZ C0
If the NZ FLAG is set (the display/prompt routine indicated the user chose to abort or a fatal condition exists), RETurn to caller with NZ to signal that the error is non-recoverable.
585E
INC (IX+0AH) DD 34 0A
INCrement the low byte of the source track count at (IX+0AH) = (5AE5H+0AH) = 5AEFH. This advances past the failed track.
5861
If the NZ FLAG is set (low byte did not wrap from FFH to 00H), JUMP to 5866H to skip the high byte increment.
5863
INC (IX+0BH) DD 34 0B
INCrement the high byte of the source track count at (IX+0BH) = 5AF0H. The low byte wrapped, so carry the increment to the high byte (16-bit increment).
5866
XOR A AF
Set Register A to 00H and set the Z FLAG. This signals to the caller that the track was skipped and the operation should retry from the next track.
5867
RET C9
RETurn to caller with Z FLAG set (continue/retry signal).
5868H - CONDITIONAL SOURCE DISK LABEL DISPLAY
Checks a flag byte at 5869H (self-modifying operand). If the flag is zero, returns immediately. If non-zero, displays the source drive information message from 59E0H, calls the drive utility at 56DDH, displays the filespec name via 58A0H, outputs a carriage return, and returns with NZ flag set. The operand at 5869H is written by other routines to enable or disable this display.
5868
XOR A AF
Set Register A to 00H and clear all flags.
5869
OR 00H F6 00
OR Register A with the immediate operand at 586AH. [SELF-MODIFYING CODE] — the operand byte at 586AH is overwritten at runtime. If the byte is 00H, A remains 00H (Z FLAG set). If non-zero, A becomes non-zero (NZ FLAG set).
586B
RET Z C8
If the Z FLAG is set (flag byte is 00H, display disabled), RETurn without displaying anything.
586C
LD HL,59E0H 21 E0 59
Point Register Pair HL to 59E0H, the source drive information message string.
586F
GOSUB to SYS0 routine at 4467H to display the null-terminated string at (HL).
5872
GOSUB to 56DDH, the drive utility wrapper that calls SYS0 48F0H. This performs a drive operation (read drive info/parameters) for the source drive.
5875
GOSUB to 58A0H to display the filespec name (filename/extension) from the current buffer position.
5878
GOSUB to 5881H to output a carriage return.
587B
OR FFH F6 FF
OR Register A with FFH, setting A to FFH and the NZ FLAG. This signals that the label was displayed.
587D
RET C9
RETurn to caller with NZ FLAG set.
587EH - DISPLAY STRING AND CARRIAGE RETURN
Displays the null-terminated string at (HL) via SYS0 4467H, then falls through to 5881H to output a carriage return character.
587E
GOSUB to SYS0 routine at 4467H to display the null-terminated string pointed to by HL.
5881H - OUTPUT CARRIAGE RETURN
Loads Register A with 0DH (carriage return) and jumps to the single-character output routine at 58BDH.
5881
LD A,0DH 3E 0D
Load Register A with 0DH (ASCII carriage return character).
5883
JUMP to 58BDH to output the carriage return character to the screen via ROM routine 0033H.
5886H - DISPLAY BUFFER WITH SPACE PADDING
Displays B bytes from the buffer at (HL), replacing any non-printable characters (below 20H or at/above 80H) with spaces. This is used for displaying filenames and disk names where non-printable characters would corrupt the display. Advances HL past each byte.
[LOOP START] — Display one character at a time, filtering non-printable values to spaces.
5886
LD A,(HL) 7E
Fetch the next byte from the buffer at (HL).
5887
CP 20H FE 20
Compare Register A against 20H (ASCII space). If A < 20H (control character), the CARRY FLAG is set.
5889
INC HL 23
Advance HL to the next byte in the buffer.
588A
If the CARRY FLAG is set (character < 20H, non-printable control code), JUMP to 5890H to substitute a space.
588C
CP 80H FE 80
Compare Register A against 80H. If A >= 80H (high-bit set, non-ASCII), the NO CARRY FLAG is set.
588E
If the CARRY FLAG is set (character is in range 20H-7FH, valid printable ASCII), JUMP to 5892H to display it as-is.
5890
LD A,20H 3E 20
Load Register A with 20H (ASCII space). Replace the non-printable character with a space.
5892
GOSUB to 58BDH to output the character in Register A to the screen.
5895
DECrement B (byte count) and loop back to 5886H if not zero. [LOOP END]
5897
RET C9
RETurn to caller. All B bytes have been displayed.
5898H - DISPLAY B SPACES
Outputs B space characters to the screen. Used for padding and alignment in status displays.
[LOOP START] — Output one space per iteration.
5898
LD A,20H 3E 20
Load Register A with 20H (ASCII space).
589A
GOSUB to 58BDH to output the space character to the screen.
589D
DECrement B and loop back to 5898H if not zero. [LOOP END]
589F
RET C9
RETurn to caller. B spaces have been output.
58A0H - DISPLAY FILESPEC NAME (FILENAME/EXTENSION)
Displays a filespec in "FILENAME/EXT" format. Advances HL by 5 to skip the directory entry header, displays 8 characters (the filename) via 58B3H, then checks whether the extension is blank (first byte is 20H). If the extension is non-blank, displays a slash separator followed by 3 extension characters. The routine at 58B3H displays characters from (HL) but skips spaces (only displays non-space characters).
58A0
LD A,L 7D
Copy the low byte of the buffer pointer from Register L to Register A.
58A1
ADD 05H C6 05
ADD 05H to Register A, advancing past the 5-byte directory entry header to the start of the filename field.
58A3
LD L,A 6F
Store the adjusted offset back into Register L. HL now points to the filename field.
58A4
LD B,08H 06 08
Load Register B with 08H (8 bytes) — the length of the filename field in a NEWDOS/80 directory entry.
58A6
GOSUB to 58B3H to display the 8-byte filename, skipping any embedded spaces.
58A9
LD A,(HL) 7E
Fetch the first byte of the extension field from (HL). After displaying 8 filename bytes, HL now points to the extension.
58AA
CP 20H FE 20
Compare Register A against 20H (ASCII space). If the first extension byte is a space, the extension is blank.
58AC
LD B,03H 06 03
Load Register B with 03H (3 bytes) — the length of the extension field.
58AE
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII /). This is the filename/extension separator character.
58B0
If the NZ FLAG is set (extension is not blank — first byte was not a space), GOSUB to 58BDH to display the / separator. If the extension is blank, skip the separator.
58B3H - DISPLAY NON-SPACE CHARACTERS FROM BUFFER
Displays B characters from the buffer at (HL), but only outputs characters that are not spaces (20H). Space characters are silently skipped. This produces a compressed display of filenames/extensions with trailing spaces removed.
[LOOP START] — Process one character per iteration, output only if non-space.
58B3
LD A,(HL) 7E
Fetch the next byte from the buffer at (HL).
58B4
CP 20H FE 20
Compare Register A against 20H (ASCII space). Sets Z FLAG if the character is a space.
58B6
INC HL 23
Advance HL to the next byte.
58B7
If the NZ FLAG is set (character is not a space), GOSUB to 58BDH to output the character. Spaces are silently skipped.
58BA
DECrement B and loop back to 58B3H if not zero. [LOOP END]
58BC
RET C9
RETurn to caller.
58BDH - SINGLE CHARACTER OUTPUT
Core character output routine used by all display functions in SYS6. Saves DE and AF, calls the ROM character output routine at 0033H to display the character in Register A at the current cursor position, then restores the registers.
58BD
PUSH DE D5
Save Register Pair DE onto the stack (preserved across the ROM call).
58BE
PUSH AF F5
Save Register A and flags onto the stack.
58BF
GOSUB to ROM routine at 0033H to display the character in Register A at the current cursor position and advance the cursor.
58C2
POP AF F1
Restore Register A and flags from the stack.
58C3
POP DE D1
Restore Register Pair DE from the stack.
58C4
RET C9
RETurn to caller.
58C5H - DISPLAY STRING AND PROMPT FOR CONFIRMATION
Displays the null-terminated string at (HL) via 4467H, then falls through to the operator confirmation prompt at 58C8H. This is the entry point used when a message must be shown before prompting.
58C5
GOSUB to SYS0 routine at 4467H to display the null-terminated string at (HL).
58C8H - OPERATOR CONFIRMATION PROMPT
Checks the batch mode flag (5995H bit 7). If batch mode is active, jumps to 5249H (the directory buffer relocation routine that bypasses operator prompts). If not batch mode, displays a response menu from 5A84H via the menu scanner at 58E4H. If the user's selection is >= 01H (an affirmative response), returns with NO CARRY. If selection is 00H (abort/cancel), loads error code 39H (BREAK abort) and jumps to the error handler.
58C8
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A.
58CB
BIT 7,A CB 7F
Test bit 7 of Register A (batch mode flag).
58CD
If the NZ FLAG is set (batch mode active), JUMP to 5249H to bypass the prompt and continue with the directory buffer relocation.
58D0
LD HL,5A84H 21 84 5A
Point Register Pair HL to 5A84H, the operator response menu string (contains the menu options like "A)bort, R)etry, C)ontinue").
58D3
GOSUB to 58E4H, the menu response scanner. Returns the selection index in A (00H for first option, 01H for second, etc.) and the corresponding flags.
58D6
CP 01H FE 01
Compare Register A against 01H. If A >= 01H, the NO CARRY FLAG is set (affirmative/continue response). If A = 00H, CARRY is set (abort response).
58D8
RET NC D0
If the NO CARRY FLAG is set (user selected option 1 or higher — continue/retry), RETurn to caller.
58D9
LD A,39H 3E 39
Load Register A with 39H, the error code for BREAK key abort.
58DB
JUMP to the error handler at 521AH with error code 39H. The user chose to abort.
58DEH - ALTERNATE MENU PROMPT (5AB3H MENU)
Displays the string at (HL) via 4467H, then loads HL with 5AB3H (an alternate response menu) and falls through to the menu scanner at 58E4H. This provides a different set of menu options compared to the 58C8H prompt.
58DE
GOSUB to SYS0 routine at 4467H to display the null-terminated string at (HL).
58E1
LD HL,5AB3H 21 B3 5A
Point Register Pair HL to 5AB3H, the alternate operator response menu string.
58E4H - MENU RESPONSE SCANNER
Interactive menu display and response scanner. The menu string at (HL) contains one or more null-terminated option entries. The routine first displays all option strings (scanning past null terminators to find and display a trailing prompt string), then waits for a keypress via 572BH. It matches the pressed key against the first character of each option string, returning the 0-based index of the matched option in Register A. If no option matches, re-prompts. The matched character is echoed to the screen followed by a carriage return.
58E4
PUSH BC C5
Save Register Pair BC onto the stack.
58E5
PUSH HL E5
Save Register Pair HL (pointer to menu string base) onto the stack.
First, scan forward through all option strings to find the prompt text that follows them. Each option is null-terminated; the prompt text follows the last option's null terminator.
58E6
LD A,(HL) 7E
Fetch the next byte from the menu string.
58E7
OR A B7
Test if A is 00H (null terminator). Sets Z FLAG if end of current option string.
58E8
INC HL 23
Advance HL past this byte.
58E9
If the NZ FLAG is set (not a null terminator), JUMP back to 58E6H to continue scanning. [SCAN LOOP]
Found a null terminator. The prompt text starts here. Display it and wait for a keypress.
58EB
GOSUB to SYS0 routine at 4467H to display the prompt string starting at (HL).
58EE
GOSUB to 572BH to wait for a keypress (via ROM 002BH) and check for BREAK key. Returns the pressed character in Register A.
58F1
POP HL E1
Restore Register Pair HL (menu string base) from the stack.
58F2
LD C,FFH 0E FF
Load Register C with FFH. C will be incremented before each option test, so it starts at FFH so the first option gets index 00H.
[MATCH LOOP START] — Compare the pressed key against the first character of each option string.
58F4
PUSH HL E5
Save Register Pair HL (current position in menu string) onto the stack for potential re-prompt.
58F5
INC (HL) 34
INCrement the byte at (HL). This tests if the byte is FFH (which would wrap to 00H and set Z). The INC/DEC pair is a non-destructive test for the end-of-options sentinel (FFH or 00H after the last option).
58F6
INC C 0C
INCrement Register C (option index counter). First iteration: C goes from FFH to 00H.
58F7
DEC (HL) 35
DECrement the byte at (HL) back to its original value (undoing the INC at 58F5H).
58F8
If the Z FLAG is set (the byte at (HL) was 00H — end of options sentinel), JUMP back to 58EEH to re-prompt. The pressed key did not match any option.
58FA
CP (HL) BE
Compare Register A (the pressed key) against the first character of the current option string at (HL).
58FB
INC HL 23
Advance HL past this character.
58FC
If the NZ FLAG is set (key does not match this option's first character), JUMP to 58F5H to advance past this option string and check the next one. [MATCH LOOP continues]
[MATCH FOUND] — The pressed key matches the current option. Echo the key, output a carriage return, and return the option index.
58FE
GOSUB to 58BDH to echo the matched character to the screen.
5901
GOSUB to 5881H to output a carriage return after the echoed character.
5904
LD A,C 79
Copy the option index from Register C to Register A. A=00H for first option, 01H for second, etc.
5905
OR A B7
OR Register A with itself. Sets Z FLAG if A=00H (first option), NZ if any other option.
5906
POP HL E1
Restore Register Pair HL from the stack (clean up the PUSH at 58F4H).
5907
POP BC C1
Restore Register Pair BC from the stack (saved at 58E4H).
5908
RET C9
RETurn to caller. Register A holds the 0-based option index. Z FLAG set if first option (abort), NZ if any other option.
5909H - DECIMAL NUMBER FORMATTER
Converts the 16-bit value in DE into a decimal ASCII string and displays it. Uses a table of four 16-bit divisor constants at 5933H (64,000; 6,400; 256; -1) for successive division. The algorithm repeatedly subtracts each divisor from the value, counting iterations to determine each digit. Leading zeros are suppressed except for the final (ones) digit. Register B controls the number of divisor iterations (4 digits plus the ones remainder), and Register C acts as the leading-zero suppression flag (0 = still suppressing, non-zero = digit has been output).
5909
LD BC,0400H 01 00 04
Load Register Pair BC: B=04H (4 divisor table entries to process), C=00H (leading-zero suppression flag, 0 = suppress).
590C
LD HL,5933H 21 33 59
Point Register Pair HL to 5933H, the base of the divisor constant table. The table contains four 16-bit values: F0D8H (61,656 — see note), 1918H (6,424), 00FCH (252), FFFFF6H... The values are adjusted divisors that account for the +2FH starting point of the digit counter.
[OUTER LOOP START] — Process one divisor per iteration to extract one decimal digit.
590F
PUSH BC C5
Save Register Pair BC (B=remaining divisors, C=leading-zero flag) onto the stack.
5910
LD C,(HL) 4E
Fetch the low byte of the current divisor from (HL) into Register C.
5911
INC HL 23
Advance HL to the high byte of the divisor.
5912
LD B,(HL) 46
Fetch the high byte of the current divisor into Register B. BC now holds the 16-bit divisor.
5913
INC HL 23
Advance HL to the next divisor entry (for the next iteration).
5914
EX DE,HL EB
EXchange DE and HL. HL now holds the value being converted (was in DE); DE holds the table pointer (saved for later).
5915
LD A,2FH 3E 2F
Load Register A with 2FH (one less than ASCII 0). This is the digit counter starting point — it will be incremented to 30H (0) on the first iteration of the division loop.
[DIVISION LOOP START] — Repeatedly subtract the divisor (BC) from the value (HL), counting how many times it fits.
5917
INC A 3C
INCrement Register A (digit counter). First iteration: A goes from 2FH to 30H (ASCII 0).
5918
ADD HL,BC 09
ADD BC (divisor) to HL. Note: the divisors in the table are stored as NEGATIVE values (two's complement), so ADD HL,BC is effectively subtracting the absolute divisor from HL.
5919
If the CARRY FLAG is set (the addition overflowed, meaning the negative divisor subtraction did NOT underflow — HL is still >= 0), JUMP back to 5917H to subtract again and increment the digit. [DIVISION LOOP END]
591B
SBC HL,BC ED 42
SUBtract BC from HL with borrow. This adds back the absolute divisor value (since BC is negative, SBC with carry effectively restores HL to the remainder before the last over-subtraction).
591D
POP BC C1
Restore Register Pair BC (B=remaining divisors, C=leading-zero flag).
591E
EX DE,HL EB
EXchange DE and HL. DE now holds the remainder (for the next digit), HL holds the table pointer.
Check for leading zero suppression. If this digit is 0 (ASCII 30H) and no non-zero digit has been output yet (C=0), suppress it.
591F
CP 30H FE 30
Compare Register A against 30H (ASCII 0). If this digit is zero, Z FLAG is set.
5921
If the NZ FLAG is set (digit is not zero), JUMP to 5927H to output it unconditionally.
5923
INC C 0C
INCrement Register C (leading-zero flag) by 1 to test if it was zero.
5924
DEC C 0D
DECrement Register C back to its original value. If C was 00H, the Z FLAG is set (still in leading-zero suppression mode).
5925
If the Z FLAG is set (C=00H, still suppressing leading zeros and this digit is zero), JUMP to 592BH to skip outputting this digit.
5927
INC C 0C
INCrement Register C to mark that a non-zero digit has been output. C > 0 means leading zeros are no longer suppressed.
5928
GOSUB to 58BDH to output the digit character in Register A to the screen.
592B
DECrement B (remaining divisors) and loop back to 590FH if not zero. [OUTER LOOP END]
All four divisor digits have been processed. Output the ones digit (the final remainder in E) directly.
592D
LD A,E 7B
Copy the ones remainder from Register E to Register A.
592E
ADD 30H C6 30
ADD 30H to Register A to convert the binary value (0-9) to its ASCII digit character (0-9).
5930
JUMP to 58BDH to output the ones digit and return to the caller of 5909H.
5933H - DECIMAL DIVISOR CONSTANT TABLE
Four 16-bit values used as negative divisors by the decimal number formatter at 5909H. The values are stored in two's complement (negative) form so the division loop can use ADD HL,BC instead of SBC HL,BC. The four divisors correspond to the ten-thousands, thousands, hundreds, and tens places of a 5-digit decimal number (max 65535).
5933
DEFB F0H,D8H F0 D8
D8F0H = -10000 (two's complement of 2710H). Ten-thousands place divisor. Stored little-endian: F0H (low), D8H (high).
5935
DEFB 18H,FCH 18 FC
FC18H = -1000 (two's complement of 03E8H). Thousands place divisor. Stored little-endian: 18H (low), FCH (high).
5937
DEFB 9CH,FFH 9C FF
FF9CH = -100 (two's complement of 0064H). Hundreds place divisor. Stored little-endian: 9CH (low), FFH (high).
5939
DEFB F6H,FFH F6 FF
FFF6H = -10 (two's complement of 000AH). Tens place divisor. Stored little-endian: F6H (low), FFH (high).
593BH - SYS6 WORK AREA VARIABLES (593BH-5960H+)
Data area containing the SYS6 runtime work variables. These bytes are not executable code — the disassembler incorrectly interprets them as instructions. This area includes the disk operation state flags, the saved high memory limit, the current drive parameter pointer, the mode flags, and the three 10-byte drive parameter blocks (primary at 5942H, source at 594CH, destination at 5956H). The contents shown reflect their state at the time of the disassembly dump and are overwritten at runtime.
593B
DEFB 00H 00
593BH: Disk operation state flags. Bit 7: drive parameter blocks initialized.
593C
DEFB FFH FF
593CH: Saved high memory limit (low byte). Used for FORMAT only. FFH = not set / default.
593D
DEFB 6FH 6F
593DH: Saved high memory limit (high byte). With 593CH = FF6FH as the initial value.
593E
DEFB 42H,59H 42 59
593EH: Current drive parameter pointer (16-bit, little-endian). Value 5942H points to the primary drive parameter block.
5940
DEFB 00H 00
5940H: Operation mode flags (low byte). Bit 0: "$" system track copy; bit 1: source=dest same drive; bit 2: destination=drive 0.
5941
DEFB 07H 07
5941H: Operation mode flags (high byte). Bit 0: disk swapping required; other bits: per-drive swap completion flags.
Primary drive parameter block (10 bytes at 5942H-594BH):
5942
DEFB 00H 00
5942H: Primary drive number (00H-03H, or FFH=unassigned). Currently drive 0.
5943
DEFB 01H,00H,00H 01 00 00
5943H-5945H: Primary parameter bytes 1-3.
5946
DEFB 99H,59H 99 59
5946H: Primary geometry data pointer (low, high). Value 5999H.
5948
DEFB 99H,59H 99 59
5948H: Primary geometry data pointer 2 (low, high). Value 5999H.
594A
DEFB 51H,5AH 51 5A
594AH: Primary buffer pointer (low, high). Value 5A51H.
Source drive parameter block (10 bytes at 594CH-5955H):
594C
DEFB FFH FF
594CH: Source drive number. FFH = no source drive assigned.
594D
DEFB 02H 02
594DH: Source parameter byte 1.
594E
DEFB E5H,5AH E5 5A
594EH: Source related pointer (low, high). Value 5AE5H (source drive parameter block base).
5950
DEFB B7H,59H B7 59
5950H: Source geometry pointer. Value 59B7H.
5952
DEFB A3H,59H A3 59
5952H: Source geometry pointer 2. Value 59A3H.
5954
DEFB 3CH,5AH 3C 5A
5954H: Source buffer pointer. Value 5A3CH.
Destination drive parameter block (10 bytes at 5956H-595FH):
5956
DEFB FFH FF
5956H: Destination drive number. FFH = no destination drive assigned.
5957
DEFB 04H 04
5957H: Destination parameter byte 1.
5958
DEFB 17H,5BH 17 5B
5958H: Destination related pointer. Value 5B17H (destination drive parameter block base).
595A
DEFB C1H,59H C1 59
595AH: Destination geometry pointer. Value 59C1H.
595C
DEFB ADH,59H AD 59
595CH: Destination geometry pointer 2. Value 59ADH.
595E
DEFB 44H,5AH 44 5A
595EH: Destination buffer pointer. Value 5A44H.
5960H - WORK AREA: BUFFER SPACE AND OPTION FLAGS (5960H-5993H)
Continuation of the SYS6 runtime work area. Addresses 5960H-5977H contain a 24-byte buffer pre-filled with spaces (20H) that holds the disk name entered by the user or read from the source disk. This is followed by zero-filled work bytes and the date/version stamp at 5981H. The ASCII text "BNOTNAMED2:/4:/:" starting at 5982H is the default disk name template with embedded date separators. The option flags bytes at 5994H-5997H control all FORMAT/COPY operational modes. All data shown reflects the initial state captured in the disassembly dump.
5960
DEFM " "
5960H-5977H (24 bytes): Disk name buffer, initialized to 24 ASCII space characters (20H). Used to store disk names for the NDN=/ODN=/SN= options. The display routines at 5886H filter these for screen output.
5978
DEFB 00H,00H,00H,00H 00 00 00 00
5978H-597BH (4 bytes): Work area scratch bytes, cleared to zero.
597C
DEFB 08H,08H 08 08
597CH-597DH: Disk name field lengths. Both set to 08H (8 bytes each). The disk name in a NEWDOS/80 boot sector consists of two 8-byte fields (name + extension) for a total of 16 characters.
597E
DEFB 82H 82
597EH: Configuration control byte. 82H = bit 7 set (active) + bit 1 set (write mode).
597F
DEFB 00H,00H 00 00
597FH-5980H: Reserved work area bytes.
5981
DEFB E0H E0
5981H: Date/version stamp value. E0H is written to the GAT date field via 43CEH during FORMAT/COPY post-processing.
The following 18 bytes at 5982H-5993H contain the default disk name "BNOTNAMED" followed by a date template "2:/4:/:" with a carriage return terminator. This is the name written to the boot sector when no NDN= option overrides it.
5982
DEFM "BNOTNAMED"
5982H-598AH (9 bytes): Default disk name string. The leading "B" is a type marker; "NOTNAMED" is the default 8-character disk name used when no name is specified by the user.
598B
DEFM "2:/4:/:"
598BH-5991H (7 bytes): Default date template in "M:/D:/Y" format. "2" = month, "/" = separator, "4" = day, "/" = separator, ":" = year placeholder. These are the default values before the actual date is filled in.
5992
DEFB 3AH,0DH,00H 3A 0D 00
5992H-5994H: End of date string: colon (3AH), carriage return (0DH), and a null terminator (00H). Note: the null at 5994H is also the start of the option flags area — it serves double duty as the string terminator and the initial value of option flags byte 1.
5994
DEFB 00H 00
5994H: Option flags byte 1. Bit 0: verify; bit 1: source!=dest; bit 2: KDD; bit 3: KDN; bit 6: default backup (whole-disk); bit 7: no-prompt. Initialized to 00H.
5995
DEFB 00H 00
5995H: Option flags byte 2. Bit 0: copy sub-mode; bit 5: FORMAT/date stamp; bit 7: batch mode. Initialized to 00H.
5996
DEFB 00H 00
5996H: Option flags byte 3 (mode flags). Bit 2: source filespec parsed; bit 3: dest filespec parsed; bit 5: FORMAT mode. Initialized to 00H.
5997
DEFB 00H 00
5997H: Option flags byte 4. Bit 3: dest filespec parsed; bit 6: suppress DEST prompt; bit 7: suppress SOURCE prompt. Initialized to 00H.
5998H - WORK AREA: DRIVE GEOMETRY BUFFERS (5998H-59D2H)
Two sets of drive geometry parameter buffers, each holding 10 bytes of drive configuration data copied from the PDRIVE table via the swap routines at 5658H. The source geometry block runs from 59A3H-59ACH and the destination geometry block from 59ADH-59B6H, with additional configuration fields and pointers preceding and following them. All bytes are initialized to 00H at load time and filled at runtime when the drives are selected.
5998
DEFB 00H 00
5998H: Work area byte (zero-initialized).
5999
DEFB 00H,00H,00H
00H,00H,00H
00H,00H,00H
00H 00 00 00 00 00 00 00 00 00 00
5999H-59A2H (10 bytes): Primary drive geometry buffer. Receives PDRIVE table data via the LDIR copy at 5679H. The primary drive parameter block at 5942H references this area at offset +04/+06.
59A3
DEFB 00H,00H
00H,00H,00H
00H,00H,00H
00H,00H 00 00 00 00 00 00 00 00 00 00
59A3H-59ACH (10 bytes): Source drive geometry buffer. The source drive parameter block at 594CH references this via its geometry pointers at 5950H/5952H.
59AD
DEFB 00H,00H
00H,00H,00H
00H,00H,00H
00H,00H 00 00 00 00 00 00 00 00 00 00
59ADH-59B6H (10 bytes): Destination drive geometry buffer. The destination drive parameter block at 5956H references this via its geometry pointers at 595AH/595CH.
59B7
DEFB 00H,00H
00H,00H,00H 00 00 00 00 00
59B7H-59BBH (5 bytes): Source drive geometry parameter block base. Additional configuration fields beyond the 10-byte PDRIVE copy.
59BC
DEFB 00H 00
59BCH: GAT configuration parameter — sectors per granule multiplier for the current disk geometry.
59BD
DEFB 00H,00H,00H,00H 00 00 00 00
59BDH-59C0H (4 bytes): Additional source configuration fields.
59C1
DEFB 00H,00H 00 00
59C1H-59C2H: Destination drive geometry/config pointer (16-bit). Loaded with the address of the destination drive's active PDRIVE entry.
59C3
DEFB 00H,00H 00 00
59C3H-59C4H: Destination disk total track/size count (16-bit).
59C5
DEFB 00H 00
59C5H: Drive geometry copy destination field.
59C6
DEFB 00H 00
59C6H: Destination disk total track count (used for GAT boundary check at 575BH).
59C7
DEFB 00H,00H,00H 00 00 00
59C7H-59C9H: Additional destination configuration fields.
59CA
DEFB 00H 00
59CAH: Sectors-per-GAT-byte value — number of granule bits per GAT byte for the current disk geometry. Used by the GAT bit-clearing loop at 577CH.
59CB
DEFB 00H,00H,00H,00H 00 00 00 00
59CBH-59CEH: Additional drive geometry fields.
59CF
DEFB 00H,00H 00 00
59CFH-59D0H: Total destination disk capacity (sector count, 16-bit). Compared against the requested count at 579DH.
59D1
DEFB 00H,00H 00 00
59D1H-59D2H: Source disk total track/size count (16-bit).
59D3H - MESSAGE STRINGS: OPERATION LABELS AND PROMPTS (59D3H-5AE4H)
All ASCII message strings used by SYS6 for screen display during FORMAT, COPY, and APPEND operations. Strings are terminated with either 03H (ETX, used by the 4467H display routine as an alternate terminator), 0DH (carriage return), or 00H (null). The disassembler misinterprets all of these as Z80 instructions. Each entry is documented with its address, ASCII text, and purpose.
59D3
DEFM "ERROR WHILE "
59D3H-59DEH (12 bytes): Error message prefix. Displayed by 57DAH before the mode-specific label. Terminated by 03H at 59DEH.
59DF
DEFB 03H 03
ETX terminator for the "ERROR WHILE " string.
59E0
DEFM "WITHIN FILE "
59E0H-59ECH (13 bytes): Source drive information message. Displayed by 5868H when the source disk label display is enabled. Two trailing spaces pad the message. Terminated by 03H at 59EDH.
59ED
DEFB 03H 03
ETX terminator for the "WITHIN FILE " string.
59EE
DEFM "PRESS "
59EEH-59F3H (6 bytes): First part of the disk swap prompt message. Continued at 59F4H.
59F4
DEFM "\"ENTER\" WHEN "
59F4H-5A00H (13 bytes): Second part of swap prompt. The quote characters (22H) surround "ENTER" for emphasis. Terminated by 03H at 5A01H.
5A01
DEFB 03H 03
ETX terminator for "PRESS \"ENTER\" WHEN ".
5A02
DEFM " DISKETTE MOUNTED ON DRIVE "
5A02H-5A1DH (28 bytes): Third part of swap prompt. The drive number digit is patched into the byte at 5A1DH at runtime.
5A1D
DEFB 30H 30
5A1DH: Drive number digit position. Contains ASCII 0 (30H) initially. Overwritten at runtime with the actual drive number digit (30H-33H for drives 0-3).
5A1E
DEFB 0DH 0D
Carriage return terminator for the swap prompt.
5A1F
DEFM "DONE"
5A1FH-5A22H (4 bytes): Completion message displayed after a successful operation.
5A23
DEFB 0DH 0D
Carriage return terminator for "DONE".
5A24
DEFM "SOURCE & DEST SAME FILE"
5A24H-5A3BH (24 bytes): Warning displayed when the source and destination filespecs resolve to the same file on the same drive. Terminated by 0DH at 5A3BH.
5A3B
DEFB 0DH 0D
Carriage return terminator.
5A3C
DEFM "SOURCE"
5A3CH-5A41H (6 bytes): Source track count label. Displayed by 57DAH when bit 7 of the mode byte is set. Terminated by 03H at 5A42H.
5A42
DEFB 03H 03
ETX terminator.
5A43
DEFB 03H 03
Additional ETX (marks end of an alternate string variant that includes just the terminator).
5A44
DEFM "DESTINATION"
5A44H-5A4EH (11 bytes): Destination track count label. Displayed by 57DAH when bit 7 of the mode byte is clear. Terminated by 03H at 5A50H.
5A4F
DEFB 03H 03
ETX terminator.
5A50
DEFB 03H 03
Additional ETX terminator.
5A51
DEFM "** SYSTEM **"
5A51H-5A5CH (12 bytes): System disk identifier message displayed during system track operations. Terminated by 03H at 5A5EH.
5A5D
DEFB 03H 03
ETX terminator.
5A5E
DEFB 03H 03
Additional ETX terminator.
5A5F
DEFM "SECTOR"
5A5FH-5A64H (6 bytes): Separator string "SECTOR" displayed between the track label and the decimal count in the status display at 5812H. Terminated by 03H at 5A66H.
5A65
DEFB 03H 03
ETX terminator.
5A66
DEFB 03H 03
Additional ETX terminator.
5A67
DEFM "READING"
5A67H-5A6DH (7 bytes): Default mode label displayed by 57DAH. Terminated by 03H at 5A6FH.
5A6E
DEFB 03H 03
ETX terminator.
5A6F
DEFB 03H 03
Additional ETX terminator.
5A70
DEFM "WRITING"
5A70H-5A76H (7 bytes): COPY mode label selected when bit 6 of the mode byte is set. Terminated by 03H at 5A78H.
5A77
DEFB 03H 03
ETX terminator.
5A78
DEFB 03H 03
Additional ETX terminator.
5A79
DEFM "VERIFYING"
5A79H-5A81H (9 bytes): FORMAT/verify mode label selected when bit 5 of the mode byte is set. Terminated by 03H at 5A83H.
5A82
DEFB 03H 03
ETX terminator.
5A83
DEFB 03H 03
Additional ETX terminator.
Operator response menu strings follow. Each menu is a sequence of option keywords (each terminated by 00H), followed by the prompt text. The menu scanner at 58E4H matches the user's keypress against the first character of each option.
5A84
DEFM "C"
5A84H: First option keyword: C (Continue/Copy). Represents option index 0 for the menu at 5A84H.
5A85
DEFM "PR"
5A85H-5A86H: Padding or alternate first option characters.
5A87
DEFB 00H 00
Null terminator for the first option.
5A88
DEFM "REPLY C (CANCEL), R (RETRY) OR P (PROCEED)"
5A88H-5AB2H (43 bytes): Prompt text displayed after all option keywords. The user presses C, R, or P to select the corresponding action. Terminated by 0DH at 5AB2H.
5AB2
DEFB 0DH 0D
Carriage return terminator for the prompt text.
5AB3
DEFM "NY"
5AB3H-5AB4H: Alternate menu first option: N (No).
5AB5
DEFB 00H 00
Null terminator for "N" option.
5AB6
DEFM " (Y OR N)"
5AB6H-5ABFH (10 bytes): Alternate menu prompt text. Terminated by 03H at 5AC1H.
5AC0
DEFB 03H 03
ETX terminator.
5AC1
DEFB 03H 03
Additional ETX terminator.
5AC2
DEFM "DISKETTE/GAT OVERFLOW"
5AC2H-5AD6H (21 bytes): Error message displayed when the GAT allocation table overflows during a copy operation. Terminated by 0DH at 5AD7H.
5AD7
DEFB 0DH 0D
Carriage return terminator.
5AD8
DEFM "DISK FULL - "
5AD8H-5AE3H (12 bytes): Error message prefix for disk full conditions. Terminated by 03H at 5AE4H. Additional context is appended by the caller.
5AE4
DEFB 03H 03
ETX terminator for "DISK FULL - ".
5AE5H - SOURCE DRIVE PARAMETER BLOCK (5AE5H-5B16H)
The 50-byte source drive parameter block referenced by IX throughout SYS6. This block is initialized at runtime when the source drive is selected via 56A2H/56BCH. The first few bytes contain status flags and buffer pointers; the remainder holds drive geometry data, track counts, and sector buffer addresses. Fields at offsets +0AH/+0BH are the track count (incremented by 585EH on read errors). Most bytes are FFH (uninitialized/unused) in the dump.
5AE5
DEFB 82H 82
5AE5H (IX+00H): Status/control flags. 82H = bit 7 set (block active) + bit 1 set (write enabled). Bit 1 is SET at 57AEH during the write setup.
5AE6
DEFB 20H,00H 20 00
5AE6H-5AE7H (IX+01H/02H): Parameter bytes. 20H at IX+01 may reflect the write mode code stored to 57EBH.
5AE8
DEFB 00H,43H,00H 00 43 00
5AE8H-5AEAH (IX+03H/04H/05H): Source buffer address field. 4300H at IX+04/03 is the DOS work area buffer address (stored by 5796H to 5B1AH for destination; similar value here for source).
5AEB
DEFB 00H 00
5AEBH (IX+06H): Source drive number (00H-03H). Compared against destination at 5B1DH by RST 18H for same-disk detection.
5AEC
DEFB FFH FF
5AECH (IX+07H): Source parameter byte.
5AED
DEFB 00H 00
5AEDH (IX+08H): Source parameter byte 2.
5AEE
DEFB 00H 00
5AEEH (IX+09H): Additional parameter.
5AEF
DEFB 00H,00H 00 00
5AEFH-5AF0H (IX+0AH/0BH): Source track count (16-bit, little-endian). Incremented by 585EH/5863H on read errors. Read by 580BH for status display.
5AF1
DEFB 5EH,01H 5E 01
5AF1H-5AF2H (IX+0CH/0DH): Source track count/position field. 015EH = 350 decimal.
5AF3
DEFB 00H,1FH 00 1F
5AF3H-5AF4H (IX+0EH/0FH): Additional source fields.
5AF5
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5AF5H-5AFCH (IX+10H through IX+17H): Uninitialized source parameter block space (8 bytes of FFH).
5AFD
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5AFDH-5B04H (IX+18H through IX+1FH): Uninitialized (8 bytes of FFH).
5B05
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5B05H-5B0CH (IX+20H through IX+27H): Uninitialized (8 bytes of FFH).
5B0D
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH
FFH,FFH FF FF FF FF FF FF FF FF FF FF
5B0DH-5B16H (IX+28H through IX+31H): Uninitialized (10 bytes of FFH). End of the 50-byte source parameter block.
5B17H - DESTINATION DRIVE PARAMETER BLOCK (5B17H-5B48H)
The 50-byte destination drive parameter block. Same layout as the source block at 5AE5H but used for the destination drive. Key fields: offset +06H (5B1DH) holds the destination drive number, offset +04H/03H (5B1AH) holds the buffer pointer (set to 4300H by 5796H), offset +08H/09H (5B1FH/5B20H) are parameter bytes, and offset +0AH/0BH (5B21H/5B22H) hold the destination sector count (stored by 578FH).
5B17
DEFB 82H,60H,00H 82 60 00
5B17H-5B19H: Destination control flags and parameters. 82H = active + write mode, 60H = parameter byte.
5B1A
DEFB 00H,00H,00H 00 00 00
5B1AH-5B1CH: Destination buffer address field. Written by 5796H with 4300H. Currently 0000H in the dump.
5B1D
DEFB 00H 00
5B1DH (+06H): Destination drive number. Compared against source at 5AEBH for same-disk detection.
5B1E
DEFB FFH FF
5B1EH (+07H): Destination parameter byte.
5B1F
DEFB 00H,00H 00 00
5B1FH-5B20H (+08H/+09H): Destination parameter fields.
5B21
DEFB 00H,00H 00 00
5B21H-5B22H (+0AH/+0BH): Destination sector count (16-bit). Written by 578FH. Read by 5800H for status display.
5B23
DEFB FFH,FFH FF FF
5B23H-5B24H (+0CH/+0DH): Destination parameter field 2. Set to FFFFH by 57ABH as the "unset" sentinel.
5B25
DEFB 00H,1FH 00 1F
5B25H-5B26H (+0EH/+0FH): Additional destination fields.
5B27
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5B27H-5B2EH (+10H through +17H): Uninitialized destination parameter space (8 bytes of FFH).
5B2F
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5B2FH-5B36H (+18H through +1FH): Uninitialized (8 bytes of FFH).
5B37
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH FF FF FF FF FF FF FF FF
5B37H-5B3EH (+20H through +27H): Uninitialized (8 bytes of FFH).
5B3F
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH
FFH,FFH FF FF FF FF FF FF FF FF FF FF
5B3FH-5B48H (+28H through +31H): Uninitialized (10 bytes of FFH). End of the 50-byte destination parameter block.
5B49H - THIRD DRIVE PARAMETER BLOCK (5B49H-5B56H)
A partial third drive parameter block. Only the first 14 bytes are visible before the linked list area begins at 5B57H. This block is used for the alternate/swap drive during three-drive operations or as scratch space during drive configuration.
5B49
DEFB 82H,60H,00H 82 60 00
5B49H-5B4BH: Third block control flags. Same pattern as the destination block (82H, 60H).
5B4C
DEFB 00H,43H,00H 00 43 00
5B4CH-5B4EH: Third block buffer pointer field. 4300H.
5B4F
DEFB 00H,FFH 00 FF
5B4FH-5B50H: Drive number (00H) and parameter byte (FFH).
5B51
DEFB 00H,00H
00H,00H,FFH,FFH 00 00 00 00 FF FF
5B51H-5B56H: Remaining fields and uninitialized bytes.
5B57H - DRIVE PARAMETER LINKED LIST (5B57H-5B63H)
The linked list of drive parameter swap entries used by the PDRIVE swap routine at 5585H. Each entry is a 4-byte record: byte 0 = entry type (00H-01H = basic, >= 02H = overlay-specific with overlay ID), byte 1 = mode flags, bytes 2-3 = pointer to the next entry or swap data block. The list is terminated when byte 0 of an entry is 00H. Three entries are visible here.
5B57
DEFB 02H,00H 02 00
5B57H-5B58H: Entry 1 — type=02H (overlay-specific, requires overlay ID 02H), mode=00H.
5B59
DEFB 64H,5BH 64 5B
5B59H-5B5AH: Entry 1 pointer → 5B64H (start of the sector processing table, which contains the swap data blocks).
5B5B
DEFB 04H,00H 04 00
5B5BH-5B5CH: Entry 2 — type=04H (overlay-specific, requires overlay ID 04H), mode=00H.
5B5D
DEFB A3H,5BH A3 5B
5B5DH-5B5EH: Entry 2 pointer → 5BA3H.
5B5F
DEFB 05H,00H 05 00
5B5FH-5B60H: Entry 3 — type=05H (overlay-specific, requires overlay ID 05H), mode=00H.
5B61
DEFB E1H,5BH E1 5B
5B61H-5B62H: Entry 3 pointer → 5BE1H.
5B63
DEFB 00H 00
5B63H: End-of-list sentinel (type=00H). The linked list traversal at 55FBH stops when it encounters this byte.
5B64H - SWAP DATA BLOCK 1 (OVERLAY 02H — SOURCE DRIVE)
Structured swap data block for overlay 02H. This is a DATA area — the bytes here are not Z80 instructions but a compact record format used by the PDRIVE parameter swap routine at 5658H. The linked list entry at 5B57H (overlay 02H) points here. The format is: one byte = byte count to copy, followed by that many data bytes representing the source PDRIVE parameters, followed by a 16-bit pointer to the next swap block (00 00H = end of chain). When the swap routine processes this block it exchanges these bytes with the live PDRIVE table in the DOS work area, so that the source drive geometry is correctly reflected for FORMAT/COPY operations involving overlay 02H.
5B64
[DATA] E8 45 01 A8 EC
[DATA — Swap Block 1, Overlay 02H] Byte count = E8H (232 decimal). This is not executable code. The bytes that follow are raw PDRIVE geometry and configuration parameters for the source drive (drive numbers, step rates, sector sizes, track counts, etc.) that will be copied into the PDRIVE table entry by the swap routine at 5658H. The disassembler has misread these bytes as Z80 instructions throughout this block.
The swap block data continues through 5BA1H. All bytes from 5B64H to 5BA2H inclusive are DATA. The two NOP bytes at 5BA1H–5BA2H (00H 00H) serve as the end-of-chain pointer (16-bit address 0000H), signalling that there are no further swap sub-blocks after this one.
5B69
[DATA] 45 01 A9 E7 46 03
[DATA] Continuation of swap block parameter bytes. These values configure source drive geometry: sectors per track, density flags, step rate, and buffer pointers.
5B6F
[DATA] C3 0B 5C
[DATA] The disassembler decodes C3 0B 5C as JP 5C0BH — this is a coincidence of the byte pattern within the swap data block. These three bytes are data, not a jump instruction.
5B72
[DATA] DC 47 01 0D 1C 48 03 C3 3E 5C
[DATA] Continuation of swap block data bytes.
5B7C
[DATA] 37 48 03 C3 43 5C
[DATA] Continuation.
5B82
[DATA] 93 48 01 00 99 48 01 01 DD 48 03 C3 1E 5C
[DATA] Continuation of source drive swap block.
5B90
[DATA] 2D 4C 01 03 58 4C 01 03 24 4A 01 21 EB 56 01 CD 00 00 00
[DATA — End of Swap Block 1] Final parameter bytes of the source drive swap record, followed by 00H 00H (the 16-bit end-of-chain pointer indicating no further sub-blocks). The swap routine stops processing this chain when it reads 0000H.
5BA3H - SWAP DATA BLOCK 2 (OVERLAY 04H — DESTINATION DRIVE)
Structured swap data block for overlay 04H. The linked list entry at 5B5BH (overlay 04H) points here. This block encodes the PDRIVE geometry parameters for the destination drive. Same format as Block 1: byte count, data bytes, 16-bit next-pointer. The three NOP bytes at 5BAA–5BACH (00H 00H 00H) end the chain (00H 00H) with one pad byte (00H). All bytes from 5BA3H through 5BDFH are DATA.
5BA3
[DATA] B2 4E 01 50 D0
[DATA — Swap Block 2, Overlay 04H] First byte (B2H) is the byte count for this sub-block (178 decimal). Remaining bytes are PDRIVE parameter data for the destination drive configuration: track count, sector count, density, step rate.
5BA8
[DATA] 4E 03 00 00 00
[DATA — End of Swap Block 2] The 03H is a trailing data byte. 00H 00H is the end-of-chain pointer. The extra 00H at 5BACH is a pad byte to align the next block.
5BAD
[DATA] 20 4E 01 AF 68 4F 01 00 7B 4F 01 1A AF 4F 01 00 0A 50 01 00 61 50 03
[DATA] Continuation of destination drive PDRIVE geometry parameters.
5BC4
[DATA] B7 D6 50 03 C3 5B 5C
[DATA] More parameter bytes. The apparent JP 5C5BH is a data byte pattern coincidence.
5BCD
[DATA] 12 51 01 1A 55 51 04 21 EF 5C
[DATA] Continuation.
5BD7
[DATA] C9 EF 4D 03 CD 71 5C
[DATA] Continuation. The apparent RET and CALL 5C71H are data byte coincidences.
5BDE
[DATA] 00 00 00
[DATA — End of Swap Block 2 chain] Three 00H bytes: 00H 00H = end-of-chain pointer, 00H = pad to next block boundary.
5BE1H - SWAP DATA BLOCK 3 (OVERLAY 05H — THIRD DRIVE)
Structured swap data block for overlay 05H (used when a third drive or alternate configuration is involved in the COPY operation). The linked list entry at 5B5FH (overlay 05H) points here. The block runs from 5BE1H through 5C09H. The sentinel at 5C09H–5C0AH (00H 00H) marks the end of the linked-list data area. Code resumes at 5C0BH.
5BE1
[DATA] 3E 4E 01 0D 49
[DATA — Swap Block 3, Overlay 05H] First byte (3EH = 62 decimal) is the byte count for this sub-block. Remaining bytes are PDRIVE parameters for the third-drive configuration.
5BE6
[DATA] 4E 01 00 AB 4E 01 18 CC 4E 02 35 56 B7 4E 01 2F 68 4E 01 18 4F 4E 03 C3 69 5C
[DATA] Third drive geometry parameters continue. The apparent JP 5C69H at 5BFDH is a data byte pattern coincidence.
5C00
[DATA] 0F 50 01 00 1D 4E 01 13 00 00 00
[DATA — End of Swap Block 3 and data area] Final parameter bytes followed by 00H 00H = end-of-chain pointer. The swap data area ends here at 5C0AH. Code resumes at 5C0BH.
5C0BH - SECTOR READ RETURN CODE PROCESSOR
This routine processes the return code after a sector read or write operation. On entry, Register A holds the FDC status/error code from the completed operation. The routine determines whether the result is a FORMAT-mode success, an end-of-data marker (06H), or a true error, and returns accordingly.
[ENTRY POINT] Register A = FDC error code (00H = success, 06H = end-of-data, other = error). Register BC = saved context from caller.
5C0B
EI FB
EI — Enable maskable interrupts. After the disk I/O operation (which ran with interrupts managed), re-enable interrupts now that the critical section is complete.
5C0C
POP BC C1
POP BC — Restore Register BC from the stack (saved by the caller before the disk operation).
5C0D
If the NZ FLAG (Not Zero) is set, meaning Register A is non-zero (the sector operation returned a non-zero code), JUMP to
5C19H to handle the non-success case. If A=00H (success), fall through.
5C0F
LD A,(4687H) 3A 87 46
Fetch the DOS mode flags byte (stored at 4687H in the SYS0 work area) into Register A. This byte controls operating mode bits; bit 5 is the FORMAT mode flag.
5C12
AND 20H E6 20
Mask Register A with 20H (00100000 binary), isolating bit 5 (the FORMAT mode flag). If bit 5 is set, the system is in FORMAT mode; otherwise COPY mode.
5C14
If the NZ FLAG is set (bit 5 was set = FORMAT mode is active), JUMP to
5C1CH to return with A=00H (success), since in FORMAT mode a zero FDC status means the format write succeeded normally.
5C16
ADD A,06H C6 06
Add 06H to Register A (which is currently 00H, since we are on the COPY-mode success path). This sets A=06H, which is the NEWDOS/80 end-of-data code, signalling to the caller that the sector read completed normally with no more data (EOF/end-of-track marker in COPY mode).
5C18
RET C9
Return to the caller. Register A = 06H (end-of-data). The caller will interpret this as a normal end-of-sector-data condition.
[ERROR PATH] Reached when Register A was non-zero on entry (sector operation failed or returned a special code).
5C19
CP 06H FE 06
Compare Register A (the error/status code from the sector operation) against 06H (end-of-data marker). If A=06H, the Z FLAG is set.
5C1B
RET NZ C0
If the NZ FLAG is set (A ≠ 06H, meaning a genuine error code other than end-of-data was returned), RETURN immediately to the caller with the error code in Register A. The caller will handle the disk error.
5C1C
XOR A AF
Set Register A to zero and clear all flags. This converts the 06H end-of-data code (or FORMAT success) into a clean 00H success return.
5C1D
RET C9
Return to the caller with A=00H (success). The Z FLAG is set. Caller treats this as a successful sector operation with no error.
5C1EH - GAT TRACK BOUNDARY CHECK AND CONDITIONAL DRIVE INIT
This routine checks whether a given track number (passed in Register A) falls within a valid range relative to the current GAT configuration, and conditionally calls the SYS0 drive initialization routine at 48AFH if the track is beyond the currently initialized boundary. On entry, Register A = track number to check; BC = preserved caller context.
[ENTRY POINT] Register A = track number to validate. Stack contains caller's context.
5C1E
PUSH BC C5
Save Register BC (caller's context) onto the stack before modifying registers during the GAT boundary calculation.
5C1F
PUSH HL E5
Save Register HL onto the stack. HL will be used as a working pointer during the GAT byte/bit offset calculation.
5C20
LD L,A 6F
Load Register L with the track number (currently in Register A). This places the track number into the low byte of HL to begin building a 16-bit offset.
5C21
LD H,00H 26 00
Load Register H with zero, completing the 16-bit value HL = 00XXH where XX is the track number. HL now holds the track number as a 16-bit unsigned integer for arithmetic use.
5C23
LD A,05H 3E 05
Load Register A with 05H. This is the function code for the GAT byte/bit offset calculation routine at
4C59H in SYS0. The value 05H selects the sector granule mapping mode appropriate for 5-sector-per-granule geometry.
5C25
GOSUB to SYS0 routine at 4C59H to calculate the GAT byte offset and bit position for the given track number. On return: Register A = GAT byte number (offset from GAT base), Register L = original track number preserved for further use.
5C28
LD H,A 67
Store the GAT byte offset (returned in Register A from 4C59H) into Register H. HL now holds: H = GAT byte index, L = track number.
5C29
LD A,L 7D
Reload Register A with the track number (from Register L, where it was preserved).
5C2A
LD L,H 6C
Move the GAT byte offset (from H) into Register L. Now: L = GAT byte index, A = track number.
5C2B
EX (SP),HL E3
Exchange Register HL with the top of stack (the saved HL value from PUSH HL at 5C1FH). After this: the caller's original HL is now in the Register HL, and the working value (L = GAT byte index) is now on the stack top for retrieval.
5C2C
INC A 3C
INCrement Register A (track number) by 1. Converts from zero-based track number to one-based count, needed for the boundary comparison.
5C2D
INC A 3C
INCrement Register A again. Now A = track number + 2. This provides a two-track lookahead margin: the drive must be initialized at least two tracks ahead of the current position.
5C2E
CP L BD
Compare Register A (track number + 2) against Register L (the GAT byte index = number of tracks currently accessible). If A > L, the CARRY FLAG is clear (track is beyond current initialization boundary).
5C2F
If the NZ FLAG is set (A ≠ L, meaning the requested track is at or beyond the currently initialized GAT boundary), GOSUB to SYS0 routine at 48AFH (basic drive initialization with A=0) to extend the initialization to cover the additional tracks. If A=L (track is within bounds), this call is skipped.
5C32
POP HL E1
Restore Register HL from the stack (discards the working value EX'd there at 5C2BH and retrieves the caller's original HL).
5C33
POP BC C1
Restore Register BC from the stack (saved at 5C1EH).
5C34
RET NZ C0
If the NZ FLAG is set (48AFH was called and returned an error — 48AFH sets Z on success, NZ on failure), RETURN with error. The caller will see NZ and handle the initialization failure.
5C35
LD A,30H 3E 30
Load Register A with 30H. This is the function code for the SYS0 track seek routine at
4C37H. The value 30H selects the standard seek with verification mode.
5C37
GOSUB to SYS0 routine at 4C37H to perform the track seek operation. Register A (30H) specifies the seek mode. On return: Z FLAG set = seek successful; NZ = seek failed.
5C3A
LD A,L 7D
Load Register A with Register L (the original track number, preserved through the GAT calculation). Load the track number back into A for the next operation.
5C3B
Jump to SYS0 routine at 48ECH to continue disk operation processing (sector read/write dispatch after a successful seek). This is a tail-call: control passes fully to 48ECH and does not return here.
5C3EH - SEEK/RESTORE ERROR HANDLER — RETRY COUNTER
This entry point handles seek or restore errors during disk operations. Register A' (alternate accumulator, accessed via EX AF,AF') holds the current retry count. The routine decrements the retry count and either retries the seek or falls through to the format-launch path at 5C43H.
[ENTRY POINT] Seek/restore error retry handler. Register A' = remaining retry count. Falls through to 5C43H on retry exhaustion.
5C3E
EX AF,AF' 08
Exchange Register A with the alternate accumulator A'. After the exchange, Register A holds the retry count (previously stored in A') and A' holds the previous error code. This gives access to the retry counter without disturbing the main register set.
5C3F
DEC A 3D
DECrement Register A (the retry count) by 1. If the retry count was 1, it is now 0 and the Z FLAG will be set.
5C40
If the NZ FLAG is set (retry count is still greater than zero after decrement), JUMP to SYS0 routine at 47DDH to retry the seek/restore operation. If the count has reached zero, fall through to 5C43H.
5C43H - SEEK RETRY EXHAUSTED — LAUNCH FORMAT OR ABORT
Reached when all seek retries have been exhausted (falling through from 5C3EH above). The routine cleans up the stack by discarding three saved frames, checks whether a previous head-load was cached at 4860H, and either launches the SYS0 FORMAT completion routine or performs a final drive-position correction before returning to the FORMAT track writer.
[ENTRY POINT] All seek retries exhausted. Stack contains three saved AF frames from the retry loop.
5C43
POP AF F1
Discard the first saved AF pair from the stack. This unwinds one level of the retry loop's saved state.
5C44
POP AF F1
Discard the second saved AF pair from the stack.
5C45
POP AF F1
Discard the third saved AF pair from the stack. The retry loop's stack frames are now fully removed; the stack is clean for the subsequent call.
5C46
LD A,(4860H) 3A 60 48
Fetch the SYS0 head-load cache flag (stored at 4860H in the DOS work area) into Register A. This byte is non-zero if the drive head was previously loaded and its position cached; it is zero if not.
5C49
OR A B7
Perform a bitwise OR of Register A with itself. This is the standard Z80 idiom to test whether Register A is zero: if A=00H the Z FLAG is set; otherwise the NZ FLAG is set.
5C4A
If the NZ FLAG is set (head cache is valid — head was loaded), JUMP to SYS0 routine at 485DH. That routine reconciles the cached head position after seek failure (it may restore the head to track 0 or update the position register).
5C4D
LD A,(IX+07H) DD 7E 07
Fetch the byte at offset +07H from Register IX (IX points to the active drive parameter block). Offset +07H holds the drive configuration parameter byte, which includes the sector size code and density flag for this drive.
5C50
LD (480FH),A 32 0F 48
Store the drive configuration parameter byte (currently in Register A) to address 480FH in the SYS0 work area. Address 480FH is the sector-size/density parameter field used by the FDC command setup routines.
5C53
LD A,64H 3E 64
Load Register A with 64H. This is the function code for the SYS0 format-track initialization routine at
4982H. The value 64H selects the format-track command path.
5C55
GOSUB to SYS0 format-track setup routine at 4982H. This prepares the FDC for writing a formatted track (sets up sector headers, gap bytes, and issues the Write Track command). On return control continues at 5C58H.
5C58
Jump to SYS0 routine at 47B8H to complete the format track write operation and return status to the caller. This is a tail-call; control does not return here.
5C5BH - SCAN NAME STRING FOR VALID NULL TERMINATOR
This routine scans a name/label string buffer (pointed to by HL) for up to 80 (50H) characters, looking for a null byte (00H) that marks the end of a valid string. If a null is found, it jumps to 50FEH to handle the null-terminated name. If no null is found within 80 bytes, it returns A=1AH with NZ set.
[ENTRY POINT] HL points to start of name string buffer. Scans up to 50H bytes for 00H terminator.
5C5B
LD B,50H 06 50
Load Register B with 50H (80 decimal). This is the maximum number of characters to scan in the name buffer before giving up.
[LOOP START] Scan loop: examine each byte of the name buffer.
5C5D
LD A,(HL) 7E
Fetch the current byte from the name buffer (at address in HL) into Register A.
5C5E
OR A B7
Test whether the byte just loaded (in Register A) is zero. If A=00H the Z FLAG is set (null terminator found); otherwise NZ.
5C5F
If the Z FLAG is set (current byte is 00H = null terminator found), JUMP to SYS6 routine at 50FEH to process the null-terminated name string. This is the normal successful path.
5C62
INC HL 23
Advance Register HL to point to the next byte in the name buffer.
5C63
DECrement B and loop back to
5C5DH if B is not zero. Repeats the scan for up to 80 characters total.
[LOOP END] when B reaches zero — no null was found.
5C65
LD A,1AH 3E 1A
Load Register A with 1AH (ASCII SUB, 26 decimal). Used as a synthetic non-null terminator when no proper null was found within the scan limit, allowing the caller to distinguish a filled buffer from a null-terminated one.
5C67
OR A B7
Set flags based on Register A (1AH ≠ 00H), so the NZ FLAG is set and CARRY FLAG is clear.
5C68
RET C9
Return to the caller with A=1AH, NZ FLAG set, indicating the name buffer had no null terminator within the scan limit.
5C69H - FILESPEC PARSE: DECREMENT ENTRY COUNT AND ADVANCE
This small utility routine decrements a filespec entry counter (in Register E) and either loops back to the parser at 4E3FH (if more entries remain) or advances HL and jumps to the post-parse handler at 4E72H (if all entries processed).
[ENTRY POINT] Register E = remaining filespec entry count. Register HL = current parse pointer.
5C69
DEC E 1D
DECrement Register E (the remaining filespec entry count) by 1.
5C6A
If the NZ FLAG is set (E was decremented but is still non-zero = more filespec entries remain to parse), JUMP back to the filespec parser entry point at 4E3FH to process the next entry.
5C6D
INC HL 23
Advance Register HL by 1 to step past the current filespec entry to the start of the next field.
5C6E
Jump to the post-parse handler at 4E72H. All filespec entries have been processed; 4E72H performs the final cleanup and stores the parsed result.
5C71H - STORE DATE/VERSION STAMP FROM DOS WORK AREA INTO BUFFER
This routine stores two bytes — the DOS date/version stamp values from the SYS0 work area at 421CH and 421AH — into a buffer pointed to by HL. Used to copy the current disk date/version stamp into the destination disk's GAT header during a COPY or FORMAT operation.
[ENTRY POINT] HL points to the destination buffer position. HL is advanced by 1 first before writing.
5C71
INC HL 23
Advance Register HL by 1 to skip one byte in the destination buffer (move past a field already written by the caller).
5C72
LD A,(421CH) 3A 1C 42
Fetch the first date/version stamp byte from SYS0 work area address 421CH (the high byte of the disk's date/version field, set during disk initialization or FORMAT) into Register A.
5C75
LD (HL),A 77
Store the first date/version stamp byte (in Register A) into the buffer at the address currently in HL.
5C76
INC HL 23
Advance HL to the next buffer position.
5C77
LD A,(421AH) 3A 1A 42
Fetch the second date/version stamp byte from SYS0 work area address 421AH (the low byte of the disk date/version field) into Register A.
5C7A
LD (HL),A 77
Store the second date/version stamp byte into the buffer at the current HL position.
5C7B
DEC HL 2B
Step HL back one position.
5C7C
DEC HL 2B
Step HL back a second position, returning HL to point to the first byte of the two-byte stamp just written. This leaves HL positioned at the start of the stamp field for the caller's reference.
5C7D
Jump to the SYS6 routine at 4E1FH to continue processing after the stamp has been written. This is a tail-call return to the main filespec/option processing flow.
5C80H - BOOT SECTOR PATCH CALLBACK
This routine is called as a callback during boot sector configuration. It checks Register A for an error and, if successful, copies the boot sector configuration byte from offset +2 of DE (the drive parameter block) into the boot sector data buffer at 64BCH. On success it restores DE to its original base before returning.
[ENTRY POINT] Register A = operation result (0=success, non-zero=error). Register DE = pointer to drive parameter block. The boot sector configuration byte is at (DE+02H).
5C80
[DATA] 01 00 01
[DATA — 3 pad/alignment bytes] The bytes 01H 00H 01H at 5C80H are data bytes within the boot sector patch table structure, not executable code. Callback code begins at 5C83H.
5C83
OR A B7
Test Register A: if A=00H (success from the preceding operation) set Z FLAG; otherwise set NZ FLAG.
5C84
RET NZ C0
If the NZ FLAG is set (the preceding operation returned an error in Register A), RETURN immediately to the caller. No byte is copied.
5C85
INC DE 13
Advance Register DE by 1 (past the first byte of the boot parameter block).
5C86
INC DE 13
Advance Register DE by 1 again. DE now points to offset +2 of the drive parameter block, which holds the boot sector configuration/patch byte.
5C87
LD A,(DE) 1A
Fetch the boot sector configuration byte from offset +2 of the parameter block (at the address in DE) into Register A.
5C88
LD (64BCH),A 32 BC 64
Store the boot sector configuration byte (in Register A) to address 64BCH. Address 64BCH is within the drive geometry data table at 64A3H–64BFH; this field holds the boot sector patch byte written into the boot sector during FORMAT. [SELF-MODIFYING: 64BCH is patched at FORMAT time.]
5C8B
DEC DE 1B
Step DE back one position (from offset +2 to offset +1).
5C8C
DEC DE 1B
Step DE back one more position, restoring DE to the original base address of the drive parameter block so the caller can continue using DE as the block pointer.
5C8D
RET C9
Return to the caller. Register A = boot configuration byte, DE = restored to parameter block base, Z FLAG set (success).
5C8EH - SET DESTINATION BUFFER POINTER AND MARK DRIVE ACTIVE
Two short utility routines. The first (5C8EH) stores Register HL as the new destination buffer pointer at 5B1AH and sets bit 6 of IX+01H, marking the destination drive buffer as active. The second (5C96H) stores Register A into the disk operation mode field at 46A6H and sets the disk-operation-active flag at 468FH to 02H.
[ENTRY POINT A — 5C8EH] HL = new destination sector buffer address.
5C8E
LD (5B1AH),HL 22 1A 5B
Store Register HL (the new destination sector buffer pointer) into memory address 5B1AH. Address 5B1AH is offset +03H within the destination drive parameter block (base 5B17H), which is the 16-bit buffer address field for the destination drive's sector buffer.
5C91
SET 6,(IX+01H) DD CB 01 F6
Set bit 6 of the byte at offset +01H from Register IX (the current drive operation parameter block). Bit 6 of this field is the "buffer active/valid" flag — setting it marks the destination drive's buffer as loaded and ready for the write operation.
5C95
RET C9
Return to the caller.
[ENTRY POINT B — 5C96H] Register A = disk operation mode byte to store.
5C96
LD (46A6H),A 32 A6 46
Store Register A (the disk operation mode byte) to address 46A6H in the SYS0 work area. Address 46A6H is the disk operation mode/type field used by the FDC command routing logic to select between read, write, and format operations.
5C99
LD A,02H 3E 02
Load Register A with 02H, the "drive active / operation pending" flag value.
5C9B
LD (468FH),A 32 8F 46
Store 02H to address 468FH in the SYS0 work area. Address 468FH is the "disk operation active" status flag; setting it to 02H signals to SYS0 that a disk operation is in progress and the FDC should not be interrupted.
5C9E
RET C9
Return to the caller.
5C9FH - DOUBLE-DENSITY COMPATIBILITY CHECK AND COPY PARAMETER SETUP
This major routine checks whether the source and destination drives are compatible for the intended COPY operation — specifically whether both drives support double density (MFM), whether they share compatible sector geometry, and whether the copy direction is valid. If incompatible parameters are detected it jumps to the error handler at 6747H. If compatible, it configures the linked-list pointers used during the COPY to route parameter swaps correctly between overlays.
[ENTRY POINT] Called after both source and destination drive parameters have been loaded. IY=4280H (DOS work area). Drive parameter blocks at 5AE5H and 5B17H contain current geometry.
5C9F
GOSUB to the routine at 63B3H to load geometry parameters for both source and destination drives into working registers. On return: Register B = source drive geometry control byte (from 59BEH); Register C = source secondary geometry byte (from 59B9H); Register D = destination geometry control byte (from 59CCH); Register E = destination secondary geometry byte (from 59C7H).
5CA2
LD A,(59BEH) 3A BE 59
Fetch the source drive geometry control byte (stored at 59BEH in the SYS6 work area) into Register A. This byte encodes the source drive's sector count per track and density flags.
5CA5
LD B,A 47
Copy the source geometry control byte from Register A into Register B, preserving it for the density and geometry comparison tests that follow.
5CA6
LD A,(59B9H) 3A B9 59
Fetch the source drive secondary geometry byte (stored at 59B9H) into Register A. This byte holds additional source drive parameters (step rate, sector size code).
5CA9
LD C,A 4F
Copy the source secondary geometry byte from Register A into Register C for comparison with the destination's corresponding byte.
5CAA
LD A,(59CCH) 3A CC 59
Fetch the destination drive geometry control byte (stored at 59CCH in the SYS6 work area) into Register A.
5CAD
LD D,A 57
Copy the destination geometry control byte from Register A into Register D.
5CAE
LD A,(59C7H) 3A C7 59
Fetch the destination secondary geometry byte (stored at 59C7H) into Register A.
5CB1
LD E,A 5F
Copy the destination secondary geometry byte from Register A into Register E. Now: B=source control, C=source secondary, D=destination control, E=destination secondary.
5CB2
LD A,C 79
Load Register A with the source secondary geometry byte (Register C), for the first compatibility test.
5CB3
AND E A3
Bitwise AND of the source secondary byte (Register A = C) with the destination secondary byte (Register E). The result in Register A has bits set only where BOTH drives have the same flag bits set (same density, same sector size etc.).
5CB4
BIT 5,A CB 6F
Test bit 5 of the AND result in Register A. Bit 5 is the double-density (MFM) flag. If bit 5 is set, BOTH source and destination support double density (the AND preserved it). If bit 5 is clear, at least one drive does not support MFM.
5CB6
If the Z FLAG is set (bit 5 was clear = at least one drive is not double-density), JUMP to
5CBEH to skip the sector-count cross-check and proceed with single-density compatible logic.
Both drives are double-density. Check whether source sector count (B) and destination sector count (D) are compatible — if the geometry difference affects the sector interleave in an incompatible way, the copy would produce an unreadable disk.
5CB8
LD A,B 78
Load Register A with the source geometry control byte (Register B).
5CB9
XOR D AA
Exclusive-OR Register A (source geometry) with Register D (destination geometry). The result has bits set where source and destination differ. This detects geometry mismatches.
5CBA
RRCA 0F
Rotate Register A right (circular). Shifts bit 0 into the CARRY FLAG. This examines the XOR result's lowest bit to check if the geometry difference affects the sector interleave in a way that makes the copy invalid.
5CBB
If the CARRY FLAG is set (the rotate shifted out a 1-bit, meaning source/destination sector geometry differs at the critical bit position = incompatible double-density configuration), JUMP to
6747H to display a geometry mismatch error and abort the operation.
Double-density compatibility confirmed, or single-density path. Now verify individual drive density flags to determine which linked list entries need to be activated for the swap.
5CBE
LD A,B 78
Load Register A with the source geometry control byte (Register B), for the per-drive density flag tests.
5CBF
BIT 5,C CB 69
Test bit 5 of Register C (the source secondary geometry byte). Bit 5 is the source drive's MFM/double-density enable flag. If set (Z FLAG clear), source is double-density; if clear (Z FLAG set), source is single-density.
5CC1
If the NZ FLAG is set (source drive IS double-density), JUMP to
5CC7H to test the destination drive's density flag.
5CC3
BIT 5,E CB 6B
Test bit 5 of Register E (the destination secondary geometry byte). Bit 5 is the destination drive's MFM/double-density flag.
5CC5
RET Z C8
If the Z FLAG is set (destination is also single-density = both drives are single-density), RETURN immediately. No linked-list reconfiguration is needed for a single-density to single-density copy; the default list is already correct.
5CC6
LD A,D 7A
Load Register A with the destination geometry control byte (Register D). This is used to determine the correct linked-list entry for a single-density-source / double-density-destination configuration.
5CC7
RRCA 0F
Rotate Register A (source or destination geometry control byte) right. Shifts bit 0 into the CARRY FLAG, allowing the carry to carry a configuration selector bit for the linked-list pointer assignment below.
5CC8
RET C D8
If the CARRY FLAG is set (the lowest geometry control bit was 1, indicating a specific sector/geometry configuration that uses the default linked list without modification), RETURN immediately. The copy can proceed with the default parameter-swap linked list.
Source or destination (or both) are double-density and require reconfigured linked-list pointers. Set up three alternative swap-block pointers at 55F7H, 5B5DH, and 5B61H to route through the correct swap data blocks for this density combination.
5CC9
LD HL,5B5BH 21 5B 5B
Load Register HL with 5B5BH, the address of the third linked-list entry's pointer field within the drive parameter linked list at 5B57H. This is the entry for the third drive / overlay 05H.
5CCC
LD (55F7H),HL 22 F7 55
Store 5B5BH into address 55F7H. Address 55F7H is the "next list entry" pointer field within the PDRIVE write-back routine at 55ECH — storing 5B5BH here redirects the list traversal to begin at the third entry block (overlay 05H data), bypassing the default first two entries.
5CCF
LD HL,5BB1H 21 B1 5B
Load Register HL with 5BB1H, which is the address of the double-density configuration variant entry within Swap Block 2 (overlay 04H) — 4 bytes into Swap Block 2 from 5BA3H, pointing to the MFM-specific parameter portion.
5CD2
LD (5B5DH),HL 22 5D 5B
Store 5BB1H into address 5B5DH. Address 5B5DH is the swap-data pointer field within the second linked-list entry at 5B5BH; storing 5BB1H here redirects the swap routine to use the double-density variant of Swap Block 2 when processing the destination drive's PDRIVE parameters.
5CD5
LD HL,5C00H 21 00 5C
Load Register HL with 5C00H, which is the address of the double-density sub-entry within Swap Block 3 at 5C00H (a different sub-entry for the double-density overlay 05H configuration).
5CD8
LD (5B61H),HL 22 61 5B
Store 5C00H into address 5B61H. Address 5B61H is the swap-data pointer field within the third linked-list entry at 5B5FH; storing 5C00H here redirects that entry's swap to the double-density variant in Swap Block 3.
Now initialize several COPY/APPEND state variables to zero and patch the COPY loop branch instruction.
5CDB
XOR A AF
Set Register A to zero and clear all flags. This prepares the zero value for clearing the following work area fields.
5CDC
LD (617FH),A 32 7F 61
Store zero to address 617FH. Address 617FH is a COPY/APPEND state variable (sector-count accumulator or iteration counter) that must be cleared before the operation begins.
5CDF
LD H,A 67
Load Register H with Register A (zero). Together with the next instruction, this builds HL = 0000H.
5CE0
LD L,A 6F
Load Register L with Register A (zero). HL = 0000H.
5CE1
LD (61BFH),HL 22 BF 61
Store 0000H (HL) into address 61BFH. Address 61BFH is a 16-bit position or sector count variable in the COPY work area, cleared at initialization.
5CE4
LD (5BB5H),HL 22 B5 5B
Store 0000H into address 5BB5H. Address 5BB5H is a 16-bit field within or adjacent to Swap Block 2 in the drive parameter linked list; clearing it resets the COPY session state for this swap block.
5CE7
LD A,18H 3E 18
Load Register A with 18H. This value (24 decimal) is a JR (relative jump) displacement byte to be patched into a self-modifying instruction within the COPY loop code, effectively enabling a specific branch path.
5CE9
LD (612DH),A 32 2D 61
Store 18H to address 612DH. [SELF-MODIFYING CODE] Address 612DH is the displacement byte of a JR instruction within the COPY sector-processing loop at ~612CH; writing 18H enables a specific branch path for the initialized COPY configuration.
5CEC
RET C9
Return to the caller. The drive compatibility check is complete and all linked-list pointers have been configured for the upcoming COPY operation.
5CEDH - SECTOR WRITE MODE FLAG PROPAGATION
This routine is the target of the sector operation stub at 57CEH (JP 5CEDH via IX→DE). It checks the FORMAT mode flag and, if FORMAT mode is active, sets bit 5 of the sector parameter block's byte at IX+02H before forwarding to the SYS0 sector write routine at 4439H. This ensures that FORMAT-mode sector writes use the correct FDC write-with-format-mark command rather than a normal data write.
[ENTRY POINT] IX points to the current sector parameter block. Called from the sector operation stub at 57CEH.
5CED
LD A,(4282H) 3A 82 42
Fetch the DOS mode byte (stored at 4282H = IY+02H in the DOS work area, with IY=4280H) into Register A. Bit 5 of this byte is the FORMAT mode flag: set=FORMAT active, clear=COPY/normal mode.
5CF0
BIT 5,A CB 6F
Test bit 5 of Register A (the FORMAT mode flag from 4282H). If bit 5 is set the Z FLAG is clear (NZ = FORMAT active); if bit 5 is clear the Z FLAG is set (Z = normal mode).
5CF2
If the Z FLAG is set (FORMAT mode is NOT active — this is a normal COPY or sector write), JUMP to
5CF8H to go directly to the SYS0 write routine without modifying the parameter block.
5CF4
SET 5,(IX+02H) DD CB 02 EE
Set bit 5 of the byte at offset +02H from Register IX (the current sector parameter block). Bit 5 of this field is the FORMAT write flag; setting it tells the SYS0 sector writer at 4439H to issue an FDC Write Sector command with the format-specific sector header, which is required during track formatting rather than normal data writing.
5CF8
Jump to SYS0 routine at 4439H (sector write dispatch). This is a tail-call: control passes to 4439H which performs the actual FDC sector write and returns status to the original caller of the stub at 57CEH.
5CFBH - SECTOR PARAMETER BLOCK DIRECTORY FLAG CHECK AND DISPATCH
This short routine checks whether the current sector parameter block (IX) has bit 5 of IX+02H set (indicating a directory/system sector) and whether bit 0 of IX+07H is set (primary directory sector flag). Based on these conditions it dispatches to either the SYS0 sector position routine at 4C57H or the GAT sector calculation at 4C59H with function code 03H.
[ENTRY POINT] IX = active sector parameter block pointer.
5CFB
BIT 5,(IX+02H) DD CB 02 6E
Test bit 5 of the byte at offset +02H of the current sector parameter block. Bit 5 is the directory/format sector flag. If set (Z FLAG clear), the parameter block is for a directory or format sector operation.
5CFF
If the Z FLAG is set (bit 5 was clear = NOT a directory sector), JUMP to
5D05H to check an additional flag and dispatch accordingly.
5D01
BIT 0,(IX+07H) DD CB 07 46
Test bit 0 of the byte at offset +07H of the current sector parameter block. Bit 0 indicates whether this is the primary (first) directory sector in the operation. If set, a special dispatch is needed; if clear, use the normal GAT calculation path.
5D05
If the Z FLAG is set (either: not a directory sector from the 5CFBH test, or IX+07H bit 0 was clear from the 5D01H test), JUMP to SYS0 routine at 4C57H (sector position/CHS calculation for a normal data sector). 4C57H computes the track/sector/side values from the linear sector number in the parameter block.
5D08
LD A,03H 3E 03
Load Register A with 03H, the function code for the "directory sector GAT lookup" mode of the SYS0 routine at 4C59H. This selects the path that maps a directory sector number to its physical track/sector location on disk.
5D0A
Jump to SYS0 routine at 4C59H with A=03H to perform the directory-sector-to-physical-location mapping. This is a tail-call; 4C59H returns status directly to the original caller.
5D0DH - DIRECTORY BUFFER POINTER DATA WORDS
This is a DATA area, not code. Four NOP bytes (00H) followed by two 16-bit data words constitute the directory buffer control pointers used by SYS6's COPY routines. The disassembler has misread these as Z80 instructions (NOPs, LD B,E, LD D,5DH). The actual structure is described below.
[DATA AREA] Four pad bytes at 5D0DH–5D10H (00H 00H 00H 00H), followed by two 16-bit pointer words.
5D0D
[DATA] 00 00 00 00
[DATA — 4 pad/alignment bytes] Four zero bytes at 5D0DH–5D10H. These serve as alignment padding between the end of the directory-sector dispatch code and the start of the directory buffer pointer data.
5D10
[DATA] 00 43
[DATA — Directory template pointer] Address 5D10H: this 16-bit word location is the directory template pointer. Its initial assembled value is 4300H; it is overwritten at runtime by the routine at 5E12H which stores the actual directory buffer base address 6491H here (little-endian: 91H at 5D10H, 64H at 5D11H). Referenced as the read-only directory template reference throughout the COPY routines.
5D12
[DATA] 16 5D
[DATA — Directory buffer base pointer] Address 5D12H: this 16-bit word is the directory buffer base pointer, initialized to 5D16H (the fixed start of the directory data buffer). The routine at 5E15H stores 6491H here at the beginning of each COPY/APPEND session. Value stored little-endian: 5D12H = 16H, 5D13H = 5DH = address 5D16H.
5D14
[DATA] 16 5D
[DATA — Directory buffer end pointer] Address 5D14H: this 16-bit word is the directory buffer end pointer, also initialized to 5D16H. As directory entries are added to the buffer during COPY processing, this pointer is advanced to track the write position. Initialized equal to 5D12H (base = end = empty buffer). Value stored little-endian: 5D14H = 16H, 5D15H = 5DH = address 5D16H.
5D16H - COPY/APPEND FILESPEC INPUT AND VALIDATION ROUTINE
This major routine handles the interactive input of filespecs (source and/or destination file specifications) for the COPY and APPEND commands. It: (1) calls the drive setup dispatcher to initialize drives, (2) reads the PDRIVE-option-flags byte (5997H) to check whether source and/or destination filespecs are still needed, (3) if filespecs are needed, prompts for input and reads from the keyboard (up to 13 valid characters per filespec), validates each character as printable/alphanumeric, and stores the result into a filespec buffer at 6491H, (4) handles BREAK/1CH abort and error conditions, and (5) calls into the source/destination drive setup after filespec entry.
[ENTRY POINT — 5D16H] Called after drive parameter blocks are initialized. IY=4280H. The flags at 5997H control whether source and/or destination filespecs are requested.
5D16
GOSUB to the routine at 6643H to perform initial drive configuration and GAT sector validation for the COPY/APPEND operation. This ensures that both source and destination drives are properly selected and their disk geometry is known before prompting the user for filespecs.
5D19
LD HL,5AE5H 21 E5 5A
Load Register HL with 5AE5H, the base address of the source drive parameter block (50 bytes starting at 5AE5H). HL is used to clear the source block's control flag.
5D1C
RES 1,(HL) CB 8E
Clear bit 1 of the byte at address 5AE5H (the source drive parameter block's control byte, offset 0). Bit 1 is the "buffer valid/loaded" flag for the source drive; resetting it forces the COPY loop to treat the source buffer as empty at the start of this filespec session.
5D1E
LD HL,5B17H 21 17 5B
Load Register HL with 5B17H, the base address of the destination drive parameter block (50 bytes starting at 5B17H). HL is repositioned to clear the destination block's flag next.
5D21
RES 1,(HL) CB 8E
Clear bit 1 of the byte at address 5B17H (the destination drive parameter block's control byte, offset 0). Bit 1 is the "buffer valid/loaded" flag for the destination drive; resetting it ensures a fresh start for the destination buffer.
5D23
LD A,(5997H) 3A 97 59
Fetch option flags byte 4 (stored at 5997H in the SYS6 work area) into Register A. This byte controls prompt suppression: bit 4 = source filespec required; bit 5 = destination filespec required; if both are clear, no filespec prompts are needed.
5D26
AND 30H E6 30
Mask Register A with 30H (00110000 binary), isolating bits 4 and 5. If the result is zero, no filespec prompts are needed.
5D28
If the Z FLAG is set (bits 4 and 5 of 5997H were both clear = no filespec prompts needed), JUMP to
5D86H to skip straight to the drive setup call.
5D2A
GOSUB to the drive setup dispatcher at 568BH with function code pre-set to 04H (drive configuration scan, alternate entry). This performs the initial drive initialization required before prompting for filespecs.
5D2D
LD HL,6491H 21 91 64
Load Register HL with 6491H, the base address of the filespec input buffer (in the message/data area). This buffer receives the typed filespec characters as the user enters them.
5D30
LD DE,4480H 11 80 44
Load Register DE with 4480H, the base address of the PDRIVE table in the SYS0 work area. Used to access the current drive's parameters when building the filespec prompt.
5D33
LD A,(448CH) 3A 8C 44
Fetch the byte at address 448CH (PDRIVE table offset 0CH from 4480H — the current PDRIVE configuration byte) into Register A. This byte encodes the disk type and option flags for the selected drive.
5D36
CP 0BH FE 0B
Compare Register A (the PDRIVE configuration byte from 448CH) against 0BH. If A is 0BH or above, the drive configuration byte is out of the valid range for filespec input and the routine should abort immediately.
5D38
If the NO CARRY FLAG is set (A ≥ 0BH = drive config byte is out of valid range), JUMP to
5D65H to push an error code and jump to the error handler.
[MAIN FILESPEC INPUT LOOP] Read characters from the keyboard into the filespec buffer. B = remaining character count (max 0DH = 13). HL = write pointer into filespec buffer at 6491H.
5D3A
LD B,0DH 06 0D
Load Register B with 0DH (13 decimal), the maximum number of valid filespec characters (8 filename + period + 3 extension + drive letter = up to 13 chars). B is the character count for the DJNZ-based input loop.
[LOOP START] Filespec character input loop. Reads one character per iteration, filters whitespace and semicolons.
5D3C
GOSUB to the character input subroutine at
5D71H, which reads one character from the keyboard (ROM routine 0013H), filters out null/high-byte-only presses, and returns the character in Register A. Z FLAG set = CR (Enter), NZ = valid printable character or 1CH (abort).
5D3F
If the Z FLAG is set (character returned is a carriage return / Enter = 0DH), JUMP back to
5D3AH to reset B=0DH and restart the input loop. Pressing Enter alone without any filespec characters restarts the prompt.
5D41
CP 20H FE 20
Compare Register A (the character just read) against 20H (ASCII space). Spaces in the filespec are ignored and skipped.
5D43
If the Z FLAG is set (character is a space), JUMP back to
5D3AH to reset the loop and skip the space.
5D45
CP 3BH FE 3B
Compare Register A against 3BH (ASCII semicolon ;). A semicolon in a filespec terminates the current filename field and introduces the extension separator.
5D47
If the NZ FLAG is set (character is NOT a semicolon), JUMP to
5D53H to store the character into the filespec buffer.
Character is ; — skip subsequent characters until a non-semicolon is read, consuming the rest of the semicolon-delimited field.
5D49
GOSUB to
5D71H to read the next keyboard character (consuming the post-semicolon input).
5D4C
If the NZ FLAG is set (character is not CR = not done with semicolon skip), JUMP back to
5D49H to read another character. Loops until CR is received.
5D4E
Unconditional JUMP back to
5D3AH to restart the character input loop after the semicolon-field has been consumed.
Non-semicolon, non-space character received — store it in the filespec buffer after validating its character class.
5D50
GOSUB to
5D71H to read the next character during the character-class validation loop (reached from DJNZ at 5D63H).
5D53
LD (HL),A 77
Store the current character (in Register A) into the filespec buffer at the address currently in HL. This writes one validated filespec character to the input buffer.
5D54
INC HL 23
Advance HL to the next position in the filespec buffer.
5D55
If the Z FLAG is set (the character just stored was a CR = 0DH, meaning the user pressed Enter after typing some characters), JUMP to
5D3AH to reset and re-enter the main input loop (input session is complete for this filespec).
Validate the character: check whether it is a valid filespec character (alphanumeric). Characters below 30H are invalid; 30H–3AH are digits 0–9 and colon; uppercase letters A–Z (41H–5AH) are valid; others are rejected.
5D57
SUB 2FH D6 2F
SUBtract 2FH (ASCII /) from Register A. Characters below 30H will produce a negative result (CARRY FLAG set), indicating an invalid filespec character.
5D59
CP 0BH FE 0B
Compare the adjusted character value against 0BH. Characters 30H–3AH map to 01H–0BH after the subtraction; if the adjusted value is less than 0BH (CARRY set), the character is a valid digit or colon (drive separator).
5D5B
If the CARRY FLAG is set (adjusted value < 0BH = character is a digit or
:), JUMP to
5D63H to accept this character and continue the loop.
5D5D
SUB 12H D6 12
SUBtract 12H (18 decimal) from the already-adjusted character value. This shifts the range for letter checking: uppercase letters A–Z at ASCII 41H–5AH, after subtracting 2FH give 12H–2BH, then subtracting 12H gives 00H–19H.
5D5F
CP 1AH FE 1A
Compare the double-adjusted value against 1AH (26 decimal = number of letters in the alphabet). If the adjusted value is less than 1AH (CARRY set), the character is a valid uppercase letter A–Z.
5D61
If the NO CARRY FLAG is set (double-adjusted value ≥ 1AH = character is NOT a valid letter or digit), JUMP to
5D65H to handle the invalid character (display error and abort).
5D63
DECrement B and loop back to
5D50H if B is not zero. B counts remaining accepted characters; when B reaches 0 the maximum filespec length has been reached.
[LOOP END] — fall through to error/abort path.
5D65
LD A,01H 3E 01
Load Register A with 01H (error code 01H). This represents a filespec parse error or invalid character error that will be passed to the error handler.
5D67
PUSH AF F5
Save Register AF (error code 01H in A, current flags) onto the stack. The error handler at 521BH expects the error code to be on the stack when it takes control via JP.
5D68
LD HL,6283H 21 83 62
Load Register HL with 6283H, the address of a filespec error message string in the SYS6 data area (e.g., "ILLEGAL FILESPEC" or similar).
5D6B
GOSUB to SYS0 string display routine at 4467H to display the error message string pointed to by HL (the null-terminated error text at 6283H).
5D6E
Jump to the main error handler entry at
521BH with the error code on the stack. This unwinds the call stack and returns control to DOS after displaying the filespec error.
5D71H - KEYBOARD CHARACTER INPUT SUBROUTINE
This subroutine reads one character from the keyboard for the filespec input routine above. It calls the ROM keyboard scan routine at 0013H, filters out null or high-byte-only presses, strips the high bit, and checks for CR (0DH). If a 1CH (cursor function code) is received it substitutes a CR to terminate input and writes a double-CR to the filespec buffer to signal that no filename was entered. On return: A = character (0DH=CR with Z FLAG set; other = character with NZ FLAG set).
[ENTRY POINT] No register inputs required. Called from the filespec input loop above.
5D71
GOSUB to the Model III ROM keyboard scan routine at 0013H. This routine waits for a key press and returns the ASCII code of the pressed key in Register A. If no key is pressed it may return 00H (no key).
5D74
If the NZ FLAG is set (ROM returned NZ, meaning a valid non-zero key code), JUMP to
5D7DH to check for the 1CH abort code.
5D76
AND 7FH E6 7F
Mask Register A with 7FH (01111111 binary), stripping the high bit. The Model III ROM may return key codes with bit 7 set for special keys; this strips that flag to get the 7-bit ASCII value.
5D78
If the Z FLAG is set after masking (A was 00H or 80H = no valid character), JUMP back to
5D71H to read another key. This filters out null returns.
5D7A
CP 0DH FE 0D
Compare Register A against 0DH (ASCII Carriage Return / Enter key). If the user pressed Enter, the Z FLAG will be set.
5D7C
RET C9
Return to the filespec input loop. Register A = character read. Z FLAG = set if Enter (0DH) was pressed, clear otherwise.
[ABORT CHECK PATH] NZ from ROM call — check whether the character is 1CH (escape/abort function code).
5D7D
CP 1CH FE 1C
Compare Register A against 1CH. On the Model III, 1CH is returned by the ROM when the right-arrow key or certain function keys are pressed. In this context it is used as an abort signal for the filespec input session.
5D7F
If the NZ FLAG is set (character is not 1CH), JUMP to
5D67H to push the error code and jump to the error handler. An unexpected non-printable code causes filespec error abort.
Character IS 1CH — synthesize a CR to terminate input cleanly and write a double-CR to the filespec buffer to signal that no filename was entered.
5D81
LD A,0DH 3E 0D
Load Register A with 0DH (CR). The 1CH code is replaced with a CR to signal end-of-input to the caller.
5D83
LD (HL),A 77
Store the CR (0DH) into the filespec buffer at the current HL position, writing the first of two CR bytes that terminate the buffer entry.
5D84
INC HL 23
Advance HL to the next buffer position.
5D85
LD (HL),A 77
Store a second CR (0DH) into the filespec buffer at the new HL position. NEWDOS/80 filespecs use a double-CR (0DH 0DH) sequence to mark end-of-filespec in certain contexts, signalling that no filename was entered.
5D86H - DRIVE SETUP AND GAT INITIALIZATION CALLS
This short sequence is the tail end of the filespec input routine and is also the jump target from 5D28H when no filespec prompts are needed. It calls three routines in sequence: (1) 5578H to set up source drive parameters, (2) 6162H to initialize or reset the GAT sector allocation state, and (3) 6178H to perform additional disk geometry initialization. On return from 6178H, the source drive number (in A) and geometry (in C) are stored to the work area at 5D8FH onward.
[ENTRY POINT — 5D86H] Reached either from the filespec input path (after 1CH abort) or directly from the no-filespec-needed branch at 5D28H.
5D86
GOSUB to the source drive setup routine at 5578H (entry: HL=594CH, source drive number variable). This configures the source drive's parameter block from the PDRIVE table, selecting the correct geometry and drive number for the subsequent read operations.
5D89
GOSUB to the routine at 6162H to initialize the GAT sector state and reset the allocation tracking for the new COPY/APPEND pass. This prepares the sector allocation bitmaps and counters for the source disk's GAT structure.
5D8C
GOSUB to the routine at 6178H to complete disk geometry initialization. On return: Register A = source drive number (0–3), Register C = source geometry parameter byte. Execution continues at 5D8FH with these values.
5D8FH - Store Geometry Results and Compute Tracks-Per-Pass Sentinel
Save the drive number and sectors-per-track returned by disk geometry init, then compute the tracks-per-pass sentinel from the high memory limit minus 24 bytes.
5D8F
LD (597CH),A 32 7C 59
Store Register A (the source drive number returned by
6178H) into memory location
597CH (source drive number cache). This preserves the drive number for later use by the directory scan loop.
5D92
LD A,C 79
Copy Register C (the sectors-per-track count returned by
6178H) into Register A.
5D93
LD (59C0H),A 32 C0 59
Store Register A (sectors-per-track count) into memory location 59C0H (source geometry byte). This preserves the sectors-per-track value for use during the COPY/FORMAT operation.
The next block computes a sentinel value that limits how many tracks can be processed in a single pass. It loads the high memory limit from 593CH (set during FORMAT initialization) and subtracts 24 (decimal) to provide a safety margin.
5D96
LD HL,(593CH) 2A 3C 59
Load Register Pair HL with the 16-bit value stored at memory location 593CH (saved high memory limit). This is the upper boundary of the available work buffer area.
5D99
LD DE,FFE8H 11 E8 FF
Load Register Pair DE with the value FFE8H, which is the two's complement representation of negative 24 (decimal). This will subtract 24 bytes from the high memory limit.
5D9C
ADD HL,DE 19
ADD Register Pair DE (FFE8H = -24) to Register Pair HL (the high memory limit). The result in HL is the high memory limit minus 24, providing a safety buffer below the absolute memory ceiling.
5D9D
LD (61DBH),HL 22 DB 61
Store Register Pair HL (the adjusted high memory limit, i.e., high-mem minus 24) into memory location 61DBH (tracks-per-pass sentinel). The directory scan loop and track buffer management routines use this value to prevent buffer overflows.
5DA0H - Check for Outstanding Filespec Prompts
Examine option flags byte 4 at 5997H to determine whether the user specified source and/or destination filespecs on the command line. If neither bit 4 (source filespec) nor bit 5 (destination filespec) is set, skip ahead to the directory scan at 5E0FH. If a source filespec was given, clear the 256-byte directory bitmap at 6291H and enter the filespec copy loop. If only a destination filespec was given, skip the bitmap clear.
5DA0
LD A,(5997H) 3A 97 59
Fetch Register A from memory location 5997H (option flags byte 4). Bit 4 of this byte indicates that a source filespec was parsed from the command line. Bit 5 indicates that a destination filespec was parsed.
5DA3
AND 30H E6 30
Mask Register A with 30H (binary 00110000), isolating bits 4 and 5. If both bits are zero, no filespecs were provided and the Z FLAG is set.
5DA5
If the Z FLAG is set (neither source nor destination filespecs were given), JUMP forward to
5E0FH to skip the filespec copy loop and proceed directly to the directory scan initialization.
5DA7
AND 10H E6 10
Further isolate bit 4 only (source filespec flag). If bit 4 is clear, the Z FLAG is set, meaning only a destination filespec was given (bit 5 was set but bit 4 was not).
5DA9
LD C,A 4F
Copy Register A (either 10H if source filespec present, or 00H if not) into Register C. Register C serves as a flag throughout the filespec copy loop: non-zero means a source filespec was provided.
5DAA
If the Z FLAG is set (no source filespec — only destination filespec present), JUMP forward to
5DB5H to skip the bitmap clear and go straight to the filespec buffer at
6491H.
[BITMAP CLEAR] — A source filespec was given (bit 4 of 5997H is set). Before processing filespecs, clear the entire 256-byte directory bitmap at 6291H to zero. This bitmap tracks which directory entries have been matched against filespecs.
5DAC
XOR A AF
Set Register A to 00H by XORing it with itself. This provides the zero-fill value for the bitmap.
5DAD
LD B,A 47
Copy Register A (00H) into Register B. Since B is zero, the DJNZ loop below will iterate 256 times (B counts down from 0 to 0, wrapping through FFH, FEH, ... 01H).
5DAE
LD HL,6291H 21 91 62
Point Register Pair HL to memory address 6291H, the start of the 256-byte directory bitmap work buffer.
[LOOP START] — Zero-fill the 256-byte directory bitmap buffer at 6291H.
5DB1
LD (HL),A 77
Store Register A (00H) into the memory location pointed to by HL (current byte of the directory bitmap buffer at 6291H).
5DB2
INC HL 23
INCrement Register Pair HL by 1 to advance to the next byte of the bitmap buffer.
5DB3
DECrement Register B by 1 and JUMP back to
5DB1H if B is not zero. This loops 256 times (B wraps from 00H→FFH, then counts down to 01H), clearing all 256 bytes of the directory bitmap.
[LOOP END] — The directory bitmap at 6291H is now fully zeroed.
5DB5H - Filespec Copy Loop: Build Drive-Qualified Filespec at 4480H
Process each filespec stored in the buffer at 6491H. For each entry: copy the filespec string into the SYS0 work buffer at 4480H, append a colon separator and the source drive number as a decimal ASCII string, then call SYS0 drive init at 4424H. On success, record the parsed drive index into the directory bitmap at 6291H. Loop until a 0DH (carriage return) terminator is encountered.
5DB5
LD HL,6491H 21 91 64
Point Register Pair HL to memory address 6491H, the start of the filespec string buffer. This buffer contains one or more filespec strings separated by 0DH terminators.
[LOOP START — OUTER FILESPEC LOOP] — Process the next filespec from the buffer at 6491H. Each iteration reads a complete filespec string, copies it to the SYS0 work area, appends the source drive number, and calls SYS0 for drive initialization.
5DB8
LD A,(HL) 7E
Fetch Register A from the memory location pointed to by HL (the current byte in the filespec buffer at 6491H).
5DB9
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). If Register A equals 0DH, the Z FLAG is set, indicating the end of all filespecs in the buffer.
5DBB
If the Z FLAG is set (the filespec buffer starts with 0DH, meaning no more filespecs remain), JUMP forward to
5E07H to handle the no-source-filespec path.
5DBD
LD DE,447FH 11 7F 44
Point Register Pair DE to memory address 447FH, which is one byte before the SYS0 work buffer at 4480H. The first INC DE in the copy loop will advance DE to 4480H before storing the first byte.
[LOOP START — CHARACTER COPY LOOP] — Copy bytes from the filespec buffer (HL) to the SYS0 work buffer (DE) until a 0DH terminator is found. The copy is inclusive of the 0DH terminator.
5DC0
INC DE 13
INCrement Register Pair DE by 1 to advance to the next write position in the SYS0 work buffer (first iteration: DE goes from 447FH to 4480H).
5DC1
LD A,(HL) 7E
Fetch Register A from the memory location pointed to by HL (the current byte of the filespec string).
5DC2
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). If Register A equals 0DH, the Z FLAG is set, indicating the end of this individual filespec string.
5DC4
LD (DE),A 12
Store Register A (the current filespec character, or the 0DH terminator) into the memory location pointed to by DE (the SYS0 work buffer position). The 0DH terminator is stored before the loop exits.
5DC5
INC HL 23
INCrement Register Pair HL by 1 to advance to the next byte in the source filespec buffer.
5DC6
If the NZ FLAG is set (the character just copied was not 0DH, i.e., the filespec string has not ended), JUMP back to
5DC0H to copy the next character.
[LOOP END — CHARACTER COPY] — At this point, a complete filespec string has been copied from 6491H to 4480H, ending with a 0DH terminator. HL now points to the byte after the 0DH in the source buffer (the start of the next filespec or another 0DH). DE points to the 0DH terminator position in the SYS0 work buffer. Now we append a colon and the source drive number as ASCII digits after the filespec.
5DC8
EX DE,HL EB
Swap Register Pairs DE and HL. Now HL points to the 0DH position in the SYS0 work buffer (where we will overwrite with the drive designator), and DE holds the position in the source filespec buffer (saved for later).
5DC9
LD (HL),3AH 36 3A
Store 3AH (ASCII colon :) into the memory location pointed to by HL, overwriting the 0DH terminator. This begins the drive designator suffix (e.g., ":0" or ":1").
5DCB
INC HL 23
INCrement Register Pair HL by 1 to advance past the colon to the position where the drive number digits will be stored.
5DCC
LD A,(594CH) 3A 4C 59
Fetch Register A from memory location 594CH (the source drive number, 0-3). This is the drive number that will be converted to ASCII decimal digits and appended to the filespec.
5DCF
LD B,64H 06 64
Load Register B with
64H (100 decimal). This is the divisor for the hundreds digit of the drive number. The decimal digit extraction routine at
61CBH divides A by B and stores the quotient as an ASCII digit.
5DD1
GOSUB to
61CBH (decimal digit extraction). This divides Register A by Register B (100), stores the ASCII quotient digit at the memory location pointed to by HL, advances HL, and returns with the remainder in A. For drive numbers 0-3, the hundreds digit is always
0.
5DD4
LD B,0AH 06 0A
Load Register B with 0AH (10 decimal). This is the divisor for the tens digit.
5DD6
GOSUB to
61CBH (decimal digit extraction). This divides the remainder from the hundreds-digit extraction by 10, stores the ASCII tens digit, advances HL, and returns with the ones-digit remainder in A. For drive numbers 0-3, the tens digit is always
0.
5DD9
ADD 30H C6 30
ADD 30H (ASCII 0) to Register A (the ones-digit remainder). This converts the final digit from binary (0-9) to its ASCII character representation (0-9). For drive numbers 0-3, this produces ASCII 0 through 3.
5DDB
LD (HL),A 77
Store Register A (the ASCII ones digit of the drive number) into the memory location pointed to by HL.
5DDC
INC HL 23
INCrement Register Pair HL by 1 to advance past the ones digit.
5DDD
LD (HL),0DH 36 0D
Store 0DH (carriage return) into the memory location pointed to by HL. This terminates the drive-qualified filespec string in the SYS0 work buffer. The buffer at 4480H now contains the original filespec plus a colon, three-digit drive number, and 0DH terminator (e.g., MYFILE/BAS:000\r).
5DDF
EX DE,HL EB
Swap Register Pairs DE and HL. Now HL is restored to the position in the source filespec buffer (pointing to the byte after the 0DH that ended the previous filespec), and DE points into the SYS0 work buffer (no longer needed).
5DE0
LD DE,4480H 11 80 44
Load Register Pair DE with 4480H, pointing to the start of the completed drive-qualified filespec string in the SYS0 work buffer.
5DE3
GOSUB to
4424H (SYS0 drive init). This initializes the drive specified in the filespec at DE (4480H). On return, A holds the error code (00H = success) and the Z FLAG reflects the result.
5DE6H - Drive Init Error/Retry Dispatch
Handle the return code from SYS0 drive init at 4424H. On success (Z), proceed to record the parsed drive index. Error code 18H means the filespec was re-directed (retry from the top of the filespec). Error code 19H means the filespec was re-assigned (also retry). Any other non-zero error is fatal.
5DE6
If the Z FLAG is set (drive init at
4424H succeeded with no error), JUMP forward to
5DF1H to record the parsed drive index into the directory bitmap.
5DE8
CP 18H FE 18
Compare Register A (the error code from drive init) against 18H. Error code 18H indicates a filespec redirection — the drive/file assignment was changed and the filespec should be re-processed from the start of this entry.
5DEA
If the Z FLAG is set (error code is 18H, filespec redirection), JUMP back to
5DB8H to re-read the current filespec from the buffer and retry.
5DEC
CP 19H FE 19
Compare Register A (error code) against 19H. Error code 19H indicates a filespec re-assignment — similar to 18H but for a different type of drive reassignment.
5DEE
If the NZ FLAG is set (error code is NOT 19H — it is an unrecoverable error), JUMP to
521AH (main error handler entry). Any error code other than 00H, 18H, or 19H is fatal.
If the Z FLAG is set (error code IS 19H), fall through. Since 19H is also a retry condition, execution falls through and continues at
5DF1H, effectively treating 19H the same as success for the purpose of recording the drive index.
5DF1H - Record Parsed Drive Index in Directory Bitmap
After a successful drive init (or error 19H), fetch the parsed directory entry index from SYS0 variable 4F56H and use it as an offset into the 256-byte directory bitmap at 6291H. Store either the source filespec flag (if C is non-zero) or a default option code (from 4D6EH) at that bitmap position. Then loop back to process the next filespec.
5DF1
LD A,(4F56H) 3A 56 4F
Fetch Register A from memory location 4F56H (the directory entry index returned by SYS0 after parsing the filespec). This is a zero-based index identifying which directory entry slot was matched.
5DF4
PUSH HL E5
Save Register Pair HL (the current position in the filespec source buffer at 6491H) onto the stack, since we need HL to index into the directory bitmap.
5DF5
LD HL,6291H 21 91 62
Point Register Pair HL to memory address 6291H, the start of the 256-byte directory bitmap work buffer.
5DF8
LD E,A 5F
Copy Register A (the directory entry index from 4F56H) into Register E.
5DF9
LD D,00H 16 00
Load Register D with 00H to form the 16-bit offset DE = 00:index.
5DFB
ADD HL,DE 19
ADD Register Pair DE (the directory entry index) to Register Pair HL (base of directory bitmap at 6291H). HL now points to the specific byte in the bitmap corresponding to this directory entry.
5DFC
LD A,C 79
Copy Register C (the source filespec flag: 10H if source filespec present, or 00H if only destination filespec) into Register A.
5DFD
OR A B7
OR Register A with itself. This sets the Z FLAG if C was 00H (no source filespec), or clears the Z FLAG if C was 10H (source filespec present).
5DFE
If the Z FLAG is set (C was 00H — no source filespec, only destination filespec), JUMP forward to
5E03H to store 00H in the bitmap entry. When C is zero, Register A already holds 00H.
5E00
LD A,(4D6EH) 3A 6E 4D
Fetch Register A from memory location 4D6EH (the filespec character storage address, which holds the current option code associated with this filespec). This value will be stored in the directory bitmap to record which copy option applies to this directory entry.
5E03
LD (HL),A 77
Store Register A (either the option code from 4D6EH, or 00H if no source filespec) into the directory bitmap at the position corresponding to this directory entry. Non-zero values mark entries that matched a user-provided filespec.
5E04
POP HL E1
Restore Register Pair HL from the stack. HL now points back into the filespec source buffer at 6491H, positioned at the byte after the 0DH that ended the previous filespec.
5E05
JUMP back to
5DB8H to process the next filespec string from the buffer.
[LOOP END — OUTER FILESPEC LOOP]
5E07H - No-Source-Filespec Path: Set Drive Mode and Re-Init Source
Reached when the filespec buffer at 6491H starts with a 0DH terminator, meaning no more filespecs remain to be processed. Set the drive setup mode to 05H and re-initialize the source drive before falling through to the directory scan initialization at 5E0FH.
5E07
LD A,05H 3E 05
Load Register A with 05H, the function code for the drive setup dispatcher that means "re-initialize the source drive with default parameters."
5E09
GOSUB to
568DH (drive setup dispatcher) with A=05H. This re-initializes the drive using the default configuration for the current operation mode.
5E0C
GOSUB to
5578H (source drive setup). This ensures the source drive parameter block is properly configured before the directory scan begins.
5E0FH - Initialize Directory Buffer Pointers and Begin Directory Scan
Reset the directory buffer start and end pointers at 5D12H and 5D14H to both point to 6491H (the beginning of the directory work buffer area). Then enter the main directory scan loop, which reads directory entries from the source disk, applies multi-criteria filtering based on option flags, and either copies entries to the directory buffer or skips them.
5E0F
LD HL,6491H 21 91 64
Point Register Pair HL to memory address 6491H, the start of the directory work buffer area.
5E12
LD (5D12H),HL 22 12 5D
Store Register Pair HL (6491H) into memory location 5D12H (directory buffer start pointer). This resets the start pointer to the beginning of the buffer.
5E15
LD (5D14H),HL 22 14 5D
Store Register Pair HL (6491H) into memory location 5D14H (directory buffer end pointer). Setting start and end to the same address means the buffer is empty.
5E18
LD C,00H 0E 00
Load Register C with 00H. This is the initial index passed to the directory buffer advance routine, requesting the first directory entry slot.
[MAIN DIRECTORY SCAN LOOP START] — The following code iterates through directory entries on the source disk. For each entry, it applies a series of flag-based filters. Entries that pass all filters are added to the directory buffer at 6491H for later processing by the COPY routine.
5E1A
GOSUB to
619DH (advance directory buffer pointer). Register C provides the index. On return, the NZ FLAG is set if the pointer has advanced past the end of available directory entries.
5E1D
If the NZ FLAG is set (the directory buffer pointer is past the end of directory entries), JUMP to
5EAAH to advance to the next directory slot and check for end-of-directory.
5E20H - Multi-Criteria Directory Entry Filter
Apply a cascade of flag-based tests to the current directory entry. The filters check FORMAT mode, option flags at 5996H, density and in-use flags in the directory entry, and file extension matches. Entries that fail any test are skipped by jumping to 5EAAH. Entries that pass all tests proceed to the operator menu at 5E63H or directly to the directory buffer write at 5E87H.
5E20
GOSUB to
61F6H (fetch FORMAT mode flag). This loads the DOS mode byte from (IY+02H) at 4282H and isolates bit 5 (FORMAT mode). On return, the NZ FLAG is set if FORMAT mode is active. HL points to 4282H on return.
5E23
LD A,(5996H) 3A 96 59
Fetch Register A from memory location 5996H (option flags byte 3). This byte contains multiple flags that control which directory entries to include or exclude during the COPY operation.
5E26
If the NZ FLAG is set (FORMAT mode is active, from the CALL to
61F6H), JUMP forward to
5E32H to skip the bit 0 and bit 5 tests. In FORMAT mode, different filtering rules apply.
[COPY MODE FILTER PATH] — Not in FORMAT mode. Check bit 0 of the option flags (5996H) for a specific copy sub-mode.
5E28
BIT 0,A CB 47
Test bit 0 of Register A (option flags byte 3 at 5996H). Bit 0 controls a specific copy sub-mode. If bit 0 is clear, the Z FLAG is set.
5E2A
If the Z FLAG is set (bit 0 of option flags byte 3 is clear — this sub-mode is not active), JUMP forward to
5E32H to skip the density flag test.
5E2C
INC HL 23
INCrement Register Pair HL by 1 to point to the next byte of the directory entry (byte+1 from the current position).
5E2D
BIT 5,(HL) CB 6E
Test bit 5 of the memory byte pointed to by HL (a flag byte within the directory entry). Bit 5 is the density/type flag — when set, it indicates this entry uses a specific density or format.
5E2F
DEC HL 2B
DECrement Register Pair HL by 1 to restore it back to the original directory entry position.
5E30
If the Z FLAG is set (bit 5 of the directory entry byte is clear — the density flag is not set), JUMP to
5EAAH to skip this entry. When the bit-0 copy sub-mode is active, entries without the density flag set are excluded.
[BIT 4 FILTER] — Test bit 4 of option flags byte 3 (5996H) for another copy sub-mode.
5E32
BIT 4,A CB 67
Test bit 4 of Register A (option flags byte 3 at 5996H). Bit 4 controls another filtering criterion. If bit 4 is clear, the Z FLAG is set.
5E34
If the Z FLAG is set (bit 4 is clear — this filter is inactive), JUMP forward to
5E3EH to skip the in-use and flag tests.
5E36
BIT 6,(HL) CB 76
Test bit 6 of the memory byte pointed to by HL (the directory entry flags byte). Bit 6 is the "in-use" or "allocated" flag in the directory entry.
5E38
If the NZ FLAG is set (bit 6 is set — entry is marked in-use/allocated), JUMP to
5EAAH to skip this entry. When bit-4 filtering is active, allocated entries are excluded.
5E3A
BIT 3,(HL) CB 5E
Test bit 3 of the memory byte pointed to by HL (another flag in the directory entry). Bit 3 is an additional entry status flag.
5E3C
If the NZ FLAG is set (bit 3 is set in the directory entry), JUMP to
5EAAH to skip this entry.
[BIT 1 FILTER — FILE EXTENSION CHECK] — Test bit 1 of option flags byte 3. When set, this enables a file extension comparison against a reference string at 624CH.
5E3E
BIT 1,A CB 4F
Test bit 1 of Register A (option flags byte 3 at 5996H). Bit 1 enables a file extension matching filter. If bit 1 is clear, the Z FLAG is set.
5E40
If the Z FLAG is set (bit 1 is clear — extension matching is disabled), JUMP forward to
5E5BH to skip the extension comparison and proceed to the density flag test.
[EXTENSION COMPARISON] — Compare the 3-byte file extension at offset +0DH in the directory entry against the reference string at 624CH. This filters entries to only those matching a specific extension (e.g., "BAS", "CMD").
5E42
PUSH HL E5
Save Register Pair HL (pointer to current directory entry) onto the stack.
5E43
PUSH DE D5
Save Register Pair DE onto the stack.
5E44
PUSH BC C5
Save Register Pair BC onto the stack.
5E45
LD DE,000DH 11 0D 00
Load Register Pair DE with 000DH (13 decimal). This is the offset from the start of a directory entry to the 3-byte file extension field.
5E48
ADD HL,DE 19
ADD Register Pair DE (000DH) to Register Pair HL (directory entry base). HL now points to the 3-byte file extension field within the directory entry.
5E49
LD DE,624CH 11 4C 62
Point Register Pair DE to memory address 624CH, the location of the 3-byte reference extension string (e.g., "BAS" or another extension to match against).
5E4C
LD B,03H 06 03
Load Register B with 03H (3). The extension field is 3 bytes long, so we compare 3 bytes.
[LOOP START — 3-BYTE EXTENSION COMPARISON]
5E4E
LD A,(DE) 1A
Fetch Register A from the memory location pointed to by DE (the current byte of the reference extension string at 624CH).
5E4F
CP (HL) BE
Compare Register A (reference extension byte) against the byte pointed to by HL (directory entry extension byte). If they match, the Z FLAG is set.
5E50
INC DE 13
INCrement Register Pair DE by 1 to advance to the next byte of the reference extension.
5E51
INC HL 23
INCrement Register Pair HL by 1 to advance to the next byte of the directory entry extension.
5E52
If the NZ FLAG is set (the current extension byte did not match), JUMP forward to
5E56H to exit the comparison loop early with a mismatch result.
5E54
DECrement Register B by 1 and JUMP back to
5E4EH if B is not zero. This loops up to 3 times to compare all 3 extension bytes. If all 3 match, B reaches zero and the Z FLAG remains set.
[LOOP END — EXTENSION COMPARISON] — The Z FLAG is set if all 3 bytes matched; NZ if any byte mismatched.
5E56
POP BC C1
Restore Register Pair BC from the stack.
5E57
POP DE D1
Restore Register Pair DE from the stack.
5E58
POP HL E1
Restore Register Pair HL from the stack (directory entry base pointer).
5E59
If the NZ FLAG is set (the file extension did not match the reference at 624CH), JUMP to
5EAAH to skip this directory entry.
5E5BH - Density Flag Test and Double-Density Compatibility Check
Load the first byte of the directory entry into Register D and test bit 6 (the density/allocation flag). If set, call the double-density compatibility check at 61EAH. If the drives are incompatible for double-density, skip the entry.
5E5B
LD D,(HL) 56
Load Register D from the memory location pointed to by HL (the first flags byte of the current directory entry). Register D is preserved across the remaining tests and used later during directory buffer writes.
5E5C
BIT 6,D CB 72
Test bit 6 of Register D (the directory entry flags byte). Bit 6 is the density flag — when set, the entry was written in double-density (MFM) mode.
5E5E
If the NZ FLAG is set (bit 6 is set — this is a double-density directory entry), GOSUB to
61EAH (check if either the source or destination drive supports MFM/double-density). On return, the NZ FLAG is set if neither drive supports double density, meaning this entry cannot be copied.
5E61
If the NZ FLAG is set (neither drive supports double density and this is a double-density entry), JUMP to
5EAAH to skip this entry because it cannot be transferred.
5E63H - Date-Stamp Update Flag and Operator Menu Prompt
Check bit 6 of option flags byte 2 (5995H) to see if the operator should be prompted for each directory entry. If set, display the filespec name and present a menu with options: 0=skip/display FORMAT message, 1=format single entry, 2=skip this entry, or 3+=add to directory buffer.
5E63
LD A,(5995H) 3A 95 59
Fetch Register A from memory location 5995H (option flags byte 2). This byte contains additional copy/format option flags.
5E66
BIT 6,A CB 77
Test bit 6 of Register A (option flags byte 2). Bit 6 is the per-entry prompt flag — when set, the operator is asked what to do with each directory entry before it is copied.
5E68
If the Z FLAG is set (bit 6 is clear — per-entry prompting is disabled), JUMP forward to
5E87H to add this entry directly to the directory buffer without prompting.
[OPERATOR PROMPT PATH] — The per-entry prompt flag is set. Display the filename and present a menu for the operator.
5E6A
PUSH DE D5
Save Register Pair DE onto the stack.
5E6B
PUSH BC C5
Save Register Pair BC onto the stack.
5E6C
GOSUB to
58A0H (display filespec name). This displays the filename and extension of the current directory entry on screen so the operator can see which file is being considered.
5E6F
LD HL,625CH 21 5C 62
Point Register Pair HL to memory address 625CH, the location of the menu option string (an ASCII string containing the list of menu choices presented to the operator).
5E72
GOSUB to
58E4H (menu response scanner). Display the menu string at HL and wait for the operator to select an option. On return, Register A contains the operator's selection (0, 1, 2, etc.) and the Z FLAG is set if the selection was 0 (the default/first option).
5E75
POP BC C1
Restore Register Pair BC from the stack.
5E76
POP DE D1
Restore Register Pair DE from the stack.
5E77
If the NZ FLAG is set (operator selected a non-default option — selection ≠ 0), JUMP forward to
5E81H to decode the specific selection.
[SELECTION 0 — SKIP AND DISPLAY FORMAT MESSAGE] — The operator selected option 0 (default). Display a message and restart the directory scan from the top.
5E79
LD HL,6D5DH 21 5D 6D
Point Register Pair HL to memory address 6D5DH, the location of the FORMAT/status display string (e.g., a clear-screen prefix or status message).
5E7C
GOSUB to
4467H (SYS0 display null-terminated string). Display the string at HL.
5E7F
JUMP back to
5E0FH to reset the directory buffer pointers and restart the directory scan from the beginning.
[SELECTION 1 OR 2] — Decode non-default operator selections.
5E81
DEC A 3D
DECrement Register A by 1. If the operator selected option 1, A becomes 0 and the Z FLAG is set.
5E82
If the Z FLAG is set (operator selected option 1 — format/copy this single entry), JUMP forward to
5EB3H to begin processing the selected entry.
5E84
DEC A 3D
DECrement Register A by 1 again. If the operator selected option 2, A becomes 0 and the Z FLAG is set.
5E85
If the Z FLAG is set (operator selected option 2 — skip this entry), JUMP to
5EAAH to advance to the next directory entry without adding this one to the buffer.
If execution reaches here, the operator selected option 3 or higher. Fall through to add this entry to the directory buffer at 5E87H.
5E87H - Write Directory Entry to Directory Buffer
Add the current directory entry to the directory buffer. Write an 80H marker (busy flag) at the current end-of-buffer position, then conditionally set bit 6 (density flag) based on a series of flag checks. Finally, append the BC register pair (additional entry data) and advance the buffer end pointer.
5E87
LD HL,(5D14H) 2A 14 5D
Load Register Pair HL from memory location 5D14H (the directory buffer end pointer). This points to the next available position in the directory buffer at 6491H and beyond.
5E8A
LD (HL),80H 36 80
Store 80H into the memory location pointed to by HL. The value 80H serves as a "busy/pending" marker byte at the start of each directory buffer entry, indicating this slot is in use.
Now check whether bit 6 (density flag) should be set in this buffer entry. Several conditions must all be met: bit 6 of Register D (the directory entry flags) must be set, bit 3 of 5997H must be clear, Register C must be less than 80H, and bits 3-4 of C must both be clear.
5E8C
BIT 6,D CB 72
Test bit 6 of Register D (the directory entry flags byte loaded at
5E5BH). Bit 6 is the density flag — set means this is a double-density entry.
5E8E
If the Z FLAG is set (bit 6 is clear — this is a single-density entry), JUMP forward to
5EA2H to skip the density flag propagation and proceed directly to storing the BC data bytes.
5E90
LD A,(5997H) 3A 97 59
Fetch Register A from memory location 5997H (option flags byte 4).
5E93
BIT 3,A CB 5F
Test bit 3 of Register A (option flags byte 4). Bit 3 indicates a destination filespec is present.
5E95
If the NZ FLAG is set (bit 3 is set — a destination filespec was given), JUMP forward to
5EA2H to skip setting the density flag. When a destination filespec is present, the density is determined by the destination, not the source.
5E97
LD A,C 79
Copy Register C into Register A for testing.
5E98
CP 80H FE 80
Compare Register A (the value of C) against 80H. If A is greater than or equal to 80H, the NO CARRY FLAG is set.
5E9A
If the NO CARRY FLAG is set (C ≥ 80H), JUMP forward to
5EA2H to skip setting the density flag.
5E9C
AND 18H E6 18
Mask Register A (value of C) with 18H (binary 00011000), isolating bits 3 and 4.
5E9E
If the NZ FLAG is set (either bit 3 or bit 4 of C is set), JUMP forward to
5EA2H to skip setting the density flag.
5EA0
SET 6,(HL) CB F6
SET bit 6 of the memory byte pointed to by HL (the 80H marker byte written at
5E87H). The byte becomes C0H. This propagates the double-density flag from the source directory entry into the directory buffer entry, indicating that this file should be copied using double-density mode.
Append the BC register pair (directory entry track and sector data) after the marker byte, then advance the buffer end pointer.
5EA2
INC HL 23
INCrement Register Pair HL by 1 to advance past the marker/flags byte to the first data byte position.
5EA3
LD (HL),C 71
Store Register C (the low byte of the directory entry data — typically a sector or index value) into the memory location pointed to by HL.
5EA4
INC HL 23
INCrement Register Pair HL by 1.
5EA5
LD (HL),B 70
Store Register B (the high byte of the directory entry data) into the memory location pointed to by HL.
5EA6
INC HL 23
INCrement Register Pair HL by 1 to point to the position after the last byte of this directory buffer entry.
5EA7
LD (5D14H),HL 22 14 5D
Store Register Pair HL (the new buffer position) into memory location 5D14H (directory buffer end pointer). This advances the end pointer by 3 bytes (1 marker byte + 2 data bytes) to reflect the newly added entry.
5EAAH - Advance to Next Directory Slot and Loop
Advance the source directory position counter by calling 61BAH, then loop back to process the next directory entry if more remain. This is the common exit/continuation point for all paths through the directory filter — both entries that passed (after being added to the buffer at 5E87H) and entries that were skipped.
5EAA
LD HL,597CH 21 7C 59
Point Register Pair HL to memory address
597CH (the source drive number stored at
5D8FH). The routine at
61BAH uses the value at this address to determine how to advance the directory position.
5EAD
GOSUB to
61BAH (advance to next directory slot). This increments the directory position counter and returns with the CARRY FLAG set if all directory entries have been processed (end-of-directory reached), or CARRY FLAG clear if more entries remain.
5EB0
If the NO CARRY FLAG is set (more directory entries remain to be scanned), JUMP back to
5E1AH to process the next directory entry through the filter cascade.
[MAIN DIRECTORY SCAN LOOP END]If the CARRY FLAG is set (all directory entries have been scanned), fall through to
5EB3H to begin processing the directory buffer entries.
5EB3H - Directory Buffer Dispatch: Check for Entries and Begin Processing
After the directory scan loop (ending at 5EB0H) has populated the directory buffer at 6491H, this code reloads the buffer control pointers and checks whether any entries were collected. If the buffer is empty, jump to the finalize/exit routine at 552DH. Otherwise, begin iterating through the buffer entries, setting up destination and source drives for each one.
5EB3
GOSUB to
6190H (reload directory buffer control pointers). This loads the directory buffer end pointer from
5D14H into
61D8H, and reloads the directory buffer start pointer from
5D12H into HL, then decrements HL by 3 to position before the first entry.
5EB6
GOSUB to
5699H (advance HL by 3 and compare against the directory buffer end pointer at 5D14H). On return, the Z FLAG is set if HL has reached or passed the end of the buffer, meaning no entries were collected.
5EB9
If the Z FLAG is set (the directory buffer is empty — no entries passed the filter cascade), JUMP to
552DH (write directory and exit). There is nothing to copy, so finalize the operation.
[DIRECTORY BUFFER ITERATION LOOP START] — The directory buffer contains at least one entry. For each entry: push the current buffer position, fetch the corresponding directory entry from disk, set up destination and source drives, and copy the entry to the destination.
5EBC
PUSH HL E5
Save Register Pair HL (the current position in the directory buffer) onto the stack. This is preserved across the destination drive setup and directory fetch operations.
5EBD
GOSUB to
61D6H (fetch next directory entry address via RST 18H). This reads the next directory entry from disk into the DOS work area. On return, the CARRY FLAG is set if the entry is past the end of the directory, and HL and DE are updated with the entry address information. The entry data address is saved to
61D8H.
5EC0
If the CARRY FLAG is set (the directory entry index is past the end — this entry needs to be appended rather than matched), JUMP forward to
5ECEH to handle the append-entry path.
[MATCHED ENTRY PATH] — The directory entry exists on disk. Set up the destination drive, copy the entry, then re-init the source drive and reload the buffer control.
5EC2
GOSUB to
5EE4H (destination drive setup routine). This calls
557DH (destination drive setup),
6162H (GAT sector state init), and
6178H (disk geometry init) for the destination drive, storing the results at 597DH and 59CEH.
5EC5
GOSUB to
5578H (source drive setup). Re-initialize the source drive parameter block so the next directory buffer entry can be read from the source.
5EC8
GOSUB to
6190H (reload directory buffer control pointers). Refresh HL and 61D8H from the stored buffer pointers after the drive setup calls.
5ECB
POP HL E1
Restore Register Pair HL from the stack (the current directory buffer position saved at
5EBCH).
5ECC
JUMP back to
5EBCH to process the next directory buffer entry.
[LOOP CONTINUE]
5ECEH - Append-Entry Path: Copy 24-Byte Directory Entry from Disk
When the directory entry index is past the current directory end (CARRY was set from 61D6H), this code reads the track number from the directory buffer entry, seeks to that track, and copies 24 bytes of directory entry data from the source disk into the destination buffer area using LDIR. Then it marks the directory buffer slot as used (SET bit 4) and continues scanning.
5ECE
INC HL 23
INCrement Register Pair HL by 1 to advance past the marker byte of the current directory buffer entry, pointing to the data field (track number byte).
5ECF
LD A,(HL) 7E
Fetch Register A from the memory location pointed to by HL (the track number stored in the directory buffer entry's data field).
5ED0
GOSUB to
56EFH (track seek with the track number in Register A). This positions the disk head at the track containing the directory entry to be copied.
5ED3
LD BC,0018H 01 18 00
Load Register Pair BC with 0018H (24 decimal). This is the number of bytes to copy — a standard NEWDOS/80 directory entry is 24 bytes.
5ED6
LDIR ED B0
Block copy 24 bytes from the source address pointed to by HL to the destination address pointed to by DE. HL and DE are both advanced by 24, and BC is decremented to zero. This copies the complete directory entry data from the disk read buffer to the directory work area.
5ED8
POP HL E1
Restore Register Pair HL from the stack (the directory buffer entry position saved at
5EBCH). HL now points to the marker byte of the current directory buffer slot.
5ED9
SET 4,(HL) CB E6
SET bit 4 of the memory byte pointed to by HL (the directory buffer marker byte). This marks the slot as "used/processed," preventing it from being processed again.
5EDB
GOSUB to
5699H (advance HL by 3 and compare against the directory buffer end pointer). This moves to the next directory buffer entry and checks if we have reached the end of the buffer.
5EDE
If the NZ FLAG is set (more directory buffer entries remain), JUMP back to
5EBCH to process the next entry.
[LOOP CONTINUE]
[DIRECTORY BUFFER ITERATION LOOP END] — All directory buffer entries have been processed. Fall through to set up the return address and call the destination drive setup routine for the final phase.
5EE0H - Push Post-Copy Return Address and Set Up Destination Drive
Push the address 60BFH onto the stack as a return address for the destination directory matching phase. Then fall through into the destination drive setup routine at 5EE4H. When the destination matching loop completes and returns via RET, execution will resume at 60BFH (the post-directory-copy dispatcher).
5EE0
LD HL,60BFH 21 BF 60
Load Register Pair HL with 60BFH, the address of the post-directory-copy dispatcher routine.
5EE3
PUSH HL E5
Save Register Pair HL (60BFH) onto the stack. This establishes
60BFH as the return address — when the destination matching routine eventually executes a RET, it will resume at 60BFH.
5EE4H - Destination Drive Setup: Init Drive, GAT, and Geometry
Set up the destination drive by calling 557DH (destination drive setup), 6162H (GAT sector state init), and 6178H (disk geometry init). Store the returned drive number at 597DH and sectors-per-track at 59CEH. Then check whether a destination filespec was specified — if so, enter the destination directory matching loop at 5EFCH; if not, jump to the no-dest-filespec path at 5F92H.
5EE4
GOSUB to
557DH (destination drive setup). This initializes the destination drive parameter block and selects the destination drive for I/O.
5EE7
GOSUB to
6162H (GAT sector state init). This reads the GAT sector from the destination drive and copies 256 bytes to the work buffer at
6291H.
5EEA
GOSUB to
6178H (disk geometry init). On return, Register A holds the destination drive number and Register C holds the sectors-per-track count for the destination.
5EED
LD (597DH),A 32 7D 59
Store Register A (the destination drive number) into memory location 597DH (destination geometry/directory pointer).
5EF0
LD A,C 79
Copy Register C (destination sectors-per-track count) into Register A.
5EF1
LD (59CEH),A 32 CE 59
Store Register A (destination sectors-per-track count) into memory location 59CEH (destination geometry count byte).
5EF4
LD A,(5997H) 3A 97 59
Fetch Register A from memory location 5997H (option flags byte 4).
5EF7
BIT 3,A CB 5F
Test bit 3 of Register A (option flags byte 4). Bit 3 indicates that a destination filespec was parsed from the command line.
5EF9
If the Z FLAG is set (bit 3 is clear — no destination filespec was given), JUMP to
5F92H to handle the no-destination-filespec path, which rebuilds the GAT from the source directory.
5EFCH - Destination Directory Matching Loop: Find Matching Entries
When a destination filespec was given (bit 3 of 5997H set), scan the destination disk's directory to find entries that match files in the source directory buffer. For each match, swap the track/sector assignment fields between source and destination entries and update the density/date pointers. This is the core of the file-level COPY operation when a destination filespec is specified.
5EFC
LD C,00H 0E 00
Load Register C with 00H. This is the starting index for the directory buffer advance routine — request the first directory entry on the destination disk.
5EFE
GOSUB to
619DH (advance directory buffer pointer, C-indexed from
6291H). On return, the NZ FLAG is set if past the end of available directory entries.
5F01
If the NZ FLAG is set (past end of destination directory entries), JUMP to
5F89H to advance the destination directory slot counter and check for more.
5F04
LD (5F1EH),HL 22 1E 5F
Store Register Pair HL (the current destination directory entry pointer) into memory location
5F1EH.
[SELF-MODIFYING CODE] — This patches the operand of the LD HL,0000H instruction at
5F1DH so that the filename comparison loop can access this directory entry pointer.
5F07
GOSUB to
6190H (reload directory buffer control pointers). Refresh HL with the source directory buffer base and save the end pointer to 61D8H.
[INNER SCAN LOOP START] — Iterate through the source directory buffer entries, looking for a filename match against the current destination directory entry.
5F0A
GOSUB to
5699H (advance HL by 3 and compare against directory buffer end). The Z FLAG is set if HL has reached or passed the end of the source directory buffer.
5F0D
If the Z FLAG is set (end of source directory buffer reached without finding a match), JUMP to
5F89H to advance to the next destination directory entry.
5F0F
BIT 4,(HL) CB 66
Test bit 4 of the memory byte pointed to by HL (the marker byte of the current source directory buffer entry). Bit 4 indicates this entry has been marked as "used/processed."
5F11
If the Z FLAG is set (bit 4 is clear — this source entry has NOT been marked as used), JUMP back to
5F0AH to skip this entry and try the next one. Only "used" entries (those that passed through the 5ECEH append path and were SET at 5ED9H) are eligible for matching.
5F13
GOSUB to
61D6H (fetch next directory entry address). This reads the source directory entry data from disk. On return, HL points to the entry data in the read buffer, and the entry's extended address is saved to 61D8H.
5F16
BIT 5,(HL) CB 6E
Test bit 5 of the memory byte pointed to by HL (a flag in the fetched source directory entry). Bit 5 is the density/processed flag.
5F18
If the NZ FLAG is set (bit 5 is set — this entry has a density flag or has already been processed), JUMP back to
5F0AH to skip it and try the next source buffer entry.
[FILENAME COMPARISON SETUP] — The source entry passed initial screening. Compare its 11-byte filename (8 name + 3 extension) against the destination directory entry. First, advance both pointers by 5 bytes to reach the filename fields.
5F1A
PUSH HL E5
Save Register Pair HL (pointer to the source directory entry data) onto the stack.
5F1B
LD B,05H 06 05
Load Register B with 05H (5). This is the number of bytes to advance both HL and DE to reach the filename field within the directory entry structure.
5F1D
LD HL,0000H 21 00 00
Load Register Pair HL with
0000H.
[SELF-MODIFYING CODE at 5F1EH] — The operand bytes at 5F1EH-5F1FH were patched at
5F04H with the address of the current destination directory entry. At runtime, HL is loaded with the actual destination entry pointer.
5F20
PUSH HL E5
Save Register Pair HL (destination directory entry pointer, loaded via self-modifying code) onto the stack.
5F21
PUSH DE D5
Save Register Pair DE onto the stack.
[LOOP START — ADVANCE BOTH POINTERS BY 5]
5F22
INC HL 23
INCrement Register Pair HL (destination entry pointer) by 1.
5F23
INC DE 13
INCrement Register Pair DE (source entry pointer) by 1.
5F24
DECrement Register B by 1 and JUMP back to
5F22H if B is not zero. After 5 iterations, both HL and DE point to offset +5 within their respective directory entries — the start of the 11-byte filename field.
[LOOP END — POINTER ADVANCE] — Now compare the 11-byte filenames.
5F26
LD B,0BH 06 0B
Load Register B with 0BH (11 decimal). This is the length of the filename+extension field to compare (8 characters of filename + 3 characters of extension).
5F28
GOSUB to
6254H (B-byte comparison loop). Compare B bytes at (DE) against (HL). On return, the Z FLAG is set if all 11 bytes match (identical filename+extension); NZ if any byte differs.
5F2B
POP HL E1
Restore Register Pair HL from the stack (the destination directory entry pointer saved before the advance loop, now pointing to the destination entry base + offset as adjusted).
5F2C
POP DE D1
Restore Register Pair DE from the stack.
5F2D
If the Z FLAG is set (filenames match — the source and destination have the same file), JUMP forward to
5F32H to enter the directory entry copy/swap path.
5F2F
POP HL E1
Restore Register Pair HL from the stack (the source directory entry pointer saved at 5F1AH). The filenames did not match.
5F30
JUMP back to
5F0AH to advance to the next source directory buffer entry and try again.
[INNER SCAN LOOP CONTINUE]
5F32H - Directory Entry Copy: Swap Track/Sector Fields Between Source and Destination
A filename match was found between a source directory buffer entry and a destination directory entry. Copy the track/sector assignment fields from the source to the destination, preserving key fields. This swaps the data allocation so the destination file now points to the source file's data sectors. Then call 6209H to update the density/date pointer, flush the GAT, and check if additional drive writes are needed.
5F32
PUSH DE D5
Save Register Pair DE onto the stack (the source entry pointer).
5F33
PUSH BC C5
Save Register Pair BC onto the stack.
5F34
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H (3). This offset advances to the track/sector assignment fields within the directory entry.
5F37
ADD HL,BC 09
ADD Register Pair BC (3) to Register Pair HL (destination entry pointer). HL now points to offset +3 in the destination directory entry — the track assignment field.
5F38
EX DE,HL EB
Swap Register Pairs DE and HL. Now DE points to the destination's track field, and HL points to the source entry.
5F39
ADD HL,BC 09
ADD Register Pair BC (3) to Register Pair HL (source entry pointer). HL now points to offset +3 in the source directory entry — the track assignment field.
Copy the first two bytes of the track/sector field from source (HL) to destination (DE).
5F3A
LD A,(DE) 1A
Fetch Register A from the memory location pointed to by DE (the destination's track assignment byte). This value is saved temporarily.
5F3B
LD (HL),A 77
Store Register A (the destination's track byte) into the source's track field at (HL). This is part of the swap — the destination's old value is written into the source.
5F3C
INC HL 23
INCrement HL by 1 to advance to the next byte (sector assignment).
5F3D
PUSH AF F5
Save Register A (the destination's original track byte) and flags onto the stack. This value is needed later by
6209H.
5F3E
INC DE 13
INCrement DE by 1 to advance to the destination's sector assignment byte.
5F3F
LD A,(DE) 1A
Fetch Register A from the memory location pointed to by DE (the destination's sector assignment byte).
5F40
LD (HL),A 77
Store Register A (the destination's sector byte) into the source's sector field at (HL).
Now advance both pointers by 16 bytes (0010H) to reach the extended track/sector fields further into the directory entry, and swap those as well.
5F41
LD BC,0010H 01 10 00
Load Register Pair BC with 0010H (16 decimal). This offset advances from the current position to the extended data pointer fields within the directory entry.
5F44
ADD HL,BC 09
ADD Register Pair BC (16) to Register Pair HL. HL now points to the source entry's extended data field.
5F45
EX DE,HL EB
Swap DE and HL. Now DE points to the source's extended field, HL points to the destination entry.
5F46
ADD HL,BC 09
ADD Register Pair BC (16) to Register Pair HL. HL now points to the destination entry's extended data field.
5F47
LD A,(HL) 7E
Fetch Register A from the destination's extended data field.
5F48
LD (DE),A 12
Store Register A into the source's extended data field — copying the destination's value to the source.
5F49
INC DE 13
INCrement DE by 1.
5F4A
INC HL 23
INCrement HL by 1.
5F4B
LD A,(HL) 7E
Fetch the next byte from the destination's extended field.
5F4C
LD (DE),A 12
Store it into the source's extended field.
5F4D
DEC DE 1B
DECrement DE by 1 to point back to the first extended byte for DE.
5F4E
EX DE,HL EB
Swap DE and HL. Now HL points to the source's extended data field, DE to the destination's.
5F4F
POP AF F1
Restore Register A (the destination's original track byte saved at 5F3DH) and flags from the stack. Register A is passed to
6209H which uses it to determine if density/date pointer updates are needed.
5F50
GOSUB to
6209H (conditional directory date pointer update). Based on the density flags and the value in Register A, this adjusts the date/time pointers in the directory entry to account for density mismatches between source and destination.
5F53
POP BC C1
Restore Register Pair BC from the stack.
5F54
POP DE D1
Restore Register Pair DE from the stack.
5F55
POP HL E1
Restore Register Pair HL from the stack (the source directory entry pointer saved at 5F1AH).
5F56
SET 5,(HL) CB EE
SET bit 5 of the memory byte pointed to by HL (the flags byte of the source directory entry). Bit 5 marks this entry as "matched and processed" so it will be skipped in subsequent scans.
5F58
INC HL 23
INCrement HL by 1.
5F59
INC HL 23
INCrement HL by 1. HL now points to the sector-assignment byte within the source directory buffer entry (offset +2).
5F5A
LD (HL),C 71
Store Register C (the track/sector data from the comparison result) into the directory buffer entry's sector field.
5F5B
LD A,C 79
Copy Register C into Register A.
5F5C
LD (5B1EH),A 32 1E 5B
Store Register A into memory location 5B1EH (destination buffer-cleared flag). This records the current sector assignment value for the destination parameter block.
5F5F
GOSUB to
5711H (flush GAT). Write the updated GAT sector back to disk and reset the cache.
5F62
LD A,(4288H) 3A 88 42
Fetch Register A from memory location 4288H (IY+08H, active overlay ID). The value 05H identifies the current overlay as the COPY module.
5F65
CP 05H FE 05
Compare Register A against 05H. If the active overlay is 05H (COPY module), the Z FLAG is set.
5F67
If the NZ FLAG is set (the active overlay is not 05H — a different module has been loaded, meaning a drive swap or reload occurred), JUMP to
5608H to handle the overlay mismatch by re-entering the module.
5F6AH - Post-Match: Check Density and Conditional Drive Write
After a successful filename match and directory entry swap, check the destination entry's density flag. If the destination entry does not have bit 6 set (not double-density), perform a sector write of the destination directory to disk via 60A9H. Then restore the overlay ID to 05H.
5F6A
INC DE 13
INCrement Register Pair DE by 1 to point to the next byte of the destination entry data.
5F6B
LD A,(DE) 1A
Fetch Register A from the memory location pointed to by DE (a flags byte in the destination directory entry).
5F6C
BIT 6,A CB 77
Test bit 6 of Register A (the density/allocation flag in the destination entry).
5F6E
DEC DE 1B
DECrement Register Pair DE by 1 to restore DE to its original position.
5F6F
If the NZ FLAG is set (bit 6 is set — the destination entry is double-density), JUMP to
5F89H to skip the sector write. Double-density entries are handled differently.
[SINGLE-DENSITY WRITE PATH] — The destination entry is single-density. Write it to the destination disk.
5F71
LD HL,428BH 21 8B 42
Point Register Pair HL to memory address 428BH (IY+0BH, DOS flags byte).
5F74
SET 2,(HL) CB D6
SET bit 2 of the DOS flags byte at 428BH. This bit signals to SYS0 that a write operation is in progress.
5F76
PUSH HL E5
Save Register Pair HL (pointer to 428BH) onto the stack so we can clear bit 2 after the write.
5F77
EX DE,HL EB
Swap DE and HL. Now HL holds the destination entry pointer and DE is free.
5F78
LD DE,5B17H 11 17 5B
Load Register Pair DE with 5B17H (destination drive parameter block base).
5F7B
GOSUB to
60A9H (sector write utility). This writes the destination directory entry to the destination disk using the parameter block at DE (5B17H). On return, the Z FLAG is set on success.
5F7E
If the NZ FLAG is set (the sector write failed), JUMP to
521AH (main error handler).
5F81
POP HL E1
Restore Register Pair HL from the stack (pointer to 428BH).
5F82
RES 2,(HL) CB 96
Clear bit 2 of the DOS flags byte at 428BH, indicating the write operation is complete.
5F84
LD A,05H 3E 05
Load Register A with 05H (the COPY overlay ID).
5F86
LD (4288H),A 32 88 42
Store Register A (05H) into memory location 4288H (IY+08H, active overlay ID). This restores the overlay ID to 05H after the write operation, which may have changed it.
5F89H - Advance Destination Directory Slot and Loop
Advance the destination directory position by calling 61BAH, then loop back to scan the next destination directory entry. This is the common continuation/exit point for the destination matching loop.
5F89
LD HL,597DH 21 7D 59
Point Register Pair HL to memory address
597DH (the destination drive number/geometry pointer stored at
5EEDH).
5F8C
GOSUB to
61BAH (advance to next directory slot). This increments the destination directory position counter. The CARRY FLAG is set if all destination directory entries have been processed.
5F8F
If the NO CARRY FLAG is set (more destination directory entries remain), JUMP back to
5EFEH to process the next entry.
[DESTINATION MATCHING LOOP END]If the CARRY FLAG is set (all destination entries scanned), fall through to the no-destination-filespec path at
5F92H, or return via the stacked address (60BFH).
5F92H - No-Destination-Filespec Path: Check Option and Rebuild GAT
When no destination filespec was specified (bit 3 of 5997H clear), or after the destination matching loop completes, check bit 3 of option flags byte 2 (5995H). If set, return immediately. Otherwise, re-initialize the source drive, copy the GAT to a backup buffer at 6391H, re-read the GAT and directory, and enter the GAT sector allocation loop to rebuild the destination disk's sector allocation from the source directory entries.
5F92
LD A,(5995H) 3A 95 59
Fetch Register A from memory location 5995H (option flags byte 2).
5F95
BIT 3,A CB 5F
Test bit 3 of Register A. Bit 3 is a skip-GAT-rebuild flag.
5F97
RET NZ C0
If the NZ FLAG is set (bit 3 is set — GAT rebuild is suppressed), RETURN to the caller. If this routine was entered via the pushed 60BFH address, execution resumes at
60BFH.
5F98
GOSUB to
56F9H (drive init with XOR A). Initialize the current drive with A=00H, which performs a basic drive reset.
5F9B
LD DE,6391H 11 91 63
Load Register Pair DE with 6391H, the address of the backup GAT buffer.
5F9E
GOSUB to
6172H (LDIR 256 bytes from HL to DE). This copies 256 bytes from the current position (the 4300H work area after drive init) to the backup buffer at 6391H, preserving the current GAT data.
5FA1
GOSUB to
6162H (GAT sector state init). Re-read the GAT sector from disk and copy it to the work buffer at 6291H.
5FA4
GOSUB to
6190H (reload directory buffer control pointers).
[GAT ALLOCATION SCAN LOOP START] — Iterate through the source directory buffer entries. For each entry, look up its allocation data and mark the corresponding sectors as allocated in the destination GAT.
5FA7
GOSUB to
5699H (advance HL by 3, compare against directory buffer end). The Z FLAG is set if the end of the buffer is reached.
5FAA
If the Z FLAG is set (end of directory buffer reached), JUMP to
6092H to finalize the GAT and complete the rebuild.
5FAD
BIT 4,(HL) CB 66
Test bit 4 of the memory byte pointed to by HL (the marker byte of the current directory buffer entry). Bit 4 marks an entry as "used/pending".
5FAF
If the Z FLAG is set (bit 4 is clear — entry is not in use), JUMP back to
5FA7H to skip this entry and advance to the next one.
5FB1
RES 4,(HL) CB A6
Clear bit 4 of the marker byte at (HL). This resets the "used" flag, preventing this entry from being processed again if the loop re-enters.
5FB3
PUSH HL E5
Save Register Pair HL (directory buffer entry pointer) onto the stack.
5FB4
BIT 5,(HL) CB 6E
Test bit 5 of the marker byte at (HL). Bit 5 indicates this entry was already matched and processed during the destination directory matching phase.
5FB6
INC HL 23
INCrement HL by 1 to point to the data byte (sector assignment) within the directory buffer entry.
5FB7
If the NZ FLAG is set (bit 5 is set — entry was already matched), JUMP to
6083H to skip the GAT allocation for this entry and advance to the next one.
[UNMATCHED ENTRY — ALLOCATE IN GAT] — This entry was not matched during the destination directory scan. Check density compatibility and verify the entry's track number is within the destination disk's range.
5FBA
GOSUB to
61EAH (check if either source or destination drive supports MFM/double-density). If neither supports MFM and this is a double-density entry, it cannot be allocated.
5FBD
If the NZ FLAG is set (density incompatibility), JUMP to
6083H to skip this entry.
5FC0
LD A,(HL) 7E
Fetch Register A from the memory location pointed to by HL (the track/sector data byte from the directory buffer entry).
5FC1
LD C,A 4F
Copy Register A into Register C. C holds the raw track/sector value for use in subsequent calculations.
5FC2
LD B,00H 06 00
Load Register B with 00H. BC now holds the track/sector value as a 16-bit number (B=00H, C=value).
5FC4
AND 1FH E6 1F
Mask Register A with 1FH (binary 00011111), isolating the lower 5 bits. This extracts the track number portion from the combined track/sector value.
5FC6
LD HL,597DH 21 7D 59
Point Register Pair HL to memory address 597DH (destination geometry/drive number byte).
5FC9
CP (HL) BE
Compare Register A (the track number from the directory entry) against the byte at (HL) (the destination drive's track count). If A ≥ (HL), the track number exceeds the destination disk's capacity.
5FCA
If the NO CARRY FLAG is set (track number ≥ destination capacity), JUMP to
6083H to skip this entry — the destination disk is too small for this file's track assignment.
5FCD
LD HL,6291H 21 91 62
Point Register Pair HL to memory address 6291H (the directory bitmap / GAT work buffer).
5FD0
ADD HL,BC 09
ADD Register Pair BC (the raw track/sector value, with B=00H) to HL. HL now points to the specific byte in the GAT work buffer corresponding to this entry's directory slot.
5FD1
LD A,(HL) 7E
Fetch Register A from the GAT work buffer byte at (HL).
5FD2
OR A B7
OR Register A with itself. The Z FLAG is set if the byte is 00H (slot is free). NZ means the slot is already allocated.
5FD3
EX DE,HL EB
Swap DE and HL. Now DE points to the GAT work buffer byte, and HL holds the previous DE value.
5FD4
If the NZ FLAG is set (the slot is already allocated in the GAT), JUMP to
6083H to skip this entry — there is a conflict.
5FD7H - Mark Entry and Copy Directory Data to Destination
The entry passed all validation checks. Mark it as processed (SET bit 5), swap the sector assignment value between the GAT work buffer and the directory buffer, seek to the appropriate track, copy 22 bytes of directory entry data using LDIR, load the file's granule/sector count, fill 10 bytes with FFH markers in the sector slot buffer, and save the drive cache flag.
5FD7
POP HL E1
Restore Register Pair HL from the stack (the directory buffer entry pointer saved at 5FB3H).
5FD8
SET 5,(HL) CB EE
SET bit 5 of the marker byte at (HL). This marks the entry as "processed" in the directory buffer.
5FDA
PUSH HL E5
Save Register Pair HL (directory buffer entry pointer) back onto the stack for later restoration at 6004H.
5FDB
INC HL 23
INCrement HL by 1.
5FDC
INC HL 23
INCrement HL by 1. HL now points to offset +2 within the directory buffer entry (the sector assignment byte).
5FDD
LD A,(HL) 7E
Fetch Register A from (HL) — the current sector assignment value stored in the directory buffer entry.
5FDE
LD (DE),A 12
Store Register A (the sector assignment) into the GAT work buffer byte at (DE). This marks the slot as allocated in the bitmap.
5FDF
LD A,C 79
Copy Register C (the raw track/sector value) into Register A.
5FE0
LD (HL),A 77
Store Register A (the raw track/sector value from C) into the directory buffer entry's sector field at (HL). This swaps the assignment: the original value goes to the GAT, and the bitmap index replaces it.
5FE1
LD (6028H),A 32 28 60
Store Register A into memory location
6028H.
[SELF-MODIFYING CODE] — This patches the operand of the CP instruction at
6027H with the current sector assignment value. The patched comparison is used later to determine the disk geometry path.
5FE4
GOSUB to
56E2H (track seek with cache validation). Seek to the track containing the directory entry data on the source disk.
5FE7
EX DE,HL EB
Swap DE and HL. Now DE holds the pointer returned by the track seek, and HL is free for loading the directory data buffer pointer.
5FE8
LD HL,(61D8H) 2A D8 61
Load Register Pair HL from memory location
61D8H (the directory buffer work pointer, updated by
61D6H and
6190H). This points to the start of the current directory entry data in the work area.
5FEB
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H (22 decimal). This is the number of directory entry data bytes to copy.
5FEE
LDIR ED B0
Block copy 22 bytes from the source address at HL (directory entry data from 61D8H) to the destination at DE. Both HL and DE advance by 22, and BC decrements to zero.
5FF0
LD C,(HL) 4E
Load Register C from the memory location pointed to by HL (the byte immediately following the 22 copied bytes — the low byte of the file's granule/sector count).
5FF1
INC HL 23
INCrement HL by 1.
5FF2
LD B,(HL) 46
Load Register B from (HL) (the high byte of the file's granule/sector count). BC now holds the 16-bit granule count.
5FF3
PUSH BC C5
Save Register Pair BC (the granule/sector count) onto the stack.
5FF4
LD B,0AH 06 0A
Load Register B with 0AH (10 decimal). This is the number of sector slot marker bytes to write.
5FF6
LD (6078H),DE ED 53 78 60
Store Register Pair DE (the current write position after the LDIR) into memory location
6078H.
[SELF-MODIFYING CODE] — This patches the operand of the LD (0000H),HL instruction at
6077H with the address where sector allocation data will be written later.
[LOOP START — FILL 10 SECTOR SLOTS WITH FFH]
5FFA
LD A,FFH 3E FF
Load Register A with FFH, the "free/empty" marker for sector slot bytes.
5FFC
LD (DE),A 12
Store Register A (FFH) into the memory location pointed to by DE (the current sector slot position).
5FFD
INC DE 13
INCrement DE by 1 to advance to the next sector slot.
5FFE
DECrement Register B by 1 and JUMP back to
5FFAH if B is not zero. This fills 10 consecutive bytes with FFH.
[LOOP END]
6000
POP BC C1
Restore Register Pair BC from the stack (the file's granule/sector count).
6001
GOSUB to
5706H (save drive cache flag). This saves the current drive cache state for later validation.
6004H - Density Flag Check and GAT Sector Allocation Calculation
Check the directory buffer entry's density flag (bit 6). If clear, skip to the next entry. If set and the track/sector value C is less than FEH, perform a complex geometry calculation to determine the GAT byte and bit positions for the sectors used by this file, then mark those sectors as allocated in the GAT bitmap at 6391H via 621CH.
6004
POP HL E1
Restore Register Pair HL from the stack (the directory buffer entry pointer saved at 5FDAH).
6005
BIT 6,(HL) CB 76
Test bit 6 of the memory byte pointed to by HL (the marker/flags byte of the directory buffer entry). Bit 6 is the density propagation flag set at
5EA0H.
6007
PUSH HL E5
Save Register Pair HL back onto the stack for later restoration at 6086H.
6008
If the Z FLAG is set (bit 6 is clear — this is a single-density entry), JUMP to
6083H to skip the GAT allocation and proceed to the next entry.
600B
LD A,C 79
Copy Register C (the raw track/sector value) into Register A.
600C
CP FEH FE FE
Compare Register A against FEH. Values FEH and above are reserved/invalid track assignments.
600E
If the NO CARRY FLAG is set (C ≥ FEH — invalid track assignment), JUMP to
6083H to skip this entry.
[GAT GEOMETRY CALCULATION] — Calculate the GAT byte/bit position for this file's sector allocation. Use SYS0 4C37H to convert the track number to a byte offset, extract the sector count and side information from the geometry, then compute the allocation mask.
6010
LD L,A 6F
Load Register L with Register A (the track/sector value).
6011
LD A,(59BCH) 3A BC 59
Fetch Register A from memory location 59BCH (GAT configuration parameter — sectors per granule multiplier).
6014
GOSUB to
4C37H (SYS0 track seek/arithmetic). This computes the track geometry based on the value in L and the GAT parameter in A. On return, HL holds the computed sector position and B holds additional geometry data.
6017
LD A,B 78
Copy Register B (geometry result) into Register A.
6018
AND 1FH E6 1F
Mask Register A with 1FH to isolate the lower 5 bits — the sector count for this track.
601A
LD C,A 4F
Copy Register A (sector count) into Register C.
601B
LD A,B 78
Copy Register B (geometry result) into Register A again.
601C
RLCA 07
Rotate Register A left 1 bit.
601D
RLCA 07
Rotate Register A left 1 bit.
601E
RLCA 07
Rotate Register A left 1 bit. Three RLCA instructions rotate bits 5-7 into bits 0-2, extracting the disk side number from the upper 3 bits of the geometry byte.
601F
AND 07H E6 07
Mask Register A with 07H to isolate bits 0-2 only. Register A now holds the side number (0-7).
6021
LD E,A 5F
Copy Register A (side number) into Register E.
6022
LD D,00H 16 00
Load Register D with 00H. DE now holds the side offset as a 16-bit value.
6024
ADD HL,DE 19
ADD Register Pair DE (side offset) to Register Pair HL (sector position). HL now points to the position adjusted for the disk side.
6025
LD A,02H 3E 02
Load Register A with 02H.
6027
CP 00H FE 00
Compare Register A (02H) against
00H.
[SELF-MODIFYING CODE at 6028H] — The operand byte at 6028H was patched at
5FE1H with the actual sector assignment value. If the patched value is 00H, A (02H) ≠ 00H so NZ. If the patched value is 02H, A=02H matches so Z.
6029
If the NZ FLAG is set (sector assignment ≠ 02H — dual-density or multi-sector path), JUMP forward to
6030H for the complex geometry calculation.
[SINGLE-DENSITY SIMPLE PATH] — The sector assignment matches the simple case. Use a fixed starting sector of 1.
602B
LD HL,0001H 21 01 00
Load Register Pair HL with 0001H. This is the starting sector offset for the single-density case.
602E
JUMP forward to
6064H to proceed with the GAT bit calculation using HL=0001H as the starting sector.
6030H - Complex Geometry Calculation for Dual-Density GAT Allocation
When the sector assignment requires the dual-density path, perform a multi-step geometry calculation using the source and destination drive parameters. This computes the correct starting sector position for the GAT bit allocation by factoring in the sectors-per-track differences between source and destination geometries.
6030
EX DE,HL EB
Swap DE and HL. Save the current computed position into DE.
6031
LD A,(59B7H) 3A B7 59
Fetch Register A from memory location 59B7H (the source drive geometry parameter block base byte).
6034
LD L,A 6F
Copy Register A into Register L.
6035
LD A,(59BCH) 3A BC 59
Fetch Register A from memory location 59BCH (GAT configuration parameter).
6038
GOSUB to
4C37H (SYS0 track seek/arithmetic) with L = source geometry byte and A = GAT parameter. Computes the geometry offset for the source configuration.
603B
EX DE,HL EB
Swap DE and HL. DE now holds the source geometry result; HL holds the side-adjusted position from before.
603C
LD A,(59C0H) 3A C0 59
Fetch Register A from memory location
59C0H (source sectors-per-track, stored at
5D93H).
603F
LD B,A 47
Copy Register A (source sectors-per-track) into Register B. B is the loop counter for the subtraction loop.
6040
PUSH DE D5
Save Register Pair DE (source geometry result) onto the stack.
[LOOP START — COUNT SECTORS] — Advance DE by B positions to compute the sector offset.
6041
INC DE 13
INCrement Register Pair DE by 1.
6042
DECrement Register B and JUMP back to
6041H if not zero. After B iterations, DE has been advanced by the source sectors-per-track count.
[LOOP END]
6044
OR A B7
Clear the CARRY FLAG by ORing A with itself (A still holds the sectors-per-track value, but only the flags matter here).
6045
SBC HL,DE ED 52
SUBtract Register Pair DE (source position + sectors-per-track) from Register Pair HL with borrow. This computes the difference between the side-adjusted position and the source geometry offset.
6047
If the CARRY FLAG is set (HL was less than DE — underflow), JUMP to
6053H to handle the negative result path.
[POSITIVE RESULT PATH] — HL ≥ DE. Add the destination geometry offset.
6049
POP DE D1
Discard the saved DE from the stack (source geometry result, no longer needed).
604A
LD A,(59CEH) 3A CE 59
Fetch Register A from memory location 59CEH (destination geometry count byte — sectors-per-track for destination).
604D
LD E,A 5F
Copy A into E.
604E
LD D,00H 16 00
Load D with 00H. DE = destination sectors-per-track as a 16-bit value.
6050
ADD HL,DE 19
ADD the destination sectors-per-track (DE) to the computed result in HL.
6051
JUMP forward to
6058H to continue with the final calculation.
[NEGATIVE RESULT PATH] — HL < DE (underflow). Adjust the calculation.
6053
ADD HL,DE 19
ADD DE back to HL to cancel the underflow and get the correct positive result.
6054
POP DE D1
Restore the saved DE (source geometry result) from the stack.
6055
OR A B7
Clear the CARRY FLAG.
6056
SBC HL,DE ED 52
SUBtract DE (source geometry result) from HL.
6058
EX DE,HL EB
Swap DE and HL. DE now holds the computed sector offset.
6059
LD A,(59C5H) 3A C5 59
Fetch Register A from memory location 59C5H (destination drive geometry copy — the first byte of the destination geometry block).
605C
LD L,A 6F
Copy A into L.
605D
LD A,(59CAH) 3A CA 59
Fetch Register A from memory location 59CAH (sectors-per-GAT-byte for the destination geometry).
6060
GOSUB to
4C37H (SYS0 track seek/arithmetic). Compute the destination geometry offset from L and A.
6063
ADD HL,DE 19
ADD the previously computed sector offset (DE) to the destination geometry result (HL). HL now holds the final starting sector position for the GAT bit allocation.
6064H - GAT Bit Allocation: Mark Sectors in Destination GAT Bitmap
Using the computed starting sector position in HL (from either the simple or complex path), calculate the GAT byte and bit offset via SYS0 4C59H, check for boundary overflow, build the allocation mask, and call 621CH to mark the file's sectors as allocated in the backup GAT buffer at 6391H.
6064
LD D,C 51
Copy Register C (the sector count for this file) into Register D. D serves as the sector count for the GAT allocation routine.
6065
LD A,(59CAH) 3A CA 59
Fetch Register A from memory location 59CAH (sectors-per-GAT-byte).
6068
GOSUB to
4C59H (SYS0 GAT byte/bit offset calculation). On return, HL holds the byte offset within the GAT, and A holds the bit position within that byte.
606B
INC H 24
INCrement Register H by 1.
606C
DEC H 25
DECrement Register H by 1. This INC/DEC sequence tests whether H is zero without modifying it — the Z FLAG is set if H = 00H (byte offset is within the first 256 bytes of the GAT).
606D
If the NZ FLAG is set (H ≠ 00H — the byte offset exceeds 255, meaning a boundary overflow), GOSUB to
5240H (boundary check / capacity error helper). This handles the error condition when the file's sectors extend beyond the GAT capacity.
6070
LD B,A 47
Copy Register A (the bit position within the GAT byte) into Register B.
6071
RRCA 0F
Rotate Register A right 1 bit through carry.
6072
RRCA 0F
Rotate Register A right 1 bit.
6073
RRCA 0F
Rotate Register A right 1 bit. Three RRCA instructions shift the bit position right by 3, moving bits 2-0 to bits 7-5. This converts the bit position into a mask-building value.
6074
PUSH HL E5
Save Register Pair HL (GAT byte offset) onto the stack.
6075
OR D B2
OR Register D (sector count) into Register A (the rotated bit position). This combines the sector count with the bit position mask.
6076
LD H,A 67
Copy Register A (combined sector count and bit position) into Register H.
6077
LD (0000H),HL 22 00 00
Store Register Pair HL into memory address
0000H.
[SELF-MODIFYING CODE at 6078H] — The operand address 0000H was patched at
5FF6H with the actual sector slot buffer address (from DE after the LDIR at 5FEEH). This writes the combined allocation data to the correct position in the sector slot buffer.
607A
LD HL,6391H 21 91 63
Point Register Pair HL to memory address 6391H, the backup GAT buffer.
607D
LD C,D 4A
Copy Register D (sector count) into Register C. C is the sector count parameter for the 621CH routine.
607E
POP DE D1
Restore Register Pair DE from the stack (the GAT byte offset saved at 6074H).
607F
INC C 0C
INCrement Register C by 1. The 621CH routine expects the count to be one greater than the number of sectors to mark.
6080
GOSUB to
621CH (GAT bit manipulation — mark sectors allocated in bitmap). This sets the appropriate bits in the GAT bitmap at 6391H to mark C sectors as allocated starting at the byte/bit position specified by DE and B.
6083H - Advance to Next Source Entry and Loop
Common continuation point for the GAT allocation loop. Fetch the next directory entry address, check its status flags, and optionally patch the self-modifying byte at 60C3H. Loop back to 5FA7H to continue processing.
6083
GOSUB to
61D6H (fetch next directory entry address via RST 18H). This advances the directory entry pointer and updates 61D8H.
6086
POP HL E1
Restore Register Pair HL from the stack (the directory buffer entry pointer saved at 6007H or 5FDAH).
6087
BIT 5,(HL) CB 6E
Test bit 5 of the memory byte pointed to by HL (the marker byte of the directory buffer entry). Bit 5 indicates this entry was matched and processed.
6089
If the NZ FLAG is set (bit 5 is set — entry was already matched), JUMP forward to
608FH to skip the self-modifying patch and go directly to the loop continuation.
608B
LD A,H 7C
Copy Register H (the high byte of the directory buffer entry address) into Register A.
608C
LD (60C3H),A 32 C3 60
Store Register A (high byte of HL) into memory location
60C3H.
[SELF-MODIFYING CODE] — This patches the operand of the LD A,00H instruction at
60C2H with the high byte of the current directory buffer entry address. The value is used later at 60BFH to detect whether any unmatched entries remain.
608F
JUMP back to
5FA7H to advance to the next directory buffer entry and continue the GAT allocation loop.
[GAT ALLOCATION SCAN LOOP END]
6092H - Finalize GAT: Flush and Copy Bitmap to Disk
Reached when all directory buffer entries have been processed (Z flag from 5FA7H→5699H→5FAAH). Flush the current GAT to disk, copy the directory bitmap from 6291H to the 4300H work area, write it to the drive, then copy the backup GAT from 6391H to 4300H and write that as well.
6092
GOSUB to
570DH (flush GAT and reset cache). Write the current GAT sector to disk.
6095
LD HL,6291H 21 91 62
Point Register Pair HL to memory address 6291H (the directory bitmap work buffer).
6098
GOSUB to
616FH (copy 256 bytes from HL to 4300H). This copies the directory bitmap from 6291H into the SYS0 work buffer at 4300H.
609B
PUSH HL E5
Save Register Pair HL (now pointing past the end of the 6291H buffer after the copy) onto the stack.
609C
LD A,01H 3E 01
Load Register A with 01H.
609E
GOSUB to
5701H (drive utility wrapper, calls 48C7H) with A=01H. This writes the buffer at 4300H (containing the directory bitmap) to the drive.
60A1
POP HL E1
Restore Register Pair HL from the stack.
60A2
GOSUB to
616FH (copy 256 bytes from HL to 4300H). Since HL was advanced past 6291H by the first call, and the backup GAT buffer starts at 6391H, this copies the backup GAT from 6391H to 4300H.
60A5
XOR A AF
Set Register A to 00H by XORing it with itself.
60A6
JUMP to
5701H (drive utility wrapper) with A=00H. This writes the backup GAT to the drive and returns to the caller (the stacked 60BFH address from
5EE0H).
60A9H - Sector Write Utility: Write via SYS0 and Extract Filespec Data
Write a sector to disk using SYS0 4925H, then clear the instruction byte at 4FB8H, extract additional fields from the parameter block, and tail-call to the filespec processor at 4E1AH. This is a utility routine called from multiple locations including the destination directory write at 5F7BH.
60A9
GOSUB to
4925H (SYS0 sector write via parameter block). Write the sector data using the parameter block pointed to by DE.
60AC
XOR A AF
Set Register A to 00H.
60AD
LD (4FB8H),A 32 B8 4F
Store Register A (00H) into memory location 4FB8H. [SELF-MODIFYING CODE] — This clears the instruction byte at 4FB8H, resetting a runtime-patched operation in SYS0.
60B0
PUSH HL E5
Save Register Pair HL onto the stack.
60B1
INC L 2C
INCrement Register L by 1.
60B2
INC L 2C
INCrement Register L by 1.
60B3
INC L 2C
INCrement Register L by 1. Three INC L instructions advance HL by 3 bytes (using L only, which is valid since the buffer is page-aligned). HL now points to offset +3 within the parameter block.
60B4
LD A,(HL) 7E
Fetch Register A from the parameter block at offset +3 (a field containing the current operation status or type code).
60B5
LD DE,0011H 11 11 00
Load Register Pair DE with 0011H (17 decimal). This is the offset from the current position to the filespec data pointer within the parameter block.
60B8
ADD HL,DE 19
ADD 17 to HL. HL now points to offset +20 (3+17) in the parameter block, which contains a 16-bit filespec data address.
60B9
LD E,(HL) 5E
Load Register E from (HL) — low byte of the filespec data address.
60BA
INC HL 23
INCrement HL by 1.
60BB
LD D,(HL) 56
Load Register D from (HL) — high byte of the filespec data address. DE now holds the complete 16-bit address.
60BC
JUMP to
4E1AH (SYS0 filespec processor continuation). This is a tail-call — when 4E1AH completes, it returns to the address on the stack (saved by the caller).
60BFH - Post-Directory-Copy Dispatcher
This is the return address pushed at 5EE0H. After the destination directory matching and GAT allocation phases complete and return, this dispatcher checks whether any unmatched entries remain (via the self-modifying byte at 60C3H). If the patched value is 00H, all entries were matched — jump to the "all done" exit at 6157H. Otherwise, continue to the second-pass copy loop at 60C8H.
60BF
GOSUB to
568BH (drive setup dispatcher alternate entry with A=04H). Re-initialize the drive configuration for the next phase.
60C2
LD A,00H 3E 00
Load Register A with
00H.
[SELF-MODIFYING CODE at 60C3H] — The operand byte at 60C3H is patched at
608CH with the high byte of the last unmatched directory buffer entry address. If no unmatched entries exist, this remains 00H.
60C4
OR A B7
OR Register A with itself to set the Z FLAG if A is 00H.
60C5
If the Z FLAG is set (A is 00H — no unmatched entries remain, either because all entries were matched or because the self-modifying byte was never patched), JUMP to
6157H (the "all done" exit that writes FFH to 5B1EH and 586AH, then jumps to 524EH for directory buffer relocation).
If NZ (unmatched entries exist), fall through to
60C8H to begin the second-pass copy loop that handles the remaining entries.
60C8H — SOURCE-TO-DESTINATION COPY LOOP (UNMATCHED ENTRIES)
This section handles the second pass of the COPY operation: copying directory entries from the source disk that were NOT matched to existing entries on the destination disk. The preceding code at 60BFH checked the self-modifying flag at 60C3H; if it was non-zero, at least one source entry had no match on the destination, so execution falls through to here. The outer loop at 60C8H iterates through all source directory entries; entries with bit 5 set in the status byte are skipped (they were already matched and copied in the first pass). For each unmatched entry, the code either overwrites an existing destination directory slot (via 60F5H) or appends to the destination directory (via 60E1H).
60C8
GOSUB to 5578H to set up source drive — loads HL from 594CH (source drive number), calls PDRIVE swap to configure the FDC for the source disk.
60CB
GOSUB to 6190H to reload the directory buffer control pointers — loads HL from (5D14H) into 61D8H (directory end pointer) and sets HL to (5D12H) minus 3 (pre-entry position for the scan loop).
[LOOP START] — Scan source directory entries, skipping those already matched (bit 5 set).
60CE
GOSUB to 5699H to advance HL by 3 bytes to the next directory entry status byte, and compare HL against the directory end pointer at 5D14H. Sets the Z FLAG if HL has reached or passed the end of the directory buffer.
60D1
If the Z FLAG is set (all source directory entries have been scanned), JUMP to 60F1H to push the "all done" return address and begin finalizing the destination directory.
60D3
BIT 5,(HL) CB 6E
Test bit 5 of the directory entry status byte at (HL). Bit 5 was set by the first-pass code at 6153H for entries that were successfully matched and copied to the destination.
60D5
If the NZ FLAG is set (bit 5 is set — this entry was already matched), JUMP back to 60CEH to advance to the next source directory entry and skip this one.
60D7
GOSUB to 61D6H to fetch the next destination directory entry address. This routine uses RST 18H to compare the current directory position (self-modified HL at 61D8H) against the directory end, and returns the next available slot address in DE. Sets the CARRY FLAG if no more slots are available (past the end of the destination directory).
60DA
If the CARRY FLAG is set (destination directory is full — no more existing slots), JUMP to 60E1H to append this entry at the end of the destination directory.
60DC
GOSUB to 60F5H to copy this source directory entry into the destination directory at the slot found by 61D6H. This switches to the destination drive, scans for a matching slot, and copies the 22-byte directory entry data.
60DF
Unconditional JUMP back to 60C8H to re-initialize the source drive and continue scanning for additional unmatched entries.
[LOOP END] — Source-to-destination copy loop.
60E1H — APPEND UNMATCHED ENTRY TO DESTINATION DIRECTORY
When the destination directory has no more existing slots (CARRY set from 61D6H), this code appends the unmatched source entry at the end of the destination directory. It sets bit 4 in the entry status byte to mark it as newly appended, seeks to the track indicated in the entry, and copies 22 bytes of directory data to the destination via LDIR.
60E1
PUSH HL E5
Save the current source directory entry pointer (HL) onto the stack for later restoration.
60E2
SET 4,(HL) CB E6
Set bit 4 in the directory entry status byte at (HL) to mark this entry as "newly appended" — this flag distinguishes new entries from existing ones during subsequent processing.
60E4
INC HL 23
Advance HL to point to offset +1 of the directory entry, which contains the track number for this file's first sector.
60E5
LD A,(HL) 7E
Load Register A with the track number from the directory entry at offset +1.
60E6
GOSUB to 56EFH to seek to the track specified in Register A. This is an entry into the 56E2H track-seek group that takes the track number in A and performs the seek with cache validation.
60E9
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H (22 decimal) — the number of bytes to copy from the source directory entry to the destination. This is the standard directory entry data length (excluding the 2-byte header).
60EC
LDIR ED B0
Block copy 22 bytes from (HL) to (DE): copies the source directory entry data (filename, extension, track/sector allocation, attributes) to the destination directory buffer. HL and DE were positioned by the preceding seek and directory scan operations.
60EE
POP HL E1
Restore HL to the source directory entry pointer saved at 60E1H.
60EF
Unconditional JUMP back to 60CEH to continue scanning for additional unmatched source directory entries.
60F1H — SOURCE SCAN COMPLETE: PUSH EXIT ADDRESS AND ENTER DESTINATION FINALIZATION
After all source directory entries have been scanned, this code pushes the "all done" exit address 6157H onto the stack, then falls through to 60F5H to begin the destination directory finalization pass. When the destination scan at 60F5H completes (via its RET Z at 60FEH), the stacked 6157H address causes execution to jump to the "all done" cleanup code.
60F1
LD HL,6157H 21 57 61
Load Register Pair HL with 6157H — the address of the "all done" exit routine that writes FFH to 5B1EH and 586AH, then jumps to 524EH for final cleanup.
60F4
PUSH HL E5
Push 6157H onto the stack as a return address. When the destination directory scan at 60F5H completes and executes RET, execution will transfer to 6157H.
60F5H — DESTINATION DIRECTORY SCAN AND COPY LOOP
This subroutine scans the destination directory for entries marked with bit 4 set (entries that were flagged during the source-to-destination copy). For each marked entry, it performs a directory lookup via 50CFH, copies 22 bytes of directory data, and then applies density-dependent field patching if the source and destination disks have different densities. This routine is called both from 60DCH (individual copy) and as a fall-through from 60F1H (batch finalization).
60F5
GOSUB to 557DH to set up destination drive — loads HL from 5956H (destination drive number), calls PDRIVE swap to configure the FDC for the destination disk.
60F8
GOSUB to 6190H to reload the directory buffer control pointers for the destination disk.
[LOOP START] — Scan destination directory entries for those marked with bit 4 (newly appended).
60FB
GOSUB to 5699H to advance HL by 3 bytes to the next directory entry and compare against the directory end pointer.
60FE
RET Z C8
If the Z FLAG is set (end of directory reached), RETurn to the caller. If this was entered from the 60F1H push, the return goes to 6157H ("all done" exit).
60FF
BIT 4,(HL) CB 66
Test bit 4 of the directory entry status byte. This bit was set at 60E2H to mark entries that were appended from the source.
6101
If the Z FLAG is set (bit 4 not set — this entry was not newly appended), JUMP back to 60FBH to skip it and check the next entry.
6103
PUSH HL E5
Save the current directory entry pointer (HL) onto the stack.
6104
RES 4,(HL) CB A6
Clear bit 4 of the directory entry status byte — remove the "newly appended" marker now that this entry is being processed.
6106
GOSUB to 61D6H to fetch the next directory entry address from the destination disk. Returns the entry address in DE.
6109
INC HL 23
Advance HL past the status byte to offset +1 of the source directory entry.
610A
LD B,(HL) 46
Load Register B with the byte at offset +1 — this is the track number of the file's first sector.
610B
INC HL 23
Advance HL to offset +2 of the directory entry.
610C
PUSH DE D5
Save DE (destination directory entry address from 61D6H) onto the stack.
610D
PUSH HL E5
Save HL (source directory entry pointer at offset +2) onto the stack.
610E
GOSUB to 50CFH (SYS0 internal directory lookup) with B = track number. This looks up the directory entry for the file on the destination disk. Returns: A = sector number, DE = directory entry address, Z FLAG set if found.
6111
If the NZ FLAG is set (directory lookup failed — file not found on destination), JUMP to 521AH (main error handler). The error code in Register A from 50CFH identifies the specific failure.
6114
EX DE,HL EB
Exchange DE and HL. Now HL points to the destination directory entry (from 50CFH), and DE holds the old HL value.
6115
POP HL E1
Restore HL from the stack — now HL points back to the source directory entry at offset +2 (saved at 610DH).
6116
LD (HL),A 77
Store Register A (the sector number returned by 50CFH) into the source directory entry at offset +2. This updates the source entry with the destination's sector assignment.
6117
POP HL E1
Restore HL from the stack — this is the second POP, restoring the destination directory entry address (saved as DE at 610CH, but the EX DE,HL at 6114H swapped the meanings). Now HL = destination directory entry pointer.
6118
PUSH DE D5
Save DE (now pointing to the source directory entry) onto the stack for later use after the block copy.
6119
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H (22 decimal) — the standard directory entry data length for the block copy.
611C
LDIR ED B0
Block copy 22 bytes from (HL) to (DE): copies the source directory entry data to the destination directory slot. After this, DE points past the end of the destination entry.
611E
POP DE D1
Restore DE from the stack — DE now points to the source directory entry (saved at 6118H).
611F
GOSUB to 61FCH to XOR the source and destination density flags. Returns Z FLAG set if densities match, NZ if they differ. Register A contains the destination density flag byte (59C7H).
6122
If the Z FLAG is set (source and destination densities match), JUMP to 614FH to skip the density patching and go directly to the GAT flush.
6124H — DENSITY-DEPENDENT DIRECTORY ENTRY FIELD PATCHING
When the source and destination disks have different densities (one single-density, one double-density), this section patches the date/version stamp fields in the copied directory entry. It checks bit 5 of the density flag: if set (destination is double-density), it loads the date stamp from the DOS work area at 421AH/421CH and uses the date callback address 5CEFH; if clear (destination is single-density), it uses zero for the date stamp and the standard date address 4296H. The patching writes the date stamp and callback pointers into the directory entry at specific offsets.
6124
BIT 5,A CB 6F
Test bit 5 of Register A (the destination density flag byte returned by 61FCH at 6206H). Bit 5 indicates MFM/double-density mode: 1 = double-density, 0 = single-density.
6126
EX DE,HL EB
Exchange DE and HL. Now HL points to the source directory entry and DE is free for loading the date stamp values.
6127
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H — the default date/version stamp value (zero means "no date stamp"). This is used when copying to a single-density destination.
612A
LD BC,4296H 01 96 42
Load Register Pair BC with 4296H — the address of the date/version stamp field in the DOS work area. This is the standard callback address for date stamp processing on single-density disks.
612D
If the Z FLAG is set (bit 5 is clear — destination is single-density), JUMP to 613AH to write the zero date stamp. [SELF-MODIFYING CODE] — The displacement byte at 612DH+1 is patched by code at 5CE9H to 18H to force an unconditional branch when density-dependent field writing is enabled.
612F
LD A,(421AH) 3A 1A 42
Load Register A with the date stamp high byte from DOS work area at 421AH. This is the first byte of the system date used for double-density directory entries.
6132
LD D,A 57
Copy the date stamp high byte into Register D. Now D = 421AH value.
6133
LD A,(421CH) 3A 1C 42
Load Register A with the date stamp low byte from DOS work area at 421CH. This is the second byte of the system date.
6136
LD E,A 5F
Copy the date stamp low byte into Register E. Now DE = the complete 16-bit date/version stamp value from the DOS work area.
6137
LD BC,5CEFH 01 EF 5C
Load Register Pair BC with 5CEFH — the address of the double-density date stamp write callback. This replaces the single-density callback address (4296H) loaded at 612AH.
613A
INC HL 23
Advance HL to the directory entry field where the date stamp will be stored.
613B
LD (HL),E 73
Store the date stamp low byte (Register E) into the directory entry.
613C
INC HL 23
Advance HL to the next byte in the directory entry.
613D
LD (HL),D 72
Store the date stamp high byte (Register D) into the directory entry. The two-byte date stamp is now written in little-endian order.
613E
INC HL 23
Advance HL to the next field in the directory entry.
613F
LD A,(HL) 7E
Load Register A with the byte at the current directory entry position — this reads the existing value at this offset, which is preserved for later use but the position is consumed by the INC HL sequence.
6140
LD DE,000DH 11 0D 00
Load Register Pair DE with 000DH (13 decimal) — the offset to skip from the current position to the callback pointer field in the directory entry.
6143
ADD HL,DE 19
Add 13 to HL, advancing the pointer to the callback pointer field in the directory entry (at offset +14H/+15H from the entry start).
6144
LD (HL),C 71
Store the callback address low byte (Register C) into the directory entry. This writes either 96H (from 4296H for SD) or EFH (from 5CEFH for DD).
6145
INC HL 23
Advance HL to the high byte of the callback pointer.
6146
LD (HL),B 70
Store the callback address high byte (Register B) into the directory entry. The callback pointer is now written as either 4296H or 5CEFH.
6147
INC HL 23
Advance HL to the next callback pointer field (offset +16H/+17H).
6148
LD (HL),C 71
Store the callback address low byte again — the directory entry has two callback pointer fields that receive the same value.
6149
INC HL 23
Advance HL to the high byte of the second callback pointer.
614A
LD (HL),B 70
Store the callback address high byte into the second callback pointer field. Both callback fields now point to the same address.
614B
INC HL 23
Advance HL past the second callback pointer to the date pointer update field.
614C
GOSUB to 6209H to conditionally update the directory date pointer. This routine checks if the source and destination densities differ and adjusts the date pointer value accordingly (incrementing or decrementing by 1 depending on the direction of the density change).
614FH — FLUSH GAT, MARK ENTRY PROCESSED, AND LOOP
After copying directory data (and optionally patching density-dependent fields), this section flushes the GAT to disk, marks the entry as processed (bit 5 set), and loops back to check the next destination directory entry.
614F
GOSUB to 5711H to flush the GAT sector to disk — writes the Granule Allocation Table for the destination disk to ensure all allocation changes are persisted.
6152
POP HL E1
Restore HL from the stack — this is the directory entry pointer saved at 6103H.
6153
SET 5,(HL) CB EE
Set bit 5 of the directory entry status byte to mark this entry as fully processed. This prevents the source scan loop at 60D3H from re-processing it.
6155
Unconditional JUMP back to 60FBH to continue scanning the destination directory for more entries with bit 4 set.
[LOOP END] — Destination directory scan and copy loop.
6157H — "ALL DONE" EXIT: CLEAR FLAGS AND RETURN TO MAIN COMMAND LOOP
This is the final exit point for the COPY/FORMAT operation. It marks both the destination buffer and the conditional source display flag as FFH (cleared/complete), then jumps to 524EH for the directory buffer relocation and return to the main command processing loop.
6157
LD A,FFH 3E FF
Load Register A with FFH — the "cleared/done" sentinel value.
6159
LD (5B1EH),A 32 1E 5B
Store FFH to 5B1EH (destination buffer-cleared flag). Setting this to FFH indicates the destination buffer has been fully processed and needs no further attention.
615C
LD (586AH),A 32 6A 58
Store FFH to 586AH (conditional source disk label display flag). Setting this to FFH suppresses further source disk label displays during cleanup.
615F
JUMP to 524EH to perform directory buffer relocation and return to the main COPY/FORMAT command processing loop.
6162H — GAT SECTOR STATE INITIALIZATION
This routine initializes the GAT (Granule Allocation Table) sector state by calling the drive initialization utility, then copying 256 bytes from the GAT buffer to the 6291H directory bitmap work buffer (and the previous 256 bytes to 4300H). The DEC H at 616DH adjusts the high byte of HL to point one page back, effectively rewinding after the LDIR advanced HL by 256 bytes.
6162
LD A,01H 3E 01
Load Register A with 01H — the function code for GAT sector read initialization.
6164
GOSUB to 56FAH to perform drive initialization with the alternate entry point. This initializes the drive and reads the GAT sector into the DOS work area buffer at 4300H.
6167
LD DE,6291H 11 91 62
Load Register Pair DE with 6291H — the address of the 256-byte directory bitmap work buffer where the GAT sector contents will be copied.
616A
GOSUB to 6172H to copy 256 bytes from (HL) to 6291H. HL was left pointing to the GAT buffer after the drive init at 56FAH returned.
616D
DEC H 25
DECrement the high byte of Register Pair HL, rewinding HL by 256 bytes. After the LDIR at 6172H advanced HL by 256, this restores HL to its original page boundary, pointing back to the start of the GAT data.
616E
RET C9
RETurn to the caller.
616FH — COPY 256 BYTES TO 4300H (DOS WORK AREA)
Copies 256 bytes from the address in HL to the DOS work area at 4300H. Falls through to the generic 256-byte LDIR at 6172H.
616F
LD DE,4300H 11 00 43
Load Register Pair DE with 4300H — the DOS work area buffer address where the 256 bytes will be copied.
6172H — COPY 256 BYTES FROM HL TO DE (LDIR UTILITY)
Generic utility that copies exactly 256 bytes from the source address in HL to the destination address in DE.
6172
LD BC,0100H 01 00 01
Load Register Pair BC with 0100H (256 decimal) — the byte count for the block copy.
6175
LDIR ED B0
Block copy 256 bytes from (HL) to (DE). HL and DE are both advanced by 256 bytes. BC becomes zero.
6177
RET C9
RETurn to the caller.
6178H — DISK GEOMETRY INITIALIZATION
This routine determines the disk geometry (tracks, sectors-per-track) for the currently selected drive. It first checks if FORMAT mode is active (bit 5 of 4282H); if so, it returns a fixed geometry of 10H (16) tracks and 06H sectors-per-track. Otherwise, it reads the disk geometry from the GAT sector data at 431FH (total sectors/granules), adds 8, then divides by 5 to compute the sectors-per-track count. The remainder becomes the total track count in Register A.
6178
GOSUB to 61F6H to fetch the FORMAT mode flag — loads A from 4282H (DOS mode byte) and ANDs with 20H. Returns NZ if FORMAT mode is active, Z if COPY mode.
617B
LD A,10H 3E 10
Load Register A with 10H (16 decimal) — the default track count for FORMAT mode operations.
617D
LD C,06H 0E 06
Load Register C with 06H (6 decimal) — the default sectors-per-track for FORMAT mode.
617F
RET NZ C0
If the NZ FLAG is set (FORMAT mode is active), RETurn immediately with A=10H (tracks) and C=06H (sectors-per-track). These are the fixed geometry values used during FORMAT operations.
6180
LD E,05H 1E 05
Load Register E with 05H (5 decimal) — the divisor for the sectors-per-track calculation.
6182
LD A,(431FH) 3A 1F 43
Load Register A with the byte at 431FH — this is the disk geometry/capacity byte from the GAT sector, representing the total sector count or granule configuration value.
6185
ADD 08H C6 08
ADD 08H (8) to Register A. This adjustment accounts for the reserved system tracks (boot sector, directory, GAT) that are not counted in the GAT capacity byte.
6187
LD B,A 47
Copy the adjusted total into Register B for use as the dividend in the division loop.
6188
LD C,00H 0E 00
Clear Register C to zero — this will accumulate the sectors-per-track quotient during the division loop.
[LOOP START] — Division loop: divide adjusted sector count (B) by 5 (E) to compute sectors-per-track (C).
618A
INC C 0C
INCrement Register C (the sectors-per-track quotient counter).
618B
SUB E 93
SUBtract E (5) from Register A (the running remainder). Sets the CARRY FLAG if the subtraction underflows (remainder < 0).
618C
If the NC FLAG is set (remainder is still non-negative), JUMP back to 618AH to continue dividing. Each iteration increments C and subtracts 5 from the remainder.
[LOOP END] — When the loop exits, C = quotient (sectors-per-track), A = remainder - 5 (needs correction).
618E
LD A,B 78
Load Register A with the original adjusted total from Register B. This replaces the underflowed remainder with the original dividend value for the return (the total track count).
618F
RET C9
RETurn to the caller with A = total tracks (adjusted sector count) and C = sectors-per-track.
6190H — RELOAD DIRECTORY BUFFER CONTROL POINTERS
Reloads the directory buffer control pointers from the stored values at 5D12H and 5D14H. This resets the directory scan position so subsequent calls to 5699H will start from the beginning of the directory buffer. The end pointer from 5D14H is stored to the working end-of-directory pointer at 61D8H, and HL is positioned 3 bytes before the start pointer (5D12H minus 3) so the first call to 5699H advances HL to the first entry.
6190
LD HL,(5D14H) 2A 14 5D
Load Register Pair HL with the directory buffer end pointer from 5D14H — this marks the end of the directory data area.
6193
LD (61D8H),HL 22 D8 61
Store HL to 61D8H (the working directory end pointer). This self-modifying location is used by 61D6H to detect when the directory scan has reached the end.
6196
LD HL,(5D12H) 2A 12 5D
Load Register Pair HL with the directory buffer start pointer from 5D12H — this marks the first directory entry.
6199
DEC HL 2B
DECrement HL by 1.
619A
DEC HL 2B
DECrement HL by 1.
619B
DEC HL 2B
DECrement HL by 1. HL is now 3 bytes before the start of the directory buffer. This pre-positions HL so the first call to 5699H (which adds 3) will advance HL to the first directory entry.
619C
RET C9
RETurn to the caller with HL pre-positioned and 61D8H set.
619DH — ADVANCE DIRECTORY BUFFER POINTER (INDEXED)
This routine uses the value in Register C as an index into the 256-byte directory bitmap at 6291H to fetch a directory entry count. If the count is less than 01H (zero entries), it returns with the CARRY FLAG set. Otherwise, it checks if the drive is in FORMAT mode and, depending on mode, performs a track seek to load the directory sector, then validates the sector status bits.
619D
LD B,00H 06 00
Load Register B with 00H, clearing the high byte so BC can be used as a 16-bit index with C as the low byte.
619F
LD HL,6291H 21 91 62
Load Register Pair HL with 6291H — the base address of the 256-byte directory bitmap work buffer.
61A2
ADD HL,BC 09
ADD BC to HL to index into the directory bitmap. HL now points to 6291H + C (the entry for drive C in the bitmap).
61A3
LD A,(HL) 7E
Load Register A with the bitmap entry value at (HL) — this is the directory entry count for the indexed drive.
61A4
CP 01H FE 01
Compare Register A against 01H. Sets the CARRY FLAG if A < 1 (i.e., A = 0, no entries). Sets the Z FLAG if A = 1 (exactly one entry).
61A6
LD B,A 47
Copy the bitmap entry value into Register B for later use.
61A7
RET C D8
If the CARRY FLAG is set (A was 0 — no entries for this drive), RETurn immediately. The caller checks CARRY to detect an empty bitmap slot.
61A8
GOSUB to 61F6H to check if FORMAT mode is active (tests bit 5 of 4282H). Returns NZ if FORMAT mode, Z if COPY mode.
61AB
LD A,C 79
Load Register A with Register C — the drive/track index value that was used to index the bitmap.
61AC
If the NZ FLAG is set (FORMAT mode is active), JUMP to 61B1H to skip the COPY-mode track limit check and go directly to the track seek.
61AE
CP 02H FE 02
Compare Register A against 02H. In COPY mode, this checks if the track index is less than 2 (tracks 0 and 1 are system tracks). Sets the CARRY FLAG if A < 2.
61B0
RET C D8
If the CARRY FLAG is set (track index is 0 or 1 — system track), RETurn immediately. In COPY mode, system tracks are handled separately and not processed through this directory buffer path.
61B1
GOSUB to 56E2H to perform a track seek with cache validation — seeks to the track specified in Register A and loads the directory sector data.
61B4
LD A,(HL) 7E
Load Register A with the first byte of the loaded sector data at (HL) — this is the sector status/flags byte.
61B5
AND 90H E6 90
Mask Register A with 90H (binary 10010000) to isolate bits 7 (not ready) and bit 4 (seek error / record not found). All other status bits are cleared.
61B7
CP 10H FE 10
Compare the masked status against 10H (bit 4 only). If exactly 10H, bit 4 is set but bit 7 is clear — this indicates a seek error without a not-ready condition. Sets the Z FLAG if the comparison matches.
61B9
RET C9
RETurn to the caller. The Z FLAG indicates whether the status matches 10H (seek error), and the CARRY FLAG from the CP indicates whether the status is less than 10H (clean status).
61BAH — ADVANCE TO NEXT DIRECTORY SLOT
This routine advances to the next directory slot by computing an offset based on the current disk geometry. In FORMAT mode, the offset is fixed at 50H (80 decimal). In COPY mode, it takes the value from Register C (sectors-per-track), adds 20H (32), and uses that as the increment. It then checks if the new position has reached or passed the total directory slot count.
61BA
GOSUB to 61F6H to check if FORMAT mode is active (tests bit 5 of 4282H).
61BD
LD A,50H 3E 50
Load Register A with 50H (80 decimal) — the fixed directory slot spacing for FORMAT mode.
61BF
If the NZ FLAG is set (FORMAT mode is active), JUMP to 61C7H to use the fixed 50H offset.
61C1
LD A,C 79
Load Register A with Register C — the sectors-per-track count for the current disk geometry.
61C2
ADD 20H C6 20
ADD 20H (32 decimal) to Register A. The directory slot spacing in COPY mode is sectors-per-track plus 32.
61C4
LD C,A 4F
Copy the computed slot spacing back into Register C.
61C5
RET NC D0
If the NC FLAG is set (the ADD at 61C2H did not overflow past FFH), RETurn with the new spacing in C. If the addition overflowed, fall through to use the overflow value at (HL).
61C6
LD A,(HL) 7E
Load Register A with the byte at (HL) — an overflow fallback value. When the sectors-per-track plus 32 exceeds 255, this provides an alternate slot count.
61C7
DEC A 3D
DECrement Register A by 1. The slot spacing is reduced by 1 to account for zero-based indexing.
61C8
INC C 0C
INCrement Register C by 1, advancing the current slot position.
61C9
CP C B9
Compare Register A (the maximum slot index) against Register C (the current position). Sets the CARRY FLAG if A < C (current position has passed the end).
61CA
RET C9
RETurn to the caller. The CARRY FLAG indicates whether the current position has exceeded the maximum slot index.
61CBH — DECIMAL DIGIT EXTRACTION (DIVIDE A BY B)
This is a general-purpose routine that extracts a decimal digit by dividing A by B. It stores the ASCII quotient digit (30H + quotient) at (HL), then returns with the remainder in A and HL advanced by 1. The initial CP B check returns with CARRY set if A < B (quotient is zero), which the caller can use to suppress leading zeros.
61CB
CP B B8
Compare Register A against Register B (the divisor). Sets the CARRY FLAG if A < B (quotient will be zero).
61CC
RET C D8
If the CARRY FLAG is set (A < B, quotient is zero), RETurn immediately. The caller uses this to skip leading zeros in multi-digit number formatting.
61CD
LD (HL),2FH 36 2F
Store 2FH (ASCII '/' — one less than '0') at (HL). This is the initial value before the division loop increments it to the correct ASCII digit.
[LOOP START] — Division loop: repeatedly subtract B from A, incrementing the stored digit each iteration.
61CF
INC (HL) 34
INCrement the byte at (HL). Starting from 2FH, the first increment produces 30H (ASCII '0'), then 31H ('1'), etc. Each iteration represents one more count of B fitting into A.
61D0
SUB B 90
SUBtract B from Register A. Reduces the dividend by the divisor each iteration.
61D1
If the NC FLAG is set (A is still non-negative after the subtraction), JUMP back to 61CFH to continue dividing.
[LOOP END] — A has underflowed; the digit at (HL) is the quotient, and A + B gives the remainder.
61D3
ADD A,B 80
ADD B back to Register A to correct the underflow. Register A now contains the remainder (A mod B).
61D4
INC HL 23
Advance HL to the next digit position in the output buffer.
61D5
RET C9
RETurn to the caller with the remainder in A and HL pointing to the next output position.
61D6H — FETCH NEXT DIRECTORY ENTRY ADDRESS (VIA RST 18H)
This routine fetches the next directory entry address from the directory buffer. It uses self-modifying code at 61D8H (HL operand) and 61DBH (DE operand) which are set by 6190H. The RST 18H instruction performs a 16-bit comparison of HL vs DE (directory current position vs end position). If HL >= DE, the CARRY FLAG is clear (entries remaining); if HL < DE, CARRY is set (past the end). After the comparison, the new position is stored back to 61D8H for the next call.
61D6
PUSH HL E5
Save the caller's HL value onto the stack.
61D7
LD HL,0000H 21 00 00
[SELF-MODIFYING CODE] — Load HL with the current directory buffer position. The two operand bytes at 61D8H are patched by 6190H (at 6193H) and updated by 61E4H after each call. The initial 0000H is replaced at runtime with the actual directory pointer.
61DA
LD DE,0000H 11 00 00
[SELF-MODIFYING CODE] — Load DE with the directory buffer end position. The operand bytes at 61DBH are set from the tracks-per-pass sentinel computed at 5D9DH (value = 593CH minus 24). This provides the upper boundary for the directory scan.
61DD
RST 18H DF
Execute RST 18H — a ROM routine that performs a 16-bit comparison of HL vs DE. Sets the CARRY FLAG if HL < DE (current position is before the end — more entries available). Clears CARRY if HL >= DE (past the end).
61DE
PUSH AF F5
Save the flags from the RST 18H comparison onto the stack. The CARRY FLAG indicates whether more entries are available.
61DF
EX DE,HL EB
Exchange DE and HL. Now HL contains the end position and DE contains the current position.
61E0
LD HL,0018H 21 18 00
Load Register Pair HL with 0018H (24 decimal) — the size of one directory entry in the buffer (24 bytes per slot).
61E3
ADD HL,DE 19
ADD DE (current position) to HL (entry size). HL = current position + 24, advancing to the next directory entry slot.
61E4
LD (61D8H),HL 22 D8 61
Store the updated position (current + 24) back to 61D8H, patching the self-modifying LD HL instruction at 61D7H for the next call to this routine.
61E7
POP AF F1
Restore the flags saved at 61DEH. The CARRY FLAG still reflects the RST 18H comparison result.
61E8
POP HL E1
Restore HL from the stack (the caller's original HL value saved at 61D6H).
61E9
RET C9
RETurn to the caller. CARRY set = past end (no more entries), CARRY clear = entries remain. DE contains the address of the next directory entry.
61EAH — CHECK IF EITHER SOURCE OR DEST DRIVE SUPPORTS MFM
This routine checks the MFM (double-density) capability of both the source and destination drives by ORing their density flag bytes. The source density flag is at 59B9H and the destination density flag is at 59C7H. The result is masked with 20H (bit 5) to isolate the MFM capability bit. Returns NZ if at least one drive supports MFM.
61EA
PUSH HL E5
Save HL onto the stack.
61EB
LD HL,59C7H 21 C7 59
Load Register Pair HL with 59C7H — the address of the destination drive density flag byte.
61EE
LD A,(59B9H) 3A B9 59
Load Register A with the source drive density flag from 59B9H.
61F1
OR (HL) B6
OR Register A with the destination density flag at (HL). The result has bit 5 set if EITHER the source or destination drive supports MFM double-density.
61F2
POP HL E1
Restore HL from the stack.
61F3
AND 20H E6 20
Mask Register A with 20H to isolate bit 5 (MFM capability). Sets the Z FLAG if neither drive supports MFM.
61F5
RET C9
RETurn to the caller. NZ = at least one drive supports MFM, Z = both drives are single-density only.
61F6H — FETCH FORMAT MODE FLAG
Simple utility that reads the DOS mode byte at 4282H and tests bit 5 (FORMAT mode). Returns NZ if FORMAT mode is active, Z if COPY mode.
61F6
LD A,(4282H) 3A 82 42
Load Register A with the DOS mode byte from 4282H (IY+02H in the DOS work area).
61F9
AND 20H E6 20
Mask Register A with 20H to isolate bit 5 (FORMAT mode flag). Sets the Z FLAG if bit 5 is clear (COPY mode), NZ if set (FORMAT mode).
61FB
RET C9
RETurn to the caller. NZ = FORMAT mode, Z = COPY mode.
61FCH — XOR SOURCE/DEST DENSITY FLAGS
This routine XORs the source and destination density flag bytes to determine if they differ. The source density flag is at 59B9H and the destination is at 59C7H. The result is masked with 20H (bit 5) to check only the MFM capability. Returns Z if densities match, NZ if they differ. Register A is loaded with the destination density byte (59C7H) before returning.
61FC
PUSH HL E5
Save HL onto the stack.
61FD
LD HL,59C7H 21 C7 59
Load Register Pair HL with 59C7H — the address of the destination density flag.
6200
LD A,(59B9H) 3A B9 59
Load Register A with the source drive density flag from 59B9H.
6203
XOR (HL) AE
XOR Register A with the destination density flag at (59C7H). Bits that differ between source and destination will be set to 1.
6204
AND 20H E6 20
Mask the XOR result with 20H to isolate bit 5 (MFM flag). Sets the Z FLAG if bit 5 is the same in both flags (densities match).
6206
LD A,(HL) 7E
Load Register A with the destination density flag byte from (59C7H). This provides the caller with the destination density value for subsequent processing.
6207
POP HL E1
Restore HL from the stack.
6208
RET C9
RETurn to the caller. Z = densities match, NZ = densities differ. A = destination density flag byte.
6209H — CONDITIONAL DIRECTORY DATE POINTER UPDATE
This routine conditionally updates a date pointer field in a directory entry based on whether the source and destination disks have different densities. If Register A is zero on entry (OR A sets Z), no update is needed. Otherwise, it calls 61FCH to check density differences, and adjusts the two-byte date pointer at (HL) by incrementing (if destination is single-density) or decrementing (if destination is double-density).
6209
OR A B7
Set flags based on Register A. If A = 0, the Z FLAG is set (no update needed).
620A
If the NZ FLAG is set (A was non-zero), GOSUB to 61FCH to XOR the source/destination density flags. Returns Z if densities match, NZ if they differ.
620D
RET Z C8
If the Z FLAG is set (either A was zero on entry, or densities match), RETurn without modifying the date pointer.
620E
LD E,(HL) 5E
Load Register E with the date pointer low byte from (HL).
620F
INC HL 23
Advance HL to the high byte of the date pointer.
6210
LD D,(HL) 56
Load Register D with the date pointer high byte from (HL). DE now contains the 16-bit date pointer value.
6211
INC DE 13
INCrement DE by 1. This is the default adjustment: add 1 to the date pointer (used when converting from double-density to single-density format).
6212
BIT 5,A CB 6F
Test bit 5 of Register A (the destination density flag from 61FCH). Bit 5 = 1 means the destination is double-density.
6214
If the Z FLAG is set (bit 5 clear — destination is single-density), JUMP to 6218H to write the incremented value. The +1 adjustment is correct for SD destinations.
6216
DEC DE 1B
DECrement DE by 1, undoing the INC at 6211H.
6217
DEC DE 1B
DECrement DE by 1 again. The net effect is DE = original value minus 1, which is the correct adjustment when converting from single-density to double-density format.
6218
LD (HL),D 72
Store the adjusted date pointer high byte (Register D) back to (HL).
6219
DEC HL 2B
Move HL back to the low byte position.
621A
LD (HL),E 73
Store the adjusted date pointer low byte (Register E) back to (HL). The date pointer has been updated.
621B
RET C9
RETurn to the caller.
621CH — GAT BIT MANIPULATION: MARK SECTORS ALLOCATED IN BITMAP
This routine marks sectors as allocated in the GAT (Granule Allocation Table) bitmap. It takes a track number in E and a sector count in C, then sets the corresponding bits in the GAT bitmap at (HL). The bitmap is organized with one bit per sector within each byte, and multiple bytes per track. The routine uses the sectors-per-GAT-byte value from 59CAH to handle bit/byte boundaries, and calls 5240H (boundary check) when all available sectors on a track are exhausted.
621C
LD D,00H 16 00
Clear Register D to zero. DE will be used as a 16-bit offset where E is the track index.
621E
ADD HL,DE 19
ADD DE (track offset) to HL (GAT bitmap base), positioning HL to the byte corresponding to track E in the bitmap.
621F
LD D,80H 16 80
Load Register D with 80H (bit 7 mask) — this is the initial bit position for sector marking. The highest bit corresponds to the first sector in the GAT byte.
6221
LD A,B 78
Load Register A with Register B — the starting sector number within the track (bit position offset).
6222
INC B 04
INCrement Register B by 1. B will serve as the DJNZ counter for the bit-shift loop. The extra 1 accounts for the DJNZ pre-decrement behavior.
[LOOP START] — Shift the bit mask right by B positions to reach the correct starting sector.
6223
RLC D CB 02
Rotate Register D left through carry. Since D started at 80H, the first RLC moves bit 7 into the CARRY and bit 0 gets the carry's old value. Successive rotations cycle the set bit rightward through the byte.
6225
DECrement B and JUMP to 6223H if B is not zero. This loop shifts the bit mask to the correct starting position for the first sector to mark.
[LOOP END] — D now contains the bit mask for the starting sector position.
6227
LD B,A 47
Save the original starting sector number (from 6221H) back into Register B for later use in the sectors-per-GAT-byte calculation.
6228
LD A,(59CAH) 3A CA 59
Load Register A with the sectors-per-GAT-byte value from 59CAH. This is the number of sectors represented by each bit in one GAT bitmap byte.
622B
SUB B 90
SUBtract B (starting sector number) from A (sectors-per-GAT-byte). The result is the number of remaining sector positions in the current GAT byte starting from the current bit position.
622C
LD B,A 47
Copy the remaining-positions count into Register B. This will be the DJNZ counter for the inner allocation loop.
[OUTER LOOP START] — Process GAT bytes, marking sectors allocated.
622D
PUSH HL E5
Save the current GAT bitmap byte pointer onto the stack.
622E
LD HL,59C6H 21 C6 59
Load HL with 59C6H — the address of the destination geometry track limit byte.
6231
LD A,E 7B
Load Register A with Register E — the current track number being allocated.
6232
CP (HL) BE
Compare the current track number against the destination track limit at (59C6H). Sets the CARRY FLAG if A < (HL) (track is within range).
6233
POP HL E1
Restore the GAT bitmap byte pointer from the stack.
6234
If the NC FLAG is set (track number >= track limit — current track is at or past the end of the disk), JUMP to 6249H to call the boundary check/capacity error helper at 5240H.
6236
LD A,(HL) 7E
Load Register A with the current GAT bitmap byte at (HL).
6237
AND D A2
AND Register A with the bit mask in D. If the result is non-zero, the sector at this bit position is already allocated.
6238
If the NZ FLAG is set (bit is already set — sector is already allocated), JUMP to 6249H to handle the conflict via the boundary check helper.
623A
LD A,(HL) 7E
Reload the GAT bitmap byte into Register A.
623B
OR D B2
OR the bit mask (D) into the bitmap byte. This sets the bit for the current sector, marking it as allocated.
623C
LD (HL),A 77
Store the updated bitmap byte back to (HL), persisting the allocation.
623D
DEC C 0D
DECrement Register C — the remaining sector count to allocate.
623E
RET Z C8
If the Z FLAG is set (C reached zero — all requested sectors have been allocated), RETurn to the caller. The allocation is complete.
623F
RLC D CB 02
Rotate the bit mask in D left by one position, moving to the next sector bit within the current GAT byte.
6241
DECrement B (remaining positions in current GAT byte) and JUMP to 622DH if B is not zero. Continue marking sectors in the current byte.
When B reaches zero, all bit positions in the current GAT byte have been exhausted. Advance to the next GAT byte.
6243
LD D,01H 16 01
Load Register D with 01H — reset the bit mask to bit 0 position for the new GAT byte.
6245
INC HL 23
Advance HL to the next byte in the GAT bitmap.
6246
INC E 1C
INCrement E (current track number) by 1, advancing to the next track.
6247
Unconditional JUMP back to 6228H to reload the sectors-per-GAT-byte value and continue allocating in the new GAT byte.
[OUTER LOOP END]
6249
GOSUB to 5240H (boundary check / capacity error helper). This routine handles the case where an allocation attempt hits a track boundary or conflict. It displays an appropriate error message and may prompt the operator for action.
624CH — ASCII STRING DATA: "RUNNY" MARKER AND COPY PROMPTS
The addresses from 624CH through 6290H contain ASCII string data used by the COPY/FORMAT display routines. These are not executable code — the disassembler has produced Z80 mnemonics but they decode as ASCII text. The strings include the "RUNNY" verification marker, the "COPY IT? (Y/N/R/Q)" operator prompt, the "COPYING" status message, and the "ILF/XLF FILE" format indicator.
624C
DEFB 20H,20H,20H 20 20 20
Three space characters — padding before the extension comparison string at 624CH. (Note: The continuation instructions list 624CH as the extension comparison target referenced from 5E42H.)
625C
DEFM "RUNNY",00H 52 55 4E 4E 59 00
ASCII string "RUNNY" followed by a null terminator (00H). This is a verification marker used by the 6254H comparison routine to validate internal data structures.
6261
DEFM " COPY IT? (Y/N/R/Q) ",03H 20 20 20 20 43 4F 50 59 20 49 54 3F 20 20 28 59 2F 4E 2F 52 2F 51 29 20 20 03
ASCII string " COPY IT? (Y/N/R/Q) " followed by 03H terminator. This is the operator prompt displayed during file-by-file COPY mode, offering options: Y=yes, N=no, R=rename, Q=quit.
627B
DEFM "COPYING",03H 43 4F 50 59 49 4E 47 03
ASCII string "COPYING" followed by 03H terminator. Displayed as a status message while file data is being transferred.
6283
DEFM "ILF/XLF FILE ",03H 49 4C 46 2F 58 4C 46 20 46 49 4C 45 20 03
ASCII string "ILF/XLF FILE " followed by 03H terminator. Displayed when the file being copied uses the ILF (Internal Linked File) or XLF (Extended Linked File) format, alerting the operator to special handling.
6254H — B-BYTE COMPARISON LOOP (DE VS HL)
A generic byte-by-byte comparison utility that compares B bytes starting at (DE) against (HL). Returns Z if all B bytes match, NZ at the first mismatch. Both DE and HL are advanced past the compared bytes.
[LOOP START] — Compare B bytes at (DE) vs (HL).
6254
LD A,(DE) 1A
Load Register A with the byte at (DE) — the source comparison byte.
6255
CP (HL) BE
Compare Register A against the byte at (HL). Sets the Z FLAG if they match, NZ if they differ.
6256
RET NZ C0
If the NZ FLAG is set (mismatch found), RETurn immediately with NZ to signal the comparison failed.
6257
INC DE 13
Advance DE to the next source byte.
6258
INC HL 23
Advance HL to the next destination byte.
6259
DECrement B and JUMP to 6254H if B is not zero. Continue comparing the next pair of bytes.
[LOOP END] — All B bytes matched; Z FLAG is set.
625B
RET C9
RETurn to the caller with the Z FLAG set (all bytes matched).
625CH–6290H — ASCII STRING DATA AREA
This block contains ASCII string constants used by the COPY/FORMAT operator menus and status display routines. The disassembler interprets these bytes as Z80 instructions, but they are pure data — never executed. The strings are referenced by address from display routines throughout SYS6. All ETX (03H) bytes serve as NEWDOS/80 string terminators, equivalent to the standard NUL terminator in other systems.
625C
DEFM "RQNY",00H
[DATA — 5 bytes] Menu response key lookup table:
R=Rename/Retry,
Q=Quit,
N=No (skip file),
Y=Yes (copy file). The NUL byte at 6260H terminates the table. Referenced by the operator menu prompt scanner at
5E63H (menu option dispatcher) to validate keyboard input against this list of accepted characters.
6261
DEFM " COPY IT? (Y/N/R/Q) ",03H
[DATA — 26 bytes] Per-file copy confirmation prompt string, terminated by ETX (03H). Displayed by the operator menu prompt routine at
5E63H when option flags enable per-entry prompting (bit 6 of 5995H). The operator responds with one of the four characters in the key table at
625CH.
627B
DEFM "COPYING",03H
[DATA — 8 bytes] Status message displayed by the copy initiation routine at
5273H via CALL
587EH (display string and carriage return). Shown to the operator after all pre-flight validation passes and the actual track-by-track copy begins.
6283
DEFM "ILF/XLF"
[DATA — 7 bytes, no terminator] Partial error message fragment meaning "ILF/XLF" (Illegal File / Cross-Linked File). Used at
5D67H where it is concatenated with the " FILE " string at
628AH to form the complete error message "ILF/XLF FILE". This 7-byte string has no terminator because the display routine at 5D67H calls 4467H (SYS0 display string) with HL pointing here, and the SYS0 routine reads until it hits the space-prefixed continuation at 628AH.
628A
DEFM " FILE ",03H
[DATA — 7 bytes] Continuation of the error message started at
6283H. Together they form the complete error message "ILF/XLF FILE " displayed when a directory entry has an illegal or cross-linked file condition. Terminated by ETX (03H) at 6290H.
6291H–6390H — DIRECTORY BITMAP WORK BUFFER (256 BYTES, RUNTIME DATA)
The 256-byte block from 6291H to 6390H is a runtime work buffer used during COPY operations to track which directory entries have been processed. Each byte in this buffer corresponds to a directory entry slot, and bits within each byte indicate processing state (e.g., bit 5 = matched, bit 4 = pending copy). The buffer is cleared to zero by the initialization routine at 5DACH before each COPY operation begins. Note that the first few bytes of this buffer overlap with the executable code below — the instruction at 6291H is reached via JP from 4D88H, meaning the first 8 bytes of the "buffer" are actually executed as code before the buffer is later cleared and repurposed for bitmap storage.
6291H — COPY/FORMAT/APPEND PRE-FLIGHT VALIDATION ENTRY
This is the main pre-flight entry point for COPY, FORMAT, and APPEND operations, reached via JP 6291H from 4D88H in the command dispatch table. The code performs drive initialization, validates option flags, copies disk name and date stamps from the GAT, checks source/destination disk label compatibility, and dispatches to the appropriate operation path. On exit, it either jumps to the filespec input loop at 5D16H (if option bit 3 of 5996H requests per-file mode), or falls through to the capacity comparison and parameter block builder at 6339H.
[ENTRY POINT] — Reached from JP 6291H at 4D88H. Register A is undefined on entry. IY = 4280H (DOS work area base) throughout.
6291
LD A,(5997H) 3A 97 59
Fetch option flags byte 4 from 5997H into Register A. This byte contains: bit 3 = destination filespec present, bit 4 = source filespec present, bit 5 = destination filespec parsed. Bits 4 and 5 together (masked as 30H below) indicate whether both source and destination filespecs have been fully parsed from the command line.
6294
AND 30H E6 30
Mask Register A with 30H (0011 0000 binary), isolating bits 4 and 5. If either bit is set, the result is non-zero (NZ FLAG), meaning at least one filespec parameter needs drive initialization via SYS0 CALL 4424H.
6296
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the GAT sector buffer in the DOS work area. This is passed to CALL 4424H as the data source for the drive initialization operation.
6299
LD DE,4480H 11 80 44
Point Register Pair DE to 4480H, the SYS0 work buffer for drive-qualified filespec strings. This is the parameter block destination for the drive init call.
629CH
If NZ FLAG is set (at least one filespec has been parsed, per the AND 30H test at 6294H), GOSUB to SYS0 routine 4424H to perform drive initialization with function code A and parameter block DE=4480H. This configures the FDC and PDRIVE tables for the drive specified in the parsed filespec. The CALL NZ means this is skipped entirely if no filespecs were parsed (both bits 4 and 5 of 5997H are clear).
629F
If CALL 4424H returned with NZ FLAG set (indicating a drive initialization error), JUMP to 5D67H which displays the "ILF/XLF FILE" error message and exits via the error handler at 521BH. A drive init failure at this stage means the filespec references an invalid or inaccessible drive.
Drive initialization succeeded (or was skipped). Now set up the drive operation mode based on option flags.
62A2
LD A,(5996H) 3A 96 59
Fetch option flags byte 3 from 5996H into Register A. Bit 3 of this byte indicates whether a filespec loop is active (the "per-file" copy sub-mode).
62A5
AND 08H E6 08
Mask with 08H to isolate bit 3. If set, the Z FLAG is cleared (NZ); if clear, the Z FLAG is set.
62A7
LD A,F3H 3E F3
Load Register A with F3H as the default drive setup function code. F3H requests a full drive reconfiguration including geometry reload and GAT read.
62A9
If the Z FLAG is set (bit 3 of 5996H is clear — no filespec loop active), JUMP to 62ADH to use the default F3H function code.
62AB
LD A,E5H 3E E5
Otherwise (filespec loop active), load Register A with E5H. This alternate function code requests a lighter-weight drive setup that preserves existing state — appropriate when iterating through files on an already-initialized drive.
62AD
GOSUB to 568DH (drive setup dispatcher) with the function code in Register A (either F3H for full init or E5H for lightweight re-init). This routine configures the source drive's FDC parameters and PDRIVE data.
62B0
GOSUB to 5578H (source drive setup) to initialize the source drive parameter block at 5AE5H. This reads the source drive's GAT and configures geometry parameters.
Source drive is now initialized. Check whether this is a single-disk operation (source=destination on same physical drive).
62B3
LD A,(428CH) 3A 8C 42
Fetch DOS status flags from 428CH (IY+0CH) into Register A. Bit 7 indicates special mode (source and destination are the same physical drive), bit 1 indicates an alternate configuration is active.
62B6
AND 82H E6 82
Mask with 82H (1000 0010 binary) to isolate bits 7 and 1. The combined pattern 80H (bit 7 set, bit 1 clear) identifies a single-drive COPY/FORMAT scenario where source and destination share the same physical drive but alternate disk swapping is NOT active.
62B8
CP 80H FE 80
Compare against 80H. If exactly 80H (bit 7 set, bit 1 clear), the Z FLAG is set — this is a same-drive operation without alternate mode.
62BA
If Z FLAG is set (same-drive, no alternate mode), JUMP to 62C3H to skip the source≠dest compatibility check and proceed directly to drive initialization. In same-drive mode, there is no separate destination to validate against.
62BC
LD A,(5994H) 3A 94 59
Fetch option flags byte 1 from 5994H into Register A. Bit 1 of this byte controls whether the source≠destination drive check is suppressed (set by the "SRC" option in the COPY command).
62BF
AND 02H E6 02
Mask with 02H to isolate bit 1 (source≠dest check suppression flag).
62C1
If NZ FLAG is set (bit 1 of 5994H is set — source≠dest check suppressed), JUMP forward to 632CH to skip all source-drive validation (disk label checks, date stamp comparison) and proceed directly to the operation dispatch at 6331H. This allows the operator to explicitly override safety checks.
Performing full source drive validation with label and date stamp checks.
62C3
GOSUB to 56F9H (drive init with XOR A) to perform a clean initialization of the source drive. This calls SYS0 48AFH with A=0 to reset the drive controller state and re-read the GAT.
62C6
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A. Bit 5 controls whether the date/version stamp copy is suppressed.
62C9
BIT 5,A CB 6F
Test bit 5 of Register A. If set (NZ FLAG), the date stamp copy is suppressed by the operator's option flags.
62CB
If NZ FLAG is set (date stamp suppressed), JUMP to 62D3H to skip the date stamp copy and proceed to disk name handling.
62CD
LD HL,(43CEH) 2A CE 43
Load Register Pair HL with the 16-bit date/version stamp from 43CEH in the GAT sector buffer. This is the source disk's creation date encoded as a 16-bit value in the DOS date format.
62D0
LD (5981H),HL 22 81 59
Store the source disk's date/version stamp (from HL) into the work area at 5981H. This saved value will later be written to the destination disk's GAT to preserve the date stamp during COPY.
Date stamp saved (or skipped). Now handle disk name copying.
62D3
LD A,(5994H) 3A 94 59
Fetch option flags byte 1 from 5994H into Register A. Bit 2 controls whether disk name geometry copy is suppressed.
62D6
BIT 2,A CB 57
Test bit 2 of Register A. If set (NZ FLAG), the disk name copy from the GAT is suppressed.
62D8
If NZ FLAG is set (disk name copy suppressed), JUMP to 62E5H to skip the name copy and check for the NDN= (New Disk Name) option.
62DA
LD HL,43D0H 21 D0 43
Point Register Pair HL to 43D0H, the disk name field in the GAT sector buffer. The GAT stores the 8-character disk name starting at offset D0H within the 256-byte GAT sector.
62DD
LD DE,5983H 11 83 59
Point Register Pair DE to 5983H, the source disk name buffer in the SYS6 work area. This buffer receives a copy of the 8-character disk name.
62E0
LD BC,0008H 01 08 00
Load Register Pair BC with 8 — the disk name is exactly 8 characters.
62E3
LDIR ED B0
Block copy 8 bytes from the GAT disk name field (43D0H) to the SYS6 work buffer (5983H). After this, 5983H contains the source disk's name for later display and comparison.
Disk name copied (or skipped). Check for NDN= (New Disk Name) option.
62E5
LD A,(5995H) 3A 95 59
Fetch option flags byte 2 from 5995H into Register A. Bit 4 indicates whether the NDN= (New Disk Name) option was specified on the command line.
62E8
BIT 4,A CB 67
Test bit 4 of Register A. If set (NZ FLAG), the NDN= option is active and the second half of the GAT disk name should be copied into the new-name buffer.
62EA
If Z FLAG is set (NDN= option NOT active), JUMP to 62F7H to skip the new disk name copy.
62EC
LD HL,43D8H 21 D8 43
Point Register Pair HL to 43D8H, the second half of the GAT disk name field (characters 9–16 of the disk label at offset D8H within the GAT sector).
62EF
LD DE,598BH 11 8B 59
Point Register Pair DE to 598BH, the new disk name buffer in the SYS6 work area. This receives the replacement name specified by NDN=.
62F2
LD BC,0008H 01 08 00
Load Register Pair BC with 8 — the new disk name is 8 characters.
62F5
LDIR ED B0
Block copy 8 bytes from GAT disk name second half (43D8H) to the new disk name buffer (598BH).
NDN= handled (or skipped). Check for source/destination disk label verification flag.
62F7
LD A,(5996H) 3A 96 59
Fetch option flags byte 3 from 5996H into Register A. Bit 7 indicates that the source/destination filespecs have been parsed and a disk label verification is required.
62FA
BIT 7,A CB 7F
Test bit 7 of Register A. If set (NZ FLAG), disk label verification was requested.
62FC
If Z FLAG is set (no label verification needed), JUMP to 6314H to skip the disk name mismatch check and proceed to date stamp validation.
62FE
LD HL,5968H 21 68 59
Point Register Pair HL to 5968H, the disk name/date stamp comparison buffer. This 16-byte buffer was initialized with the expected disk label when the operator specified a source disk name on the command line.
6301
GOSUB to 624FH to compare the disk name. The routine at 624FH loads DE=43D0H (GAT disk name field), B=08H (8 bytes), and executes an 8-byte comparison loop at
6254H. Returns with Z FLAG set if all 8 bytes match (disk names are identical), NZ FLAG if they differ.
6304
If Z FLAG is set (disk name matches expected label), JUMP to 632CH — validation passed, proceed to operation dispatch.
Disk name does NOT match. Display mismatch warning and prompt operator.
6306
LD HL,5A3CH 21 3C 5A
Point Register Pair HL to 5A3CH, the message string "SOURCE " (terminated by ETX). This labels the following display as pertaining to the source disk.
6309
GOSUB to 6930H to display the source label prefix. The routine at 6930H saves HL, calls SYS0 4467H to display the string at HL ("SOURCE "), then displays the "DISKETTE NAME MISMATCH" message from 6DC1H, and returns.
630C
GOSUB to 693CH to display the current disk's actual name and date information. The routine at 693CH calls 4467H with the HL from the stack, then displays "DISKETTE OLD NAME/DATE = " (from 6DA7H), followed by the 8-character disk name from 43D0H via CALL 5886H, 4 spaces, and another 8-character field, ending with a carriage return.
630F
GOSUB to 58C8H (operator confirmation prompt) to ask the operator whether to continue despite the name mismatch. Returns with Z FLAG set if the operator confirms (presses Y), NZ FLAG if the operator declines.
6312
If NZ FLAG is set (operator declined — disk name mismatch was NOT accepted), JUMP back to 62C3H to re-initialize the source drive and repeat the validation. This allows the operator to swap disks and retry.
Disk name verification passed (or skipped, or operator accepted mismatch). Now check date stamp compatibility.
6314
LD A,(428CH) 3A 8C 42
Fetch DOS status flags from 428CH (IY+0CH) into Register A. Re-check bits 7 and 1 to determine if this is a same-drive operation (same test as at 62B3H).
6317
AND 82H E6 82
Mask with 82H to isolate bits 7 and 1.
6319
CP 80H FE 80
Compare against 80H. If exactly 80H (same-drive, no alternate mode), Z FLAG is set.
631B
If NZ FLAG is set (different drives, or alternate mode active), JUMP to 632CH to skip the date stamp comparison. Date stamp validation only applies to same-drive operations where the system must verify the correct disk is inserted.
631D
LD HL,(43CEH) 2A CE 43
Load Register Pair HL with the current source disk's date/version stamp from the GAT sector buffer at 43CEH.
6320
LD DE,(5978H) ED 5B 78 59
Load Register Pair DE with the previously cached source disk geometry value from 5978H. This was stored during the initial drive analysis and serves as a verification token — if the disk in the drive has changed, this value will no longer match.
6324
OR A B7
Clear the Carry Flag to prepare for a clean 16-bit subtraction.
6325
SBC HL,DE ED 52
SUBtract DE (cached geometry value) from HL (current GAT date stamp). If HL equals DE, the result is zero and the Z FLAG is set — the disk has not changed. If they differ (NZ FLAG), the disk has been swapped.
6327
LD A,37H 3E 37
Load Register A with error code 37H (date stamp mismatch error). This error code is pre-loaded before the conditional jump so it is ready if the comparison fails.
6329
If NZ FLAG is set (date stamp does NOT match cached value — the disk has been changed), JUMP to 521AH (main error handler) with error code 37H in Register A. This aborts the operation because the source disk identity cannot be verified.
632CH — OPERATION DISPATCH: FILESPEC MODE OR FULL-DISK COPY
All pre-flight validation paths converge here. The code clears the label verification flag (bit 7 of 5996H) since it has been processed, then checks option bit 3 of 5996H to determine the operation mode. If bit 3 is set, this is a per-file COPY with filespecs, and control jumps to the filespec input/validation loop at 5D16H. Otherwise, this is a full-disk operation (COPY or FORMAT), and the code compares source vs. destination capacity to determine if the copy will fit, builds drive parameter blocks, and initiates the copy.
632C
LD HL,5996H 21 96 59
Point Register Pair HL to option flags byte 3 at 5996H.
632F
RES 7,(HL) CB BE
Clear bit 7 of the byte at (HL) — reset the "source/destination parsed and label verification pending" flag now that verification is complete (or was skipped).
6331
LD A,(5996H) 3A 96 59
Re-fetch option flags byte 3 from 5996H into Register A (after clearing bit 7).
6334
BIT 3,A CB 5F
Test bit 3 of Register A. If set, a filespec-based copy is requested (per-file mode).
6336
If NZ FLAG is set (filespec loop mode), JUMP to 5D16H to enter the COPY/APPEND filespec input and validation routine. This branches to the per-file copy path where the operator specifies individual files to copy.
[FULL-DISK COPY/FORMAT PATH] — Compare source and destination disk capacities to validate the operation is feasible.
6339
LD HL,(59D1H) 2A D1 59
Load Register Pair HL with the source disk total track/size count (16-bit) from 59D1H. This value represents the total number of usable sectors on the source disk.
633C
LD DE,(59C3H) ED 5B C3 59
Load Register Pair DE with the destination disk total track/size count (16-bit) from 59C3H. This is the destination's total sector capacity.
6340
RST 18H DF
Execute RST 18H (NEWDOS/80 directory traversal system call). In this context, RST 18H performs a 16-bit comparison of HL (source capacity) against DE (destination capacity). Returns with Carry Flag set if HL < DE (source fits in destination), No Carry if HL >= DE (source may not fit).
6341
LD A,(5994H) 3A 94 59
Fetch option flags byte 1 from 5994H into Register A. Bit 1 controls whether the source>destination size check is overridden.
6344
LD C,A 4F
Copy option flags byte 1 into Register C for later bit testing. Register A will be needed for other purposes.
6345
LD HL,(59C1H) 2A C1 59
Load Register Pair HL with the destination drive geometry/config pointer from 59C1H. This points to the destination's sector configuration data.
6348
If No Carry Flag (source capacity >= destination capacity — the source fits or they are equal), JUMP to 6352H to store the destination capacity pointer and continue. The copy is feasible.
634A
BIT 1,C CB 49
Test bit 1 of Register C (saved option flags byte 1). If set, the operator explicitly allowed source>destination size mismatch via the SRC option.
634C
If Z FLAG is set (bit 1 clear — size override NOT requested), JUMP to 5204H which loads error code 3CH (parameter conflict) and exits via the error handler. The source disk is larger than the destination and no override was given.
634F
LD HL,(59CFH) 2A CF 59
Load Register Pair HL with the total destination disk capacity (sector count) from 59CFH. When the size override is active, use the full destination capacity as the copy limit rather than the destination geometry pointer.
6352
LD (5AF1H),HL 22 F1 5A
Store the capacity value (from HL) into 5AF1H, the destination capacity pointer in the destination drive parameter block. This sets the upper bound for the copy operation.
6355
NOP 00
No operation (padding byte — 2 NOPs at 6355H-6356H may be a patched-out instruction from development).
6356
NOP 00
No operation (second padding byte).
6357
BIT 1,C CB 49
Test bit 1 of Register C (option flags byte 1) again. If set, the SRC override is active and the GAT compatibility check below should be skipped.
6359
If NZ FLAG is set (SRC override active), JUMP to 6365H to skip the GAT sectors-per-granule compatibility check.
635B
LD HL,59CAH 21 CA 59
Point Register Pair HL to 59CAH, the destination disk's sectors-per-GAT-byte value. This encodes how many sectors each GAT bitmap byte represents.
635E
LD A,(59BCH) 3A BC 59
Fetch the source disk's GAT configuration parameter (sectors-per-granule multiplier) from 59BCH into Register A.
6361
CP (HL) BE
Compare Register A (source sectors-per-granule) against the byte at (HL) (destination sectors-per-GAT-byte at 59CAH). If they are equal, the Z FLAG is set — the disks have compatible granule geometry.
6362
If NZ FLAG is set (source and destination granule geometries do NOT match), JUMP to 5204H to exit with error code 3CH (parameter conflict). A full-disk copy requires matching granule structures between source and destination.
Capacity and geometry checks passed. Perform final drive initialization and start the copy.
6365
GOSUB to 674DH (double-density capability check). This routine verifies that both source and destination drives support the required density mode (MFM/FM) for the copy. If either drive cannot handle the other's density, the routine exits with an error.
6368
GOSUB to 67C5H (main drive initialization) to perform the full physical drive setup. This calls the geometry patcher at 6759H, initializes FDC parameters via 557DH, and executes mode-dependent initialization (FORMAT track writes or COPY drive prep).
636B
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H to zero out the progress counters.
636E
LD (5AEFH),HL 22 EF 5A
Store 0000H to 5AEFH, zeroing the source sector count/progress field in the source drive parameter block. This resets the track counter before the copy begins.
6371
LD (5B21H),HL 22 21 5B
Store 0000H to 5B21H, zeroing the destination sector count/progress field in the destination drive parameter block.
6374
JUMP to 5273H to display the "COPYING" status message and enter the main track-by-track copy loop. This is the point of no return — the actual disk copy begins.
6377H — BUILD SOURCE/DESTINATION PARAMETER BLOCKS AND START COPY
This routine is called from 4DF0H (JP 6377H) during the COPY command's post-option-parse phase. It builds the source and destination drive parameter blocks by calling 6437H twice, runs the double-density compatibility reconfiguration at 5C9FH, sets up drive buffers, and jumps to the copy loop entry at 5279H.
6377
LD BC,594CH 01 4C 59
Load Register Pair BC with 594CH, the address of the source drive number variable. This will be passed to the parameter block builder to identify which drive to configure.
637A
LD DE,5AE5H 11 E5 5A
Load Register Pair DE with 5AE5H, the base address of the source drive parameter block (50 bytes). This is the destination buffer where the parameter block will be built.
637D
GOSUB to 6437H to build the source drive parameter block. The routine reads the drive number from (BC)=594CH, fetches geometry from the PDRIVE table, and populates the 50-byte parameter block at DE=5AE5H.
6380
LD BC,5956H 01 56 59
Load Register Pair BC with 5956H, the address of the destination drive number variable.
6383
LD DE,5B17H 11 17 5B
Load Register Pair DE with 5B17H, the base address of the destination drive parameter block (50 bytes).
6386
GOSUB to 6437H to build the destination drive parameter block from (BC)=5956H into the buffer at DE=5B17H.
6389
GOSUB to 5C9FH (double-density compatibility check and linked-list reconfiguration). This routine compares the source and destination drive density modes and adjusts the PDRIVE linked list if a density conversion is required.
638C
GOSUB to 568BH (drive setup dispatcher alternate entry with A=04H). This performs a buffer flush and drive state preparation for the copy operation.
638F
JUMP to 5279H to enter the main copy loop. This starts the track buffer size calculation (comparing 593CH high memory limit against 5D14H directory buffer end) and begins the actual sector-by-sector copy operation.
6392H — PARSE DRIVE DESIGNATOR FROM FILESPEC
This short routine parses a drive number from the current filespec position and stores it in three locations: the destination drive number field (5B1DH), the destination drive variable (5956H), and the self-modifying current drive number at 4DFAH. Called from 4D4DH during command-line parsing.
6392
GOSUB to 6ECAH to parse a drive number from the filespec string. On return, Register A contains the drive number (0–7) and the Carry Flag is set if a valid drive number was found. If no valid drive designator is present, Carry is clear.
6395
RET NC D0
If the No Carry Flag is set (no valid drive designator found), RETurn to the caller. The three storage locations are not updated.
6396
LD (5B1DH),A 32 1D 5B
Store the parsed drive number (from Register A) into 5B1DH, the destination drive number field within the destination drive parameter block at 5B17H.
6399
LD (5956H),A 32 56 59
Store the drive number into 5956H, the destination drive number variable in the SYS6 work area.
639C
LD (4DFAH),A 32 FA 4D
[SELF-MODIFYING CODE] Store the drive number into 4DFAH, which is the operand of the "LD A,00H" instruction at 4DF9H. This patches the current drive number so that subsequent code at 4DF9H loads the correct drive when executed.
639F
RET C9
RETurn to the caller. The drive number is now stored in all three locations.
63A0H — PARSE "=" PARAMETER FROM FILESPEC
This routine checks if the current filespec position contains an "=" character. If it does, it parses the hexadecimal value following the "=" sign using the hex parser at 6EE6H and stores the result into the geometry data table entry pointed to by DE. Called from 4D53H and also used at 63A3H as a shared entry point for the option keyword parser.
63A0
LD DE,64A9H 11 A9 64
Load Register Pair DE with 64A9H, pointing to a specific entry in the drive geometry data table at 64A3H. The parsed "=" parameter value will be stored at this address. This entry is 6 bytes into the table (64A3H + 6 = 64A9H).
63A3
LD A,(HL) 7E
Fetch the current character from the filespec string (pointed to by HL) into Register A.
63A4
CP 3DH FE 3D
Compare Register A against 3DH (ASCII =). If equal, the Z FLAG is set — an "=" parameter follows.
63A6
RET NZ C0
If NZ FLAG is set (current character is NOT "="), RETurn to the caller. No "=" parameter is present at this position.
63A7
PUSH DE D5
Save the geometry table destination pointer (DE=64A9H or caller-supplied value) onto the stack.
63A8
INC HL 23
INCrement HL to advance past the "=" character and point to the first digit of the hex value.
63A9
GOSUB to 6EE6H (parse hex parameter from filespec). This routine converts the hex digit string at (HL) into a 16-bit binary value. On return, Register A contains the low byte of the parsed value, and HL is advanced past the hex digits.
63AC
POP DE D1
Restore the geometry table destination pointer from the stack into Register Pair DE.
63AD
OR A B7
Set flags based on Register A (the parsed hex value). If the parsed value is zero, Z FLAG is set — zero is treated as an invalid parameter.
63AE
LD (DE),A 12
Store the parsed hex value (from Register A) into the geometry table entry pointed to by DE. This writes the operator-specified parameter into the drive geometry data table.
63AF
RET NZ C0
If NZ FLAG is set (parsed value is non-zero — valid parameter), RETurn to the caller. The parameter has been stored successfully.
63B0
If the parsed value was zero (invalid), JUMP to 5218H which loads error code 34H (parse error) and enters the main error handler at 521AH. A zero "=" parameter is not allowed.
63B3H — DRIVE GEOMETRY LOADER: FLUSH BUFFERS AND LOAD SOURCE/DEST GEOMETRY
This routine is the top-level geometry initialization entry. It flushes all three drive buffers, sets the "drive parameter blocks initialized" flag at 593BH bit 7, flushes again with two parameter blocks, then loads geometry data for both the source and destination drives. Finally, it processes the geometry data table at 64A3H to apply any operator-specified overrides. Called from 5C9FH (DD compatibility check) and 6630H (APPEND geometry setup).
63B3
LD B,03H 06 03
Load Register B with 03H — flush all three drive parameter blocks (source, destination, and third).
63B5
GOSUB to 5646H (flush all drive buffers) with B=03H. This iterates through all three parameter blocks and writes any dirty buffers to disk.
63B8
LD B,02H 06 02
Load Register B with 02H — prepare to flush the first two parameter blocks (source and destination).
63BA
LD HL,593BH 21 3B 59
Point Register Pair HL to 593BH, the disk operation state flags byte.
63BD
SET 7,(HL) CB FE
Set bit 7 of (593BH), marking "drive parameter blocks initialized." This flag tells subsequent routines that the geometry data in the parameter blocks is valid and does not need re-reading from disk.
63BF
GOSUB to 5646H again with B=02H to flush the source and destination drive buffers after setting the initialization flag.
Buffers flushed. Now load source drive geometry into the work area.
63C2
LD BC,(594CH) ED 4B 4C 59
Load Register Pair BC with the source drive number from 594CH. The low byte C contains the drive number (0–7); B contains the byte at 594DH.
63C6
LD HL,59B7H 21 B7 59
Point Register Pair HL to 59B7H, the source drive geometry parameter block base. This 10-byte block will receive a copy of the source drive's geometry data from the PDRIVE table.
63C9
LD A,FFH 3E FF
Load Register A with FFH as the "load fresh" flag. When passed to
63ECH, FFH means "copy geometry from the PDRIVE table without modification."
63CB
GOSUB to 63ECH (conditional geometry copy) to load source drive geometry from the PDRIVE table into the work buffer at 59B7H.
Source geometry loaded. Now load destination drive geometry.
63CE
LD BC,(5956H) ED 4B 56 59
Load Register Pair BC with the destination drive number from 5956H. C = destination drive number.
63D2
LD HL,59C5H 21 C5 59
Point Register Pair HL to 59C5H, the destination drive geometry copy destination (10+6 bytes).
63D5
LD A,FFH 3E FF
Load Register A with FFH — same "load fresh" flag for the destination drive.
63D7
GOSUB to 63ECH to load destination drive geometry from PDRIVE into the buffer at 59C5H.
Both source and destination geometry loaded. Now process the geometry data override table.
63DA
LD HL,64A3H 21 A3 64
Point Register Pair HL to 64A3H, the drive geometry data table. This table contains a count byte followed by triplets of (destination-address-low, destination-address-high, override-value).
63DD
LD C,(HL) 4E
Load Register C with the count byte at 64A3H (value = 04H — four entries in the table).
63DE
INC HL 23
[LOOP START — geometry override application] Advance HL to the next triplet entry.
63DF
LD E,(HL) 5E
Load Register E with the low byte of the destination address from the current table entry.
63E0
INC HL 23
Advance HL to the high byte of the destination address.
63E1
LD D,(HL) 56
Load Register D with the high byte. DE now contains the 16-bit target address where the override value should be stored.
63E2
INC HL 23
Advance HL to the override value byte.
63E3
LD A,(HL) 7E
Load Register A with the override value from the table entry.
63E4
OR A B7
Test the override value. If zero, Z FLAG is set — a zero value means "no override."
63E5
If Z FLAG (override value is zero), JUMP to 63E8H to skip the store.
63E7
LD (DE),A 12
Store the non-zero override value (Register A) to the destination address (DE).
63E8
DEC C 0D
DECrement the loop counter (Register C).
63E9
If NZ FLAG (more entries remain), JUMP back to 63DEH. [LOOP END]
63EB
RET C9
RETurn to the caller.
63ECH — CONDITIONAL GEOMETRY COPY WITH DRIVE-NUMBER FLAG UPDATE
Copies 10 bytes of drive geometry from the PDRIVE table into the work area at (HL). If Register A is FFH on entry, the routine returns immediately (the caller handles the copy separately). Otherwise, A contains a drive index that is rotated into the high nibble and used as an offset into the operation mode flags at 5940H. Called from 63CBH and 63D7H.
63EC
CP FFH FE FF
Compare Register A against FFH. If equal, Z FLAG is set — "raw copy" request with no flag manipulation.
63EE
RET Z C8
If Z FLAG (A=FFH), RETurn immediately. The geometry copy will be handled through the separate PDRIVE table read path in 63B3H.
63EF
RLCA 07
Rotate Register A left (first of four rotations to shift drive index into high nibble).
63F0
RLCA 07
Rotate left again (second).
63F1
RLCA 07
Rotate left (third).
63F2
RLCA 07
Rotate left (fourth). The original low-nibble drive index is now in the high nibble. Drive 1 (01H) becomes 10H; drive 2 (02H) becomes 20H.
63F3
PUSH HL E5
Save the geometry destination pointer (HL=59B7H or 59C5H) onto the stack.
63F4
LD HL,5940H 21 40 59
Point Register Pair HL to 5940H, the operation mode flags word.
63F7
PUSH AF F5
Save the rotated drive index and flags onto the stack.
63F8
LD A,C 79
Load Register A with the drive number from Register C.
63F9
OR A B7
Test the drive number. If zero (drive 0), Z FLAG is set.
63FA
If NZ (drive is not 0), JUMP to 6406H to skip drive-0 flag setup.
Drive 0 path: update operation mode flags.
63FC
DEC A 3D
DECrement A (from 00H to FFH) to create a full bit mask.
63FD
XOR B A8
XOR A with B to invert specific bits based on the high byte of the drive number word.
63FE
INC HL 23
Advance HL to 5941H (second byte of flags word).
63FF
AND (HL) A6
AND the mask with the current value at 5941H, clearing specific drive-associated bits.
6400
LD (HL),A 77
Store the updated flags back to 5941H.
6401
DEC HL 2B
Move HL back to 5940H.
6402
INC B 04
INCrement B to set bit 0 for drive 0 participation.
6403
LD A,(HL) 7E
Fetch current operation mode flags from 5940H.
6404
OR B B0
OR with B to set the drive 0 participation bit.
6405
LD (HL),A 77
Store updated flags back to 5940H.
Compare source and destination drive numbers for same-drive detection.
6406
LD A,(5956H) 3A 56 59
Fetch destination drive number from 5956H.
6409
LD B,A 47
Copy destination drive number into Register B.
640A
LD A,(594CH) 3A 4C 59
Fetch source drive number from 594CH.
640D
CP B B8
Compare source against destination. Z FLAG if equal (same drive).
640E
If NZ (different drives), JUMP to 6417H.
Same drive — set single-drive swap mode flags.
6410
LD A,(HL) 7E
Fetch operation mode flags from (HL)=5940H.
6411
OR 06H F6 06
Set bits 1 and 2: same-drive mode + swap required.
6413
LD (HL),A 77
Store updated flags.
6414
INC HL 23
Advance to 5941H.
6415
LD (HL),01H 36 01
Store 01H to 5941H — single-drive swap mode active.
6417
GOSUB to 6424H to initialize the PDRIVE linked list sentinel and read the GAT sector.
641A
POP AF F1
Restore the rotated drive index from the stack.
641B
ADD A,L 85
Add the rotated drive index to L to compute offset into the PDRIVE table.
641C
LD L,A 6F
Load L with the computed offset, making HL point to the drive's PDRIVE geometry entry.
641D
POP DE D1
Restore the geometry destination pointer (DE=59B7H or 59C5H).
641E
LD BC,000AH 01 0A 00
Load BC with 10 — the geometry entry is 10 bytes.
6421
LDIR ED B0
Block copy 10 bytes of geometry data from the PDRIVE table to the destination work buffer.
6423
RET C9
RETurn to the caller.
6424H — INIT PDRIVE LINKED LIST SENTINEL AND READ GAT
Writes sentinel value 0002H to the PDRIVE linked list start pointer at 5B53H, then reads the GAT sector for the drive specified in the third parameter block at 5B49H. Called from 6417H.
6424
LD HL,0002H 21 02 00
Load Register Pair HL with 0002H, the PDRIVE linked list sentinel value.
6427
LD (5B53H),HL 22 53 5B
Store 0002H to 5B53H, initializing the linked list pointer.
642A
LD HL,4300H 21 00 43
Point HL to 4300H, the GAT sector buffer.
642D
LD DE,5B49H 11 49 5B
Point DE to 5B49H, the third drive parameter block.
6430
GOSUB to SYS0 4436H (read sector) with DE=parameter block, HL=destination buffer.
6433
RET Z C8
If Z FLAG (read succeeded), RETurn.
6434
If read failed, JUMP to 521AH (main error handler) with error code in A.
6437H — BUILD DRIVE PARAMETER BLOCK FROM FILESPEC DRIVE DESIGNATOR
Constructs a drive parameter block at (DE) using the drive number at (BC) and filespec data. Handles three cases: (1) colon delimiter (3AH) — parse explicit drive letter; (2) ETX (03H) — use default drive; (3) other characters — continue scanning. Also detects same-drive operations and sets flags at 5940H. Called from 637DH and 6386H.
6437
LD HL,5940H 21 40 59
Point HL to 5940H, the operation mode flags word.
643A
LD A,(DE) 1A
[LOOP START — filespec scan] Fetch the current character from the filespec buffer at (DE).
643B
CP 3AH FE 3A
Compare against 3AH (ASCII :). A colon separates the drive designator from the filename.
643D
INC DE 13
Advance DE to the next character (advance happens regardless).
643E
If NZ (not a colon), JUMP to 6458H to check for ETX or continue scanning.
Colon found — parse the drive designator.
6440
LD A,(HL) 7E
Fetch operation mode flags from 5940H.
6441
CP 06H FE 06
Compare against 06H. If >=6, both drives already assigned — error.
6443
If No Carry (too many drives), JUMP to 6482H for parameter error.
6445
PUSH HL E5
Save flags pointer (HL=5940H).
6446
PUSH BC C5
Save drive number destination pointer (BC).
6447
EX DE,HL EB
Exchange DE and HL. HL now points to the filespec string.
6448
GOSUB to 6ED6H (parse and validate drive designator). Returns drive number (0–7) in A.
644B
POP BC C1
Restore drive number destination pointer.
644C
POP HL E1
Restore flags pointer (HL=5940H).
644D
OR A B7
Test Register A. Z if drive 0, NZ if non-zero.
644E
LD (BC),A 02
Store parsed drive number to (BC) — either 594CH (source) or 5956H (destination).
644F
RET NZ C0
If NZ (valid non-zero drive), RETurn.
6450
INC BC 03
Advance BC to configuration flags byte.
6451
LD A,(BC) 0A
Fetch the configuration flags byte.
6452
BIT 0,(HL) CB 46
Test bit 0 of (5940H) — whether drive 0 is already assigned.
6454
RET Z C8
If Z (drive 0 not yet assigned), RETurn — drive 0 is valid.
6455
OR (HL) B6
OR config flags with operation mode flags to merge drive state.
6456
LD (HL),A 77
Store merged flags back to 5940H.
Non-colon path: check for ETX or continue scanning.
6458
CP 03H FE 03
Compare against 03H (ETX terminator).
645A
If NZ (not ETX), JUMP back to 643AH to continue scanning. [LOOP END]
ETX — end of filespec with no explicit drive. Use default drive.
645C
LD A,(HL) 7E
Fetch operation mode flags from 5940H.
645D
CP 06H FE 06
Compare against 06H.
645F
If Carry (flags < 06H — under-assigned), JUMP to 6474H.
6461
LD A,(BC) 0A
Fetch current drive number from (BC).
6462
OR A B7
Test drive number.
6463
INC BC 03
Advance BC past drive number.
6464
If NZ (non-zero drive), JUMP to 6468H.
6466
SET 0,(HL) CB C6
Set bit 0 of 5940H — mark drive 0 as assigned.
6468
ADD 30H C6 30
Convert binary drive number (0–7) to ASCII ('0'–'7').
646A
LD (DE),A 12
Store ASCII drive character into filespec buffer at (DE).
646B
DEC DE 1B
DECrement DE to position before the drive digit.
646C
EX DE,HL EB
Exchange DE and HL.
646D
LD (HL),3AH 36 3A
Insert colon (3AH) before the drive digit in the filespec.
646F
INC HL 23
Advance past the colon.
6470
INC HL 23
Advance past the drive digit.
6471
LD (HL),03H 36 03
Store ETX terminator after the inserted drive designator.
6473
RET C9
RETurn. The filespec has been patched with the default drive designator.
Under-assigned case: validate and set up common drive.
6474
BIT 0,A CB 47
Test bit 0 of operation mode flags. If set, drive 0 already assigned.
6476
If NZ (drive 0 assigned but flags < 06H — conflict), JUMP to parameter error.
6478
LD A,(5997H) 3A 97 59
Fetch option flags byte 4 from 5997H.
647B
AND C0H E6 C0
Isolate bits 6 and 7.
647D
LD H,B 60
Copy B into H (HL = BC, the drive number destination pointer).
647E
LD L,C 69
Copy C into L.
647F
If Z (no special mode flags), JUMP to 5538H for standard drive setup using HL as pointer.
6482
JUMP to 5200H — general parameter error exit.
64A3H–64C0H — DRIVE GEOMETRY DATA TABLE AND BOOT SECTOR TEMPLATE [DATA]
Two data structures. First (64A3H–64AFH): geometry data table with count byte and 4 triplets of (target-addr-lo, target-addr-hi, value). Second (64BAH–64C0H): 7-byte boot sector config template patched at runtime by 5C88H, 6799H, 676CH, 6774H.
64A3
DEFB 04H
[DATA — 1 byte] Entry count: 4 geometry override triplets follow.
64A4
DEFW 59BAH, DEFB 00H
[DATA — entry 1] Target: 59BAH (source density control). Override: 00H (use PDRIVE default).
64A7
DEFW 59C8H, DEFB 00H
[DATA — entry 2] Target: 59C8H (destination side count). Override: 00H.
64AA
DEFW 59CDH, DEFB 00H
[DATA — entry 3] Target: 59CDH (boot sector patch). Override: 00H.
64AD
DEFW 59CEH, DEFB 00H
[DATA — entry 4] Target: 59CEH (dest geometry count). Override: 00H.
64BA
DEFB 00H,FEH,11H,F3H,11H,05H,00H
[DATA — 7 bytes, boot sector config template] Used by
67B3H (LD DE,64BAH) and
5C80H (LD HL,64BAH). Byte 64BCH patched by
5C88H/
6799H. Bytes 64BFH/64C0H patched by INC (HL) at
6774H/
676CH.
64B0H — CLEAR 256-BYTE BUFFER AT 4300H
Fills 256 bytes of the GAT sector buffer at 4300H with the value in Register A. Called with A=FFH from 6675H and A=00H from 66C1H.
64B0
LD HL,4300H 21 00 43
Point HL to 4300H, the 256-byte GAT sector buffer.
64B3
LD B,00H 06 00
Load B with 00H (256 iterations via DJNZ wrap).
64B5
LD (HL),A 77
[LOOP START] Store fill byte to (HL).
64B6
INC HL 23
Advance to next byte.
64B7
Loop back if B not zero. [LOOP END — 256 iterations]
64C1H — DOUBLE-DENSITY BOOT SECTOR WRITER (FDC DIRECT I/O)
Critical low-level FDC routine that writes boot sector data using direct port I/O with NMI-based interrupt handling. Operates with interrupts disabled in the alternate register set (EXX). Reads boot data byte-by-byte via CALL 4345H. Handles double-sided disks via sector comparison against 12H (18). Contains an NMI-driven halt loop at 655AH broken by the NMI handler restoring SP from 43A6H.
[CRITICAL FDC ROUTINE] — Interrupts disabled. Alternate register set. Direct port I/O at F0H–F4H. NMI handler at 43A2H.
64C1
EXX D9
Switch to alternate register set. Main registers preserved for caller.
64C2
LD SP,41E0H 31 E0 41
Set SP to 41E0H, dedicated DOS stack for NMI-driven FDC operations.
64C5
LD HL,51FFH 21 FF 51
HL' = 51FFH — destination pointer (pre-incremented to 5200H on first use).
64C8
[OUTER LOOP] Read next byte from boot data source. Returns in A.
64CB
CP 20H FE 20
Bytes <20H are commands; >=20H are track/sector numbers.
64CD
LD B,A 47
Save byte in B'.
64CE
If >=20H, JUMP to 64F9H for sector data copy path.
64D0
LD D,A 57
Command byte to D' (track number for seek).
64D1
Read sector count for this track.
64D4
LD C,A 4F
Sector count to C'.
64D5
Read starting sector number.
64D8
LD E,A 5F
Starting sector to E'.
64D9
DEC B' and jump to 64EDH if not zero (second pass). Falls through on first pass.
64DB
Read next data byte from boot stream.
64DE
LD D,A 57
Store in D'.
64DF
DEC C 0D
DEC sector count.
64E0
DEC C 0D
DEC again (count by 2 per pass).
64E1
INC L 2C
[INNER LOOP — data fill] INC L' (page-aligned advance).
64E2
If L' wrapped (page overflow), GOSUB 4348H for page advance.
64E5
LD A,(HL) 7E
Fetch source byte from (HL').
64E6
LD (DE),A 12
Store to destination (DE').
64E7
INC DE 13
Advance destination.
64E8
DEC C 0D
DEC byte count.
64E9
Loop back if more bytes. [INNER LOOP END]
64EB
Back to outer loop for next command.
64ED
Second pass — DEC B' and jump to count-down at 64E8H.
64EF
Read verification track byte.
64F2
LD D,A 57
Expected track to D'.
64F3
LD A,(DE) 1A
Fetch written byte at (DE').
64F4
CP A5H FE A5
Compare against A5H — NEWDOS/80 boot signature.
64F6
INC DE 13
Advance past signature.
64F7
PUSH DE D5
Save dest pointer.
64F8
RET Z C8
If signature matches, PUSH+RET Z acts as conditional computed jump to (DE').
64F9
LD HL,43F0H 21 F0 43
HL' = 43F0H — sector staging area.
64FC
JUMP to SYS0 43CCH for FDC read/write dispatch.
64FFH — SECTOR READ COMPLETION AND FDC MULTI-SECTOR WRITE DISPATCHER
Reached from within the boot sector writer's control flow. Verifies buffer readiness, switches to alternate registers, seeks to target track, writes sectors with NMI-based DRQ handling, and handles double-sided disk side switching. Contains halt loop at 655AH broken by NMI handler.
64FF
INC L 2C
INC L' to advance buffer position.
6500
LD A,(HL) 7E
Fetch byte at current buffer position.
6501
RET NZ C0
If NZ (data ready), RETurn to process.
6502
EXX D9
Switch to alternate registers for FDC ops.
6503
LD B,0AH 06 0A
B' = 0AH — 10 retries.
6505
LD L,01H 2E 01
[RETRY LOOP] L'=01H — drive 0, side 0 select.
6507
PUSH DE D5
Save track/sector position.
6508
PUSH BC C5
Save retry counter.
6509
LD A,E 7B
Load sector number from E'.
650A
SUB 12H D6 12
SUB 18. Carry if side 0; No Carry if side 1.
650C
If Carry (side 0), JUMP to 6511H.
650E
LD E,A 5F
Adjusted sector for side 1.
650F
LD L,11H 2E 11
L'=11H — drive 0, side 1 (bit 4).
6511
GOSUB SYS0 43D7H — drive select/density config.
6514
LD A,L 7D
Drive select value from L'.
6515
OUT (F4H),A D3 F4
Output to drive select register.
6517
LD A,D 7A
Track number from D'.
6518
OUT (F3H),A D3 F3
Output to FDC data register (seek target).
651A
LD A,E 7B
Sector number from E'.
651B
OUT (F2H),A D3 F2
Output to FDC sector register.
651D
LD A,1BH 3E 1B
FDC Seek command: head load, verify, 30ms step.
| 1793 FDC Command: 1BH (0001 1011) | | Function |
| 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | | Seek, h=1 head load, V=0, r=11 (30ms) |
651F
OUT (F0H),A D3 F0
Send Seek command to FDC.
6521
Re-configure drive select after seek.
6524
LD A,L 7D
Drive select from L'.
6525
OR 40H F6 40
Set bit 6 — write precompensation enable.
6527
LD E,A 5F
Save select+precomp in E'.
6528
LD D,02H 16 02
D'=02H — DRQ bit mask.
652A
IN A,(F0H) DB F0
Clear pending FDC status.
Set up NMI handler for DRQ-driven transfer.
652C
LD (43A6H),SP ED 73 A6 43
Save SP for NMI recovery.
6530
LD HL,43A2H 21 A2 43
NMI handler entry point.
6533
LD (404AH),HL 22 4A 40
Store handler address to NMI vector.
6536
LD A,C3H 3E C3
JP opcode.
6538
LD (4049H),A 32 49 40
Write JP at NMI dispatch, forming "JP 43A2H".
653B
LD A,C0H 3E C0
Enable FDC + motor-on NMI.
653D
OUT (E4H),A D3 E4
Output to NMI mask register.
653F
LD A,88H 3E 88
FDC Read Sector: multiple records, no settle.
| 1793 FDC Command: 88H (1000 1000) | | Function |
| 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | | Read Sector, m=1 multi, S=0, E=0, C=0 |
6541
OUT (F0H),A D3 F0
Send Read Sector command. NMI handler services DRQ.
6543
LD HL,5100H 21 00 51
HL' = 5100H — sector read destination.
6546
LD BC,00F3H 01 F3 00
B'=00H (256 bytes), C'=F3H (FDC data port).
654C
IN A,(F0H) DB F0
[DRQ POLL] Read FDC status.
654E
AND D A2
Test DRQ bit (D'=02H).
654F
Poll until DRQ asserts.
6551
INI ED A2
Input byte from F3H to (HL'), advance HL', DEC B'.
6553
LD A,E 7B
Drive select + precomp.
6554
OUT (F4H),A D3 F4
[INI LOOP] Re-assert drive select.
6556
INI ED A2
Input next byte.
6558
Loop until 256 bytes done.
655A
[HALT LOOP] JR to self. NMI handler breaks out by restoring SP from 43A6H.
[NMI EXIT] — NMI handler restores SP, execution resumes here.
655D
OUT (E4H),A D3 E4
Disable NMI (00H to mask register).
655F
LD SP,0000H 31 00 00
[SELF-MODIFYING] Restore SP. Operand at 6560H patched by NMI handler.
6562
IN A,(F0H) DB F0
Read final FDC status.
6564
AND FCH E6 FC
Test error bits 2–7 (ignore Busy/DRQ).
6566
LD A,D0H 3E D0
Force Interrupt command.
6568
OUT (F0H),A D3 F0
Return FDC to idle.
656A
POP BC C1
Restore retry counter.
656B
POP DE D1
Restore track/sector.
656C
If FDC error, JUMP to retry path.
Success — advance to next sector.
656E
INC E 1C
INC sector number.
656F
LD A,E 7B
New sector number.
6570
SUB 12H D6 12
Check for track/side boundary at sector 18.
6572
If not at boundary, JUMP to 6577H.
6574
INC D 14
Advance to next track.
6575
LD E,00H 1E 00
Reset sector to 0.
6577
EXX D9
Switch back to main registers.
6578
LD A,(HL) 7E
Fetch next control byte.
6579
RET C9
RETurn with byte in A.
Error — Restore and retry.
657D
LD A,0BH 3E 0B
Restore command: head load, verify, 30ms step.
| 1793 FDC Command: 0BH (0000 1011) | | Function |
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | | Restore, h=1 head load, V=0, r=11 (30ms) |
657F
OUT (F0H),A D3 F0
Send Restore — head seeks to track 0.
6581
DEC B' and retry. [RETRY LOOP END]
All retries exhausted — fatal error display and halt.
6583
LD HL,43E8H 21 E8 43
Error message text at 43E8H.
6586
LD A,(HL) 7E
[DISPLAY LOOP] Fetch character.
6587
CP 03H FE 03
Check for ETX.
6589
If ETX, loop forever — system halts (requires reset).
658B
INC HL 23
Next character.
658C
ROM: display character at cursor.
658F
Loop for next character.
6591H — FDC READY WAIT (BUSY LOOP)
Polls FDC status at port F0H until Busy flag (bit 0) clears, returns final status in A.
6591
Initial FDC timing delay.
6594
IN A,(F0H) DB F0
[POLL] Read FDC status.
6596
RRCA 0F
Shift Busy bit into Carry.
6597
If Carry (busy), keep polling.
6599
IN A,(F0H) DB F0
Final clean status read.
659B
RET C9
RETurn with status in A.
659CH — SHORT DELAY LOOP
Timing delay counting down from 8. Approximately 40 T-states. Used for brief gaps between FDC register accesses.
659C
LD A,08H 3E 08
Load delay counter (8 iterations).
659E
DEC A 3D
[DELAY LOOP] DECrement A.
65A2H–65F9H — DATA AREAS: ERROR MESSAGES, BOOT TEMPLATES, FDC PARAMETERS [DATA]
Multiple data blocks referenced by COPY, FORMAT, and boot sector routines. None of this is executable code — the disassembler interprets the bytes as Z80 instructions but they are pure data constants and self-modifying targets.
65A2
DEFB 1CH + 1FH
Clear the Screen ...
65A4
DEFM "ERROR",03H
Error display string - "ERROR" and ETX (03H). Referenced by the DD write track error display.
65AA
DEFB 1CH + 1FH
Clear the Screen ...
65AC
DEFM "NO SYS",03H
Error display string - "NO SYS" error message. Displayed when boot sector references a system file not found on disk.
Gap at 65B3H–65B6H (4 bytes, unused padding).
65B7
DEFB 00H,00H
00H,5EH,00H
00H,00H,00H
[DATA — 8 bytes, 65B7H–65BEH] Self-modifying geometry bytes. 65B7H and 65B9H are patched by
675CH (LD (65B7H),A) and
6762H (LD (65B9H),A) with destination drive geometry values (59CBH=track count, 59CCH=density/side config). Byte 65BAH=5EH is part of the boot sector directory entry template. Remaining bytes are zero padding.
65BF
DEFM "BOOT SYS"
DEFB 60H,7FH
1FH,B2H,05H
00H,00H,00H
DEFB FFH,FFH,FFH,FFH
[DATA — 23 bytes, 65BFH–65D5H] DD boot sector directory entry template for "BOOT/SYS". First 8 bytes = filename "BOOT" + 4 spaces. Next 3 bytes = extension "SYS". Followed by directory entry metadata: 60H=file attributes, 7FH=EOF offset, 1FH=record length low, B2H=record length high, 05H=first granule, then 3 zero bytes and 4 FFH bytes (granule allocation map with unused entries marked FFH). Referenced by
66E6H (LD HL,65BAH for track 1 boot entry).
65DA
DEFB 5DH,00H
00H,00H,00H
DEFM "DIR SYS"
DEFB A7H,1DH,F9H
[DATA — 19 bytes, 65DAH–65ECH] DD boot sector directory entry template for "DIR/SYS". Byte 65DAH=5DH (directory start granule). Followed by 4 zero bytes, then "DIR" + 5 spaces + "SYS" filename/extension. Trailing bytes A7H, 1DH, F9H are file attributes and metadata. Referenced by
66EFH (LD HL,65DAH for track 2 directory entry).
65ED
DEFB E5H,0AH
00H
[DATA — 3 bytes, 65EDH–65EFH] FDC format parameters. E5H=fill byte for formatted sectors (standard IBM fill pattern), 0AH=sector interleave count (patched by
66DEH with computed interleave via LD (65EEH),A). 00H=padding. 65EEH is also patched by
66E1H simultaneously with
670CH.
65F0
DEFB 11H,01H
DEFB FFH,FFH
FFH,FFH,FFH
FFH,FFH,FFH
[DATA — 10 bytes, 65F0H–65F9H] Boot sector footer template. 11H=sector count (17 sectors per track, standard NEWDOS/80 DD format). 01H=boot track indicator. Followed by 8 bytes of FFH padding — unused granule allocation slots filled with the "empty" marker. This is the end of the boot sector template data; 65FAH begins the APPEND command entry point.
65FAH — APPEND COMMAND — MAIN ENTRY POINT
This is the main entry point for the APPEND command. APPEND adds data to a destination diskette that already contains formatted data. It parses the source drive, optional hex parameter, disk name, and date stamp from the command line, then sets operating mode flags before falling through to the shared COPY/FORMAT/APPEND initialization code. The dispatch at 4D00H reaches here when the command code in Register A is 28H.
65FA
GOSUB to 6392H to parse the drive designator from the command line. This routine reads the next non-whitespace token from the command buffer and stores the parsed drive number at 5B1DH, calling subroutines at 5956H and 4DFAH internally. On success, the Carry flag is set; on failure (no valid drive found), the No Carry flag is set.
65FD
If the No Carry flag is set (drive designator parsing failed), JUMP to 5218H — the parse error handler — which displays an error message and aborts the command.
6600
GOSUB to 63A0H to parse an optional "=" hex parameter from the command line. If the command line contains "=nn", the hex value is extracted and stored for use by the operation. HL is positioned past the parsed parameter on return.
6603
PUSH HL E5
Save Register Pair HL (the current command line parse pointer) onto the stack. HL must be preserved because the next instructions modify (HL) indirectly through a different HL value.
6604
LD HL,5997H 21 97 59
Point Register Pair HL to 5997H — option flags byte 4. This flags byte controls special modes for the COPY/FORMAT/APPEND command dispatcher.
6607
SET 2,(HL) CB D6
Set bit 2 of the option flags byte at 5997H. Bit 2 marks APPEND mode — this tells the FORMAT/COPY/APPEND shared logic that the operation is an APPEND (adding data to an existing formatted diskette) rather than a full FORMAT or COPY.
6609
POP HL E1
Restore Register Pair HL from the stack, recovering the command line parse pointer saved at 6603H.
660A
GOSUB to 6EB4H to skip whitespace in the command line buffer. On return, Carry is set if a non-whitespace character was found (more parameters follow); No Carry if end-of-line was reached.
660D
If the Carry flag is set (a non-whitespace character follows — indicating a disk name was typed), GOSUB to 4F95H to copy the disk name from the default disk name area at 5983H into the operation parameter block. If No Carry (no disk name on command line), this call is skipped.
6610
GOSUB to 6FB7H to parse an optional disk name from the command line. If a disk name string is present, it is stored in the operation parameter block for later verification against the target diskette's label.
6613
GOSUB to 6EB4H again to skip whitespace after the disk name. Carry is set if more parameters remain on the command line.
6616
If the No Carry flag is set (no more parameters on the command line — no date stamp was typed), JUMP forward to 661FH to skip the date stamp parsing and proceed directly to setting operation mode flags.
6618
GOSUB to 5025H to parse the date stamp from the command line. This routine reads a date string in MM/DD/YY format and returns the packed date value in Register Pair DE.
661B
LD (5981H),DE ED 53 81 59
Store the parsed date stamp (Register Pair DE) to memory at 5981H. This saves the user-specified date for later comparison against the target diskette's date stamp or for writing to the new diskette label.
[APPEND PARAMETER PARSING COMPLETE] — At this point, the drive designator, optional hex parameter, disk name, and date stamp have all been parsed from the command line. Execution now sets the operation mode flags and falls through to the shared FORMAT/COPY/APPEND initialization.
661F
LD B,40H 06 40
Load Register B with 40H (64 decimal). This value is the APPEND mode flag bitmask that will be passed to the mode flag setter at 4EA7H.
6621
GOSUB to 4EA7H to set operation mode flags in the option flags bytes at 5994H-5997H based on the bitmask in Register B (40H = APPEND mode).
6624
LD HL,5994H 21 94 59
Point Register Pair HL to 5994H — option flags byte 1. This byte controls various operational behaviors for COPY/FORMAT/APPEND.
6627
LD A,(HL) 7E
Load Register A with the current value of the option flags byte 1 at 5994H.
6628
AND F9H E6 F9
Mask Register A with F9H (binary 11111001), isolating all bits EXCEPT bits 1 and 2. This tests whether any flags other than bit 1 (suppress src≠dest check) and bit 2 (unused) are set.
662A
If the NZ flag is set (at least one other flag bit is active — the user specified explicit options), JUMP forward to 6630H to skip auto-copy mode activation and proceed with the user's explicit settings.
662C
LD A,(HL) 7E
Reload Register A with the option flags byte 1 at 5994H (same value as before the AND).
662D
OR 80H F6 80
Set bit 7 of the option flags byte. Bit 7 enables auto-copy mode — when no explicit options were specified (the AND F9H test was zero), the APPEND defaults to automatically copying all data.
662F
LD (HL),A 77
Store the updated flags byte (with bit 7 set) back to 5994H.
6630H — APPEND/FORMAT/COPY — GEOMETRY LOAD AND DISPLAY
This section loads source and destination drive geometry, displays the "STARTING DISKETTE FORMAT" message, computes the destination diskette's capacity, sets up sector I/O, and pushes a cleanup return address before falling through to the format/copy pre-validation dispatcher. This code is shared by APPEND, FORMAT, and COPY commands.
6630
GOSUB to 63B3H — the drive geometry loader. This routine reads the PDRIVE configuration for both the source and destination drives and populates the geometry parameter blocks at 59C5H (destination) and related locations with track count, sectors per track, density, and side configuration.
6633
LD HL,6DF2H 21 F2 6D
Point Register Pair HL to 6DF2H — the address of the string "STARTING DISKETTE FORMAT" (terminated by 0DH) in the message string pool.
6636
GOSUB to 4467H (SYS0 display string routine) to print the message pointed to by HL. This displays "STARTING DISKETTE FORMAT" on the screen to inform the operator that the format operation is beginning.
6639
GOSUB to 6710H to compute the destination diskette's capacity and validate that it does not exceed the maximum supported size (192 granules). This routine calculates total sectors, usable sectors, and checks the granule count. If the disk is too large, it exits via the error handler at 5243H.
663C
GOSUB to 4DF3H (SYS0) to set up for sector I/O operations. This initializes the sector read/write parameter blocks and prepares the disk I/O subsystem for the upcoming format or copy operation.
663F
LD HL,552DH 21 2D 55
Load Register Pair HL with 552DH — the address of the cleanup/exit routine for COPY/FORMAT/APPEND operations.
6642
PUSH HL E5
Push 552DH onto the stack as a return address. When the format/copy/append operation completes and a RET instruction is executed, control will transfer to 552DH for cleanup processing (flushing buffers, releasing resources, etc.). This is a common pattern for setting up a guaranteed cleanup exit path.
[FALL-THROUGH] — Execution falls through directly into the format/copy pre-validation dispatcher at 6643H. The 552DH cleanup address remains on the stack as the ultimate return target.
6643H — FORMAT/COPY PRE-VALIDATION DISPATCHER
This routine performs the core pre-validation and initialization for a FORMAT or COPY operation. It initializes the destination drive, checks various option flags to determine if certain steps should be skipped, displays "INITIALIZING SYSTEM DATA", writes the boot sector, initializes the allocation bitmap (GAT), copies the disk label, computes the total sector count, and then enters the format track write loop to write system tracks 0–9.
6643
GOSUB to 67C5H — the drive initialization for FORMAT routine. This calls the geometry self-modification patcher at 6759H, initializes the buffer at 557DH, and dispatches to GAT reading, name/date validation, motor speed checks, and DD auto-detect depending on option flags. (67C5H is documented in Chunk 16.)
6646
LD A,(5997H) 3A 97 59
Load Register A with the value of option flags byte 4 at 5997H.
6649
BIT 3,A CB 5F
Test bit 3 of option flags byte 4. Bit 3 indicates filespec loop mode — a mode where the operation processes individual files rather than whole tracks.
664B
RET NZ C0
If the NZ flag is set (bit 3 is active — filespec loop mode is enabled), RETURN. In filespec loop mode, the track-level format initialization below is not needed, so execution returns to the caller (which will handle file-by-file processing). The return address on the stack is 552DH (the cleanup routine pushed at 6642H).
664C
LD A,(5996H) 3A 96 59
Load Register A with the value of option flags byte 3 at 5996H.
664F
BIT 7,A CB 7F
Test bit 7 of option flags byte 3. Bit 7 indicates label verification pending — the diskette's label still needs to be verified before formatting can proceed.
6651
RET NZ C0
If the NZ flag is set (bit 7 is active — label verification is still pending), RETURN. The format cannot proceed until the label is verified, so control returns to 552DH for cleanup.
6652
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H — zero. This will be used to zero the sector progress counters.
6655
GOSUB to 5784H to zero the sector progress counters. This resets the counters that track how many sectors have been read or written during the operation, preparing for a fresh count.
6658
LD A,(5994H) 3A 94 59
Load Register A with the value of option flags byte 1 at 5994H.
665B
BIT 1,A CB 4F
Test bit 1 of option flags byte 1. Bit 1 indicates suppress source≠destination check — when set, the format skips verifying that the source and destination are different drives.
665D
RET NZ C0
If the NZ flag is set (bit 1 is active — src≠dest check is suppressed), RETURN. This exit path is used when the format does not need to write system data (e.g., during a format-only pass on a disk that already has system data). Control returns to 552DH.
[SYSTEM DATA INITIALIZATION BEGINS] — All option flag checks have passed. The format operation now proceeds to write the boot sector, initialize the GAT (Granule Allocation Table), set up directory entries, and write system tracks.
665E
LD HL,6DD9H 21 D9 6D
Point Register Pair HL to 6DD9H — the address of the string "INITIALIZING SYSTEM DATA" (terminated by 0DH) in the message pool.
6661
GOSUB to 4467H (SYS0 display string routine) to print "INITIALIZING SYSTEM DATA" on the screen, informing the operator that the system tracks are being written.
6664
GOSUB to 67ACH to write the boot sector (sector 0, track 0) to the destination diskette. This writes the boot configuration template from 64BAH to the first sector of the disk.
6667
LD DE,6EB4H 11 B4 6E
Load Register Pair DE with 6EB4H. This is the address of the whitespace-skip routine, but here it serves as a sector buffer address for the second sector write. The sector write routine at 67B6H uses DE as the source address for the data to write.
666A
LD BC,0002H 01 02 00
Load Register Pair BC with 0002H — sector number 2. This is the target sector for the next write operation.
666D
If the Z flag is set (the boot sector write at 67ACH completed successfully), GOSUB to 67B6H to write sector 2 using the data pointed to by DE (6EB4H) and the sector number in BC (0002H). If NZ (boot sector write failed), this call is skipped.
6670
If the NZ flag is set (either the boot sector or sector 2 write failed), JUMP to 521AH — the main error handler — to display a disk write error and abort.
[GAT INITIALIZATION] — The boot sector and sector 2 have been written successfully. Now the code initializes the Granule Allocation Table (GAT) in the 256-byte sector buffer at 4300H.
6673
LD A,FFH 3E FF
Load Register A with FFH (all bits set). This fill value will mark all granules as allocated in the initial GAT buffer.
6675
GOSUB to 64B0H to fill the 256-byte sector buffer at 4300H with the value in Register A (FFH). This pre-fills the GAT with all-allocated markers; the allocation bitmap initializer will then clear the bits for granules that should be free.
6678
LD DE,(59D1H) ED 5B D1 59
Load Register Pair DE with the usable sector capacity from 59D1H. This value was computed by the capacity validation routine at 6710H and represents the number of sectors available for file data after subtracting system overhead.
667C
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H — the start of the 256-byte sector buffer used for building the GAT (Granule Allocation Table).
667F
LD (5B1AH),HL 22 1A 5B
Store the sector buffer address (4300H) to 5B1AH — the current sector address pointer. This tells the sector I/O routines where to read from or write to.
6682
LD C,L 4D
Load Register C with the low byte of HL, which is 00H (low byte of 4300H). Register C = 00H is used as a zero value for the bitmap initialization call.
6683
PUSH HL E5
Save Register Pair HL (4300H — the sector buffer address) onto the stack. It will be needed after the bitmap initialization call to mark track 0 as allocated.
6684
GOSUB to 5762H to initialize the allocation bitmap. This routine sets up the GAT in the buffer at 4300H based on the destination disk's geometry, marking system tracks as allocated and data tracks as free. Register Pair DE contains the usable sector count; Register C was set to 00H.
6687
POP HL E1
Restore Register Pair HL from the stack — HL = 4300H, pointing to the start of the GAT buffer.
6688
SET 0,(HL) CB C6
Set bit 0 of the byte at (HL) = 4300H. In the GAT, byte 0 represents track 0's allocation status. Setting bit 0 marks track 0 as allocated (track 0 contains the boot sector and system data, so it must never be allocated to user files).
[DESTINATION GEOMETRY SETUP] — The GAT bitmap is initialized. Now the code copies the destination disk's geometry parameters to the working area and computes the number of sectors per GAT allocation entry.
668A
LD A,(59CDH) 3A CD 59
Load Register A with the boot sector count (number of sectors on track 0) from 59CDH. This is part of the destination disk geometry.
668D
LD (59C5H),A 32 C5 59
Store the boot sector count to 59C5H — the first byte of the destination geometry parameter block. This copies the track 0 sector count into the working geometry area.
6690
LD HL,(42B9H) 2A B9 42
Load Register Pair HL with the pointer to the current drive's PDRIVE table entry from 42B9H. The PDRIVE table contains the hardware configuration for each drive.
6693
LD (HL),A 77
Store the boot sector count (Register A) to the PDRIVE table entry pointed to by HL. This updates the PDRIVE entry to reflect the destination disk's track 0 sector count.
6694
LD B,00H 06 00
Load Register B with 00H. Register B is cleared to form a 16-bit value with Register E (DE) for the GAT allocation fill routine.
6696
LD E,A 5F
Copy Register A (boot sector count) to Register E. Now DE = 00:boot_sector_count, forming the starting offset for GAT allocation.
6697
LD A,(59CEH) 3A CE 59
Load Register A with the destination geometry count (total tracks or sectors per track) from 59CEH.
669A
LD C,A 4F
Copy Register A to Register C. Now BC = 00:geometry_count — the number of entries to fill in the GAT allocation table.
669B
PUSH DE D5
Save Register Pair DE (the boot sector count offset) onto the stack. DE will be needed later for the sector count computation.
669C
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H — the GAT sector buffer.
669F
GOSUB to 621CH — the GAT allocation fill routine. This fills the GAT buffer at 4300H with allocation data based on the geometry parameters in BC (count) and DE (starting offset), marking the appropriate granules as allocated for system use.
[DISK LABEL COPY] — The GAT allocation is filled. Now the disk label and configuration data is copied from the parsed parameter area into the GAT buffer at the label offset (43CBH).
66A2
LD HL,597EH 21 7E 59
Point Register Pair HL to 597EH — the source for the disk label/configuration data. This area was populated earlier during command line parsing with the disk name, date stamp, and other configuration parameters.
66A5
LD DE,43CBH 11 CB 43
Point Register Pair DE to 43CBH — the destination within the GAT buffer where the disk label and configuration data is stored. In the NEWDOS/80 GAT sector layout, offset CBH (203 bytes into the sector) is where the 22-byte disk label/configuration block resides.
66A8
LD BC,0016H 01 16 00
Load Register Pair BC with 0016H (22 decimal) — the byte count for the block copy. The disk label/configuration block is exactly 22 bytes.
66AB
LDIR ED B0
Block copy 22 bytes from 597EH (parsed disk label area) to 43CBH (GAT buffer label area). This transfers the disk name, date stamp, and configuration data into the GAT sector that will be written to the destination disk.
[SECTOR COUNT COMPUTATION] — Now the code computes the total number of sectors to be formatted by multiplying the sectors-per-GAT-byte value by 5 (using shift-and-add: A*4 + A = A*5).
66AD
POP HL E1
Restore the value saved at 669BH from the stack into Register Pair HL. This recovers DE that was pushed — HL now holds the boot sector count value (originally in DE as 00:boot_sector_count).
66AE
LD A,(59CAH) 3A CA 59
Load Register A with the sectors per GAT byte value from 59CAH. This is the number of sectors represented by each byte in the GAT allocation table.
66B1
LD H,A 67
Copy Register A (sectors per GAT byte) to Register H. H is used as a temporary save for the original value during the multiply-by-5 computation.
66B2
RLCA 07
Rotate Register A left through carry — this effectively multiplies A by 2. A now contains sectors_per_GAT_byte × 2.
66B3
RLCA 07
Rotate Register A left again — multiplies A by 2 again. A now contains sectors_per_GAT_byte × 4.
66B4
ADD A,H 84
ADD the original value (saved in Register H) to Register A. A = (sectors_per_GAT_byte × 4) + sectors_per_GAT_byte = sectors_per_GAT_byte × 5. This computes the total number of sectors in 5 GAT entries.
66B5
GOSUB to 4C37H — the SYS0 8-bit multiply routine (A × L → HL). Register A contains sectors_per_GAT_byte × 5, and Register L contains the boot sector count value recovered from the stack. The result in HL is the total sector count for the format operation.
66B8
LD (5B21H),HL 22 21 5B
Store the computed total sector count (Register Pair HL) to 5B21H — the destination sector counter. This value tracks how many sectors remain to be formatted.
66BB
LD C,00H 0E 00
Load Register C with 00H — initialize the track counter to zero. Register C will count tracks from 0 through 9 (the system tracks) during the format loop.
66BD
JUMP forward to 66FBH — the sector write portion of the format track loop. This skips the buffer-fill logic on the first iteration since the GAT buffer at 4300H already contains the fully initialized GAT data for track 0.
66BFH — FORMAT TRACK WRITE LOOP (SYSTEM TRACKS 0–9)
This loop writes the system tracks (tracks 0 through 9) to the destination diskette during a FORMAT operation. For each track, the sector buffer at 4300H is prepared with the appropriate content: track 0 gets the GAT (already set up), track 1 gets the boot jump vector and interleave data, track 2 gets the BOOT/SYS directory entry template, track 3 gets the DIR/SYS directory entry template, and tracks 4–9 are written as zeroed sectors. After writing each track, the loop increments the track counter and repeats until all 10 system tracks are written.
66BF
PUSH BC C5
Save Register Pair BC onto the stack. Register C contains the current track counter (0–9), and it must be preserved across the buffer-fill and write operations.
66C0
XOR A AF
Set Register A to 00H (zero) by XOR'ing it with itself. This value will be used to clear the sector buffer.
66C1
GOSUB to 64B0H to fill the 256-byte sector buffer at 4300H with 00H (zeros). This clears the buffer before building the content for the current track.
66C4
LD A,C 79
Load Register A with Register C — the current track number (0–9).
66C5
DEC A 3D
DECrement Register A by 1. This converts the track number so that track 1 becomes 0 (Z flag set), track 2 becomes 1, track 3 becomes 2, etc. Track 0 becomes FFH (non-zero, will fall through all checks).
66C6
If the NZ flag is set (track number is NOT 1), JUMP to 66E6H to check for tracks 2 and 3. Track 1 requires special handling: it gets the boot jump vector and interleave values.
[TRACK 1: BOOT JUMP VECTOR AND INTERLEAVE] — Track 1 (sector 1) contains the boot code entry point and sector interleave values. The code builds this sector in the buffer at 4300H.
66C8
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H — the start of the sector buffer.
66CB
LD (HL),A2H 36 A2
Store A2H to the first byte of the sector buffer (4300H). This is the low byte of the boot jump vector. Together with the next byte, this forms the entry address that the boot code jumps to after loading.
66CD
INC HL 23
INCrement HL to point to 4301H — the second byte of the sector buffer.
66CE
LD (HL),C4H 36 C4
Store C4H to the second byte of the sector buffer (4301H). This is the high byte of the boot jump vector. The two bytes form the address C4A2H, which is where NEWDOS/80's boot code begins execution after the boot loader reads the system tracks into memory.
[INTERLEAVE COMPUTATION] — Now the code computes the sector interleave value from the destination geometry and patches it into three self-modifying locations in the format engine code.
66D0
LD A,(59CEH) 3A CE 59
Load Register A with the destination geometry count (sectors per track) from 59CEH.
66D3
SUB 02H D6 02
SUBtract 2 from the sectors-per-track value. The interleave computation uses (sectors_per_track − 2) as the base value.
66D5
LD C,A 4F
Save the adjusted value (sectors_per_track − 2) in Register C for the multiply operation.
66D6
RLCA 07
Rotate Register A left — multiply by 2. A = (sectors_per_track − 2) × 2.
66D7
RLCA 07
Rotate Register A left again — multiply by 2 again. A = (sectors_per_track − 2) × 4.
66D8
ADD A,C 81
ADD the saved value in Register C to Register A. A = (sectors_per_track − 2) × 4 + (sectors_per_track − 2) = (sectors_per_track − 2) × 5. This computes the interleave factor.
66D9
LD (431FH),A 32 1F 43
Store the computed interleave value to 431FH — a [SELF-MODIFYING CODE] location in the sector buffer area. This patches the interleave value used by the track format engine during physical sector layout.
66DC
ADD 0AH C6 0A
ADD 0AH (10 decimal) to the interleave value in Register A. This creates a second interleave variant offset by 10 sectors.
66DE
LD (65EEH),A 32 EE 65
Store the adjusted interleave value to 65EEH — a [SELF-MODIFYING CODE] location within the format engine code. This patches the interleave value used for the first format pass.
66E1
LD (670CH),A 32 0C 67
Store the same adjusted interleave value to 670CH — another [SELF-MODIFYING CODE] location. This patches the interleave value used for a second format reference point.
66E4
JUMP forward to 66FAH to restore BC and proceed to the sector write. Track 1's buffer is now fully prepared with the boot jump vector and interleave data.
[TRACKS 2–3: DIRECTORY ENTRY TEMPLATES] — For tracks 2 and 3, the code copies pre-built directory entry templates (BOOT/SYS and DIR/SYS) into the sector buffer. These are the first two entries in the system directory.
66E6
LD HL,65BAH 21 BA 65
Point Register Pair HL to 65BAH — the BOOT/SYS directory entry template (32 bytes of pre-built directory data for the BOOT/SYS system file). This is the default source for the block copy.
66E9
CP 02H FE 02
Compare Register A against 02H. Register A contains the decremented track number (track − 1). If A = 02H, the original track number was 3 (the DIR/SYS track). If A < 02H (Carry set), track was 2 (the BOOT/SYS track). If A > 02H (No Carry, NZ), the track is 4–9.
66EB
If the Carry flag is set (A < 02H — this is track 2, the BOOT/SYS track), JUMP to 66F2H to copy the BOOT/SYS template (HL already points to 65BAH). Track 2 gets the BOOT/SYS directory entry.
66ED
If the NZ flag is set (A > 02H — tracks 4–9), JUMP to 66FAH to skip the template copy. Tracks 4–9 are written with the zeroed buffer (no directory entries needed).
66EF
LD HL,65DAH 21 DA 65
Point Register Pair HL to 65DAH — the DIR/SYS directory entry template (32 bytes). This replaces the BOOT/SYS template pointer for track 3.
66F2
LD DE,4300H 11 00 43
Point Register Pair DE to 4300H — the destination in the sector buffer where the 32-byte directory entry template will be copied.
66F5
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H (32 decimal) — the byte count for the directory entry template copy. Each directory entry is exactly 32 bytes.
66F8
LDIR ED B0
Block copy 32 bytes from the template at (HL) — either 65BAH (BOOT/SYS) or 65DAH (DIR/SYS) — to the sector buffer at 4300H.
66FA
POP BC C1
Restore Register Pair BC from the stack. Register C contains the current track counter (0–9), preserved from the PUSH at 66BFH.
[SECTOR WRITE AND LOOP CONTROL] — The sector buffer at 4300H is now populated with the appropriate content for the current track. Write it to disk, then advance to the next track.
66FB
SET 0,(IX+00H) DD CB 00 C6
Set bit 0 of the byte at (IX+00H). IX points to the destination drive parameter block at 5B17H. Bit 0 of the parameter block flags byte is the dirty flag — setting it marks the sector buffer as containing data that needs to be written to disk.
66FF
GOSUB to 57D4H to write the sector to disk. This routine writes the 256-byte buffer at the address stored in 5B1AH (4300H) to the sector specified by the parameter block at IX (5B17H). On return, Z flag is set for success, NZ for failure.
6702
RES 0,(IX+00H) DD CB 00 86
Clear bit 0 of the byte at (IX+00H) — reset the dirty flag. The sector has been written (or the write failed), so the buffer is no longer marked as needing a write.
6706
If the NZ flag is set (the sector write at 57D4H failed), JUMP to 521AH — the main error handler — to display a write error and abort the FORMAT operation.
6709
INC C 0C
INCrement Register C (the track counter) by 1. Advance to the next system track.
670A
LD A,C 79
Load Register A with the updated track counter from Register C.
670B
CP 0AH FE 0A
Compare Register A against 0AH (10 decimal). If A < 0AH, the Carry flag is set (more system tracks remain to be written). If A ≥ 0AH, No Carry (all 10 system tracks 0–9 have been written).
670D
If the Carry flag is set (track counter < 10 — more system tracks to write), JUMP back to 66BFH — the [LOOP START] — to prepare and write the next track. [LOOP END when C reaches 10]
670F
RET C9
RETURN to the caller. All 10 system tracks (0–9) have been written to the destination diskette. Control returns to the address following the CALL that entered the format/copy pre-validation dispatcher (which was the cleanup routine at 552DH, pushed at 6642H).
6710H — COMPUTE DESTINATION CAPACITY AND VALIDATE
This routine computes the total sector capacity and usable sector capacity of the destination diskette based on its geometry parameters, then validates that the disk does not exceed the maximum supported size of 192 granules. IX is pointed to 59C5H (the destination geometry parameter block) and the computed values are stored at offsets +0AH/+0BH (total sectors = 59CFH/59D0H) and +0CH/+0DH (usable sectors = 59D1H/59D2H). If the granule count exceeds C0H (192), the routine jumps to the "DISK TOO LARGE" error handler.
6710
LD HL,59C5H 21 C5 59
Point Register Pair HL to 59C5H — the start of the destination geometry parameter block.
6713
PUSH IX DD E5
Save the current IX register onto the stack. IX will be temporarily reassigned to point to the geometry parameter block.
6715
PUSH HL E5
Push HL (59C5H) onto the stack for transfer to IX via POP IX.
6716
POP IX DD E1
Pop the stack value into IX. IX now points to 59C5H — the destination geometry parameter block. This is a standard Z80 technique for loading IX from HL (since there is no direct LD IX,HL instruction).
[TOTAL SECTOR COMPUTATION] — Multiply the number of tracks by the sectors per track to get the total number of sectors on the destination diskette.
6718
LD A,(IX+04H) DD 7E 04
Load Register A with the byte at (IX+04H) = 59C9H — the number of tracks on the destination diskette.
671B
LD L,(IX+03H) DD 6E 03
Load Register L with the byte at (IX+03H) = 59C8H — the sectors per track on the destination diskette.
671E
GOSUB to 4C37H — the SYS0 8-bit multiply routine (A × L → HL). Register A = track count, Register L = sectors per track. The result in HL = total sector count.
[DISASSEMBLER NOTE] — The raw disassembly shows split opcodes at 6721H–672FH due to the disassembler failing to properly decode 3-byte IX-indexed instructions. The actual instructions are:
6721H: DD 75 0A = LD (IX+0AH),L
6724H: DD 74 0B = LD (IX+0BH),H
672AH: DD 75 0C = LD (IX+0CH),L
672DH: DD 74 0D = LD (IX+0DH),H
6721
LD (IX+0AH),L DD 75 0A
Store the low byte of the total sector count (Register L) to (IX+0AH) = 59CFH. This is the low byte of the total sector capacity.
6724
LD (IX+0BH),H DD 74 0B
Store the high byte of the total sector count (Register H) to (IX+0BH) = 59D0H. Together with 59CFH, this forms the 16-bit total sector count.
6727
GOSUB to 5CFBH to compute the usable capacity — the number of sectors available for file data after subtracting system overhead (boot sector, GAT, directory, and HIT sectors). HL contains the total sector count on entry; on return, HL contains the usable sector count.
672A
LD (IX+0CH),L DD 75 0C
Store the low byte of the usable sector count (Register L) to (IX+0CH) = 59D1H.
672D
LD (IX+0DH),H DD 74 0D
Store the high byte of the usable sector count (Register H) to (IX+0DH) = 59D2H. Together with 59D1H, this forms the 16-bit usable sector count.
[GRANULE COUNT VALIDATION] — Compute the number of granules on the disk and verify it does not exceed the maximum of C0H (192). NEWDOS/80 supports a maximum of 192 granules per diskette.
6730
LD A,(IX+05H) DD 7E 05
Load Register A with the byte at (IX+05H) = 59CAH — the sectors per granule value (or a related geometry parameter used for granule computation).
6733
GOSUB to 4C59H — the SYS0 division/validation utility. This divides the usable sector count by the sectors-per-granule value to compute the number of granules. The result is returned in HL with A containing the remainder.
6736
OR A B7
OR Register A with itself to test for zero. If A = 0, there is no remainder from the granule division (the sector count divides evenly). If A ≠ 0, there are leftover sectors that form a partial granule.
6737
If the Z flag is set (no remainder — even granule count), JUMP to 673AH to skip the increment. The granule count in HL is exact.
6739
INC HL 23
INCrement HL by 1. If there were leftover sectors, they form one additional partial granule, so the total granule count is rounded up by 1.
673A
LD A,H 7C
Load Register A with the high byte of the granule count (Register H). If H is non-zero, the granule count exceeds 255, which is far beyond the 192 maximum.
673B
OR A B7
OR Register A with itself to test if H = 0.
673C
If the NZ flag is set (H ≠ 0 — granule count > 255), JUMP to 6747H to display the "DISK TOO LARGE" error. The disk has more granules than NEWDOS/80 can manage.
673E
LD A,L 7D
Load Register A with the low byte of the granule count (Register L). Since H is zero, the total granule count fits in a single byte.
673F
CP C1H FE C1
Compare Register A against C1H (193 decimal). If A < C1H, the Carry flag is set (granule count ≤ 192, which is valid). If A ≥ C1H, No Carry (too many granules).
6741
LD (IX+01H),A DD 77 01
Store the computed granule count (Register A) to (IX+01H) = 59C6H. This saves the granule count in the destination geometry parameter block regardless of whether it is valid — the next instruction checks validity.
6744
POP IX DD E1
Restore the original IX value from the stack (saved at 6713H).
6746
RET C D8
If the Carry flag is set (granule count < 193 — the disk is within the supported size), RETURN to the caller. The destination capacity has been successfully computed and validated.
[ERROR: DISK TOO LARGE] — If execution reaches here, the destination diskette exceeds the maximum supported size of 192 granules.
6747
LD HL,6E56H 21 56 6E
Point Register Pair HL to 6E56H — the address of the "DISK TOO LARGE" error message string in the message pool.
674A
JUMP to 5243H — the error message display and abort routine. This prints the "DISK TOO LARGE" message pointed to by HL and aborts the FORMAT/COPY/APPEND operation.
674DH — DD (DOUBLE DENSITY) CAPABILITY CHECK
This routine checks whether the destination drive supports double density (DD) formatting. If the drive does not support DD and the option to suppress the check is not set, the routine exits with the "DISK TOO LARGE" error. If DD is supported (or the check is suppressed), the routine returns normally.
674D
GOSUB to 61EAH to check if the drive supports double density. This routine reads the drive's PDRIVE configuration and tests the DD capability flag. On return, Z flag is set if DD is supported; NZ if not supported.
6750
RET Z C8
If the Z flag is set (the drive supports DD), RETURN. The DD check passes — no error needed.
6751
LD A,(5994H) 3A 94 59
Load Register A with the value of option flags byte 1 at 5994H. The code will check whether the DD error is suppressed by the user.
6754
BIT 1,A CB 4F
Test bit 1 of the option flags. Bit 1 is the suppress error check flag — when set, the DD mismatch is tolerated (the user explicitly requested to ignore it).
6756
If the Z flag is set (bit 1 is NOT set — the suppress flag is inactive), JUMP to 6747H — the "DISK TOO LARGE" error exit. The drive cannot handle DD format and the user has not suppressed this check, so the operation is aborted.
6758
RET C9
RETURN to the caller. Bit 1 was set (suppress flag active), so the DD capability mismatch is ignored and the operation continues.
6759H — CONFIGURE SELF-MODIFYING GEOMETRY BYTES FOR FORMAT
This routine patches multiple self-modifying code locations throughout the FORMAT engine with geometry values for the destination diskette. It reads the source/destination track count, density/side configuration, sectors per track, boot sector count, and step rate from the geometry parameter block at 59xxH, and writes these values into specific instruction operand bytes in the 64xxH–65xxH range. This allows the FORMAT engine's inner loops to use the correct parameters for the target diskette geometry without needing to read from memory on every iteration. Self-modifying code is used extensively for performance — the Z80's limited register set makes it impractical to keep all geometry values in registers simultaneously.
6759
LD A,(59CBH) 3A CB 59
Load Register A with the source track count from 59CBH.
675C
LD (65B7H),A 32 B7 65
Store the source track count to 65B7H — a [SELF-MODIFYING CODE] location. This patches the track count operand in the FORMAT engine so it knows how many tracks to format based on the source disk.
675F
LD A,(59CCH) 3A CC 59
Load Register A with the source density/side configuration byte from 59CCH. This byte encodes the density (SD/DD), side count (SS/DS), and other geometry flags in individual bits.
6762
LD (65B9H),A 32 B9 65
Store the density/side configuration to 65B9H — a [SELF-MODIFYING CODE] location. This patches the density/side config byte in the FORMAT engine.
[DD CHECK] — Test bit 1 of the configuration byte to determine if the destination disk uses double density format.
6765
BIT 1,A CB 4F
Test bit 1 of the density/side config byte (still in Register A). Bit 1 = 1 indicates double density (DD); bit 1 = 0 indicates single density (SD).
6767
If the Z flag is set (bit 1 = 0 — single density), JUMP to 676DH to skip the DD adjustment.
6769
LD HL,64C0H 21 C0 64
Point Register Pair HL to 64C0H — a [SELF-MODIFYING CODE] location in the boot sector template area.
676C
INC (HL) 34
INCrement the byte at 64C0H by 1. This adjusts the boot sector template for double density — the boot code needs different parameters when the diskette is DD formatted.
[DS CHECK] — Test bit 4 of the configuration byte to determine if the destination disk uses double-sided format.
676D
BIT 4,A CB 67
Test bit 4 of the density/side config byte. Bit 4 = 1 indicates double-sided (DS); bit 4 = 0 indicates single-sided (SS).
676F
If the Z flag is set (bit 4 = 0 — single-sided), JUMP to 677AH to skip the DS adjustments.
6771
LD HL,64BFH 21 BF 64
Point Register Pair HL to 64BFH — a [SELF-MODIFYING CODE] location in the boot sector template area.
6774
INC (HL) 34
INCrement the byte at 64BFH by 1. This adjusts the boot sector template for double-sided formatting.
6775
LD HL,6576H 21 76 65
Point Register Pair HL to 6576H — a [SELF-MODIFYING CODE] location — the double-sided flag byte in the format track engine.
6778
LD (HL),01H 36 01
Store 01H to 6576H. This sets the double-sided flag in the format engine to 01H, indicating that both sides of the diskette should be formatted.
[SIDE SELECT CHECK] — Test bit 0 of the configuration byte for side select control.
677A
BIT 0,A CB 47
Test bit 0 of the density/side config byte. Bit 0 controls side selection for the FDC.
677C
If the Z flag is set (bit 0 = 0 — no side select modification needed), JUMP to 6788H to skip the side select patching.
677E
LD HL,6506H 21 06 65
Point Register Pair HL to 6506H — a [SELF-MODIFYING CODE] location — the first side select byte in the format track engine.
6781
SET 7,(HL) CB FE
Set bit 7 of the byte at 6506H. Bit 7 of the side select byte controls which physical disk head is selected during formatting. Setting bit 7 enables side 1 selection.
6783
LD HL,6510H 21 10 65
Point Register Pair HL to 6510H — a [SELF-MODIFYING CODE] location — the second side select byte in the format track engine.
6786
SET 7,(HL) CB FE
Set bit 7 of the byte at 6510H, matching the side select modification at 6506H. Both locations must be patched identically to ensure consistent side selection during format operations.
[SECTORS PER TRACK AND BIT 6 CHECK] — Load the sectors-per-track value and check bit 6 of the config byte for a halving adjustment.
6788
BIT 6,A CB 77
Test bit 6 of the density/side config byte (still preserved in Register A from 675FH). Bit 6 indicates that the sectors-per-track value should be halved (RRCA) — used for certain geometry configurations where each side has half the logical sector count.
678A
LD A,(59C9H) 3A C9 59
Load Register A with the sectors per track value from 59C9H.
678D
LD (6571H),A 32 71 65
Store the sectors-per-track value to 6571H — a [SELF-MODIFYING CODE] location. This patches the sectors-per-track comparison value in the format engine's inner loop (the SUB instruction at 6570H uses this value as its operand).
6790
If the Z flag is set (bit 6 = 0 — no halving needed), JUMP to 6793H to skip the RRCA. The sectors-per-track value is used as-is.
6792
RRCA 0F
Rotate Register A right through carry — divide the sectors-per-track value by 2. When bit 6 of the config byte is set, each physical track holds half the logical sectors (used for certain interleaved or double-sided configurations).
6793
LD (650BH),A 32 0B 65
Store the (possibly halved) sectors-per-track value to 650BH — a [SELF-MODIFYING CODE] location. This patches the sector boundary value used by the format engine to determine when it has completed one physical track.
[BOOT SECTOR COUNT AND TRACK/SECTOR WORD] — Patch the boot sector count and compute the track/sector limit word for the format engine.
6796
LD A,(59CDH) 3A CD 59
Load Register A with the boot sector count (sectors on track 0) from 59CDH.
6799
LD (64BCH),A 32 BC 64
Store the boot sector count to 64BCH — a [SELF-MODIFYING CODE] location in the boot sector configuration template. This patches the boot sector count byte so the boot code knows how many sectors to read during the boot process.
679C
LD L,A 6F
Copy the boot sector count from Register A to Register L. L = boot sector count (low byte of the track/sector word).
679D
LD A,(59CEH) 3A CE 59
Load Register A with the destination geometry count (total tracks or sectors per track, depending on context) from 59CEH.
67A0
LD H,A 67
Copy the geometry count to Register H. H = geometry count (high byte of the track/sector word).
67A1
DEC H 25
DECrement Register H by 1. The format engine needs the last valid track number (count − 1), not the total count. For example, if there are 40 tracks (tracks 0–39), H is decremented from 40 to 39.
67A2
LD (65F0H),HL 22 F0 65
Store Register Pair HL to 65F0H — a [SELF-MODIFYING CODE] location. This patches the track/sector count word used by the format engine. L = boot sector count, H = last valid track number.
67A5
LD A,(59C7H) 3A C7 59
Load Register A with the step rate byte from 59C7H. The step rate controls how fast the FDC moves the head between tracks (00=6ms, 01=12ms, 10=20ms, 11=30ms on the WD1793).
67A8
LD (65B8H),A 32 B8 65
Store the step rate to 65B8H — a [SELF-MODIFYING CODE] location. This patches the step rate operand in the format engine so FDC seek commands use the correct stepping speed for the destination drive.
67AB
RET C9
RETURN to the caller. All self-modifying geometry locations have been patched with the destination diskette's geometry parameters. The format engine is now configured for the target disk type.
67ACH — WRITE BOOT SECTOR HELPERS
These two short helper routines write sectors to the destination diskette using the boot configuration template at 64BAH and the destination drive parameter block at 5B17H. The first routine (67ACH) writes sector 0 (the boot sector), then increments the sector counter for the caller. The second routine (67B3H) is the shared sector write engine that sets up the parameter block and calls the SYS0 write routine.
67AC
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H — sector number 0. This is the boot sector (the first physical sector on the diskette).
67AF
GOSUB to 67B3H to write sector 0 (the boot sector) using the boot configuration template at 64BAH. BC = 0000H specifies which sector to write.
67B2
INC BC 03
INCrement Register Pair BC from 0000H to 0001H. This advances the sector counter to sector 1, preparing for the next write operation by the caller.
[SHARED SECTOR WRITE ENGINE] — This entry point (67B3H) is used by both the boot sector writer above and the conditional sector 2 writer at 666DH. It sets up the sector I/O parameter block and calls the SYS0 write routine.
67B3
LD DE,64BAH 11 BA 64
Point Register Pair DE to 64BAH — the boot sector configuration template. This is a pre-built data block containing the boot sector's initialization data (step rate, density, sector count, and other boot parameters).
67B6
LD (5B1AH),DE ED 53 1A 5B
Store Register Pair DE (the boot template address 64BAH, or a different source address when called from 666DH) to 5B1AH — the current sector address pointer. This tells the sector write routine where to read the data that will be written to disk.
67BA
LD IX,5B17H DD 21 17 5B
Point IX to 5B17H — the destination drive parameter block. The sector write routine at 57D4H expects IX to point to the parameter block for the target drive.
67BE
LD (5B21H),BC ED 43 21 5B
Store Register Pair BC (the sector number) to 5B21H — the destination sector counter. This tells the write routine which sector to write to on the destination diskette.
67C2
JUMP to 57D4H — the SYS0 sector write routine. This writes the data from the address stored at 5B1AH to the sector specified at 5B21H on the drive specified by the parameter block at IX (5B17H). On return, Z flag is set for success, NZ for failure. The JP (not CALL) means 57D4H will return directly to the caller of 67B3H/67B6H.
67C5H — DRIVE INITIALIZATION FOR FORMAT
This routine initializes the destination drive in preparation for a FORMAT operation. It patches the self-modifying geometry bytes via 6759H, initializes the buffer, then reads and validates the existing GAT sector on the disk. Depending on option flags in Register C (copied from 5994H), it dispatches to various validation paths: checking whether the disk already has data, verifying disk name/date, handling unreadable disks, and prompting the operator before proceeding.
67C5
GOSUB to 6759H to configure the self-modifying geometry bytes for the FORMAT engine. This patches track count, density/side config, sectors per track, boot sector count, step rate, and interleave values into the format engine code based on the destination drive's PDRIVE parameters.
67C8
LD IX,5B17H DD 21 17 5B
Point IX to 5B17H — the destination drive parameter block. IX will remain set to this value throughout the FORMAT initialization, used by the sector read/write routines.
67CC
GOSUB to 557DH to initialize the sector buffer. This prepares the I/O buffer for the upcoming read operation that will attempt to read the existing GAT sector from the destination diskette.
67CF
LD A,(5994H) 3A 94 59
Load Register A with the value of option flags byte 1 at 5994H. These flags control various FORMAT behaviors based on user-specified options.
67D2
LD C,A 4F
Copy the option flags to Register C. Register C will hold these flags throughout the remainder of this routine, serving as a fast reference for the multiple BIT tests that follow without needing to reload from memory.
67D3
BIT 6,C CB 71
Test bit 6 of the option flags (Register C). Bit 6 indicates skip disk read/validation — when set, the routine skips reading the existing GAT and jumps directly to the motor speed check and format setup.
67D5
If the NZ flag is set (bit 6 is active — skip validation), JUMP to 6888H to bypass GAT reading, name/date checking, and the "disk has data" warning. Execution proceeds directly to the motor speed check and format setup.
[GAT SECTOR READ ATTEMPT] — Bit 6 was not set, so the routine attempts to read the existing GAT sector from the destination disk to check whether it already contains data.
67D8
GOSUB to 57C8H — the disk read subroutine (IX-based read wrapper). This attempts to read the GAT sector from the destination diskette into the sector buffer at 4300H. On return: Z flag set = read successful, NZ = read failed with error code in Register A.
67DB
If the Z flag is set (GAT sector read succeeded — the disk is readable), JUMP to 67F0H to validate the GAT contents and check disk name/date.
[READ FAILED] — The GAT sector read failed. Check whether this is an expected "unreadable disk" error or a more serious hardware error.
67DD
CP 05H FE 05
Compare Register A (the error code from the failed read) against 05H. Error code 05H indicates a record-not-found / unformatted disk condition — the disk has no valid sector data, which is expected if the disk is blank or has never been formatted.
67DF
If the NZ flag is set (error code ≠ 05H — this is NOT a simple "unformatted" error but a real disk I/O error), JUMP to 521AH — the main error handler — to display the error and abort.
67E2
BIT 7,C CB 79
Test bit 7 of the option flags (Register C). Bit 7 indicates auto-copy mode. If auto-copy is active and the disk is unformatted, the code should proceed to format without prompting.
67E4
If the NZ flag is set (bit 7 is active — auto-copy mode), JUMP to 6888H to skip the "unreadable diskette" message and proceed directly to format setup. In auto-copy mode, an unformatted disk is expected and the format proceeds silently.
67E7
LD HL,6D93H 21 93 6D
Point Register Pair HL to 6D93H — the address of the string "UNREADABLE DISKETTE" (terminated by 0DH) in the message pool.
67EA
GOSUB to 4467H (SYS0 display string routine) to print "UNREADABLE DISKETTE" to the screen, warning the operator that the destination disk cannot be read.
67ED
JUMP to 6882H to display the operator prompt (Y/N/R/Q) asking whether to proceed with formatting the unreadable diskette.
67F0H — GAT SECTOR VALIDATION AND HIT TABLE FILL
This section is reached when the GAT sector was successfully read from the destination disk. It validates the GAT contents using 48AFH, checks whether the disk already has data (triggering a warning), and fills the HIT (Hash Index Table) area of the GAT buffer with 3FH values for formatting purposes.
67F0
XOR A AF
Set Register A to 00H (zero) and clear all flags. Register A = 0 serves as a parameter for the GAT validation call.
67F1
GOSUB to 48AFH (SYS0) to validate the GAT sector contents in the buffer. This routine checks whether the GAT sector contains valid NEWDOS/80 formatting data. On return: Z flag set if GAT is empty/invalid (no data), NZ if the disk contains valid data. Register A returns a status code.
67F4
If the Z flag is set (GAT validation indicates the disk is empty or has no valid data), JUMP to 6808H to skip the "disk has data" handling and proceed to name/date checking.
67F6
LD L,A 6F
Save the GAT validation status code (Register A) into Register L for temporary storage.
67F7
LD A,C 79
Load Register A with the option flags from Register C (copy of 5994H).
67F8
AND 19H E6 19
Mask the option flags with 19H (binary 00011001), isolating bits 0, 3, and 4. These bits represent options that control whether the "disk has data" condition should be treated as an error.
67FA
LD A,L 7D
Restore the GAT validation status code from Register L back to Register A.
67FB
If the NZ flag is set (from the AND 19H test — one or more of bits 0, 3, or 4 are active in the option flags), JUMP to 521AH — the main error handler. When these option bits are set, the presence of existing data on the disk is treated as an error condition that aborts the format.
[HIT TABLE FILL] — The disk has data but the option flags allow proceeding. Fill the HIT (Hash Index Table) portion of the GAT buffer (16 bytes starting at 43D0H) with 3FH values to prepare for reformatting.
67FE
LD HL,43D0H 21 D0 43
Point Register Pair HL to 43D0H — the start of the HIT (Hash Index Table) area within the GAT sector buffer. The HIT begins at offset D0H (208 decimal) in the 256-byte GAT sector.
6801
LD B,10H 06 10
Load Register B with 10H (16 decimal) — the number of bytes in the HIT area to fill.
6803
LD (HL),3FH 36 3F
[LOOP START] Store 3FH (63 decimal, binary 00111111) to the current HIT byte. The value 3FH marks each HIT entry as unassigned/available for the new format.
6805
INC HL 23
INCrement HL to point to the next HIT byte.
6806
DECrement Register B and JUMP back to 6803H if B ≠ 0. This fills all 16 HIT bytes with 3FH. [LOOP END when B reaches 0]
6808H — DISK NAME AND DATE VERIFICATION
This section checks whether the operator should be warned about existing data on the diskette, verifies that the disk name matches the expected name (if specified), verifies the date stamp, and conditionally copies the disk name and date from the existing GAT into the working parameter area. Multiple option flag bits in Register C control which checks are performed.
6808
BIT 7,C CB 79
Test bit 7 of the option flags (Register C). Bit 7 = auto-copy mode.
680A
If the Z flag is set (bit 7 = 0 — NOT auto-copy mode), JUMP to 6814H to proceed with the detailed name/date verification checks.
680C
LD HL,6D81H 21 81 6D
Point Register Pair HL to 6D81H — the address of the string "DISKETTE HAS DATA" (terminated by 0DH) in the message pool.
680F
GOSUB to 4467H (SYS0 display string routine) to print "DISKETTE HAS DATA" to the screen. This warns the operator that the destination disk already contains formatted data that will be destroyed.
6812
JUMP to 687CH to display the diskette's name/date information followed by an operator prompt.
[DETAILED VERIFICATION] — Auto-copy mode is off. Check the system configuration and option flags to determine whether disk name/date matching is required.
6814
LD A,(428CH) 3A 8C 42
Load Register A with the value at 428CH — a system configuration byte in the SYS0 work area. This byte contains flags that indicate system-level settings related to disk operations.
6817
AND 82H E6 82
Mask Register A with 82H (binary 10000010), isolating bits 1 and 7. These two bits control whether automatic disk name verification is enabled.
6819
CP 80H FE 80
Compare Register A against 80H. This checks whether bit 7 is set AND bit 1 is clear — the specific combination that enables automatic name verification. If A = 80H, the Z flag is set (match); otherwise NZ.
681B
If the NZ flag is set (the system config does NOT require automatic name verification), JUMP to 6842H to skip the name/date verification and proceed to conditional data copying.
681D
LD A,(5996H) 3A 96 59
Load Register A with option flags byte 3 at 5996H.
6820
BIT 3,A CB 5F
Test bit 3 of option flags byte 3. Bit 3 controls whether the disk name verification should actually be performed for this operation.
6822
If the Z flag is set (bit 3 = 0 — name verification not required for this operation), JUMP to 6842H to skip verification.
6824
LD A,(5995H) 3A 95 59
Load Register A with option flags byte 2 at 5995H.
6827
BIT 0,A CB 47
Test bit 0 of option flags byte 2. Bit 0 indicates whether the user specified a date stamp to verify against the diskette's existing date.
6829
If the Z flag is set (bit 0 = 0 — no date stamp was specified for verification), JUMP to 6837H to display the disk name mismatch error without comparing dates.
[DATE STAMP COMPARISON] — The user specified a date stamp. Compare the diskette's existing date stamp against the user-specified date.
682B
LD HL,(43CEH) 2A CE 43
Load Register Pair HL with the date stamp from the GAT sector buffer at 43CEH. Offset CEH in the GAT sector is where the 2-byte packed date stamp is stored. This is the date that was written when the disk was last formatted.
682E
LD DE,(597AH) ED 5B 7A 59
Load Register Pair DE with the user-specified date stamp from 597AH. This is the date the user provided on the command line for verification.
6832
OR A B7
Clear the Carry flag by OR'ing A with itself. This is required before the SBC instruction, which subtracts with carry.
6833
SBC HL,DE ED 52
SUBtract Register Pair DE from HL with carry. If HL = DE (the date stamps match), the result is zero and the Z flag is set. If HL ≠ DE (dates don't match), the NZ flag is set.
6835
If the Z flag is set (date stamps match), JUMP to 6842H to proceed. The disk's date matches the expected date, so verification passes.
[DATE MISMATCH ERROR] — The diskette's date stamp does not match the user-specified date. Display the mismatch message and abort.
6837
LD HL,5A44H 21 44 5A
Point Register Pair HL to 5A44H — the address of the "DESTINATION" label string in the message area. This string identifies which disk (destination) has the mismatch.
683A
GOSUB to 4467H (SYS0 display string) to print "DESTINATION" to identify which disk has the problem.
683D
LD A,37H 3E 37
Load Register A with error code 37H (55 decimal) — the NEWDOS/80 error code for a disk name/date mismatch.
683F
JUMP to 521AH — the main error handler — with error code 37H in Register A. This displays the name/date mismatch error and aborts the FORMAT operation.
6842H — CONDITIONAL DISK NAME/DATE COPY AND DISPLAY
This section conditionally copies the disk name and date stamp from the existing GAT sector buffer into the working parameter area (for preservation during reformat), compares the disk name against the expected name, and optionally displays the diskette's name/date information to the operator.
6842
BIT 3,C CB 59
Test bit 3 of the option flags (Register C). Bit 3 indicates that the disk name should be copied from the existing GAT into the parameter area to preserve it during the reformat.
6844
If the Z flag is set (bit 3 = 0 — do not copy disk name), JUMP to 6853H to skip the name copy and check the date copy flag.
6846
PUSH BC C5
Save Register Pair BC onto the stack. BC is preserved because the LDIR instruction below will destroy its contents.
6847
LD HL,43D0H 21 D0 43
Point Register Pair HL to 43D0H — the disk name area within the GAT sector buffer. Offset D0H is where the 8-byte disk name is stored in the GAT.
684A
LD DE,5983H 11 83 59
Point Register Pair DE to 5983H — the destination in the parameter area where the disk name will be stored for use by the format operation.
684D
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H (8 decimal) — the byte count for the disk name. NEWDOS/80 disk names are exactly 8 bytes.
6850
LDIR ED B0
Block copy 8 bytes from 43D0H (GAT disk name) to 5983H (parameter area). This preserves the existing disk name so it can be written back during the reformat.
6852
POP BC C1
Restore Register Pair BC from the stack (option flags in C).
6853
BIT 0,C CB 41
Test bit 0 of the option flags (Register C). Bit 0 indicates that the date stamp should be copied from the existing GAT into the parameter area.
6855
If the Z flag is set (bit 0 = 0 — do not copy date stamp), JUMP to 6864H to skip the date copy and proceed to the name comparison check.
6857
PUSH BC C5
Save Register Pair BC onto the stack (LDIR will destroy BC).
6858
LD HL,43D8H 21 D8 43
Point Register Pair HL to 43D8H — the date stamp area within the GAT sector buffer. Offset D8H is where the 8-byte date data is stored in the GAT (includes packed date plus additional config bytes).
685B
LD DE,598BH 11 8B 59
Point Register Pair DE to 598BH — the destination in the parameter area for the date stamp data.
685E
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H (8 decimal) — the byte count for the date stamp block.
6861
LDIR ED B0
Block copy 8 bytes from 43D8H (GAT date area) to 598BH (parameter area). This preserves the existing date information for the reformat.
6863
POP BC C1
Restore Register Pair BC from the stack.
[DISK NAME COMPARISON] — Check whether the user specified a disk name that must match the existing diskette's name.
6864
BIT 4,C CB 61
Test bit 4 of the option flags (Register C). Bit 4 indicates that a disk name comparison is required — the user specified a name that must match the existing disk.
6866
If the Z flag is set (bit 4 = 0 — no name comparison needed), JUMP to 6878H to skip the comparison and check the display flag.
6868
LD HL,5970H 21 70 59
Point Register Pair HL to 5970H — the buffer containing the expected disk name specified by the user on the command line.
686B
GOSUB to 624FH — the 8-byte buffer comparison routine. This compares the 8 bytes at (HL) = 5970H (expected name) against the corresponding bytes in the GAT buffer. On return: Z flag set if the names match, NZ if they differ.
686E
If the Z flag is set (disk names match), JUMP to 6878H. The name verification passes — proceed to the display flag check.
[NAME MISMATCH DISPLAY] — The disk name does not match the expected name. Display the mismatch information to the operator.
6870
LD HL,5A44H 21 44 5A
Point Register Pair HL to 5A44H — the "DESTINATION" label string.
6873
GOSUB to 6930H — the disk name mismatch display routine. This displays the "DESTINATION" label followed by the "DISKETTE NAME MISMATCH" message.
6876
JUMP to 687CH to display the diskette's actual name/date information followed by the operator prompt.
[DISPLAY CHECK] — Check whether the diskette's name/date should be displayed to the operator.
6878
BIT 5,C CB 69
Test bit 5 of the option flags (Register C). Bit 5 indicates that the diskette name/date should be displayed to the operator for informational purposes.
687A
If the Z flag is set (bit 5 = 0 — do not display name/date), JUMP to 6888H to skip display and proceed to the motor speed check.
687C
LD HL,5A44H 21 44 5A
Point Register Pair HL to 5A44H — the "DESTINATION" label string.
687F
GOSUB to 693CH — the disk name/date display routine. This prints the "DESTINATION" label, then "DISKETTE OLD NAME/DATE = " followed by the 8-byte disk name, 4 hex bytes of date data, and 8 more bytes of config info from the GAT buffer.
6882
GOSUB to 58C8H — the operator prompt (Y/N/R/Q). This displays a prompt asking the operator whether to proceed, retry, or quit. On return: Z flag set = proceed (Y), NZ = do not proceed (N, R, or Q).
6885
If the NZ flag is set (operator chose NOT to proceed — selected N, R, or Q), JUMP back to 67CCH to re-initialize the buffer and retry the entire drive initialization sequence. This gives the operator the chance to insert a different diskette and try again.
6888H — FORMAT MOTOR SPEED CHECK AND DD AUTO-DETECT
This section checks whether the format operation should proceed with filespec loop mode, performs motor speed verification and seek validation via the FDC, and handles automatic double-density detection. It writes a test boot sector using a temporary drive configuration to determine if the destination disk can support the requested density, then restores the original drive parameters. If the test fails, an appropriate error is generated.
6888
LD A,(5997H) 3A 97 59
Load Register A with option flags byte 4 at 5997H.
688B
BIT 3,A CB 5F
Test bit 3 of option flags byte 4. Bit 3 indicates filespec loop mode.
688D
RET NZ C0
If the NZ flag is set (bit 3 is active — filespec loop mode), RETURN. In filespec loop mode, the motor speed check and format engine setup are not needed because the format operates file-by-file rather than track-by-track.
688E
LD A,(59C7H) 3A C7 59
Load Register A with the step rate byte from 59C7H in the destination geometry parameter block.
6891
BIT 5,A CB 6F
Test bit 5 of the step rate byte. Bit 5 being set in the step rate byte indicates the drive requires DD capability verification before formatting can proceed.
6893
If the NZ flag is set (bit 5 is active — DD verification needed), GOSUB to 6751H to check whether the drive actually supports double density. If the drive does not support DD and the suppress flag is not set, 6751H will abort via the "DISK TOO LARGE" error at 6747H.
6896
LD HL,6D60H 21 60 6D
Point Register Pair HL to 6D60H — the address of the string "FORMATTING" (terminated by 0DH) in the message pool.
6899
GOSUB to 4467H (SYS0 display string) to print "FORMATTING" on the screen to inform the operator that the low-level format is beginning.
689C
GOSUB to 471BH (SYS0) to perform motor speed verification. This routine checks the FDC motor speed by timing index pulses to ensure the drive motor is spinning at the correct RPM for reliable formatting. On return: Z flag set = speed OK, NZ = speed error.
689F
If the Z flag is set (motor speed OK), GOSUB to 46F5H (SYS0) to perform seek validation. This verifies that the drive's head positioning mechanism is working correctly by performing test seeks. On return: Z flag set = seek OK, NZ = seek error.
68A2
If the NZ flag is set (either motor speed check or seek validation failed), JUMP to 521AH — the main error handler — to display the error and abort the FORMAT operation.
[DD AUTO-DETECT CHECK] — Motor speed and seek are OK. Check whether automatic DD detection should be performed.
68A5
LD A,(5997H) 3A 97 59
Load Register A with option flags byte 4 at 5997H.
68A8
AND 02H E6 02
Mask with 02H, isolating bit 1. Bit 1 of option flags byte 4 indicates that DD auto-detection should be performed — the code will write a test sector in DD mode to see if the drive supports it.
68AA
If the Z flag is set (bit 1 = 0 — DD auto-detect not requested), JUMP to 68D1H to skip the auto-detect logic and proceed with normal format setup.
[DD AUTO-DETECT: TRACK SETUP] — DD auto-detect is requested. Set up a test track/sector address for writing a test sector to verify DD capability.
68AC
LD DE,0001H 11 01 00
Load Register Pair DE with 0001H. Register D = 00H (track 0 side indicator), Register E = 01H (sector number 1). This is the test sector location for the DD auto-detect write.
68AF
LD A,D 7A
Load Register A with Register D (00H — the track/side indicator).
68B0
ADD A,E 83
ADD Register E (01H) to Register A. A = 00H + 01H = 01H. This computes the physical sector address.
68B1
LD C,A 4F
Copy the computed sector address (01H) to Register C.
68B2
If the Carry flag is set (overflow from the ADD — which would only happen if D+E > FFH), JUMP to 68B8H. Under normal circumstances, 00H+01H does not carry, so this branch is not taken.
68B4
LD A,(59C8H) 3A C8 59
Load Register A with the destination side count from 59C8H.
68B7
CP C B9
Compare Register A (side count) against Register C (computed sector address). If A < C, the Carry flag is set — the sector address exceeds the valid range for this disk geometry.
68B8
If the Carry flag is set (sector address is out of range for the destination disk geometry), JUMP to 5218H — the parse error handler — to abort. The DD auto-detect test sector is beyond the disk's valid address space.
68BB
BIT 1,(IY+07H) FD CB 07 4E
Test bit 1 of the byte at (IY+07H) = 4287H (IY = 4280H, offset +07H). This is a system configuration flag in the DOS work area that indicates whether the drive supports double-sided operation.
68BF
If the Z flag is set (bit 1 = 0 — single-sided drive), JUMP to 68C2H to skip the side increment.
68C1
INC D 14
INCrement Register D by 1. For a double-sided drive, D is incremented from 00H to 01H, indicating that the test should include the second side.
68C2
LD A,D 7A
Load Register A with Register D (the side indicator — 00H for single-sided, 01H for double-sided).
68C3
LD (6B24H),A 32 24 6B
Store the side indicator to 6B24H — a [SELF-MODIFYING CODE] location in the format track engine. This patches the side select value so the format writes to the correct disk side.
68C6
OUT (F3H),A D3 F3
Output Register A to port F3H — the FDC data register. This loads the side indicator value into the FDC's data register as part of the format track setup. On the WD1793, the data register is used during Write Track (Format) commands to supply the track image data.
68C8
LD C,18H 0E 18
Load Register C with 18H (24 decimal). This is a command parameter — the FDC seek command code with specific step rate and head load settings.
68CA
GOSUB to 46F7H (SYS0) to perform an FDC seek operation using the command in Register C (18H). This seeks to the test track to position the head for the DD auto-detect write. 46F7H is a lower-level entry point that bypasses some of 46F5H's validation.
68CD
LD A,D 7A
Load Register A with Register D (the side indicator).
68CE
ADD A,E 83
ADD Register E (sector number) to Register A. This recomputes the physical sector address after the seek operation.
68CF
JUMP to 6923H to call the format setup routine at 695AH with the computed track parameters and continue with the format initialization.
68D1H — NORMAL FORMAT SETUP AND DD AUTO-DETECT VIA PROBE
This code handles the normal format setup path (when DD auto-detect flag was not set in option byte 4) and an advanced DD auto-detect path that temporarily modifies the drive's PDRIVE parameters to test whether the disk can accept double-density writes. It writes a test boot sector with modified parameters, then restores the originals and checks the result.
68D1
LD A,(59C8H) 3A C8 59
Load Register A with the destination side count from 59C8H.
68D4
LD HL,5996H 21 96 59
Point Register Pair HL to 5996H — option flags byte 3.
68D7
BIT 7,(HL) CB 7E
Test bit 7 of option flags byte 3. Bit 7 indicates label verification pending.
68D9
If the NZ flag is set (bit 7 is active — label verification is pending), JUMP to 6923H to proceed to the format setup with the current sector count. DD probing is skipped when label verification is still pending.
68DB
BIT 6,(IY+02H) FD CB 02 76
Test bit 6 of the byte at (IY+02H) = 4282H (IY = 4280H, offset +02H). This is a system configuration flag that indicates whether the system supports DD probing (automatic density detection via test writes).
68DF
If the Z flag is set (bit 6 = 0 — DD probing is NOT supported by the system), JUMP to 6923H to skip probing and proceed with the normal format setup.
[DD PROBE: SAVE AND MODIFY PDRIVE PARAMETERS] — DD probing is supported. Save the current PDRIVE parameters, temporarily modify them to test DD capability, write a test boot sector, then restore the originals.
68E1
PUSH IX DD E5
Save the current IX value (5B17H — destination parameter block) onto the stack.
68E3
LD IX,(42B9H) DD 2A B9 42
Load IX with the pointer to the PDRIVE table entry for the current drive from 42B9H. IX now points to the actual PDRIVE configuration data for the destination drive.
68E7
LD A,01H 3E 01
Load Register A with 01H. This value will be XOR'ed with the current side configuration to toggle the density bit.
68E9
LD E,(IY+07H) FD 5E 07
Load Register E with the byte at (IY+07H) = 4287H — the current drive configuration flags from the DOS work area. Register E saves the original value for later restoration.
68EC
XOR E AB
XOR Register A (01H) with Register E (drive config flags). This toggles bit 0 of the configuration, which controls the density setting.
68ED
AND 41H E6 41
Mask with 41H (binary 01000001), keeping only bits 0 and 6. Bit 0 is the toggled density flag; bit 6 is a related control bit. All other bits are cleared.
68EF
LD (IX+07H),A DD 77 07
Store the modified configuration to (IX+07H) in the PDRIVE table. This temporarily changes the drive's density setting to the opposite of its current value for the test write.
68F2
LD D,(IX+04H) DD 56 04
Load Register D with (IX+04H) — the original track count from the PDRIVE entry. Register D saves this value for restoration after the test.
68F5
LD (IX+04H),04H DD 36 04 0A
Store 0AH (10 decimal) to (IX+04H) — temporarily set the track count to 10 in the PDRIVE entry. The test write only needs to write to the system tracks area (tracks 0–9), so the track count is reduced to limit the test scope.
[NOTE] — The hex bytes show DD 36 04 0A. The disassembler displays this as LD (IX+04H),04H, but the actual immediate value is 0AH (the fourth byte). This is a 4-byte IX-indexed instruction: DD 36 offset value.
68F9
EX (SP),IX DD E3
Exchange IX with the value on top of the stack. IX was pointing to the PDRIVE entry; the stack had 5B17H (destination parameter block). After this exchange: IX = 5B17H (parameter block), and the stack now holds the PDRIVE entry address.
68FB
PUSH DE D5
Save Register Pair DE onto the stack. Register D holds the original track count, and Register E holds the original drive config flags. Both must be restored after the test.
68FC
LD A,01H 3E 01
Load Register A with 01H — the sector count parameter for the format setup routine.
68FE
GOSUB to 695AH — the format setup routine. This configures FDC timing parameters from the geometry table at 6CC1H and patches the self-modifying locations in the format engine for the test write. Register A = 01H is the sector count for the test.
6901
If the NZ flag is set (format setup failed), JUMP to 6906H to skip the test boot sector write and proceed to restoration.
6903
GOSUB to 67ACH to write a test boot sector (sector 0) using the temporarily modified drive parameters. If this write succeeds, the drive supports the tested density mode.
[DD PROBE: RESTORE ORIGINAL PARAMETERS] — Whether the test succeeded or failed, restore the original PDRIVE parameters.
6906
POP DE D1
Restore Register Pair DE from the stack. Register D = original track count, Register E = original drive config flags.
6907
EX (SP),IX DD E3
Exchange IX with the stack top. IX now points back to the PDRIVE table entry, and the stack holds 5B17H again.
6909
PUSH AF F5
Save Register A and flags onto the stack. The flags contain the result of the test write (Z = success, NZ = failure) which must be preserved across the PDRIVE restoration.
690A
LD (IX+07H),E DD 73 07
Restore the original drive config flags (Register E) to (IX+07H) in the PDRIVE table.
690D
LD (IX+04H),D DD 72 04
Restore the original track count (Register D) to (IX+04H) in the PDRIVE table.
6910
GOSUB to 4720H (SYS0) to reinitialize the drive with the restored original parameters. This ensures the FDC is reconfigured to match the original PDRIVE settings after the temporary modification.
6913
EX AF,AF' 08
Exchange Register A and flags with the alternate register set (AF'). This saves the result of the 4720H call in AF' for later checking.
6914
POP AF F1
Restore Register A and flags from the stack (the test write result saved at 6909H).
6915
POP IX DD E1
Restore IX from the stack. IX = 5B17H (destination parameter block), its original value before the DD probe began.
6917
If the NZ flag is set (the test boot sector write FAILED — the drive does NOT support the tested density), JUMP to 6926H to check the error code and handle the failure.
6919
EX AF,AF' 08
Swap back to AF' to check the result of the drive reinitialization (4720H) that was saved earlier.
691A
If the NZ flag is set (drive reinitialization FAILED), JUMP to 6926H to handle the error.
[DD PROBE SUCCESS] — Both the test write and the drive reinitialization succeeded. The drive supports the tested density. Update the geometry and proceed.
691C
GOSUB to 6CAEH to update the geometry parameters based on the successful DD probe. This adjusts the working geometry to reflect the confirmed density capability.
691F
LD A,(59C8H) 3A C8 59
Load Register A with the destination side count from 59C8H (possibly updated by the 6CAEH call).
6922
INC A 3C
INCrement Register A by 1. This converts the side count (0-based: 0 = single, 1 = double) to a 1-based value (1 = single, 2 = double) as required by the format setup routine.
6923
GOSUB to 695AH — the format setup routine. Register A contains the sector count or side indicator. This configures the FDC timing parameters and patches the format engine for the actual format operation.
6926
EI FB
Re-enable interrupts. Interrupts were disabled during the low-level FDC operations to prevent timing interference. They are now safe to re-enable.
6927
RET Z C8
If the Z flag is set (format setup completed successfully), RETURN to the caller. The drive initialization is complete and the format engine is ready to begin track formatting.
6928
CP FFH FE FF
Compare Register A against FFH. Error code FFH indicates a specific format failure (motor speed error or unrecoverable format problem) that should display a descriptive message rather than a generic error code.
692A
If the NZ flag is set (error code ≠ FFH — a standard error code), JUMP to 521AH — the main error handler — to display the error code and abort.
692D
JUMP to 5243H — the error message display and abort routine. For error code FFH, the message pointer in HL (set by 695AH before returning) contains the address of a descriptive error string.
6930H — DISPLAY HELPER: DISK NAME MISMATCH
This short helper routine displays the disk label string passed in HL (typically "DESTINATION" or "SOURCE") followed by the "DISKETTE NAME MISMATCH" message. It is called when the disk name on the target diskette does not match the user-specified name.
6930
PUSH HL E5
Save Register Pair HL (the label string address, e.g., 5A44H = "DESTINATION") onto the stack for later use.
6931
GOSUB to 4467H (SYS0 display string) to print the label string at (HL) — e.g., "DESTINATION".
6934
LD HL,6DC1H 21 C1 6D
Point Register Pair HL to 6DC1H — the address of the string "DISKETTE NAME MISMATCH" (terminated by 0AH) in the message pool.
6937
GOSUB to 4467H to print "DISKETTE NAME MISMATCH" on the screen.
693A
POP HL E1
Restore Register Pair HL from the stack (the label string address).
693B
RET C9
RETURN to the caller with HL pointing to the original label string.
693CH — DISPLAY HELPER: DISK NAME/DATE INFORMATION
This helper routine displays the disk label string (e.g., "DESTINATION"), followed by the "DISKETTE OLD NAME/DATE = " header, then the actual disk name (8 bytes), date stamp (4 hex bytes), and additional configuration data (8 bytes) from the GAT sector buffer at 43D0H. It provides the operator with a complete view of the existing diskette's identity before proceeding with a destructive format operation.
693C
GOSUB to 4467H (SYS0 display string) to print the label string at (HL) — e.g., "DESTINATION" — passed by the caller.
693F
LD HL,6DA7H 21 A7 6D
Point Register Pair HL to 6DA7H — the address of the string "DISKETTE OLD NAME/DATE = " (terminated by 03H) in the message pool.
6942
GOSUB to 4467H to print "DISKETTE OLD NAME/DATE = " on the screen.
6945
LD HL,43D0H 21 D0 43
Point Register Pair HL to 43D0H — the disk name area within the GAT sector buffer (offset D0H = 208 bytes into the sector).
6948
LD B,08H 06 08
Load Register B with 08H (8 decimal) — the number of bytes in the disk name field.
694A
GOSUB to 5886H to display 8 filtered characters from the buffer at (HL). This routine outputs B bytes from (HL), filtering control codes for safe display. HL advances past the displayed bytes on return.
694D
LD B,04H 06 04
Load Register B with 04H (4 decimal) — the number of hex bytes to display for the date stamp.
694F
GOSUB to 5898H to display 4 bytes as hex values from the buffer at (HL). This shows the packed date stamp and related bytes in hexadecimal format. HL advances past the displayed bytes.
6952
LD B,08H 06 08
Load Register B with 08H (8 decimal) — the number of additional config/label bytes to display.
6954
GOSUB to 5886H to display 8 more filtered characters from the buffer. This shows the remaining disk label configuration data.
6957
JUMP to 5881H to output a carriage return (CR/LF), then return to the caller. The JP (rather than CALL + RET) means 5881H's RET will return directly to the caller of 693CH.
695AH — FORMAT SETUP: CONFIGURE FDC TIMING PARAMETERS
This routine configures the FDC (Floppy Disk Controller) timing parameters for the FORMAT operation by reading values from the FDC timing parameter table at 6CC1H. The table is indexed by drive type (derived from the system configuration byte at 4287H). Each table entry is 26 (1AH) bytes containing timing constants, gap lengths, fill bytes, and other values that are patched into self-modifying code locations throughout the format track engine (6AxxH–6BxxH). After loading timing parameters, it initializes tracking variables and validates motor speed timing. Register A on entry contains the sector count or side indicator.
695A
LD (6C74H),A 32 74 6C
Store Register A to 6C74H — a [SELF-MODIFYING CODE] location that saves the sector count / side indicator passed by the caller.
695D
GOSUB to 4720H (SYS0) to reinitialize the drive. On return: Z = OK, NZ = error.
6960
RET NZ C0
If NZ (drive init failed), RETURN with error.
[TIMING TABLE INDEX] — Compute index into FDC timing table based on drive type.
6961
LD A,(4287H) 3A 87 42
Load Register A with drive configuration flags from 4287H (IY+07H).
6964
RLCA 07
Rotate A left, shifting drive type bits into lower positions.
6965
AND 03H E6 03
Mask to 2-bit drive type index (0–3).
6967
LD L,1AH 2E 1A
L = 1AH (26) — size of each timing table entry.
6969
GOSUB to 4C37H (SYS0) — 8-bit multiply A × L → HL. Result = byte offset into timing table.
696C
LD DE,6CC1H 11 C1 6C
DE = 6CC1H — base address of the FDC timing parameter table.
696F
ADD HL,DE 19
HL = table base + offset = start of selected entry.
[TIMING PARAMETER PATCHING] — Read bytes sequentially from the table entry and patch them into self-modifying locations in the format track engine.
6970
LD A,(HL) 7E
Load byte 0 — Gap 1 fill byte count.
6971
LD (6B42H),A 32 42 6B
Patch 6B42H — [SELF-MOD] Gap 1 length in format engine.
6974
INC HL 23
Advance to next table byte.
6975
LD (6B90H),A 32 90 6B
Patch 6B90H — [SELF-MOD] second copy of gap fill value (inter-sector gap).
6978
LD A,(HL) 7E
Load byte 1 — sync field byte value.
6979
LD (6B10H),A 32 10 6B
Patch 6B10H — [SELF-MOD] ID field sync byte.
697D
LD (6B66H),A 32 66 6B
Patch 6B66H — [SELF-MOD] data field sync byte.
6980
LD A,(HL) 7E
Load byte 2 — data address mark.
6981
LD (6B7CH),A 32 7C 6B
Patch 6B7CH — [SELF-MOD] data address mark.
6985
LD A,(HL) 7E
Load byte 3 — ID address mark.
6986
LD (6B82H),A 32 82 6B
Patch 6B82H — [SELF-MOD] ID address mark.
698A
LD A,(HL) 7E
Load byte 4 — fill pattern count.
698B
LD (6B96H),A 32 96 6B
Patch 6B96H — [SELF-MOD] fill pattern count.
698F
LD A,(HL) 7E
Load byte 5 — Gap 2 length.
6990
LD (6B04H),A 32 04 6B
Patch 6B04H — [SELF-MOD] Gap 2 byte count.
6994
LD A,(HL) 7E
Load byte 6 — Gap 3 length.
6995
LD (6B48H),A 32 48 6B
Patch 6B48H — [SELF-MOD] Gap 3 byte count.
6999
LD A,(HL) 7E
Load byte 7 — Gap 4 fill count.
699A
LD (6B5AH),A 32 5A 6B
Patch 6B5AH — [SELF-MOD] Gap 4 byte count.
[16-BIT TIMING PARAMETERS] — Load 16-bit word values from the table into BC, then patch self-modifying LD nn instructions.
699E
LD E,(HL) 5E
Load byte 8 (low) into E.
69A0
LD D,(HL) 56
Load byte 9 (high) into D. DE = 16-bit timing constant for motor speed computation.
69A2
LD C,(HL) 4E
Load byte 10 (low) into C.
69A4
LD B,(HL) 46
Load byte 11 (high) into B. BC = nominal revolution timing reference.
69A5
LD (69DBH),BC ED 43 DB 69
Patch 69DBH — [SELF-MOD] operand of LD HL,nnnn at 69DAH.
69AA
LD C,(HL) 4E
Load byte 12 (low).
69AC
LD B,(HL) 46
Load byte 13 (high). BC = precompensation scaling factor.
69AD
LD (69F3H),BC ED 43 F3 69
Patch 69F3H — [SELF-MOD] operand of LD DE,nnnn at 69F2H.
69B2
LD C,(HL) 4E
Load byte 14 (low).
69B4
LD B,(HL) 46
Load byte 15 (high). BC = low speed threshold.
69B5
LD (69D7H),BC ED 43 D7 69
Patch 69D7H — [SELF-MOD] operand of LD BC,nnnn at 69D6H.
69BA
LD A,(HL) 7E
Load byte 16 — additional timing constant.
69BB
LD (6A01H),A 32 01 6A
Patch 6A01H — [SELF-MOD] timing operand in interleave builder.
69BF
LD A,(HL) 7E
Load byte 17 — the interleave factor.
69C0
LD (6A34H),A 32 34 6A
Patch 6A34H — [SELF-MOD] interleave factor in the table builder.
69C3
INC HL 23
Advance HL past last used byte.
69C4
NOP 00
No operation — padding (3 NOPs for future patches).
69C5
NOP 00
No operation — padding.
69C6
NOP 00
No operation — padding.
[INITIALIZE TRACKING VARIABLES] — Zero the side toggle and interleave offset, then compute motor speed timing.
69C8
LD (6A03H),A 32 03 6A
Clear 6A03H — [SELF-MOD] interleave offset variable.
69CB
LD (6C62H),A 32 62 6C
Clear 6C62H — [SELF-MOD] side toggle variable.
69CE
EX DE,HL EB
HL = 16-bit timing constant from 699EH–69A0H.
69CF
GOSUB to 6CA3H — get adjusted sectors per track in Register E (halved for DS).
69D2
LD A,E 7B
A = adjusted sectors per track.
69D3
GOSUB to 4C39H (SYS0) — 8-bit multiply. HL = expected byte count for one disk revolution.
[MOTOR SPEED VALIDATION] — Check motor RPM using timing windows. Self-modifying operands below were patched from the timing table.
69D6
LD BC,0000H 01 00 00
BC = 0000H — [SELF-MOD] at 69D7H patched at 69B5H. BC = low speed threshold.
69D9
EX DE,HL EB
DE = revolution byte count.
69DA
LD HL,0000H 21 00 00
HL = 0000H — [SELF-MOD] at 69DBH patched at 69A5H. HL = nominal revolution reference.
69DD
OR A B7
Clear Carry flag (required before SBC).
69DE
SBC HL,DE ED 52
HL = nominal − actual. Carry set = motor too slow.
69E0
PUSH HL E5
Save timing difference.
69E1
If NC (speed OK or fast), JUMP to 69F2H for precompensation calculation.
[MOTOR SLOW — TOLERANCE CHECK]
69E4
ADD HL,HL 29
HL × 4 (amplify error).
69E5
ADD HL,BC 09
ADD threshold. Carry = within tolerance.
69E6
If Carry (within tolerance), JUMP to 69EFH.
69E8
POP HL E1
Discard saved difference.
69E9
LD HL,6D6BH 21 6B 6D
HL = 6D6BH — "MOTOR FAST" error message.
69EC
OR FFH F6 FF
A = FFH, NZ flag set. Error code FFH = motor speed error.
69EE
RET C9
RETURN with NZ, A=FFH. Caller handles error.
[PRECOMPENSATION OFFSET COMPUTATION]
69EF
LD HL,0000H 21 00 00
HL = 0 (zero precomp offset when within tolerance).
69F2
LD DE,0000H 11 00 00
DE = 0000H — [SELF-MOD] at 69F3H patched at 69ADH. DE = precomp scaling factor.
69F5
ADD HL,DE 19
HL = timing offset + precomp factor.
69F6
LD (6BCBH),HL 22 CB 6B
Patch 6BCBH — [SELF-MOD] precomp timing in format engine.
69F9
POP HL E1
Restore original timing difference.
69FA
ADD HL,DE 19
ADD precomp factor.
69FB
ADD HL,BC 09
ADD low speed threshold.
69FC
ADD HL,BC 09
ADD threshold again (double).
69FD
LD (6BD4H),HL 22 D4 6B
Patch 6BD4H — [SELF-MOD] second precomp timing operand.
6A00H — INTERLEAVE TABLE CONSTRUCTION
This section computes the sector interleave offset, builds an interleave table at 6485H that determines the physical order of sectors on each track, and applies an optional rotation for double-sided disks. The table is built by placing logical sector numbers at positions separated by the interleave factor, with collision resolution for occupied slots. After construction, 1-based sector numbering is applied if bit 4 of the drive config flags requires it.
6A00
LD A,02H 3E 02
A = 02H — base interleave offset.
6A02
ADD 00H C6 00
ADD 00H — [SELF-MOD] at 6A03H, patched by 69C8H (init 0) and updated at 6A44H. Adds accumulated offset from previous tracks.
6A04
GOSUB to 6CA3H — get adjusted sectors per track in E.
6A07
CP E BB
Compare offset vs sectors per track.
6A08
If Carry (within range), skip wrap.
6A0A
SUB E 93
Wrap offset by subtracting sectors per track.
6A0B
LD (6A03H),A 32 03 6A
Store adjusted offset to 6A03H — [SELF-MOD].
6A0E
LD (6A03H),A 32 03 6A
Redundant store (coding artifact).
6A11
INC A 3C
Convert to 1-based count.
6A12
LD D,A 57
D = total sectors to place / rotation count.
6A13
PUSH DE D5
Save DE (D=count, E=sectors/track).
[CLEAR TABLE] — Fill interleave table at 6485H with FFH markers.
6A14
LD HL,6485H 21 85 64
HL = 6485H — interleave table buffer.
6A17
LD B,E 43
B = sectors per track (entries to clear).
6A18
LD (HL),FFH 36 FF
[LOOP] Store FFH (unassigned).
6A1A
INC HL 23
Advance to next entry.
6A1B
Loop until all cleared. [END CLEAR LOOP]
[FILL TABLE] — Place logical sector numbers at interleaved physical positions.
6A1D
LD D,00H 16 00
D = 00H — starting logical sector number.
6A1F
LD B,D 42
B = 00H (cleared).
6A20
JUMP to initialize C=0.
6A22
INC C 0C
Next physical position (collision skip).
6A23
LD A,C 79
A = current position.
6A24
CP E BB
Compare vs sectors per track.
6A25
If within range, check slot.
6A27
LD C,00H 0E 00
Wrap position to 0.
6A29
LD HL,6485H 21 85 64
HL = table base.
6A2C
ADD HL,BC 09
HL = table[position].
6A2D
LD A,(HL) 7E
Load slot value.
6A2E
INC A 3C
If FFH→00H (Z=empty), else NZ (occupied).
6A2F
If occupied, skip to next. [COLLISION RESOLUTION]
6A31
LD (HL),D 72
Store logical sector number D in empty slot.
6A32
LD A,C 79
A = current position.
6A33
ADD 02H C6 02
ADD 02H — [SELF-MOD] at 6A34H patched at 69C0H with interleave factor.
6A35
CP E BB
Compare vs sectors per track.
6A36
If within range, skip wrap.
6A38
SUB E 93
Wrap position.
6A39
LD C,A 4F
C = new position.
6A3A
INC D 14
Next logical sector number.
6A3B
LD A,D 7A
A = sector counter.
6A3C
CP E BB
All sectors placed?
6A3D
If more to place, loop. [INTERLEAVE FILL LOOP]
[OFFSET UPDATE AND TABLE ROTATION]
6A3F
LD HL,6A03H 21 03 6A
HL = interleave offset variable.
6A42
LD A,(HL) 7E
Load current offset.
6A43
ADD A,C 81
Accumulate final position for next track.
6A44
LD (HL),A 77
Store updated offset.
6A45
POP DE D1
Restore DE (D=rotation count, E=sectors/track).
6A46
DEC D 15
DECrement rotation count.
6A47
If Z (done), JUMP to 6A59H.
6A49
LD C,E 4B
C = sectors/track for LDDR.
6A4B
LD HL,6484H 21 84 64
HL = one before table start.
6A4E
ADD HL,BC 09
HL = last entry.
6A4F
LD D,H 54
DE = HL (LDDR destination).
6A50
LD E,L 5D
Complete DE copy.
6A51
DEC BC 0B
BC = bytes to shift.
6A52
LD A,(HL) 7E
Save last entry value before shift.
6A53
DEC HL 2B
Move source pointer back.
6A54
LDDR ED B8
Block copy in reverse — shifts all entries right by one position.
6A56
LD (DE),A 12
Place saved last entry at the now-empty first slot. Table rotated right by 1.
6A57
Loop back to check if more rotations needed.
[DS SECTOR NUMBER ADJUSTMENT] — Increment all sector numbers by 1 if drive config requires 1-based numbering.
6A59
LD A,(4287H) 3A 87 42
Load drive config flags from 4287H.
6A5C
BIT 4,A CB 67
Test bit 4 — 1-based sector numbering.
6A5E
If Z (0-based), skip adjustment.
6A60
LD B,E 43
B = sectors per track (loop count).
6A61
LD HL,6485H 21 85 64
HL = interleave table start.
6A64
INC (HL) 34
[LOOP] INCrement sector number by 1 (0→1, 1→2, etc.).
6A66
Loop until all incremented. [END ADJUST LOOP]
6A68H — FORMAT ENGINE INITIALIZATION
This section sets the retry counter, reinitializes the drive, updates the progress display, configures the drive select register for formatting (including side selection and write precompensation), loads FDC timing parameters into registers, installs the NMI handler for Write Track completion detection, disables interrupts, and issues the WD1793 Write Track (Format) command to begin physical track formatting.
6A68
LD A,0AH 3E 0A
A = 0AH (10) — format retry count.
6A6A
LD (6C94H),A 32 94 6C
Store to 6C94H — [SELF-MOD] retry counter.
6A6D
GOSUB to 4720H (SYS0) — reinitialize the drive. Z = OK.
6A70
RET NZ C0
If NZ (failed), RETURN with error.
6A71
GOSUB to 5733H — update format progress display (track number on screen).
6A74
LD HL,427FH 21 7F 42
HL = 427FH — drive select register shadow.
6A77
LD B,(IY+07H) FD 46 07
B = drive config flags from 4287H.
6A7A
BIT 0,B CB 40
Test bit 0 — side 1 select required.
6A7C
If Z (no side select), skip.
6A7E
SET 7,(HL) CB FE
Set bit 7 of drive select shadow — side 1 selection.
6A80
LD A,(6B24H) 3A 24 6B
A = current track number from 6B24H [SELF-MOD].
6A83
LD C,A 4F
C = track number.
6A84
LD A,(4283H) 3A 83 42
A = precompensation start track from 4283H.
6A87
RRCA 0F
Divide threshold by 2.
6A88
CP C B9
Compare threshold vs current track.
6A89
If NC (threshold ≥ track, no precomp needed), skip.
6A8B
SET 5,(HL) CB EE
Set bit 5 of drive select shadow — enable MFM/precompensation.
6A8D
LD A,B 78
A = drive config flags.
6A8E
AND 40H E6 40
Isolate bit 6 — precomp control flag.
6A90
If Z (no additional precomp), skip.
6A92
LD A,(6C62H) 3A 62 6C
A = side toggle from 6C62H.
6A95
AND 01H E6 01
Isolate bit 0 — current side.
6A99
SET 4,(HL) CB E6
Set bit 4 — enable side 1 precomp.
6A9B
LD (6B2AH),A 32 2A 6B
Patch 6B2AH — [SELF-MOD] side/precomp config.
6A9E
GOSUB to 4715H (SYS0) — output drive select value to port F4H.
6AA1
GOSUB to 46FFH (SYS0) — FDC seek to target track.
6AA4
GOSUB to 6CA3H — get adjusted sectors per track in E.
6AA7
LD A,E 7B
A = sectors per track.
6AA8
LD (6AF2H),A 32 F2 6A
Patch 6AF2H — [SELF-MOD] sector count in format loop.
6AAB
LD A,(427FH) 3A 7F 42
A = drive select shadow.
6AAE
OR 40H F6 40
Set bit 6 — precomp enable.
6AB0
LD (6AF0H),A 32 F0 6A
Patch 6AF0H — [SELF-MOD] drive select in format loop.
[FDC WRITE TRACK SETUP] — Load timing params into registers, disable interrupts, install NMI handler, issue Write Track command.
6AB3
LD E,02H 1E 02
E = 02H — DRQ bit mask (bit 1 of FDC status).
6AB5
LD A,(6B90H) 3A 90 6B
A = gap fill byte count.
6AB8
LD D,A 57
D = gap fill byte (data for OUT to FDC).
6AB9
LD A,(6B96H) 3A 96 6B
A = fill pattern count.
6ABC
LD B,A 47
B = fill count (DJNZ counter).
6ABD
DEC B 05
Adjust for DJNZ (tests after decrement).
6ABE
LD C,F3H 0E F3
C = F3H — FDC data register port.
6AC0
DI F3
Disable interrupts — critical timing section begins. The FDC Write Track requires precise byte-by-byte timing with no interrupt interference.
6AC1
LD A,(00F0H) 3A F0 00
Read FDC status from memory-mapped address 00F0H.
[NMI HANDLER INSTALLATION] — Install custom NMI handler at 6BA5H. When the FDC completes Write Track (index hole detected), an NMI fires and jumps to this handler to cleanly exit the format loop.
6AC4
LD (6BA9H),SP ED 73 A9 6B
Save SP to 6BA9H — [SELF-MOD]. NMI handler will restore SP to unwind the format loop stack.
6AC8
LD HL,6BA5H 21 A5 6B
HL = 6BA5H — NMI handler address.
6ACB
LD (404AH),HL 22 4A 40
Patch NMI vector target at 404AH.
6ACE
LD A,C3H 3E C3
A = C3H — JP opcode.
6AD0
LD (4049H),A 32 49 40
Store JP opcode at 4049H. With address at 404AH, creates JP 6BA5H at the NMI dispatch point.
6AD3
LD HL,6485H 21 85 64
HL = 6485H — interleave table. HL reads sector numbers during the Write Track data stream.
6AD6
LD A,C0H 3E C0
A = C0H — NMI enable mask.
6AD8
OUT (E4H),A D3 E4
Enable NMI via port E4H.
6ADA
LD A,F4H 3E F4
A = F4H — WD1793 Write Track (Format) command.
6ADC
OUT (F0H),A D3 F0
Issue Write Track command to FDC command register. The FDC waits for index hole then begins accepting data bytes via DRQ.
6ADE
GOSUB to 4789H (SYS0) — wait for FDC ready/first DRQ.
6AE1H — FORMAT TRACK INNER LOOP (WRITE TRACK FDC DATA STREAM)
The core of the physical track format engine — a tightly-timed loop feeding the complete track image to the WD1793 FDC byte-by-byte. Register C = F3H (data port), Register D = current data byte, Register A = drive select value (port F4H), Register E = sector countdown, Register B = loop counter, HL = interleave table pointer. Each sector consists of: gap→sync→ID address mark→track/side/sector/length→CRC→gap→sync→data mark→256×E5H→CRC→gap. The loop runs with interrupts disabled and exits via NMI at the index hole. Self-modifying locations contain timing values patched from the FDC timing table.
[DRQ POLL — WAIT FOR FIRST DATA REQUEST]
6AE1
IN A,(F0H) DB F0
[POLL LOOP] Read FDC status register.
6AE3
AND E A3
Test DRQ bit (E=02H).
6AE4
If Z (no DRQ yet), keep polling.
[GAP 1 — INITIAL GAP BYTES]
6AE6
OUT (C),D ED 51
Send first gap byte to FDC.
6AE8
IN A,(F0H) DB F0
Read FDC status.
6AED
OUT (C),D ED 51
Send second gap byte.
[SECTOR FORMAT DATA STREAM] — Each sector: Gap fill → Sync → ID Address Mark (FEH) → Track → Side → Sector Number → Length (01H) → CRC (F7H) → Gap 3 → Sync → Data Address Mark (FBH) → 256 × E5H → CRC (F7H) → Inter-sector gap. The OUT (F4H),A / OUT (C),D pattern maintains drive select while clocking data. HL advances through the interleave table for sector numbers.
6AEF
LD A,00H 3E 00
[SELF-MOD] at 6AF0H — drive select value (patched at 6AB0H).
6AF1
LD E,00H 1E 00
[SELF-MOD] at 6AF2H — sectors per track (patched at 6AA8H). E = sector countdown.
6AF3
OUT (F4H),A D3 F4
[SECTOR LOOP START] Maintain drive select.
6AF5
OUT (C),D ED 51
Send gap byte.
6AF7
OUT (F4H),A D3 F4
Maintain drive select.
6AF9
OUT (C),D ED 51
Send gap byte.
6AFD
LD D,00H 16 00
[SELF-MOD] — sync field byte.
6AFF
OUT (F4H),A D3 F4
Maintain drive select.
6B01
OUT (C),D ED 51
Send sync byte.
6B03
LD B,01H 06 01
[SELF-MOD] at 6B04H — Gap 2 count.
6B05
OUT (F4H),A D3 F4
Maintain drive select.
6B07
OUT (C),D ED 51
Send sync/gap byte.
6B0B
OUT (F4H),A D3 F4
Maintain drive select.
6B0D
OUT (C),D ED 51
Send byte.
6B0F
LD D,00H 16 00
[SELF-MOD] at 6B10H — ID sync byte.
6B11
OUT (F4H),A D3 F4
Maintain drive select.
6B13
OUT (C),D ED 51
ID sync byte 1.
6B15
OUT (F4H),A D3 F4
Maintain drive select.
6B17
OUT (C),D ED 51
ID sync byte 2.
6B19
OUT (F4H),A D3 F4
Maintain drive select.
6B1B
OUT (C),D ED 51
ID sync byte 3.
6B1D
LD D,FEH 16 FE
D = FEH — ID Address Mark.
6B1F
OUT (F4H),A D3 F4
Maintain drive select.
6B21
OUT (C),D ED 51
Send ID Address Mark (FEH).
6B23
LD D,00H 16 00
[SELF-MOD] at 6B24H — current track number.
6B25
OUT (F4H),A D3 F4
Maintain drive select.
6B27
OUT (C),D ED 51
Send track number.
6B29
LD D,00H 16 00
[SELF-MOD] at 6B2AH — side number.
6B2B
OUT (F4H),A D3 F4
Maintain drive select.
6B2D
OUT (C),D ED 51
Send side number.
6B2F
LD D,(HL) 56
D = sector number from interleave table at (HL).
6B30
INC HL 23
Advance to next interleave entry.
6B31
OUT (F4H),A D3 F4
Maintain drive select.
6B33
OUT (C),D ED 51
Send sector number.
6B35
LD D,01H 16 01
D = 01H — sector length code (256 bytes).
6B37
OUT (F4H),A D3 F4
Maintain drive select.
6B39
OUT (C),D ED 51
Send sector length (01H).
6B3B
LD D,F7H 16 F7
D = F7H — CRC generate command.
6B3D
OUT (F4H),A D3 F4
Maintain drive select.
6B3F
OUT (C),D ED 51
Send F7H — FDC generates 2-byte ID CRC.
6B41
LD D,FFH 16 FF
[SELF-MOD] at 6B42H — Gap 3 fill byte.
6B43
OUT (F4H),A D3 F4
Maintain drive select.
6B45
OUT (C),D ED 51
Gap 3 byte.
6B47
LD B,0AH 06 0A
[SELF-MOD] at 6B48H — Gap 3 count.
6B49
OUT (F4H),A D3 F4
Maintain drive select.
6B4B
OUT (C),D ED 51
Gap 3 byte.
6B4D
OUT (F4H),A D3 F4
Maintain drive select.
6B4F
OUT (C),D ED 51
Gap 3 byte.
6B51
Remaining Gap 3 bytes.
6B53
LD D,00H 16 00
D = data sync byte.
6B55
OUT (F4H),A D3 F4
Maintain drive select.
6B57
OUT (C),D ED 51
Data sync byte.
6B59
LD B,04H 06 04
[SELF-MOD] at 6B5AH — data sync count.
6B5B
OUT (F4H),A D3 F4
Maintain drive select.
6B5D
OUT (C),D ED 51
Data sync byte.
6B61
OUT (F4H),A D3 F4
Maintain drive select.
6B63
OUT (C),D ED 51
Final data sync byte.
6B65
LD D,00H 16 00
[SELF-MOD] at 6B66H — data field sync value.
6B67
OUT (F4H),A D3 F4
Maintain drive select.
6B69
OUT (C),D ED 51
Data field sync 1.
6B6B
OUT (F4H),A D3 F4
Maintain drive select.
6B6D
OUT (C),D ED 51
Data field sync 2.
6B6F
OUT (F4H),A D3 F4
Maintain drive select.
6B71
OUT (C),D ED 51
Data field sync 3.
6B73
LD D,FBH 16 FB
D = FBH — Data Address Mark.
6B75
OUT (F4H),A D3 F4
Maintain drive select.
6B77
OUT (C),D ED 51
Send Data Address Mark (FBH).
6B79
LD B,80H 06 80
B = 80H (128). Data field = 128 iterations × 2 bytes = 256 bytes.
6B7B
LD D,E5H 16 E5
[SELF-MOD] at 6B7CH — data fill byte. E5H = standard format fill.
6B7D
OUT (F4H),A D3 F4
Maintain drive select.
6B7F
OUT (C),D ED 51
Data fill byte 1.
6B81
LD D,E5H 16 E5
[SELF-MOD] at 6B82H — second fill byte per iteration.
6B83
OUT (F4H),A D3 F4
Maintain drive select.
6B85
OUT (C),D ED 51
Data fill byte 2.
6B87
128 × 2 = 256 data bytes. [DATA FILL LOOP]
6B89
LD D,F7H 16 F7
D = F7H — CRC generate.
6B8B
OUT (F4H),A D3 F4
Maintain drive select.
6B8D
OUT (C),D ED 51
Send F7H — FDC generates 2-byte data CRC.
6B8F
LD D,FFH 16 FF
[SELF-MOD] at 6B90H — inter-sector gap fill.
6B91
OUT (F4H),A D3 F4
Maintain drive select.
6B93
OUT (C),D ED 51
Inter-sector gap byte.
6B95
LD B,0AH 06 0A
[SELF-MOD] at 6B96H — inter-sector gap count.
6B97
DEC E 1D
DECrement sector countdown.
6B98
If NZ (more sectors), loop back. [SECTOR LOOP]
[GAP 4 — FILL UNTIL INDEX] — All sectors written. Pad track with gap bytes until NMI fires at the index hole.
6B9B
LD HL,0001H 21 01 00
HL = 1 — gap byte counter.
6B9E
OUT (F4H),A D3 F4
[GAP 4 FILL — INFINITE LOOP] Maintain drive select.
6BA0
OUT (C),D ED 51
Send gap fill byte.
6BA2
INC HL 23
Count gap bytes.
6BA3
Infinite loop — exits only via NMI at 6BA5H when index hole detected.
6BA5H - NMI Handler: Format Track Complete
This is the NMI (Non-Maskable Interrupt) handler that fires when the FDC detects the index hole after the Write Track command has written the entire track. The NMI signals that the track format operation is complete. The handler restores the stack pointer (from a self-modified address), disables further NMIs, restores the NMI vector at 4049H to its standard RETN instruction, reads and saves the FDC completion status, issues a Force Interrupt to halt the FDC, and re-establishes the drive select latch. Execution then falls through to the format verification section.
[NMI HANDLER ENTRY] — The CPU arrives here via the NMI vector at address 0066H, which jumps through the vector at 4049H. The stack pointer is unknown (corrupted by NMI during tight I/O loops), so it must be restored from the self-modified value at 6BA9H that was saved before the format write began.
6BA5
XOR A AF
Set Register A to 00H and clear all flags. This zero value will be used to disable NMI generation.
6BA6
OUT (E4H),A D3 E4
Output 00H to port E4H (NMI mask register) to disable all NMI sources. This prevents any further NMI interrupts from firing while the handler executes.
6BA8
LD SP,0000H 31 00 00
[SELF-MODIFYING CODE] Restore the stack pointer to the value that was saved at address 6BA9H before the format write operation began. The 0000H shown here is a placeholder; the actual SP value was patched into bytes 6BA9H–6BAAH by the format setup code.
6BAB
LD DE,45EDH 11 ED 45
Load Register Pair DE with 45EDH. This value encodes the Z80 instruction ED 45 (RETN — Return from NMI) as a two-byte sequence, stored little-endian: E=EDH (low byte at 4049H), D=45H (high byte at 404AH). This will restore the standard NMI vector.
6BAE
LD (4049H),DE ED 53 49 40
Store the RETN instruction bytes (ED 45) to the NMI vector at 4049H. The format code had previously patched this vector to point to this NMI handler (6BA5H); now we restore it to the standard RETN instruction so that any subsequent NMIs will simply return harmlessly.
6BB2
IN A,(F0H) DB F0
Read the FDC status register from port F0H into Register A. This captures the completion status of the Write Track (Format) command. The status bits indicate whether the format operation succeeded or encountered errors.
| 1793 FDC Status After Write Track (Type III) | | Status Register |
| N | F | 0 | R | C | L | D | B | | Type III Command Status Register N: 1=Not Ready, 0=Ready F: 1=Write Fault, 0=No Fault Bit 5: Unused (0) R: 1=Record Not Found, 0=Record Found C: 1=CRC Error, 0=No Error L: 1=Lost Data, 0=No Data Lost D: 1=Data Request (DRQ), 0=No Request B: 1=Busy, 0=Not Busy |
6BB4
LD B,A 47
Save the FDC status byte into Register B for later analysis. Register B will be examined after the Force Interrupt to check for format errors.
6BB5
LD A,D0H 3E D0
Load Register A with D0H — the FDC Force Interrupt command with no interrupt conditions (bits 3–0 all zero). This immediately halts any in-progress FDC command.
6BB7
OUT (F0H),A D3 F0
Send the Force Interrupt command (D0H) to the FDC command register at port F0H. This terminates the Write Track command that just completed and returns the FDC to an idle state.
| 1793 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt Bit 7-4: Command Code (1101) I3: 0=No Immediate Interrupt, 0=Disabled I2: 0=No Index Pulse Interrupt, 0=Disabled I1: 0=No Ready→Not Ready Interrupt, 0=Disabled I0: 0=No Not Ready→Ready Interrupt, 0=Disabled All 0: Terminate without interrupt |
6BB9
GOSUB to SYS0 routine at 4715H to re-establish the drive select latch. After the NMI and Force Interrupt, the drive select state may need to be refreshed by outputting the current drive select byte to port F4H.
6BBCH - Check Verify Pending Flag / FDC Status Analysis
After the NMI handler restores the system state, this section checks whether the verify-after-format step should be skipped (if bit 7 of option flags byte 3 at 5996H is set, indicating label-only verify is pending). If verify is not skipped, the FDC status from the format operation is analyzed for errors by masking with FCH (checking bits 7–2: Not Ready, Write Fault, Record Not Found, CRC Error, Lost Data, and ignoring DRQ and Busy).
6BBC
LD A,(5996H) 3A 96 59
Fetch option flags byte 3 from address 5996H into Register A. This byte contains various format option flags set during command parsing.
6BBF
BIT 7,A CB 7F
Test bit 7 of the option flags byte. Bit 7 indicates that label verify is pending — meaning the format has already been verified and we should skip directly to the double-sided toggle and track advance logic.
6BC1
If the NZ FLAG is set (bit 7 = 1, label verify pending), JUMP to 6C5BH to skip format verification and proceed to the double-sided toggle / track advance logic.
[FORMAT STATUS ANALYSIS] — Bit 7 was not set, so we proceed to check the FDC status from the Write Track command. Register B still holds the FDC status byte saved at 6BB4H.
6BC4
LD A,B 78
Copy the saved FDC status byte from Register B into Register A for bit testing.
6BC5
AND FCH E6 FC
Mask the status with FCH (11111100 binary) to isolate bits 7–2 while clearing bits 1–0 (DRQ and Busy). This checks for error conditions: Not Ready (bit 7), Write Fault (bit 6), unused (bit 5), Record Not Found (bit 4), CRC Error (bit 3), and Lost Data (bit 2).
6BC7
If any error bits are set (NZ FLAG), JUMP to the FDC error decode routine at 6C88H which identifies which specific error occurred and enters the retry/abort logic.
6BCAH - Motor Speed Range Validation
After confirming the FDC reported no errors from the Write Track command, this section validates that the disk motor speed is within acceptable limits. The NMI handler's index-hole timing provides a measurement stored in HL. Two self-modifying thresholds are compared: the lower bound at 6BCBH (if HL is below this, the motor is too fast) and the upper bound at 6BD4H (if HL is above this, the motor is too slow). Both threshold values were patched by the format setup code at 69F5H–69FDH from the timing parameter tables.
6BCA
LD BC,0000H 01 00 00
[SELF-MODIFYING CODE] Load Register Pair BC with the
motor speed lower bound. The value
0000H is a placeholder; the actual threshold was patched into bytes 6BCBH–6BCCH by the timing setup code at
69F5H. If the measured motor speed (in HL) falls below this value, the motor is spinning too fast.
6BCD
OR A B7
Clear the Carry flag to prepare for a clean 16-bit subtraction.
6BCE
SBC HL,BC ED 42
SUBtract the motor speed lower bound (Register Pair BC) from the measured speed count (Register Pair HL). If HL < BC, the Carry flag is set, meaning the motor is spinning too fast.
6BD0
If the CARRY FLAG is set (motor too fast), JUMP to 6C7CH to display the "MOTOR FAST" error message and enter the retry/abort logic.
6BD3
LD BC,007DH 01 7D 00
[SELF-MODIFYING CODE] Load Register Pair BC with the
motor speed upper tolerance range. The value
007DH is a placeholder; the actual threshold was patched into bytes 6BD4H–6BD5H by the timing setup code at
69FDH. This represents the acceptable range above the lower bound.
6BD6
OR A B7
Clear the Carry flag for the next subtraction.
6BD7
SBC HL,BC ED 42
SUBtract the upper tolerance range (Register Pair BC) from the remaining speed count (Register Pair HL, which already had the lower bound subtracted). If the result is zero or positive (No Carry), the motor speed exceeds the acceptable range and is too slow.
6BD9
If the NO CARRY FLAG is set (motor too slow), JUMP to 6C81H to display the "MOTOR SLOW" error message and enter the retry/abort logic.
[MOTOR SPEED OK] — The motor speed is within acceptable limits. Proceed to set up and execute the sector verify read-back operation.
6BDCH - Patch Read Sector Command for Verify
With the motor speed validated, this section patches the SYS0 sector read routine to use the Read Sector command (88H, with multi-record and settle delay options), restores the appropriate density setting, and then calls the sector read routine at 5C96H to perform the verify read-back of the just-formatted track.
6BDC
LD A,88H 3E 88
Load Register A with 88H — the FDC Read Sector command with multi-record mode enabled and settle delay. This command will be patched into the SYS0 read routine.
| 1793 FDC Command: 88H (10001000) | | Function Description |
| 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | | Command=Read Sector Bit 7-5: Read Command (100) m: 1=Multiple Records, 0=Single Record S: 1=Side Compare, 0=No Side Compare E: 1=15ms Settle Delay, 0=No Delay C: 1=Side 1, 0=Side 0 Bit 0: 0 |
6BDE
LD (4687H),A 32 87 46
Store the Read Sector command byte (88H) into SYS0 address 4687H, which is the location within the SYS0 disk read routine where the FDC command byte is held. This patches SYS0 to use the multi-record Read Sector command for the verify operation.
6BE1
LD A,(45F5H) 3A F5 45
Fetch the saved density/configuration byte from SYS0 address 45F5H into Register A. This byte contains the original drive select and density settings that must be restored before reading sectors back.
6BE4
LD (469EH),A 32 9E 46
Store the density/configuration byte into SYS0 address 469EH, which is the location within the SYS0 read routine where the drive select/density byte is loaded before issuing the FDC command. This ensures the verify read uses the correct density setting.
6BE7
GOSUB to 5C96H to perform the sector verify read-back operation. This routine reads sectors from the just-formatted track to verify they were written correctly. On return, Register B contains the FDC status of the read operation.
6BEAH - Sector-by-Sector Verify Loop
This section implements the sector-by-sector verify loop. For each sector on the track, it reads the interleave table entry (from the table at 6485H) to determine which physical sector to verify next, sets the FDC sector register, patches the SYS0 seek routine to skip actual head movement (since we are already on the correct track), performs a seek to update the FDC track register, re-establishes drive select, restores the seek routine, and then checks the FDC status for verify errors.
6BEA
LD HL,6485H 21 85 64
Point Register Pair HL to the sector interleave table at 6485H. This table maps logical sector order to physical sector numbers for the verify operation.
6BED
GOSUB to 6CA3H to get the sectors per track count into Register E. If the disk is double-sided, this value is halved (one side at a time).
[VERIFY SECTOR LOOP START] — Register E holds the number of sectors remaining to verify. HL points to the current entry in the interleave table at 6485H.
6BF0
INC HL 23
INCrement HL to advance to the next entry in the sector interleave table. The table entries are 1-based sector numbers; the first byte is skipped or handled elsewhere.
6BF1
LD A,(HL) 7E
Fetch the physical sector number from the current interleave table entry into Register A.
6BF2
OUT (F2H),A D3 F2
Output the physical sector number to the FDC Sector Register at port F2H. This tells the FDC which sector to read for verification.
6BF4
IN A,(F1H) DB F1
Read the current FDC Track Register value from port F1H into Register A. This saves the current track register value so it can be restored after the seek operation.
6BF6
PUSH HL E5
Save the interleave table pointer (Register Pair HL) onto the stack. It will be needed after the seek/verify to continue to the next sector.
[PATCH SEEK ROUTINE] — The SYS0 seek routine at 466FH normally steps the head to a new track. Since we are already on the correct track (just reading back what we wrote), we patch the seek routine's first byte at 46C9H to be a RET (C9H) instruction, effectively making the seek a no-op. The original byte is saved and restored afterward.
6BF7
LD HL,46C9H 21 C9 46
Point Register Pair HL to SYS0 address 46C9H, which is a byte within the SYS0 seek subroutine. This byte will be temporarily patched.
6BFA
LD D,(HL) 56
Save the original byte at 46C9H into Register D. This byte will be restored after the verify seek.
6BFB
PUSH DE D5
Save Register Pair DE onto the stack. D holds the original seek byte; E holds the sector count.
6BFC
PUSH HL E5
Save the address of the seek byte (46C9H in HL) onto the stack for later restoration.
6BFD
LD (HL),C9H 36 C9
[SELF-MODIFYING CODE] Patch the byte at 46C9H to C9H (RET instruction). This turns the SYS0 seek subroutine into an immediate return, preventing any actual head stepping during the verify. The head is already on the correct track.
6BFF
PUSH AF F5
Save Register A (the original FDC Track Register value read at 6BF4H) onto the stack.
6C00
LD A,(6B24H) 3A 24 6B
Fetch the current track number from address 6B24H (the format track counter, a self-modifying variable) into Register A.
6C03
OUT (F1H),A D3 F1
Output the current track number to the FDC Track Register at port F1H. This ensures the FDC believes the head is at the correct track for the sector read verify.
6C05
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H to serve as a dummy sector address. Since this is a verify-only read (we discard the data), the buffer address is not critical.
6C08
GOSUB to SYS0 seek routine at 466FH. Because the seek subroutine at 46C9H has been patched to RET immediately, this call effectively just sets up the FDC registers and issues the Read Sector command without moving the head. The read result status is returned in Register B.
6C0B
GOSUB to SYS0 routine at 4715H to re-establish the drive select latch after the disk I/O operation.
[RESTORE SEEK ROUTINE] — The patched seek byte, original track register value, and saved registers are now restored.
6C0E
POP AF F1
Restore the original FDC Track Register value into Register A (saved at 6BFFH).
6C0F
OUT (F1H),A D3 F1
Restore the FDC Track Register to its previous value by outputting Register A to port F1H.
6C11
POP HL E1
Restore the address of the patched seek byte (46C9H) into Register Pair HL (saved at 6BFCH).
6C12
POP DE D1
Restore Register Pair DE from the stack (saved at 6BFBH). D holds the original seek byte; E holds the remaining sector count.
6C13
LD (HL),D 72
Restore the original byte at 46C9H from Register D, undoing the RET patch and returning the SYS0 seek routine to normal operation.
6C14
POP HL E1
Restore the interleave table pointer into Register Pair HL (saved at 6BF6H).
6C15H - Verify Status Check
After each sector verify read, the FDC status (in Register B) is checked for error conditions. The mask 9CH (10011100 binary) tests for Not Ready (bit 7), Record Not Found (bit 4), CRC Error (bit 3), and Lost Data (bit 2), while ignoring Write Protect (bit 6), Deleted Data (bit 5), DRQ (bit 1), and Busy (bit 0). If no errors are found, execution branches to the multi-sector loop continuation.
6C15
LD A,B 78
Copy the FDC status byte from Register B (returned by the verify read at 466FH) into Register A for bit testing.
6C16
AND 9CH E6 9C
Mask the status with 9CH (10011100 binary) to test for: Not Ready (bit 7), Record Not Found (bit 4), CRC Error (bit 3), and Lost Data (bit 2). DRQ, Busy, Write Protect, and Deleted Data bits are ignored.
6C18
If the Z FLAG is set (all tested error bits are zero — verify succeeded), JUMP to 6C50H to continue with the next sector in the multi-sector verify loop.
6C1AH - Verify Error: Retry Logic
When a sector verify read fails, this section manages the retry logic. It decrements the retry counter at 6C94H (initialized to 0AH = 10 retries). If retries remain, execution jumps back to 6A6DH to re-do the entire format-and-verify cycle for this track. If all retries are exhausted, the code re-enables interrupts, builds an error message identifying the track and side where the failure occurred, displays it, and prompts the operator to retry or cancel.
[ERROR PATH] — A sector verify read failed. The retry counter at 6C94H controls how many automatic retries are attempted before prompting the operator.
6C1A
LD HL,6C94H 21 94 6C
Point Register Pair HL to the
retry counter at address
6C94H. This is a self-modifying variable within the LD A instruction at 6C93H; its initial value of 0AH (10 decimal) was set at
6A68H.
6C1D
DEC (HL) 35
DECrement the retry counter by 1.
6C1E
If the NZ FLAG is set (retries remaining), JUMP back to 6A6DH to re-initialize the drive and retry the entire format-and-verify cycle for this track.
[RETRIES EXHAUSTED] — All automatic retries have failed. Build and display an error message, then prompt the operator.
6C21
EI FB
Re-enable interrupts. Interrupts were disabled during the format and verify operations for timing-critical FDC I/O; they must be re-enabled before calling display and keyboard routines.
6C22
LD HL,6EAAH 21 AA 6E
Point Register Pair HL to the side 0 error message component at 6EAAH. This 5-byte string is used when the error occurred on side 0 of a double-sided disk (or the only side of a single-sided disk).
6C25
LD A,(6C62H) 3A 62 6C
Fetch the current side indicator from address 6C62H (a self-modifying variable). 00H = side 0, 01H = side 1.
6C28
OR A B7
Test whether the side indicator is zero (side 0).
6C29
If the Z FLAG is set (side 0), JUMP to 6C2EH to continue with the side 0 message component already loaded in HL.
6C2B
LD HL,6EAFH 21 AF 6E
Point Register Pair HL to the side 1 error message component at 6EAFH. This replaces the side 0 component when the error occurred on side 1.
6C2E
LD DE,6E95H 11 95 6E
Point Register Pair DE to the error message build area at 6E95H. The side indicator string (5 bytes from HL) will be copied here to assemble the complete error message.
6C31
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H (5 bytes) as the block transfer count — the length of the side indicator component string.
6C34
LDIR ED B0
Block copy 5 bytes from the side indicator string (pointed to by HL) to the error message build area at 6E95H (pointed to by DE). This patches the correct side number ("0" or "1") into the error message template.
6C36
LD HL,6E88H 21 88 6E
Point Register Pair HL to the beginning of the format error message template at 6E88H. This template contains the assembled error string including track number placeholder and side indicator.
6C39
GOSUB to SYS0 routine at 4467H to display the error message string pointed to by HL. This prints the format error message (e.g., "FORMAT ERROR TRK nn SIDE n") to the screen.
6C3C
LD A,(6B24H) 3A 24 6B
Fetch the current track number from address 6B24H into Register A. This is the track where the format verify error occurred.
6C3F
LD E,A 5F
Copy the track number into Register E (low byte of DE) for the decimal display routine.
6C40
LD D,00H 16 00
Clear Register D (high byte of DE) so DE contains the 16-bit track number (0–34).
6C42
GOSUB to 5909H to display the track number in Register Pair DE as a decimal number on screen.
6C45
GOSUB to 5881H to output a carriage return character, advancing the display to the next line.
6C48
GOSUB to 58C8H to display an operator prompt (e.g., "RETRY? (Y/N)") and wait for a response. Returns NZ if the operator chose to retry.
6C4B
If the NZ FLAG is set (operator chose to retry), JUMP to 6A68H to reset the retry counter and re-attempt the format-and-verify cycle for this track.
6C4E
If the operator declined to retry (Z FLAG), JUMP to 6C5BH to skip the remaining verify and proceed to the double-sided toggle / track advance logic.
6C50H - Multi-Sector Verify Loop Continuation
After a successful sector verify, this section decrements the remaining sector count and loops back to verify the next sector. When E reaches 1, the interleave table is indexed differently (using the first entry at 6485H directly). When all sectors are verified, execution falls through to the double-sided toggle logic.
6C50
DEC E 1D
DECrement Register E (remaining sector count) by 1. One more sector has been successfully verified.
6C51
LD A,01H 3E 01
Load Register A with 01H for comparison. When the sector count reaches 1, the last sector must be handled specially.
6C53
CP E BB
Compare Register A (01H) against Register E (remaining sector count). If E > 1, the Carry flag is set; if E = 1, the Z flag is set; if E < 1 (= 0, all done), neither flag is set.
6C54
If the CARRY FLAG is set (more than 1 sector remaining, i.e., E > 1), JUMP back to 6BF0H to increment the interleave table pointer and verify the next sector.
6C56
LD A,(6485H) 3A 85 64
Fetch the first entry from the sector interleave table at 6485H into Register A. When exactly 1 sector remains (Z flag from the CP), this entry provides the last sector number to verify.
6C59
If the Z FLAG is set (exactly 1 sector remaining), JUMP to 6BF2H to output this sector number to the FDC Sector Register and verify it. This bypasses the INC HL at 6BF0H since we loaded the sector number directly from 6485H.
[ALL SECTORS VERIFIED] — When E = 0 (no sectors remaining), neither Carry nor Zero is set by the CP at 6C53H, so execution falls through to the double-sided toggle logic at 6C5BH.
6C5BH - Double-Sided Disk Toggle
After all sectors on the current side of the current track have been formatted and verified (or skipped), this section handles double-sided disks. It checks IY+07H bit 6 (the double-sided flag in the drive parameter block). If the disk is double-sided and we just finished side 0, the side indicator at 6C62H is toggled from 0 to 1 and execution jumps back to 6A02H to format side 1 of the same track. If we just finished side 1 (or the disk is single-sided), execution falls through to the track advance logic.
6C5B
BIT 6,(IY+07H) FD CB 07 76
Test bit 6 of IY+07H (byte offset 07H in the PDRIVE parameter block at IY base 4280H, address 4287H). Bit 6 indicates whether this disk drive is double-sided (1 = double-sided, 0 = single-sided).
6C5F
If the Z FLAG is set (bit 6 = 0, single-sided disk), JUMP to 6C6EH to skip the side toggle and proceed directly to the track advance logic.
6C61
LD A,00H 3E 00
[SELF-MODIFYING CODE] Load Register A with the current side indicator. The value at address 6C62H toggles between 00H (side 0) and 01H (side 1) as each side is formatted. This byte is modified by the XOR and LD instructions that follow.
6C63
XOR 01H EE 01
Toggle bit 0 of Register A: if it was 00H (side 0), it becomes 01H (side 1), and vice versa.
6C65
LD (6C62H),A 32 62 6C
[SELF-MODIFYING CODE] Store the toggled side indicator back to address 6C62H (the immediate operand of the LD A instruction at 6C61H). This updates the side state for the next pass.
6C68
If the Z FLAG is set (the XOR result was zero, meaning the side indicator just toggled back to 00H — i.e., we just finished side 1 and reset to side 0), JUMP to 6C6EH for track advance. Both sides of this track are now complete.
6C6A
XOR A AF
Set Register A to 00H and clear all flags. This zero value will be used as a parameter for the format side 1 entry point.
6C6B
JUMP to 6A02H to format side 1 of the current track. Address 6A02H is the format track entry that adjusts the sector start for the current side and begins the Write Track operation for side 1.
6C6EH - Track Advance Logic
After both sides (or the only side) of the current track have been formatted and verified, this section advances to the next track. The track counter at 6B24H is incremented and compared against 23H (35 decimal, the total number of tracks on a standard TRS-80 disk: tracks 0–34). If all tracks are done, the routine returns to the caller. Otherwise, the geometry is updated and the format process continues with the next track.
6C6E
LD HL,6B24H 21 24 6B
Point Register Pair HL to the current track counter at address 6B24H. This self-modifying variable holds the track number being formatted (0–34).
6C71
INC (HL) 34
INCrement the track counter by 1, advancing to the next track.
6C72
LD A,(HL) 7E
Load the updated track number into Register A for comparison.
6C73
CP 23H FE 23
Compare the track number against 23H (35 decimal). TRS-80 disks use tracks 0 through 34 — when the counter reaches 35, all tracks have been formatted.
6C75
RET Z C8
If the Z FLAG is set (track counter = 35, all tracks formatted), RETurn to the caller. The disk format operation is complete.
6C76
GOSUB to 6CAEH to update the disk geometry parameters (motor delay, seek to the new track) after advancing to the next track.
6C79
JUMP to 6A00H to begin formatting the next track. This is the top of the main format loop that handles sector interleave setup and Write Track command for each track.
6C7CH - Error Exits: Motor Speed and FDC Errors
These are the error exit paths for motor speed violations and FDC errors detected during format or verify operations. Motor speed errors load a pointer to the appropriate error message ("MOTOR FAST" or "MOTOR SLOW") and set Register B to FFH (a special error code indicating a motor speed problem). FDC errors are decoded by rotating the status byte to find the highest set error bit and recording its position in Register B. All paths converge at 6C93H for retry or abort handling.
[MOTOR TOO FAST ERROR]
6C7C
LD HL,6D6BH 21 6B 6D
Point Register Pair HL to the "MOTOR FAST" error message string at address 6D6BH.
6C7F
JUMP to 6C84H to set the motor speed error code and enter the retry logic.
[MOTOR TOO SLOW ERROR]
6C81
LD HL,6D76H 21 76 6D
Point Register Pair HL to the "MOTOR SLOW" error message string at address 6D76H.
6C84
LD B,FFH 06 FF
Load Register B with FFH as a special error code indicating a motor speed error (as opposed to an FDC status error). This distinguishes motor problems from FDC controller errors in the retry logic at 6C9CH.
6C86
JUMP to 6C93H to enter the retry/abort logic with the motor speed error code.
[FDC ERROR DECODE] — Register A contains the FDC status byte (masked with FCH at 6BC5H). This loop rotates A left, counting the bit position of the highest set error bit into Register B.
6C88
LD B,11H 06 11
Load Register B with 11H (17 decimal) as the initial error code counter. As A is rotated left, B is decremented for each zero bit until a set bit is found. The final value of B identifies which error bit was set.
6C8A
DEC B 05
[LOOP START] DECrement the error code counter in Register B by 1.
6C8B
RLCA 07
Rotate Register A left through carry. The highest bit of A shifts into the Carry flag. If this bit was set, the Carry flag will be set and the loop ends.
6C8C
If the NO CARRY FLAG is set (current bit was 0, not an error bit), loop back to 6C8AH to try the next bit. [LOOP END when Carry is set]
6C8E
LD A,B 78
Copy the error code from Register B into Register A. This value identifies which FDC status bit caused the error (e.g., 10H=Not Ready, 0FH=Write Fault, etc.).
6C8F
CP 0FH FE 0F
Compare the error code against 0FH (15 decimal). Error code 0FH corresponds to a specific FDC error (Write Fault, bit 6). If this specific error occurred, the format may need special handling.
6C91
If the Z FLAG is set (error code = 0FH, Write Fault), JUMP to 6CA1H to exit with an unrecoverable error (OR A / RET sets flags and returns).
6C93H - Retry or Abort Decision
This is the common retry/abort entry point for all format errors (motor speed and FDC errors). The retry counter at 6C94H is decremented; if retries remain, execution jumps back to 6A6DH to re-attempt the format. If retries are exhausted, the error code in Register B is checked for specific conditions before returning with error status.
6C93
LD A,00H 3E 00
[SELF-MODIFYING CODE] Load Register A with the
retry counter. The value at address
6C94H was initialized to 0AH (10 decimal) at
6A68H and is decremented on each retry attempt. The 00H shown is the initial placeholder before the first format attempt patches it.
6C95
DEC A 3D
DECrement the retry counter by 1.
6C96
LD (6C94H),A 32 94 6C
[SELF-MODIFYING CODE] Store the updated retry counter back to address 6C94H (the immediate operand of the LD A instruction at 6C93H).
6C99
If the NZ FLAG is set (retries remaining), JUMP to 6A6DH to re-initialize the drive and retry the format-and-verify operation for this track.
[RETRIES EXHAUSTED — CHECK ERROR TYPE] — All retries are used up. Check the error code in Register B for specific conditions.
6C9C
LD A,B 78
Copy the error code from Register B into Register A for comparison.
6C9D
CP 0BH FE 0B
Compare the error code against 0BH (11 decimal). Error code 0BH corresponds to CRC Error (bit 3 of FDC status). CRC errors during format verify can sometimes be recovered by re-enabling interrupts and prompting the operator (the path at 6C21H).
6C9F
If the Z FLAG is set (error code = 0BH, CRC Error), JUMP to 6C21H to re-enable interrupts, display the error message with track/side information, and prompt the operator for a manual retry.
[UNRECOVERABLE ERROR] — The error is not a CRC error, so it cannot be retried. Return with flags set to indicate failure.
6CA1
OR A B7
Set flags based on Register A. Since A holds a non-zero error code, the NZ flag will be set, indicating an error condition to the caller.
6CA2
RET C9
RETurn to the caller with NZ flag set, signaling that the format operation failed with an unrecoverable error.
6CA3H - Helper: Get Sectors Per Track
This small helper routine retrieves the sectors-per-track value from the PDRIVE parameter block at IY+04H and halves it if the disk is double-sided (since each side contains half the total sectors per track for format purposes).
6CA3
LD E,(IY+04H) FD 5E 04
Fetch the sectors per track value from byte offset 04H of the PDRIVE parameter block (IY base 4280H, address 4284H) into Register E.
6CA6
BIT 6,(IY+07H) FD CB 07 76
Test bit 6 of IY+07H (address 4287H), the double-sided flag in the PDRIVE parameter block. Bit 6 = 1 means the disk is double-sided.
6CAA
RET Z C8
If the Z FLAG is set (bit 6 = 0, single-sided disk), RETurn with the full sectors-per-track count in Register E.
6CAB
SRL E CB 3B
Shift Register E right by 1 bit (logical shift, zero fills from left), effectively dividing the sectors-per-track by 2. For a double-sided disk, each side contains half the total sectors per track.
6CAD
RET C9
RETurn with the halved sectors-per-track count in Register E.
6CAEH - Helper: Update Geometry After Track Advance
This helper routine is called after advancing to a new track. It checks bit 2 of the PDRIVE flags at 4287H (which indicates double-density mode), conditionally calls itself at 6CB6H (a quirk of the code layout where 6CB6H is the LD BC,0100H instruction that follows), performs a motor delay via SYS0 routine 4C92H, and then seeks to the new track position via SYS0 routine 46F7H.
6CAE
LD A,(4287H) 3A 87 42
Fetch byte 07H of the PDRIVE parameter block from address 4287H into Register A. This byte contains drive configuration flags including the double-density bit.
6CB1
BIT 2,A CB 57
Test bit 2 of the PDRIVE flags byte. Bit 2 indicates double-density mode (1 = DD enabled, 0 = SD only).
6CB3
If the NZ FLAG is set (bit 2 = 1, double-density mode), GOSUB to 6CB6H. This is a conditional call to the next instruction — when the call executes, the LD BC,0100H at 6CB6H runs as a subroutine (loading BC and then falling through to the motor delay and seek). When the CALL does not execute, the same code runs inline. This effectively executes the motor delay and seek twice for double-density disks (once as a subroutine, once inline), providing the extra settling time DD operations require.
6CB6
LD BC,0100H 01 00 01
Load Register Pair BC with 0100H. B=01H (loop count), C=00H (parameter). This sets up the parameters for the SYS0 motor delay routine.
6CB9
GOSUB to SYS0 utility routine at 4C92H to perform a motor delay. This provides time for the drive motor speed to stabilize after any head movement or density change.
6CBC
LD C,58H 0E 58
Load Register C with 58H (88 decimal) as the step time parameter for the seek operation.
6CBE
JUMP to SYS0 routine at 46F7H to seek the drive head to the new track position. This routine uses the step time in C and the target track from the track counter. Execution returns to the caller of 6CAEH via the RET inside 46F7H.
6CC1H - Format Timing Parameter Tables
These four 26-byte tables contain timing parameters used by the format track write routine. Each table is calibrated for a specific combination of recording density and CPU/drive speed. The format setup code at 6959H–69C3H selects the appropriate table and patches its values into self-modifying code locations throughout the format write routine. The tables control gap lengths, sync byte counts, data mark timing, and other critical values that must be precisely timed for the FDC to correctly write sector headers and data fields.
Table 0 (6CC1H–6CDAH): Single Density, Low-Speed Drive — 26 bytes of timing parameters for formatting in FM (single density) mode on a standard-speed (1 MHz class) drive.
6CC1
DEFB FF,00,E5,E5,09 FF 00 E5 E5 09
Bytes 0–4: FF=marker, 00=base delay, E5=fill byte, E5=fill byte, 09=gap length parameter.
6CC6
DEFB 01,09,01 01 09 01
Bytes 5–7: 01=sync count, 09=ID field gap, 01=data mark offset.
6CC9
DEFB 2C 2C
Byte 8: 2CH=inter-sector gap 3 length (44 decimal).
6CCA
DEFB 01,EC,0B 01 EC 0B
Bytes 9–11: 01=loop parameter, ECH=timing constant, 0BH=gap 4 parameter.
6CCD
DEFB 0B,00,3E,00 0B 00 3E 00
Bytes 12–15: 0BH=additional timing, 00=padding, 3EH=data field timing, 00=padding.
6CD1
DEFB 02,02,00,00 02 02 00 00
Bytes 16–19: 02=CRC byte count, 02=CRC byte count, 00=reserved, 00=reserved.
6CD5
DEFB 00,00,00,00,00,00 00 00 00 00 00 00
Bytes 20–25: Reserved/padding (all 00H).
Table 1 (6CDBH–6CF4H): Single Density, High-Speed Drive — 26 bytes of timing parameters for formatting in FM mode on a high-speed (2 MHz class) drive.
6CDB
DEFB FF,00,E5,E5,08 FF 00 E5 E5 08
Bytes 0–4: FF=marker, 00=base delay, E5=fill byte, E5=fill byte, 08=gap length (shorter for higher speed).
6CE0
DEFB 01,09,01 01 09 01
Bytes 5–7: 01=sync count, 09=ID field gap, 01=data mark offset.
6CE3
DEFB 2B 2B
Byte 8: 2BH=inter-sector gap 3 length (43 decimal — slightly shorter for higher speed).
6CE4
DEFB 01,E6,13 01 E6 13
Bytes 9–11: 01=loop parameter, E6H=timing constant (adjusted for speed), 13H=gap 4 parameter.
6CE7
DEFB 0A,00,68,00 0A 00 68 00
Bytes 12–15: 0AH=additional timing, 00=padding, 68H=data field timing (longer for speed), 00=padding.
6CEB
DEFB 04,03,00,00 04 03 00 00
Bytes 16–19: 04=CRC timing, 03=CRC timing, 00=reserved, 00=reserved.
6CEF
DEFB 00,00,00,00,00,00 00 00 00 00 00 00
Bytes 20–25: Reserved/padding (all 00H).
Table 2 (6CF5H–6D0EH): Double Density, Low-Speed Drive — 26 bytes of timing parameters for formatting in MFM (double density) mode on a standard-speed drive.
6CF5
DEFB 4E,F5,6D,B6,0E 4E F5 6D B6 0E
Bytes 0–4: 4EH=gap fill byte (MFM standard), F5H=MFM write splice mark, 6DH=parameter, B6H=parameter, 0EH=gap length.
6CFA
DEFB 06,14,0A 06 14 0A
Bytes 5–7: 06=sync byte count (MFM uses more syncs), 14H=ID field gap (20 decimal), 0AH=data mark offset.
6CFD
DEFB 4A 4A
Byte 8: 4AH=inter-sector gap 3 length (74 decimal — longer for double density).
6CFE
DEFB 01,DD,17 01 DD 17
Bytes 9–11: 01=loop parameter, DDH=timing constant, 17H=gap 4 parameter.
6D01
DEFB 10,00,7D,00 10 00 7D 00
Bytes 12–15: 10H=additional timing, 00=padding, 7DH=data field timing, 00=padding.
6D05
DEFB 04,03,00,00 04 03 00 00
Bytes 16–19: 04=CRC timing, 03=CRC timing, 00=reserved, 00=reserved.
6D09
DEFB 00,00,00,00,00,00 00 00 00 00 00 00
Bytes 20–25: Reserved/padding (all 00H).
Table 3 (6D0FH–6D28H): Double Density, High-Speed Drive — 26 bytes of timing parameters for formatting in MFM mode on a high-speed drive.
6D0F
DEFB 4E,F5,6D,B6,34 4E F5 6D B6 34
Bytes 0–4: 4EH=gap fill byte (MFM), F5H=MFM write splice mark, 6DH=parameter, B6H=parameter, 34H=gap length (52 decimal — much longer for high-speed DD).
6D14
DEFB 0A,26,0A 0A 26 0A
Bytes 5–7: 0AH=sync byte count (more syncs needed at higher speed), 26H=ID field gap (38 decimal), 0AH=data mark offset.
6D17
DEFB 86 86
Byte 8: 86H=inter-sector gap 3 length (134 decimal — significantly longer for high-speed DD).
6D18
DEFB 01,9C,27 01 9C 27
Bytes 9–11: 01=loop parameter, 9CH=timing constant, 27H=gap 4 parameter.
6D1B
DEFB 44,00,D0,00 44 00 D0 00
Bytes 12–15: 44H=additional timing, 00=padding, D0H=data field timing, 00=padding.
6D1F
DEFB 05,04,00,00 05 04 00 00
Bytes 16–19: 05=CRC timing, 04=CRC timing, 00=reserved, 00=reserved.
6D23
DEFB 00,00,00,00,00,00 00 00 00 00 00 00
Bytes 20–25: Reserved/padding (all 00H).
6D29H - Reserved/Padding Area
This area from 6D29H to 6D5CH is filled with 00H bytes. It serves as reserved padding between the timing parameter tables and the message string pool that follows. The last three bytes (6D5AH–6D5CH) are also 00H.
6D29
DEFB 00H (52 bytes) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
52 bytes of 00H padding from 6D29H through 6D5CH. This reserved area provides space between the format timing tables and the message strings. All bytes are zero.
6D5DH - Format Parameter Bytes
Three bytes of format parameter data referenced by the format initialization code. These values provide default track and sector configuration information used during command parsing.
6D5D
DEFB 1CH 1C
Value 1CH (28 decimal) — default parameter byte (track count or offset value used by format initialization).
6D5E
DEFB 1FH 1F
Value 1FH (31 decimal) — default parameter byte (sector count or limit value).
6D5F
DEFB 03H 03
Value 03H — ETX (End of Text) marker, serving as a string/data terminator.
6D60H - Message String Pool
This is the main message string pool for SYS6. All user-visible messages displayed during FORMAT, COPY, and BACKUP operations are stored here as ASCII text terminated by 0DH (carriage return), 0AH (line feed + CR), or 03H (ETX — used when the message continues with additional output such as a filename or number). These strings are displayed by calling the SYS0 display routine at 4467H with HL pointing to the start of the string.
6D60
DEFM "FORMATTING" + 0DH 46 4F 52 4D 41 54 54 49 4E 47 0D
11 bytes: "FORMATTING" followed by carriage return (0DH). Displayed when the FORMAT operation begins writing track data to the disk.
6D6B
DEFM "MOTOR FAST" + 0DH 4D 4F 54 4F 52 20 46 41 53 54 0D
11 bytes:
"MOTOR FAST" followed by carriage return (0DH). Displayed when motor speed validation at
6BCAH detects the drive motor is spinning too fast for reliable formatting.
6D76
DEFM "MOTOR SLOW" + 0DH 4D 4F 54 4F 52 20 53 4C 4F 57 0D
11 bytes:
"MOTOR SLOW" followed by carriage return (0DH). Displayed when motor speed validation at
6BCAH detects the drive motor is spinning too slowly for reliable formatting.
6D81
DEFM "DISKETTE HAS DATA" + 0DH 44 49 53 4B 45 54 54 45 20 48 41 53 20 44 41 54 41 0D
18 bytes: "DISKETTE HAS DATA" followed by carriage return (0DH). Warning displayed when a FORMAT command is attempted on a disk that already contains data, giving the user a chance to abort before overwriting.
6D93
DEFM "UNREADABLE DISKETTE" + 0DH 55 4E 52 45 41 44 41 42 4C 45 20 44 49 53 4B 45 54 54 45 0D
20 bytes:
"UNREADABLE DISKETTE" followed by carriage return (0DH). Displayed when the disk detection code at
67C5H cannot read any valid sectors, indicating a blank, damaged, or incompatible diskette.
6DA7
DEFM "DISKETTE OLD NAME/DATE = " + 03H 44 49 53 4B 45 54 54 45 20 4F 4C 44 20 4E 41 4D 45 2F 44 41 54 45 20 3D 20 03
26 bytes: "DISKETTE OLD NAME/DATE = " followed by ETX (03H). Displayed during FORMAT when a previously named diskette is being reformatted. The ETX terminator signals that additional output (the actual old name and date) follows immediately.
6DC1
DEFM "DISKETTE NAME MISMATCH" + 0AH + 0DH 44 49 53 4B 45 54 54 45 20 4E 41 4D 45 20 4D 49 53 4D 41 54 43 48 0A 0D
24 bytes: "DISKETTE NAME MISMATCH" followed by line feed (0AH) and carriage return (0DH). Warning displayed during COPY or BACKUP when the destination diskette's name does not match the expected name, indicating a possible wrong disk insertion.
6DD9
DEFM "INITIALIZING SYSTEM DATA" + 0DH 49 4E 49 54 49 41 4C 49 5A 49 4E 47 20 53 59 53 54 45 4D 20 44 41 54 41 0D
25 bytes: "INITIALIZING SYSTEM DATA" followed by carriage return (0DH). Displayed after formatting is complete, when the boot sector, directory, and system allocation tables are being written to the freshly formatted disk.
6DF2
DEFM "STARTING DISKETTE FORMAT" + 0DH 53 54 41 52 54 49 4E 47 20 44 49 53 4B 45 54 54 45 20 46 4F 52 4D 41 54 0D
25 bytes: "STARTING DISKETTE FORMAT" followed by carriage return (0DH). Displayed as the initial status message when a FORMAT operation begins.
6E0B
DEFM "STARTING DISKETTE COPY" + 0DH 53 54 41 52 54 49 4E 47 20 44 49 53 4B 45 54 54 45 20 43 4F 50 59 0D
23 bytes: "STARTING DISKETTE COPY" followed by carriage return (0DH). Displayed as the initial status message when a COPY or BACKUP operation begins.
6E22
DEFM "ARE SYSTEM AND " + 03H 41 52 45 20 53 59 53 54 45 4D 20 41 4E 44 20 03
16 bytes: "ARE SYSTEM AND " followed by ETX (03H). First part of a two-part prompt asking whether the system and target diskettes are the same physical disk. The ETX signals that additional text follows.
6E32
DEFM "THE SAME DISKETTE?" + 03H 54 48 45 20 53 41 4D 45 20 44 49 53 4B 45 54 54 45 3F 03
19 bytes: "THE SAME DISKETTE?" followed by ETX (03H). Second part of the two-part prompt. Combined with 6E22H, the full message reads: "ARE SYSTEM AND THE SAME DISKETTE?"
6E45
DEFM "FORMAT DISKETTE?" + 03H 46 4F 52 4D 41 54 20 44 49 53 4B 45 54 54 45 3F 03
17 bytes: "FORMAT DISKETTE?" followed by ETX (03H). Confirmation prompt displayed before a FORMAT operation begins, giving the operator a chance to abort.
6E56
DEFM "EITHER BAD PARAMETER OR CONFLICT WITH PDRIVE DATA" + 0DH 45 49 54 48 45 52 20 42 41 44 20 50 41 52 41 4D 45 54 45 52 20 4F 52 20 43 4F 4E 46 4C 49 43 54 20 57 49 54 48 20 50 44 52 49 56 45 20 44 41 54 41 0D
50 bytes:
"EITHER BAD PARAMETER OR CONFLICT WITH PDRIVE DATA" followed by carriage return (0DH). Error message displayed when FORMAT or COPY command parameters are invalid or conflict with the PDRIVE configuration table settings for the target drive. Referenced at
6747H.
6E88H - Format Error Message Template
This is the composite format error message template used when a format verify operation fails after all retries are exhausted. The message is constructed from multiple components: the prefix "CAN'T FORMAT " at 6E88H, a side indicator area at 6E95H (5 bytes that are overwritten with either "FRONT" or " BACK"), followed by the fixed text "SIDE OF TRACK " and an ETX terminator (03H). The track number is appended by the display routine at 5909H. The two 5-byte side indicator source strings are stored at 6EAAH ("FRONT") and 6EAFH (" BACK").
6E88
DEFM "CAN'T FORMAT " 43 41 4E 27 54 20 46 4F 52 4D 41 54 20
13 bytes: "CAN'T FORMAT " — the prefix of the format error message. The trailing space separates it from the side indicator that follows at 6E95H.
6E95
DEFM "FRONT" 46 52 4F 4E 54
5 bytes:
"FRONT" — the
side indicator build area. These 5 bytes are overwritten at runtime by the retry logic at
6C2EH with either "FRONT" (from 6EAAH for side 0) or " BACK" (from 6EAFH for side 1).
6E9A
DEFM " SIDE OF TRACK " + 03H 20 53 49 44 45 20 4F 46 20 54 52 41 43 4B 20 03
16 bytes:
" SIDE OF TRACK " followed by ETX (03H). The remainder of the error message template. After the ETX terminator, the code at
6C42H appends the track number as a decimal value. The complete message reads: "CAN'T FORMAT FRONT SIDE OF TRACK nn" or "CAN'T FORMAT BACK SIDE OF TRACK nn".
6EAA
DEFM "FRONT" 46 52 4F 4E 54
5 bytes: "FRONT" — the side 0 indicator source string. This is copied to the build area at 6E95H when the format error occurred on side 0 (the front side of the disk).
6EAF
DEFM " BACK" 20 42 41 43 4B
5 bytes: " BACK" — the side 1 indicator source string. This is copied to the build area at 6E95H when the format error occurred on side 1 (the back side of the disk). The leading space aligns the text visually.
6EB4H - Skip Whitespace and Validate Input
This utility routine skips leading whitespace characters in the input buffer pointed to by HL, then validates that the current character is not a carriage return (end of input). It calls 6EBFH to check for CR, and if not CR, calls the SYS0 whitespace-skip routine at 4C7EH. The routine returns with Z set if the input is at end-of-line (CR found), or with HL pointing past the whitespace and the first non-whitespace character in A.
6EB4
GOSUB to 6EBFH to check if the current character at (HL) is a carriage return (0DH). Returns Z if CR found (end of input).
6EB7
RET Z C8
If the Z FLAG is set (character is CR — end of input line), RETurn immediately to the caller with Z set, signaling no more input to process.
6EB8
GOSUB to SYS0 routine at 4C7EH to skip whitespace characters (spaces and tabs) in the input buffer. On return, HL points to the first non-whitespace character and A contains that character. Carry is set if a valid non-whitespace character was found.
6EBB
RET C D8
If the CARRY FLAG is set (a valid non-whitespace character was found), RETurn to the caller with the character in A and HL pointing to it. Carry set indicates success — valid input found.
6EBC
RET Z C8
If the Z FLAG is set (the whitespace skip routine hit end-of-input), RETurn with Z set indicating no valid input remains.
6EBD
DEC HL 2B
DECrement HL to back up one position in the input buffer. This compensates for the 4C7EH routine having advanced past a character that is neither whitespace nor a valid input character.
6EBE
RET C9
RETurn to the caller with HL adjusted and neither Carry nor Zero set, indicating an invalid character was encountered.
6EBFH - Check for Carriage Return
A tiny helper that fetches the character at (HL) and compares it against 0DH (carriage return). Returns Z if the character is CR (end of input line).
6EBF
LD A,(HL) 7E
Fetch the character at the current input buffer position (pointed to by HL) into Register A.
6EC0
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). If the character is CR, the Z FLAG is set, indicating end-of-input.
6EC2
RET Z C8
If the Z FLAG is set (character is carriage return), RETurn to the caller immediately. Z flag signals end of input line.
6EC3H - Skip Whitespace with Error Exit
Similar to 6EB4H, this routine skips whitespace in the input buffer using SYS0 routine 4C7EH. If no valid input character is found (the skip routine returns No Carry and No Zero), the code jumps to the error handler at 521AH. This enforces that the next input token must be present.
6EC3
GOSUB to SYS0 routine at 4C7EH to skip whitespace characters in the input buffer pointed to by HL. Returns with Carry set if a valid character is found, or NC if end-of-input or invalid.
6EC6
RET NC D0
If the NO CARRY FLAG is set (no valid character found — either end of input or invalid data), RETurn to the caller. The NC condition is then checked by the caller.
6EC7
If Carry was set (a character was found but it is invalid in context), JUMP to the error handler at 521AH. This is a syntax error — the input contains an unexpected character where a valid token was required.
6ECAH - Parse Drive Number from Input
This routine parses a drive number specification from the input buffer. It checks for an optional colon prefix, converts the ASCII digit to a binary drive number (0–9), validates it against the system maximum, and sets up the drive for subsequent operations. Returns with Carry set and drive number in A/E on success.
6ECA
LD A,(HL) 7E
Fetch the current input character from the buffer position pointed to by HL into Register A.
6ECB
CP 3AH FE 3A
Compare Register A against 3AH (ASCII : colon). A colon prefix before the drive number is optional in NEWDOS/80 syntax (e.g., ":0" or just "0").
6ECD
If the NZ FLAG is set (character is not a colon), JUMP to 6ED0H to process the character as a digit directly.
6ECF
INC HL 23
INCrement HL to skip past the colon character and advance to the drive digit.
6ED0
LD A,(HL) 7E
Fetch the drive digit character from the input buffer into Register A.
6ED1
SUB 30H D6 30
SUBtract 30H (ASCII '0') from Register A, converting the ASCII digit character to its binary value (0–9). If the character was not a digit, the result will be negative (Carry set) or >= 10.
6ED3
CP 0AH FE 0A
Compare the binary value against 0AH (10 decimal). Valid drive numbers are 0–9. If A >= 10, the character was not a valid digit and the NO CARRY flag is set.
6ED5
RET NC D0
If the NO CARRY FLAG is set (value >= 10, invalid drive number), RETurn to the caller with NC indicating failure — the input did not contain a valid drive digit.
6ED6
GOSUB to 6EE6H to parse and validate the drive number as a decimal value, returning the result in Register Pair DE.
6ED9
GOSUB to SYS0 routine at 4723H to initialize the specified drive. This routine validates the drive number in E against the system configuration and sets up the drive parameter block. Returns NZ on error.
6EDC
If the NZ FLAG is set (drive initialization failed — invalid drive number or drive not available), JUMP to 6EC7H which falls through to the error handler at 521AH.
6EDE
LD A,E 7B
Copy the validated drive number from Register E into Register A for the caller.
6EDF
SCF 37
Set the Carry flag to signal success — a valid drive number was parsed and the drive has been initialized.
6EE0
RET C9
RETurn to the caller with Carry set (success), drive number in A and E.
6EE1H - Parse Hex Number from Input
This routine parses a hexadecimal number from the input buffer. It calls 6EF0H to parse with hex digit support enabled (bit 0 of B set), then validates the result is not too large. Used for parsing hex addresses or values in command options.
6EE1
GOSUB to 6EF0H to parse a hexadecimal number from the input. This routine enables hex digit parsing (letters A–F) and returns the parsed value in Register Pair DE.
6EE4
JUMP to 6EE9H to validate the parsed result and check for overflow.
6EE6H - Parse Decimal Number from Input
This routine parses a decimal number from the input buffer. It calls 6F0EH to parse with decimal-only mode (no hex letters), then validates the result. Used for parsing numeric parameters like drive numbers and track counts.
6EE6
GOSUB to 6F0EH to parse a decimal number from the input. This routine disables hex digit parsing (only accepts 0–9) and returns the parsed value in Register Pair DE.
6EE9
LD A,D 7A
Load the high byte of the parsed number from Register D into Register A for overflow check.
6EEA
OR A B7
Test whether the high byte of the result is zero. If D is non-zero, the parsed number is larger than 255 (too large for most SYS6 parameters).
6EEB
LD A,E 7B
Load the low byte of the parsed number from Register E into Register A. If D was zero, then A now contains the complete 8-bit result.
6EEC
RET Z C8
If the Z FLAG is set (D was zero — result fits in 8 bits), RETurn with the parsed value in Register A and E. This is the success exit.
6EED
If D was non-zero (number overflow — value too large), JUMP to 5218H to display an error message and abort the command.
6EF0H - Parse Hex Number with "H" Suffix Detection
This routine parses a number from the input that may be hexadecimal. It saves HL, calls the number accumulator at 6F13H (which uses 6F15H internally), and then checks whether the number is followed by an "H" suffix (indicating hex). If the character after the digits is "H" (48H), the number is treated as hexadecimal; if not, it is treated as decimal. Register B bit 0 controls whether hex letters A–F are accepted: bit 0 = 1 means hex mode.
6EF0
PUSH HL E5
Save the current input buffer pointer onto the stack. If the parse fails or the number turns out to be decimal, HL can be restored.
6EF1
GOSUB to 6F13H to initialize Register B to 00H and then call the number accumulator at 6F15H. This parses a sequence of digits from the input into Register Pair DE, treating them provisionally as either hex or decimal based on context.
6EF4
LD A,(HL) 7E
Fetch the character immediately following the parsed digits into Register A. If the number has an "H" suffix, this character will be 'H' (48H).
6EF5
SUB 41H D6 41
SUBtract 41H (ASCII 'A') from Register A. If the character was 'H' (48H), the result is 07H. If it was 'A'–'G', the result is 00H–06H.
6EF7
CP 08H FE 08
Compare the result against 08H. If the character was a letter A–H (result 0–7), the Carry flag is set. This tests whether the post-number character is a letter that could be part of a hex suffix.
6EF9
If the NO CARRY FLAG is set (character is not A–H, meaning no hex suffix), JUMP to 6F08H to check if any digits were parsed and handle accordingly.
6EFB
POP HL E1
Restore the original input buffer pointer from the stack. The first parse may have been decimal; we need to re-parse as hex.
6EFC
LD B,01H 06 01
Load Register B with 01H to enable hex digit mode. Bit 0 of B = 1 tells the number accumulator at 6F15H to accept hex letters A–F as digits.
6EFE
PUSH HL E5
Save the restored input buffer pointer onto the stack again before the re-parse.
6EFF
GOSUB to 6F15H to re-parse the number from the input with hex digit support enabled (B bit 0 = 1). This time, letters A–F are accepted as hex digits, and the accumulation uses base 16.
6F02
LD A,(HL) 7E
Fetch the character following the re-parsed hex number into Register A. After a valid hex parse, this should be 'H' (the hex suffix).
6F03
CP 48H FE 48
Compare Register A against 48H (ASCII H). The "H" suffix confirms this is a hexadecimal number.
6F05
INC HL 23
INCrement HL to advance past the "H" suffix character (or just advance if it was not "H").
6F06
If the NZ FLAG is set (character was not "H" — invalid hex number format), JUMP to 6EEDH to report a number overflow/parse error at 5218H.
6F08
BIT 1,B CB 48
Test bit 1 of Register B. The number accumulator at 6F15H sets bit 1 when at least one digit was successfully parsed. If bit 1 is clear, no digits were found.
6F0A
POP BC C1
Restore the saved HL into Register Pair BC (discarding it from the stack). The POP goes to BC rather than HL because we want to keep the current HL position.
6F0B
RET NZ C0
If the NZ FLAG is set (bit 1 was set — digits were parsed successfully), RETurn to the caller with the parsed number in DE and HL pointing past the digits.
6F0C
If no digits were parsed (bit 1 was clear), JUMP to 6EEDH to report a parse error at 5218H.
6F0EH - Parse Decimal Number Entry Point
Entry point for parsing a strictly decimal number. This pushes HL, sets up a return address at 6F08H (the digit-check exit), and falls through to 6F13H/6F15H with B bit 0 = 0 (decimal-only mode). The pushed return address at 6F08H ensures that after the number accumulator returns, the digit-found check is performed.
6F0E
PUSH HL E5
Save the current input buffer pointer onto the stack for possible restoration if the parse fails.
6F0F
LD DE,6F08H 11 08 6F
Load Register Pair DE with the address 6F08H, which is the digit-found validation exit point.
6F12
PUSH DE D5
Push the return address 6F08H onto the stack. When the number accumulator at 6F15H eventually executes a RET, it will return to 6F08H to check whether any digits were parsed.
6F13H - Initialize Number Parser
Initializes the number parser by clearing Register B (which controls hex/decimal mode via bit 0, and tracks whether any digits were parsed via bit 1), then falls through to the main number accumulator loop at 6F15H.
6F13
LD B,00H 06 00
Load Register B with 00H to initialize the parser state: bit 0 = 0 (decimal mode, no hex letters), bit 1 = 0 (no digits parsed yet).
6F15H - Number Accumulator Loop
This is the core number parsing engine used by both decimal and hexadecimal number routines. It reads digits from the input buffer pointed to by HL, accumulates them into Register Pair DE as a multi-digit number, and uses Register B bit 0 to control whether hex letters (A–F) are accepted. The accumulation multiplies DE by 10 (decimal mode) or 16 (hex mode) for each new digit and adds the digit value. Register B bit 1 is set when at least one valid digit has been parsed. Returns when a non-digit character is encountered.
6F15
LD DE,0000H 11 00 00
Initialize Register Pair DE to 0000H as the number accumulator. Parsed digits will be accumulated here.
[DIGIT PARSE LOOP START] — Each iteration reads one character, checks if it is a valid digit (0–9 or A–F in hex mode), and accumulates it into DE.
6F18
LD A,(HL) 7E
Fetch the next character from the input buffer into Register A.
6F19
SUB 30H D6 30
SUBtract 30H (ASCII '0') from Register A, converting ASCII digit '0'–'9' to binary 0–9. Non-digit characters will produce values outside 0–9.
6F1B
CP 0AH FE 0A
Compare the result against 0AH (10 decimal). If A is 0–9 (Carry set), it is a valid decimal digit.
6F1D
If the CARRY FLAG is set (value 0–9, valid decimal digit), JUMP to 6F29H to accumulate this digit into the running total.
Not a decimal digit — check if hex letters are enabled and if this is A–F.
6F1F
BIT 0,B CB 40
Test bit 0 of Register B (hex mode flag). If bit 0 = 0, hex letters are not accepted and this is the end of the number.
6F21
RET Z C8
If the Z FLAG is set (bit 0 = 0, decimal-only mode), RETurn — the character is not a digit and hex is not enabled, so the number is complete.
6F22
SUB 11H D6 11
SUBtract 11H (17 decimal) from Register A. After the earlier SUB 30H, the value for 'A' (41H) would be 11H, so this converts 'A' to 0, 'B' to 1, ..., 'F' to 5.
6F24
CP 06H FE 06
Compare the result against 06H. Valid hex letters A–F produce values 0–5. If A >= 6, the character is not a valid hex digit.
6F26
RET NC D0
If the NO CARRY FLAG is set (value >= 6, not a valid hex letter), RETurn — the number is complete.
6F27
ADD A,0AH C6 0A
ADD 0AH (10 decimal) to Register A, converting the hex letter offset (0–5) to the hex digit value (10–15). Now A contains the binary value of the hex digit (A=10, B=11, ..., F=15).
[ACCUMULATE DIGIT] — Register A contains the binary digit value (0–15). The running total in DE must be multiplied by the base (10 or 16) and the new digit added.
6F29
PUSH HL E5
Save the input buffer pointer onto the stack while the accumulation arithmetic is performed.
6F2A
LD H,D 62
Copy Register D (high byte of accumulator) into H. HL now holds a copy of the current accumulated value from DE.
6F2B
LD L,E 6B
Copy Register E (low byte of accumulator) into L. HL = DE = current accumulated total.
6F2C
LD C,A 4F
Save the current digit value from Register A into Register C for later addition.
6F2D
XOR A AF
Set Register A to 00H. A is used as a 24-bit overflow extension during the multiply — it tracks carries above 16 bits.
6F2E
SET 1,B CB C8
Set bit 1 of Register B to flag that at least one valid digit has been parsed. This flag is checked at 6F08H to determine if the parse was successful.
[MULTIPLY BY BASE] — HL (and A as overflow) is multiplied by the base. In hex mode (bit 0 = 1), the base is 16 (shift left 4 times). In decimal mode (bit 0 = 0), the base is 10 (shift-and-add: ×2, ×2, +original, ×2 = ×10).
6F30
ADD HL,HL 29
Shift HL left by 1 bit (multiply by 2). This is the first step in both ×10 and ×16.
6F31
ADC A,A 8F
Rotate overflow byte A left with carry from HL shift. Tracks 24-bit precision.
6F32
ADD HL,HL 29
Shift HL left again (×4 total now).
6F33
ADC A,A 8F
Rotate overflow byte A left with carry.
6F34
BIT 0,B CB 40
Test bit 0 of Register B (hex/decimal mode flag).
6F36
If the Z FLAG is set (bit 0 = 0, decimal mode), JUMP to 6F3BH to continue with the ×10 algorithm (add original value, then ×2 more).
6F38
ADD HL,HL 29
[HEX MODE] Shift HL left again (×8 total), continuing toward ×16.
6F39
JUMP to 6F3CH to do the final ×2 (total ×16 for hex).
6F3B
ADD HL,DE 19
[DECIMAL MODE] ADD the original value (saved in DE before shifts) to HL. HL was ×4; adding the original makes it ×5.
6F3C
ADC A,A 8F
Rotate overflow byte with carry from the ADD.
6F3D
ADD HL,HL 29
Final shift: decimal ×5 × 2 = ×10; hex ×8 × 2 = ×16.
6F3E
ADC A,A 8F
Rotate overflow byte with carry from the final shift.
[ADD DIGIT] — HL now contains the old accumulator × base. Add the new digit value (saved in C).
6F3F
LD E,C 59
Load the digit value from Register C into Register E.
6F40
LD D,00H 16 00
Clear Register D so DE contains the digit value as a 16-bit number.
6F42
ADD HL,DE 19
ADD the digit value (in DE) to the accumulated total (in HL). HL now contains (old_total × base) + new_digit.
6F43
ADC A,A 8F
Rotate overflow byte with any carry from the addition. If A is non-zero, the number has overflowed 16 bits.
6F44
EX DE,HL EB
Exchange DE and HL. DE now contains the updated accumulated total; HL is free.
6F45
POP HL E1
Restore the input buffer pointer from the stack (saved at 6F29H).
6F46
RET NZ C0
If the NZ FLAG is set from ADC A,A (overflow byte A became non-zero — number overflow beyond 16 bits), RETurn with NZ to signal an error. The accumulated value exceeds the 16-bit capacity.
6F47
INC HL 23
INCrement HL to advance to the next character in the input buffer.
6F48
JUMP back to 6F18H to read and process the next digit character. [DIGIT PARSE LOOP END]
6F4AH - "H" Command Handler (Hex Dump / Help)
This routine handles the "H" command (entered from the SYS6 command dispatcher when CP 68H matched at 4D08H). It parses a filename into the work buffer at 5AE5H, looks up the file using the "TO" keyword search, resets the input parser, calls 5210H for further processing, sets up parameter blocks at 65B0H and 64B0H, opens both source and destination files, and performs a sector-by-sector copy between them using SYS0 read/write routines.
6F4A
LD DE,5AE5H 11 E5 5A
Point Register Pair DE to the filename work buffer at 5AE5H. This buffer will receive the parsed filename.
6F4D
GOSUB to 4E8DH to parse the filename from the input buffer into the work buffer at DE (5AE5H).
6F50
GOSUB to 6FE4H to search for the "TO" keyword in the input and advance past it, preparing to parse the destination specification.
6F53
GOSUB to 4E8AH to reset the filename parser state, preparing for parsing the destination filename.
6F56
GOSUB to 5210H for additional command processing and parameter validation.
6F59
LD HL,65B0H 21 B0 65
Point Register Pair HL to the source file parameter block at 65B0H.
6F5C
LD B,00H 06 00
Load Register B with 00H as a flag/mode parameter for the file open routine.
6F5E
GOSUB to SYS0 routine at 4424H to open the source file using the parameter block at HL. Returns NZ on error.
6F61
RET NZ C0
If the NZ FLAG is set (source file open failed), RETurn with error status to the caller.
6F62
GOSUB to SYS0 routine at 4448H to perform additional file setup on the source file (read first sector, initialize position).
6F65
RET NZ C0
If the NZ FLAG is set (source file setup failed), RETurn with error status.
6F66
EXX D9
Exchange the primary and alternate register sets. The source file state (in the primary registers) is swapped to the alternate set, freeing the primary registers for the destination file setup.
6F67
LD HL,64B0H 21 B0 64
Point Register Pair HL to the destination file parameter block at 64B0H.
6F6A
LD B,00H 06 00
Load Register B with 00H as a flag/mode parameter for the file open routine.
6F6C
LD DE,5AE5H 11 E5 5A
Point Register Pair DE to the filename work buffer at 5AE5H, which contains the parsed destination filename.
6F6F
GOSUB to SYS0 routine at 4424H to open the destination file.
6F72
RET NZ C0
If the NZ FLAG is set (destination file open failed), RETurn with error status.
[SECTOR COPY LOOP] — Read sectors from the source file and write them to the destination file until end-of-file or error.
6F73
GOSUB to ROM routine at 0013H to read the next byte/sector from the source file (using the alternate register set context). Returns Z if end-of-file, NZ with data if successful.
6F76
If the NZ FLAG is set (data was read — not end-of-file), JUMP to 6F82H to check for error conditions.
6F78
EXX D9
Exchange to the alternate register set (which holds the source file context).
6F79
GOSUB to ROM routine at 001BH to write the data to the destination file.
6F7C
EXX D9
Exchange back to the primary register set.
6F7D
If the Z FLAG is set (write succeeded), JUMP back to 6F73H to read and copy the next sector. [SECTOR COPY LOOP continues]
6F7F
If a read or write error occurred, JUMP to the error handler at 521AH to display the error and abort.
6F82
CP 1CH FE 1C
Compare the error/status code in Register A against 1CH (Position error — before start of file). This is a recoverable condition in certain file copy scenarios.
6F84
If the Z FLAG is set (error code = 1CH, position-before-start), JUMP to 6F8AH to handle this condition by closing the files normally.
6F86
CP 1DH FE 1D
Compare the error/status code against 1DH (Position error — past EOF). This is the normal end-of-file condition during a file copy.
6F88
If the NZ FLAG is set (error code is neither 1CH nor 1DH — a real error), JUMP to 6F7FH to go to the error handler at 521AH.
6F8A
EXX D9
Exchange to the alternate register set for the source file context.
6F8B
JUMP to SYS0 routine at 4428H to close both files and return to the command handler. This routine closes the open FCBs and returns control to the SYS6 caller.
6F8EH - Parse Filename from Input Buffer
This routine parses up to 8 characters of a filename from the input buffer at HL into the destination buffer at DE. Valid characters are alphanumeric (A–Z, 0–9). Non-alphanumeric characters are replaced with spaces (20H) to pad the filename to exactly 8 characters. Register C counts the number of valid characters parsed; the routine returns with NZ if at least one valid character was found.
6F8E
LD B,08H 06 08
Load Register B with 08H (8 decimal) as the maximum filename length counter. TRS-80 filenames are up to 8 characters.
6F90
LD C,00H 0E 00
Load Register C with 00H to initialize the valid character count to zero.
6F92
JUMP to 6F9DH to begin checking the first character (entering via the alphabetic check path).
[FILENAME CHARACTER LOOP START]
6F94
LD A,(HL) 7E
Fetch the next character from the input buffer into Register A.
6F95
CP 3AH FE 3A
Compare Register A against 3AH (ASCII : colon). Characters below ':' include digits '0'–'9'.
6F97
If the NO CARRY FLAG is set (character >= ':', not a digit), JUMP to 6F9DH to check if it is an alphabetic character instead.
6F99
CP 30H FE 30
Compare Register A against 30H (ASCII '0'). If A is in the range 30H–39H ('0'–'9'), it is a valid digit.
6F9B
If the NO CARRY FLAG is set (character >= '0', and we already know it is < ':', so it is a valid digit), JUMP to 6FA6H to store it in the filename buffer.
6F9D
LD A,(HL) 7E
Re-fetch the character from the input buffer (in case we arrived here from the initial entry or the digit check fell through).
6F9E
CP 5BH FE 5B
Compare Register A against 5BH (one past ASCII 'Z'). Characters at or above 5BH are not uppercase letters.
6FA0
If the NO CARRY FLAG is set (character >= 5BH, not an uppercase letter), JUMP to 6FAEH to pad with a space instead.
6FA2
CP 41H FE 41
Compare Register A against 41H (ASCII 'A'). If A is in the range 41H–5AH ('A'–'Z'), it is a valid letter.
6FA4
If the CARRY FLAG is set (character < 'A', not a valid letter), JUMP to 6FAEH to pad with a space.
6FA6
LD (DE),A 12
Store the valid alphanumeric character from Register A into the filename buffer at DE.
6FA7
INC HL 23
INCrement the input buffer pointer to the next character.
6FA8
INC DE 13
INCrement the filename buffer pointer to the next position.
6FA9
INC C 0C
INCrement the valid character count in Register C.
6FAA
DECrement B (remaining character slots) and loop back to 6F94H if not zero. [FILENAME CHARACTER LOOP END when B = 0]
6FAC
All 8 character positions have been processed. JUMP to 6FB4H to set the return flags.
[SPACE PAD] — The character at the current position is not alphanumeric. Fill remaining positions with spaces.
6FAE
LD A,20H 3E 20
Load Register A with 20H (ASCII space) to pad the filename.
6FB0
LD (DE),A 12
Store the space character into the filename buffer at DE.
6FB1
INC DE 13
INCrement the filename buffer pointer.
6FB2
DECrement B and loop to fill remaining positions with spaces until all 8 are written.
6FB4
LD A,C 79
Load the valid character count from Register C into Register A.
6FB5
OR A B7
Test whether any valid characters were parsed (C > 0 sets NZ). Z flag means no valid characters were found (empty filename).
6FB6
RET C9
RETurn to the caller. NZ = at least one valid character parsed (success); Z = no valid characters found (failure). Character count in A.
6FB7H - Validate Disk Date/Name Against Input
This routine validates the disk name and date from the input against the stored disk information at 598BH. It uses the skip-whitespace routine at 6EB4H to find the input data, then compares up to 3 fields (name components) character by character against the stored values. If a mismatch is found, execution jumps to the error at 5218H. If the input matches, it calls 4470H to store the validated information.
6FB7
LD DE,598BH 11 8B 59
Point Register Pair DE to the disk name/date buffer at 598BH in the SYS6 work area.
6FBA
LD C,03H 0E 03
Load Register C with 03H (3 decimal) as the field counter — the name/date consists of 3 comparison fields.
6FBC
GOSUB to 6EB4H to skip whitespace in the input buffer and find the start of the next data field. Returns Carry if valid input found, Z if end of line.
6FBF
If the NO CARRY FLAG is set (no valid input found), JUMP to 6FDDH to accept the current values without further comparison and store them.
[FIELD COMPARISON LOOP] — Compare up to 2 characters per field between input and stored name.
6FC1
LD B,02H 06 02
Load Register B with 02H (2 characters per field to compare).
6FC3
LD A,(HL) 7E
[CHAR COMPARE LOOP START] Fetch the next character from the input buffer.
6FC4
CP 30H FE 30
Compare against 30H (ASCII '0'). Characters below '0' are non-data characters (delimiters, control chars).
6FC6
If the CARRY FLAG is set (character < '0', end of field), JUMP to 6FDAH to handle the mismatch or field boundary.
6FC8
EX DE,HL EB
Exchange DE and HL. Now HL points to the stored name/date buffer, DE to the input buffer.
6FC9
CP (HL) BE
Compare the input character (in A) against the stored character at (HL).
6FCA
If the NO CARRY FLAG is set (input character >= stored character — mismatch or greater), JUMP to 6FDAH for error handling.
6FCC
LD (HL),A 77
Store the input character into the stored name/date buffer, updating it with the new value.
6FCD
EX DE,HL EB
Exchange back so HL = input buffer, DE = stored buffer.
6FCE
INC DE 13
INCrement the stored buffer pointer.
6FCF
INC HL 23
INCrement the input buffer pointer.
6FD0
DECrement B and loop back to 6FC3H for the next character in this field. [CHAR COMPARE LOOP END]
6FD2
DEC C 0D
DECrement the field counter in Register C.
6FD3
RET Z C8
If the Z FLAG is set (all 3 fields compared successfully), RETurn to the caller — the disk name/date validation is complete.
6FD4
LD A,(DE) 1A
Fetch the next separator character from the stored buffer.
6FD5
CP (HL) BE
Compare the stored separator against the input separator.
6FD6
INC DE 13
INCrement the stored buffer pointer past the separator.
6FD7
INC HL 23
INCrement the input buffer pointer past the separator.
6FD8
If the Z FLAG is set (separators match), JUMP back to 6FC1H to compare the next field.
6FDA
If the comparison failed (mismatch), JUMP to 5218H to display an error and abort.
6FDD
PUSH HL E5
Save the input buffer pointer onto the stack.
6FDE
EX DE,HL EB
Exchange DE and HL so HL points to the name/date buffer at 598BH.
6FDF
GOSUB to SYS0 routine at 4470H to store/process the validated disk name and date information from the buffer at HL.
6FE2
POP HL E1
Restore the input buffer pointer from the stack.
6FE3
RET C9
RETurn to the caller with the disk name/date validated and stored.
6FE4H - Search for "TO" Keyword in Input
This utility routine searches for the "TO" keyword in the command input. It first skips whitespace via 6EC3H, then uses the SYS0 keyword comparison routine at 4C6AH to check whether the input at HL matches the "TO" keyword string stored at 6FF6H. If found, the input pointer is advanced past the keyword. If not found, the routine returns. If found but followed by an error condition, execution jumps to 521AH.
6FE4
GOSUB to 6EC3H to skip whitespace in the input buffer. On return, HL points to the first non-whitespace character.
6FE7
LD D,H 54
Copy the high byte of the current input pointer into D. DE will point to the same position as HL for the keyword comparison.
6FE8
LD E,L 5D
Copy the low byte of the current input pointer into E. DE = HL = start of potential keyword.
6FE9
LD BC,6FF6H 01 F6 6F
Point Register Pair BC to the "TO" keyword string at address 6FF6H. This address contains the bytes 54H, 4FH, 00H ("TO" + NUL terminator).
6FEC
GOSUB to SYS0 routine at 4C6AH to compare the input at DE against the keyword string at BC. Returns Z if the keyword matches, NZ if it does not.
6FEF
RET NZ C0
If the NZ FLAG is set (input does not match "TO"), RETurn to the caller with NZ — no "TO" keyword found. HL is unchanged.
6FF0
GOSUB to SYS0 routine at 4C7EH to skip any whitespace following the "TO" keyword, advancing HL to the next token (typically the destination filename or drive number).
6FF3
RET NC D0
If the NO CARRY FLAG is set (end of input or no valid token after "TO"), RETurn with NC. The caller will handle the missing operand.
6FF4
EX DE,HL EB
Exchange DE and HL so HL points to the position after "TO" and any whitespace, ready for the next parse stage.
6FF5
RET C9
RETurn to the caller with HL pointing past the "TO" keyword and following whitespace. Carry set indicates success.
6FF6H - "TO" Keyword Data
The "TO" keyword string used by the keyword search routine at 6FE4H. This is a NUL-terminated ASCII string.
6FF6
DEFM "TO" + 00H 54 4F 00
3 bytes: ASCII "TO" followed by a NUL terminator (00H). Used by the SYS0 keyword comparison routine at 4C6AH when searching for the "TO" keyword that separates source and destination in COPY and similar commands.
End of SYS6/SYS — Address 6FF8H is the last byte of the module.