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

Page Customization

SYS16/SYS – PDRIVE Commands

SYS16/SYS is the NEWDOS/80 overlay module that implements the PDRIVE (Physical Drive) command. PDRIVE is one of the most powerful and complex commands in NEWDOS/80, allowing the user to view and modify the physical drive configuration table that controls how DOS communicates with each of the four physical floppy disk drives (drives 0–3) and six pseudo-drives (drives 4–9).

Each PDRIVE entry is a 16-byte record stored in a 10-entry table at 4300H in RAM. The entry contains all the parameters DOS needs to know about a drive: its interface type (TI), drive type (TD), track count (TC), sectors per track (SPT), track stepping rate (TSR), granules per lump (GPL), directory start lump (DDSL), and directory granule allocation count (DDGA). These parameters are read from the system diskette's boot sector during each computer RESET.

The PDRIVE command syntax is:

PDRIVE,dn1,dn2,TI=type,TD=type,TC=tracks,SPT=sectors,TSR=rate,GPL=granules,DDSL=lump,DDGA=count

where dn1 is the drive whose PDRIVE entry is to be changed, and dn2 is an optional source drive whose current settings are copied first. All keyword=value parameters are optional and modify specific fields of the PDRIVE entry.

PDRIVE Data Structure

Table at 4300H – Ten 16-byte entries (160 bytes total, 4300H–439FH)

OffsetHolds
00HTI flags byte 0 (interface type bit flags, low byte)
01HTI flags byte 1 (interface type bit flags, high byte)
02HConfiguration flags (TD drive type in bits 2–4, plus additional flags)
03HAdditional configuration
04HTC – Track count
05HSPT – Sectors per track
06HSign-extension byte for offset 07H
07HTSR – Track stepping rate code (bits 0–2)
08HGPL – Granules per lump
09HDDSL – Directory start lump number
0AH–0FHAdditional configuration and computed values

Key Variables and Self-Modifying Code

AddressHolds
4300HPDRIVE working table buffer (160 bytes, 10 entries × 16 bytes)
4302HFlag byte: non-zero means changes were made to the PDRIVE table
43A0HCurrent number of configured drives (used as upper bound for copy-back)
4EA2HCurrent drive/entry number being processed (0–9) [SELF-MODIFYING CODE at 4EA1H]
4DF5H–4DF6HSelf-modifying flag: LD A,00H modified to non-zero to skip re-display [SELF-MODIFYING CODE]
5114HFlag: non-zero means a second drive number (dn2) was specified
5118HCounter/flag for command table scanning
510EHPointer into command table strings at 511CH
5106H–510DHMaximum sectors-per-track table (8 bytes, one per TD drive type A–H)
511CH–5176HCommand keyword strings (TI=, TD=, TC=, SPT=, TSR=, GPL=, DDSL=, DDGA=, DSL=)
50CBH–5105HText messages (error and status strings)

Major Routine Reference

AddressRoutine
4D00HPDRIVE Command Entry Point: parses the command line for drive numbers and parameters
4D5EHHex Digit Parser: validates and converts a hex digit character
4D69HTI Flag Letter Processor: converts letter flags (A–P) into bit positions
4DA4HMain Processing Loop: iterates through all 10 PDRIVE entries
4DB5HSign Extension and Write-Back: extends 8-bit TSR values to 16-bit
4DDAHDisplay All Entries: loops through 10 entries displaying each one
4DE8HCopy Table to System Area: copies working buffer to DOS system memory at 4291H
4E16HDisplay Single Entry: formats and prints one PDRIVE entry's parameters
4E97HCalculate IX Pointer: computes pointer to a specific entry in the PDRIVE table
4EB0HParameter Validation: validates and constructs PDRIVE parameters from parsed values
4FC3HSet Up Command Table Pointer: initializes for parameter keyword scanning
4FCCHParse Next Command Token: gets next token from command line input
4FECHCross-Drive Compatibility Check: verifies no incompatible settings across drives
500FHCharacter Output: wrapper for ROM character display at 0033H
5017HCommand Table Scanner: matches input against keyword=value command strings
502EHDecimal Number Parser: parses a decimal number from the command line
503FHHex Number Parser Entry: parses a hex number from the command line
5062HGeneral Number Parser: core numeric conversion (decimal or hex) routine
5099H16-Bit Decimal Output: displays a 16-bit value as a decimal number
51CBHCommand Line Scanner with Table Reset: scans characters and resets PDRIVE table on specific input

Disassembly

4D00H - PDRIVE COMMAND ENTRY POINT

Entry point for the PDRIVE command. On entry, Register A holds the SVC function code and Register B holds command-line flags. The code first validates that SVC function code 32H (PDRIVE) was requested.

4D00
CP 32H FE 32
Compare Register A against 32H (decimal 50, the SVC function code for the PDRIVE command). If Register A equals 32H, the Z FLAG is set; otherwise the NZ FLAG is set.
4D02
LD A,2AH 3E 2A
Load Register A with 2AH (decimal 42, NEWDOS/80 error code for "general error"). This pre-loads the error code in case the SVC validation fails.
4D04
If the NZ FLAG has been set (the SVC function code in Register A was not 32H, meaning this is not a PDRIVE command request), JUMP to 503CH to issue error code 2AH ("general error") via the DOS error handler at 4409H. [ERROR PATH — wrong SVC code]

The SVC function code matched 32H, confirming this is a PDRIVE command. Register B still holds the command-line flags passed by the caller. Now save those flags and set up the command-line parser.

4D07
LD A,B 78
Load Register A with the contents of Register B (the command-line flags byte passed by the DOS command dispatcher).
4D08
LD (5114H),A 32 14 51
Store the command-line flags byte (Register A) to memory location 5114H (a local variable that preserves the original flags for later use during PDRIVE processing).
4D0B
GOSUB to 4FC3H to initialize the PDRIVE display format. This routine loads Register A with 02H (the display column count), stores it at 5118H (the display format control byte), and points Register Pair DE to 510EH (the default PDRIVE parameter template). On return, DE points to the parameter template buffer at 510EH.
4D0E
GOSUB to the DOS routine at 4436H to parse the command line. This SYS0 routine advances HL past whitespace and returns with flags indicating whether there are more parameters to process. Z FLAG set means end of command line (no parameters); NZ FLAG set means parameters remain.
4D11
RET NZ C0
If the NZ FLAG has been set (the command-line parser at 4436H found more parameters to process), RETURN to the caller. This is the path for PDRIVE with arguments — the caller will continue processing parameters. [NOTE: This RET NZ returns to the DOS dispatcher which re-enters the PDRIVE handler through the normal parameter processing path.]

When 4436H returns Z, it means the command line is empty — bare PDRIVE with no arguments — so fall through to display all drive configurations.

4D12
GOSUB to 4FCCH to check the command line for the next token. This routine calls the DOS command-line scanner at 4C7AH and returns: CARRY set = error/BREAK; Z FLAG set = end of line; NZ FLAG set = more tokens remain. It also checks flags at 5114H and 4DF6H to determine if this is a display-only invocation.
4D15
RET C D8
If the CARRY FLAG has been set (the command-line scanner encountered an error or BREAK key), RETURN to the caller with the error. [ERROR PATH — parse error or BREAK]
4D16
If the Z FLAG has been set (the command line is empty — bare PDRIVE with no arguments), JUMP to 4DDAH to display all 10 drive configurations (drives 0-9). [DISPLAY-ALL PATH]

4D19H - PARSE FIRST DRIVE NUMBER (dn1)

The command line has parameters. Parse the first drive number (dn1) which specifies the target drive whose configuration will be viewed or modified. The syntax is PDRIVE,dn1 or PDRIVE,dn1,keyword=value or PDRIVE,dn1=dn2.

4D19
GOSUB to 4D5EH to parse a single-digit drive number (0-9) from the command line. On return, Register A holds the drive number (0-9) and HL points past the parsed digit. If the character is not a valid digit (0-9), the routine issues error code 20H ("parameter error") and does not return.
4D1C
LD (4EA2H),A 32 A2 4E
Store the parsed drive number (Register A, value 0-9) to memory location 4EA2H (the "current drive number" variable used throughout PDRIVE processing to track which drive entry is being operated on).
4D1F
LD A,(HL) 7E
Load Register A with the next character from the command line (pointed to by HL). This character determines whether the command uses the dn1=dn2 copy syntax or the dn1,keyword=value modification syntax.
4D20
CP 3DH FE 3D
Compare Register A against 3DH (ASCII =). If Register A equals 3DH, the Z FLAG is set (copy syntax); otherwise the NZ FLAG is set (keyword syntax or display).
4D22
If the NZ FLAG has been set (the next character is not =, so this is not the dn1=dn2 copy syntax), JUMP forward to 4D3FH to process the command using keyword parsing. [KEYWORD PATH]

4D24H - COPY DRIVE CONFIGURATION (dn1=dn2)

The user entered PDRIVE,dn1=dn2 syntax to copy the entire PDRIVE configuration from drive dn2 to drive dn1. Parse the source drive number, calculate the source entry address, then block-copy the 16-byte PDRIVE entry.

4D24
INC HL 23
INCrement Register Pair HL by 1 to advance the command-line pointer past the = character to the source drive number digit.
4D25
GOSUB to 4D5EH to parse the source drive number (dn2) from the command line. On return, Register A holds the source drive number (0-9).
4D28
RLCA 07
Rotate Register A Left with Carry. This is the first of four RLCA instructions that shift the source drive number into the upper nibble. After this instruction, the drive number has been multiplied by 2.
4D29
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 4.
4D2A
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 8.
4D2B
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 16 and shifted into the upper nibble of Register A. Each PDRIVE entry is 16 bytes (10H), so multiplying the drive number by 16 produces the byte offset into the PDRIVE table.

Register A now contains (dn2 × 16), which is the byte offset from the base of the PDRIVE table at 4300H to the start of drive dn2's 16-byte configuration entry.

4D2C
PUSH HL E5
Save Register Pair HL (the command-line pointer) onto the stack, since it will be overwritten during the block copy operation.
4D2D
LD H,43H 26 43
Load Register H with 43H (the high byte of the PDRIVE table base address 4300H).
4D2F
LD L,A 6F
Load Register L with Register A (the byte offset dn2 × 16). Register Pair HL now points to 4300H + (dn2 × 16), which is the start of the source drive's PDRIVE entry.
4D30
XOR A AF
Set Register A to ZERO and clear all flags. Register A = 00H will be passed to the routine at 4E9AH to specify the target drive number for the IX pointer setup.
4D31
GOSUB to 4E9AH to set up the IX register to point to the destination drive's (dn1's) PDRIVE entry. This routine reads the drive number previously stored at 4EA2H, calculates the offset (drive × 16), and sets IX = 4300H + (dn1 × 16). On return, IX points to the destination drive's 16-byte PDRIVE entry.
4D34
PUSH IX DD E5
Save Register Pair IX (pointer to the destination PDRIVE entry) onto the stack.
4D36
POP DE D1
Restore the top of stack into Register Pair DE. This transfers the IX value (destination PDRIVE entry address) into DE, since LDIR uses DE as the destination pointer.
4D37
LD BC,0010H 01 00 10
Load Register Pair BC with 0010H (decimal 16). This is the byte count for the LDIR block copy — each PDRIVE entry is exactly 16 bytes.
4D3A
LDIR ED B0
Block copy 16 bytes from the source PDRIVE entry (HL = 4300H + dn2 × 16) to the destination PDRIVE entry (DE = 4300H + dn1 × 16). This copies the entire drive configuration from drive dn2 to drive dn1. After execution, HL and DE point past their respective 16-byte entries, and BC = 0.
4D3C
POP HL E1
Restore Register Pair HL from the stack (the command-line pointer saved at 4D2CH), repositioning HL to continue parsing any remaining command-line parameters.
4D3D
JUMP forward to 4D9EH to check for additional parameters on the command line. After copying the drive configuration, there may be further keyword=value modifications to apply. [CONTINUE TO PARAMETER LOOP]

4D3FH - KEYWORD PARAMETER PARSING ENTRY

The command line did not use the dn1=dn2 copy syntax. Check for more tokens, then enter the keyword parsing loop to process keyword=value parameters such as TI=A, TD=E, TC=40, etc.

4D3F
GOSUB to 4FCCH to scan the command line for the next token. Returns: CARRY = error/BREAK, Z = end of line, NZ = token found.
4D42
RET C D8
If the CARRY FLAG has been set (error or BREAK encountered during command-line scanning), RETURN to the caller with the error. [ERROR PATH]
4D43
If the Z FLAG has been set (end of command line — no more parameters after the drive number), JUMP to 4DDAH to display the single drive's configuration. [DISPLAY SINGLE DRIVE PATH]

There are more tokens on the command line. Point BC to the keyword table at 511CH and initialize the keyword index counter, then search for a matching keyword.

4D46
LD BC,511CH 01 1C 51
Load Register Pair BC with 511CH, the address of the PDRIVE keyword table. This table contains null-terminated keyword strings (e.g., "TI=", "TD=", "TC=") followed by dispatch bytes that encode which parameter to modify and how to parse the value.
4D49
LD D,01H 16 01
Load Register D with 01H, initializing the keyword index counter. D tracks how many keyword table entries have been examined, used to skip past null-terminated entries in the table.
4D4B
GOSUB to 5017H, the keyword table scanner. This routine compares the command-line token (pointed to by HL) against each keyword entry in the table (pointed to by BC). It returns with: Z FLAG set = no match found (all keywords exhausted, parse error); NZ FLAG set = match found, BC points to the matched entry's dispatch byte, D holds the keyword index.
4D4E
GOSUB to 4E97H to set up the IX register pointer to the current drive's PDRIVE entry. This routine reads the dispatch byte from (BC), extracts the low nibble as the PDRIVE entry field offset, and calculates IX = 4300H + (drive × 16). On return, IX points to the target drive's PDRIVE entry.
4D51
LD A,(BC) 0A
Load Register A with the dispatch byte from the keyword table (pointed to by BC). The high bits of this byte encode the parameter type: Bit 7 set = numeric value parameter, Bit 6 set = flag-letter parameter (like TI=), Bits 0-3 = PDRIVE entry field offset.
4D52
BIT 7,A CB 7F
Test Bit 7 of Register A (the dispatch byte). If Bit 7 is set, the NZ FLAG is set, meaning this keyword expects a numeric value (like TC=40 or SPT=10). If Bit 7 is clear, the Z FLAG is set, meaning this keyword uses a different value format.
4D54
If the Z FLAG has been set (Bit 7 of the dispatch byte is clear — this is NOT a numeric parameter), JUMP forward to 4D69H to check Bit 6 for flag-letter parsing. [FLAG-LETTER OR SINGLE-VALUE PATH]

Bit 7 is set — this keyword expects a numeric value (e.g., TC=40, SPT=10, TSR=3, GPL=5, DDSL=17, DDGA=2). Parse the number from the command line and store it in the appropriate PDRIVE entry field.

4D56
GOSUB to 502EH to parse a numeric value from the command line. This routine reads decimal or hexadecimal digits from the command line and returns the parsed value in Register Pair DE (16-bit result), with Register A holding the low byte.
4D59
JUMP forward to 4D9BH to store the parsed numeric value into the appropriate PDRIVE entry field (at IX+offset) and continue processing the next parameter. [STORE VALUE AND CONTINUE]

4D5BH - PARAMETER ERROR EXIT

Issue a "parameter not valid" error (error code 2FH) when a parsed value is out of range.

4D5B
JUMP to 503AH which loads Register A with 2FH (error code for "parameter not valid") and then jumps to the DOS error handler at 4409H. This routine does not return. [ERROR PATH — invalid parameter value]

4D5EH - PARSE SINGLE-DIGIT DRIVE NUMBER SUBROUTINE

Subroutine to parse a single decimal digit (0-9) from the command line as a drive number. Called from 4D19H (parse dn1) and 4D25H (parse dn2). Returns the digit value in Register A. Issues error 20H if the character is not a valid digit.

4D5E
GOSUB to 502EH to parse a number from the command line. This routine handles both decimal and hexadecimal input. On return, Register Pair DE holds the parsed 16-bit value and Register A holds the low byte (E).
4D61
CP 0AH FE 0A
Compare Register A (the parsed number) against 0AH (decimal 10). If Register A is less than 10, the CARRY FLAG is set (valid drive number 0-9). If Register A is 10 or greater, the NO CARRY FLAG is set (invalid — too large for a drive number).
4D63
RET C D8
If the CARRY FLAG has been set (the parsed value is 0-9, a valid drive number), RETURN to the caller with the drive number in Register A. [SUCCESS — valid drive number]
4D64
LD A,20H 3E 20
Load Register A with 20H (decimal 32, NEWDOS/80 error code for "parameter error"). The parsed value was 10 or greater, which is not a valid drive number.
4D66
JUMP to 503CH to issue the error. The routine at 503CH passes error code 20H (in Register A) to the DOS error handler at 4409H. This routine does not return. [ERROR PATH — drive number out of range]

4D69H - FLAG-LETTER PARAMETER PARSER (TI= TYPE)

Bit 7 of the dispatch byte was clear. Now test Bit 6 to determine if this keyword uses flag-letter parsing (like TI=ADHK where each letter sets a bit in a 16-bit field) or single-letter parsing (like TD=E where one letter selects a drive type).

4D69
BIT 6,A CB 77
Test Bit 6 of Register A (the dispatch byte). If Bit 6 is set, the NZ FLAG is set, meaning this keyword uses flag-letter parsing (a string of letters, each setting a bit). If Bit 6 is clear, the Z FLAG is set, meaning this keyword uses single-letter parsing.
4D6B
If the Z FLAG has been set (Bit 6 is clear — this is a single-letter parameter like TD=E), JUMP forward to 4D93H to parse a single letter value. [SINGLE-LETTER PATH]

Bit 6 is set — this is a flag-letter parameter like TI=ADHK. Each letter A-P maps to a bit position in a 16-bit field stored across two bytes in the PDRIVE entry (IX+00H and IX+01H). First, clear those two bytes, then process each letter in the value string.

4D6D
XOR A AF
Set Register A to ZERO and clear all flags. This zero value will be used to clear the two TI flag bytes in the PDRIVE entry before setting individual bits.
4D6E
LD (IX+00H),A DD 77 00
Store 00H (Register A) to the first TI flag byte at IX+00H (the low byte of the TI flags field in the current drive's PDRIVE entry). This clears all flag bits before rewriting them from the command line.
4D71
LD (IX+01H),A DD 77 01
Store 00H (Register A) to the second TI flag byte at IX+01H (the high byte of the TI flags field in the current drive's PDRIVE entry). Both TI flag bytes are now cleared.

[LOOP START — flag-letter processing loop] For each letter in the TI= value string, determine which byte (IX+00H or IX+01H) and which bit position the letter maps to, then set that bit.

4D74
PUSH IX DD E5
Save Register Pair IX (pointer to the current drive's PDRIVE entry) onto the stack. IX will be transferred to DE for byte-level bit manipulation.
4D76
POP DE D1
Restore the top of stack into Register Pair DE. DE now holds the same address as IX — the start of the current drive's PDRIVE entry. DE will be used to point at either IX+00H or IX+01H depending on the letter value.
4D77
LD A,(HL) 7E
Load Register A with the next character from the command-line value string (pointed to by HL). This is one of the flag letters (A-P) or a delimiter indicating the end of the TI= value.
4D78
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A, converting the letter to a zero-based index: A=0, B=1, C=2, ... P=15. If the result is negative (character was below A), the CARRY FLAG is set.
4D7A
CP 08H FE 08
Compare Register A (the letter index, 0-15) against 08H (decimal 8). If Register A is less than 8, the CARRY FLAG is set (letters A-H map to the first byte IX+00H). If Register A is 8 or greater, the NO CARRY FLAG is set (letters I-P map to the second byte IX+01H).
4D7C
If the CARRY FLAG has been set (letter index is 0-7, mapping to the first byte at IX+00H), JUMP forward to 4D85H to calculate the bit mask. DE already points to IX+00H. [FIRST BYTE — letters A-H]
4D7E
INC DE 13
INCrement Register Pair DE by 1 so DE now points to IX+01H (the second TI flag byte) instead of IX+00H. Letters I-P are stored in this second byte.
4D7F
SUB 08H D6 08
SUBtract 08H from Register A to adjust the letter index from the range 8-15 down to 0-7, since bits within a single byte are numbered 0-7.
4D81
CP 08H FE 08
Compare the adjusted letter index against 08H. If the index is 8 or greater (the original letter was beyond P), the NO CARRY FLAG is set, indicating an invalid letter.
4D83
If the NO CARRY FLAG has been set (the letter index exceeds the valid range A-P), JUMP forward to 4D9EH to exit the flag-letter loop and continue with the next command-line parameter. The invalid character is treated as a delimiter ending the TI= value. [EXIT LOOP — end of TI= value]

Register A holds a valid bit index (0-7) within the target byte. Now create a bitmask with a single bit set at the correct position. The technique is: start with 80H (bit 7 set), then rotate left (A+1) times to wrap the set bit into the correct position.

4D85
LD B,A 47
Load Register B with Register A (the bit index, 0-7). Register B will serve as the loop counter for the RLCA rotation loop.
4D86
LD A,80H 3E 80
Load Register A with 80H (binary 10000000). This is the initial bitmask with bit 7 set. It will be rotated left to position the set bit at the correct index.
4D88
INC B 04
INCrement Register B by 1. The bit index is 0-based, but DJNZ decrements before testing, so B must be incremented by 1 to produce the correct number of rotations: index 0 → 1 rotation (80H→01H), index 1 → 2 rotations (80H→02H), etc.
4D89
RLCA 07
Rotate Register A Left with Carry. This shifts the set bit one position to the left (wrapping from bit 7 to bit 0). [LOOP START — bit rotation]
4D8A
DECrement Register B by 1 and if B is not zero, JUMP back to 4D89H to rotate again. After B rotations, Register A contains a single-bit mask at the position corresponding to the letter's bit index. [LOOP END — bit rotation]

Register A now holds the bitmask for this flag letter. OR it into the target byte (IX+00H or IX+01H, pointed to by DE) to set that flag bit without disturbing other bits already set by previously processed letters.

4D8C
EX DE,HL EB
Exchange DE and HL. HL now points to the target TI flag byte (IX+00H or IX+01H) and DE holds the command-line pointer.
4D8D
OR (HL) B6
OR Register A (the single-bit mask) with the current value of the TI flag byte at (HL). This sets the bit corresponding to the current flag letter while preserving any bits already set by previous letters.
4D8E
LD (HL),A 77
Store the updated flag byte (Register A) back to memory at (HL), writing the modified TI flags with the new bit set.
4D8F
EX DE,HL EB
Exchange DE and HL again, restoring HL to the command-line pointer and DE to the PDRIVE entry pointer.
4D90
INC HL 23
INCrement Register Pair HL by 1 to advance the command-line pointer to the next character in the TI= value string.
4D91
JUMP back to 4D74H to process the next flag letter in the TI= value string. [LOOP — continue processing flag letters]

4D93H - SINGLE-LETTER PARAMETER PARSER (TD= TYPE)

Parse a single letter value for keywords like TD=E (drive type). The letter A-Z is converted to a zero-based index (0-25) and stored directly in the PDRIVE entry field.

4D93
LD A,(HL) 7E
Load Register A with the next character from the command line (pointed to by HL). This is the single letter following the = sign (e.g., the E in TD=E).
4D94
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A, converting the letter to a zero-based index: A=0, B=1, ... H=7. This index represents the drive type code.
4D96
CP 1AH FE 1A
Compare Register A (the letter index) against 1AH (decimal 26). If Register A is less than 26, the CARRY FLAG is set (valid letter A-Z). If 26 or greater, the NO CARRY FLAG is set (invalid character — not a letter).
4D98
INC HL 23
INCrement Register Pair HL by 1 to advance the command-line pointer past the letter character. This is done before the validity check so that HL is positioned correctly regardless of the branch outcome.
4D99
If the NO CARRY FLAG has been set (the character was not a valid letter A-Z), JUMP back to 4D5BH to issue error code 2FH ("parameter not valid"). [ERROR PATH — invalid TD letter]

4D9BH - STORE PARSED VALUE INTO PDRIVE ENTRY

Common convergence point for both numeric parameters (from 4D59H) and single-letter parameters (from 4D99H). Store the parsed value (in Register A) into the PDRIVE entry field at IX+00H, then continue to check for more parameters.

4D9B
LD (IX+00H),A DD 77 00
Store the parsed value (Register A) into the PDRIVE entry field at IX+00H. The IX pointer was set by 4E97H to point to the specific field within the 16-byte PDRIVE entry that corresponds to the matched keyword (e.g., for TC=, IX points to the track count byte; for TD=, IX points to the drive type byte).

4D9EH - PARAMETER LOOP CONTINUATION

After processing one keyword=value parameter (or completing the dn1=dn2 copy), check if there are more parameters on the command line. If so, loop back to parse the next keyword. If not, fall through to display or save the configuration.

4D9E
GOSUB to 4FCCH to scan the command line for the next token. Returns: CARRY = error/BREAK, Z = end of line, NZ = more tokens remain.
4DA1
RET C D8
If the CARRY FLAG has been set (error or BREAK encountered), RETURN to the caller with the error. [ERROR PATH]
4DA2
If the NZ FLAG has been set (more tokens remain on the command line), JUMP back to 4D46H to load the keyword table pointer and parse the next keyword=value parameter. [LOOP — process next keyword]

4DA4H - DISPLAY ALL 10 DRIVE CONFIGURATIONS

End of command line reached after setting parameters. Now display all 10 drive configurations (drives 0-9) by calling the single-drive display routine (4EB0H) in a loop. Register A is used as the drive counter, cycling from 0 to 9.

4DA4
XOR A AF
Set Register A to ZERO and clear all flags. Register A = 0 initializes the drive counter to drive 0, the first drive to display. [LOOP START — display all drives]
4DA5
LD (4EA2H),A 32 A2 4E
Store the current drive counter (Register A, value 0-9) to memory location 4EA2H (the "current drive number" variable). The display routine at 4EB0H reads this variable to determine which drive's configuration to show.
4DA8
PUSH AF F5
Save Register A (the current drive counter) and the flags onto the stack before calling the display routine, which will modify Register A.
4DA9
GOSUB to 4EB0H to display the configuration for the current drive (whose number is stored at 4EA2H). This routine formats and prints the drive's parameters (TI, TD, TC, SPT, TSR, GPL, DDSL, DDGA) to the screen.
4DAC
POP AF F1
Restore Register A (the drive counter) and flags from the stack.
4DAD
INC A 3C
INCrement Register A (the drive counter) by 1 to advance to the next drive number.
4DAE
CP 0AH FE 0A
Compare Register A (the drive counter) against 0AH (decimal 10). If Register A equals 10, the Z FLAG is set (all 10 drives 0-9 have been displayed). If less than 10, the NZ FLAG is set (more drives remain).
4DB0
If the NZ FLAG has been set (the drive counter has not yet reached 10, meaning more drives remain to display), JUMP back to 4DA5H to store the next drive number and display it. [LOOP — display next drive]
4DB2
GOSUB to 4FECH to perform the PDRIVE compatibility check after displaying all drives. This routine scans all 10 drive entries and checks whether any incompatible TI flag combinations exist across drives, setting a warning flag if needed. [LOOP END — all 10 drives displayed]

4DB5H - SIGN-EXTEND BYTE 07H ACROSS ALL 10 DRIVES

After displaying all drives and performing the compatibility check, this loop iterates through all 10 PDRIVE entries and sign-extends byte 07H (the SPT low byte or sector configuration byte) into byte 06H. If bit 3 of Register C (set by the compatibility check at 4FECH) is set, the sign extension propagates the high bit of byte 07H into byte 06H. Otherwise byte 06H is cleared to 00H.

4DB5
LD IX,4300H DD 21 00 43
Load Register Pair IX with 4300H, pointing IX to the start of the first PDRIVE entry (drive 0) in the Drive Configuration Table at 4300H.
4DB9
LD B,0AH 06 0A
Load Register B with 0AH (decimal 10), the loop counter for processing all 10 PDRIVE entries (drives 0-9). [LOOP START — sign-extend all drives]
4DBB
LD E,(IX+07H) DD 5E 07
Load Register E with the value at IX+07H (byte 07H of the current PDRIVE entry). This byte holds the SPT (sectors per track) value or a related sector configuration parameter for this drive.
4DBE
LD D,00H 16 00
Load Register D with 00H, initializing the sign-extension byte to zero. If the value does not need sign extension, D remains 00H and will be stored into byte 06H.
4DC0
BIT 3,C CB 59
Test Bit 3 of Register C (a flag returned by the compatibility check routine at 4FECH). If Bit 3 is set, the NZ FLAG is set, meaning sign extension is required. If Bit 3 is clear, the Z FLAG is set, meaning no sign extension is needed.
4DC2
If the Z FLAG has been set (Bit 3 of C is clear — no sign extension needed), JUMP forward to 4DC9H to store D (00H) directly into byte 06H. [NO SIGN EXTENSION]

Bit 3 of C is set — sign extension is required. If bit 7 of the SPT byte (IX+07H) is set, it indicates a value greater than 127 sectors per track, and the high byte (IX+06H) needs to be set to FFH to form a proper 16-bit signed representation.

4DC4
LD A,E 7B
Load Register A with Register E (the SPT byte from IX+07H). Register A is needed for the RLCA rotation to test the high bit.
4DC5
RLCA 07
Rotate Register A Left with Carry. This moves bit 7 of the SPT byte into the CARRY FLAG. If the SPT value had bit 7 set (value 128-255), CARRY is now set.
4DC6
OR FCH F6 FC
OR Register A with FCH (binary 11111100). This sets bits 7-2 of Register A. Combined with the RLCA, if bit 7 of the original SPT byte was set, Register A now holds FFH or FDH. The purpose is to construct the sign-extension byte.
4DC8
LD D,A 57
Load Register D with Register A (the computed sign-extension value). If the original SPT had bit 7 set, D now holds a non-zero sign-extension byte; otherwise D was already 00H from 4DBEH.
4DC9
LD (IX+06H),D DD 72 06
Store Register D (the sign-extension byte, either 00H or the computed value) into IX+06H (byte 06H of the current PDRIVE entry, the high byte of the SPT field).
4DCC
LD DE,0010H 11 00 10
Load Register Pair DE with 0010H (decimal 16). Each PDRIVE entry is 16 bytes, so adding 16 to IX advances to the next drive's entry.
4DCF
ADD IX,DE DD 19
ADD Register Pair DE (0010H) to Register Pair IX, advancing IX from the current PDRIVE entry to the next drive's entry.
4DD1
DECrement Register B (the drive counter) by 1 and if B is not zero, JUMP back to 4DBBH to process the next drive's sign extension. [LOOP END — sign-extend all drives]

4DD3H - WRITE PDRIVE TABLE TO DISK

All 10 drives have been sign-extended. Now write the modified PDRIVE configuration table back to disk. This calls the SYS0 disk write routines to persist the changes.

4DD3
GOSUB to 4FC3H to reinitialize the PDRIVE display format variables. This resets Register A to 02H, stores it at 5118H, and points DE to 510EH. This setup is needed before the disk write operation to ensure consistent state.
4DD6
GOSUB to the SYS0 routine at 443CH to write the PDRIVE configuration table back to disk. This DOS routine flushes the in-memory PDRIVE table (4300H-439FH) to the system disk's PDRIVE sector. On return, Z FLAG set = success, NZ FLAG set = error.
4DD9
RET NZ C0
If the NZ FLAG has been set (the disk write at 443CH failed), RETURN to the caller with the error condition. [ERROR PATH — disk write failed]

4DDAH - DISPLAY SINGLE DRIVE OR ALL DRIVES (DISPLAY-ONLY ENTRY)

This is the entry point reached when the command line contains only PDRIVE (no parameters) or PDRIVE,dn1 (display only). It is also reached from the JP Z at 4D16H and 4D43H. Display all 10 drive configurations by looping through drives 0-9.

4DDA
XOR A AF
Set Register A to ZERO and clear all flags. Register A = 0 initializes the drive counter to drive 0.
4DDB
PUSH AF F5
Save Register A (the current drive counter, 0-9) and the flags onto the stack before calling the display routine. [LOOP START — display drives]
4DDC
GOSUB to 4E16H to display the configuration for the drive specified in Register A. This routine stores the drive number at 4EA2H, prints the drive number header, prints keyword labels from the keyword table, and formats each parameter value for display.
4DDF
POP AF F1
Restore Register A (the drive counter) and flags from the stack.
4DE0
INC A 3C
INCrement Register A (the drive counter) by 1 to advance to the next drive number.
4DE1
CP 0AH FE 0A
Compare Register A (the drive counter) against 0AH (decimal 10). If Register A is less than 10, the CARRY FLAG is set (more drives to display). If 10 or greater, the NO CARRY FLAG is set (all drives displayed).
4DE3
If the CARRY FLAG has been set (the drive counter is still less than 10), JUMP back to 4DDBH to display the next drive. [LOOP — display next drive]
4DE5
GOSUB to 4FECH to perform the PDRIVE compatibility check across all 10 drives. This routine returns with C holding status flags about cross-drive TI compatibility. [LOOP END — all drives displayed]

4DE8H - DISPLAY INCOMPATIBILITY WARNING IF NEEDED

After displaying all drives and running the compatibility check, test whether any incompatible TI flag combinations were found. If so, display a warning message. Then check whether any drives are actually configured before proceeding.

4DE8
LD HL,50DCH 21 DC 50
Load Register Pair HL with 50DCH, the address of the incompatibility warning message string: "*** TI= SPEC BETWEEN DRIVES INCOMPATIBLE" (terminated by 0DH).
4DEB
If the NO CARRY FLAG has been set (the compatibility check at 4FECH returned NC, meaning incompatible TI flag combinations were detected across drives), GOSUB to the SYS0 string display routine at 4467H to print the warning message at 50DCH to the screen. If CARRY was set (no incompatibility), this CALL is skipped.
4DEE
LD A,(4302H) 3A 02 43
Load Register A with the value at 4302H (byte 02H of the first PDRIVE entry — drive 0's configuration flags byte). This byte contains flags indicating whether drive 0 is configured and active.
4DF1
OR A B7
OR Register A with itself to set the Z FLAG based on the value at 4302H. If drive 0's configuration flags are all zero, the Z FLAG is set, meaning drive 0 is not configured.
4DF2
If the Z FLAG has been set (drive 0's configuration flags at 4302H are all zero, meaning drive 0 is not configured), JUMP to 4030H in SYS0. This is a critical error — the system disk drive must be configured — so control transfers to the DOS re-initialization or error recovery routine. [CRITICAL ERROR — drive 0 not configured]

4DF5H - COPY PDRIVE TABLE TO SYSTEM AREA

After displaying and validating all drives, copy a portion of the in-memory PDRIVE table to the system work area at 4291H. This copies selected bytes from each of the first 4 (or fewer) PDRIVE entries. The variable at 4DF6H is a [SELF-MODIFYING CODE] target — its value controls whether this copy operation executes.

4DF5
LD A,00H 3E 00
Load Register A with 00H. [SELF-MODIFYING CODE] — the immediate operand at address 4DF6H is modified at runtime. When the byte at 4DF6H is 00H, the copy operation is skipped. When modified to a non-zero value, the copy executes. The routine at 51CBH/4FCCH can write a non-zero value here to enable disk writes.
4DF7
OR A B7
OR Register A with itself to set the Z FLAG. If the self-modifying byte at 4DF6H was 00H, Register A is zero and the Z FLAG is set. If non-zero, the NZ FLAG is set.
4DF8
RET Z C8
If the Z FLAG has been set (the self-modifying byte at 4DF6H is 00H, meaning the copy operation is disabled — display-only mode), RETURN to the caller without copying. [DISPLAY-ONLY EXIT]

The self-modifying byte at 4DF6H is non-zero, meaning PDRIVE changes should be written to the system work area. Copy selected bytes from the PDRIVE table at 4300H to the system area at 4291H. The copy processes up to 4 drives, copying 10 bytes per drive with a 6-byte gap between entries.

4DF9
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, pointing HL to the start of the PDRIVE table (drive 0's entry). HL is the source pointer for the copy.
4DFC
LD DE,4291H 11 91 42
Load Register Pair DE with 4291H, pointing DE to the system work area where PDRIVE data is stored for use by the DOS disk routines. DE is the destination pointer.
4DFF
LD A,(43A0H) 3A A0 43
Load Register A with the value at 43A0H (the byte immediately following the last PDRIVE entry at 4390H-439FH). This byte holds the number of configured drives (1-10). It determines how many drive entries to copy.
4E02
DEC A 3D
DECrement Register A by 1. The drive count is 1-based, so decrementing converts it to a 0-based maximum index (0-9). If the original count was 1, A becomes 0.
4E03
CP 04H FE 04
Compare Register A (the 0-based drive index) against 04H (decimal 4). If Register A is less than 4, the CARRY FLAG is set (4 or fewer drives). If 4 or more, the NO CARRY FLAG is set.
4E05
If the CARRY FLAG has been set (the drive count is 4 or fewer), JUMP forward to 4E09H to use the actual count. [USE ACTUAL COUNT]
4E07
LD A,03H 3E 03
Load Register A with 03H (decimal 3). The system work area at 4291H only has room for 4 drives (indices 0-3), so cap the drive count at 4 (0-based index 3).
4E09
INC A 3C
INCrement Register A by 1, converting the 0-based index back to a 1-based count. Register A now holds the number of drives to copy (1-4).
4E0A
LD BC,000AH 01 0A 00
Load Register Pair BC with 000AH (decimal 10). This is the byte count for each LDIR copy — 10 bytes are copied from each PDRIVE entry to the system work area. [LOOP START — copy drives to system area]
4E0D
LDIR ED B0
Block copy 10 bytes from the current PDRIVE entry (HL) to the system work area (DE). After execution, HL has advanced 10 bytes into the 16-byte PDRIVE entry, and DE has advanced 10 bytes in the system area.
4E0F
LD C,06H 0E 06
Load Register C with 06H (decimal 6). After copying 10 bytes from a 16-byte PDRIVE entry, 6 bytes remain. These 6 bytes are skipped in the source to advance HL to the start of the next PDRIVE entry.
4E11
ADD HL,BC 09
ADD Register Pair BC (0006H) to Register Pair HL, advancing the source pointer past the remaining 6 bytes of the current PDRIVE entry to the start of the next entry.
4E12
DEC A 3D
DECrement Register A (the drive counter) by 1.
4E13
If the NZ FLAG has been set (the drive counter has not reached zero, meaning more drives remain to copy), JUMP back to 4E0AH to copy the next drive's 10 bytes. [LOOP — copy next drive]
4E15
RET C9
RETURN to the caller. The PDRIVE data for up to 4 drives has been copied to the system work area at 4291H.

4E16H - DISPLAY SINGLE DRIVE CONFIGURATION

Entry point to display the full configuration for one drive. On entry, Register A holds the drive number (0-9). This routine prints the drive number, then iterates through the keyword table to print each parameter label and its current value. Called from the display-all loop at 4DDCH and from the display-after-modify path at 4DA9H (via 4EB0H).

4E16
LD (4EA2H),A 32 A2 4E
Store the drive number (Register A, value 0-9) to memory location 4EA2H (the "current drive number" variable). The display subroutines reference this variable to determine which PDRIVE entry to read.
4E19
PUSH AF F5
Save Register A (the drive number) and flags onto the stack before making calls that will modify Register A.
4E1A
ADD 30H C6 30
ADD 30H (ASCII 0) to Register A, converting the binary drive number (0-9) to its ASCII digit character (0-9).
4E1C
GOSUB to 500FH to print the ASCII drive number character (Register A) to the screen. The routine at 500FH saves DE and AF, calls the ROM character output routine at 0033H, then restores AF and DE.
4E1F
LD B,03H 06 03
Load Register B with 03H (decimal 3). This is the count of padding asterisk/space pairs to print before the keyword labels, formatting the display header as "N * " (drive number followed by alignment characters).
4E21
POP AF F1
Restore Register A (the drive number) and flags from the stack.
4E22
LD HL,43A0H 21 A0 43
Load Register Pair HL with 43A0H, the address of the byte that holds the number of configured drives. This value is compared against the current drive number to determine if the drive is configured.
4E25
CP (HL) BE
Compare Register A (the current drive number, 0-9) against the value at (HL) (the configured drive count at 43A0H). If the drive number is less than the configured count, the CARRY FLAG is set (drive is configured). If equal or greater, the NO CARRY FLAG is set (drive is not configured).
4E26
If the NO CARRY FLAG has been set (the current drive number is equal to or greater than the configured drive count — this drive is not configured), JUMP forward to 4E2EH to print the asterisk-padded header without parameter values. [UNCONFIGURED DRIVE PATH]

The drive is configured (drive number is less than the configured count). Reduce the asterisk count by 1 to leave room for parameter display, then print an asterisk marker to indicate a configured drive.

4E28
DEC B 05
DECrement Register B (the asterisk/space counter) by 1, reducing it from 3 to 2. Configured drives print fewer padding characters to leave room for the parameter values that follow.
4E29
LD A,2AH 3E 2A
Load Register A with 2AH (ASCII *). This asterisk character is printed as a visual marker indicating that this drive is configured and active.
4E2B
GOSUB to 500FH to print the asterisk character (Register A = 2AH) to the screen.

Now print B padding spaces to align the keyword labels. For configured drives B=2; for unconfigured drives B=3.

4E2E
LD A,20H 3E 20
Load Register A with 20H (ASCII space). This space character is used as padding between the drive number/asterisk and the keyword labels. [LOOP START — print padding spaces]
4E30
GOSUB to 500FH to print a space character to the screen.
4E33
DECrement Register B (the padding counter) by 1 and if B is not zero, JUMP back to 4E2EH to print another space. [LOOP END — padding spaces]

4E35H - PRINT KEYWORD LABELS AND VALUES FROM TABLE

Walk through the keyword table at 511CH, printing each keyword's label string and then its corresponding value from the current drive's PDRIVE entry. The keyword table entries are null-terminated strings followed by a dispatch byte that encodes the field offset and value type.

4E35
LD BC,511CH 01 1C 51
Load Register Pair BC with 511CH, the base address of the PDRIVE keyword table. BC will walk through the table as each keyword is processed.
4E38
LD A,(BC) 0A
Load Register A with the current byte from the keyword table (pointed to by BC). During label printing, this is a character of the keyword name (e.g., T, I, =). A value of 00H marks the end of the keyword name string. [LOOP START — print keyword label characters]
4E39
OR A B7
OR Register A with itself to set the Z FLAG. If the byte is 00H (null terminator marking the end of the keyword name), the Z FLAG is set. If non-zero (a printable character), the NZ FLAG is set.
4E3A
INC BC 03
INCrement Register Pair BC by 1 to advance the keyword table pointer to the next byte.
4E3B
If the NZ FLAG has been set (the byte is a non-zero printable character), GOSUB to 500FH to print the character to the screen. If Z was set (null terminator), this CALL is skipped.
4E3E
If the NZ FLAG has been set (the last byte was a printable character, not the null terminator), JUMP back to 4E38H to print the next character of the keyword label. [LOOP — continue printing label]

The null terminator has been reached — the keyword label has been fully printed. BC now points to the dispatch byte that follows the null terminator. Set up IX to point to the correct PDRIVE entry, then read the dispatch byte to determine how to format and print the value.

4E40
GOSUB to 4E97H to set up IX to point to the current drive's PDRIVE entry field. This routine reads the dispatch byte at (BC), extracts the low nibble as the field offset, and calculates IX = 4300H + (drive × 16) + offset. On return, IX points to the specific field within the PDRIVE entry.
4E43
LD A,(BC) 0A
Load Register A with the dispatch byte from the keyword table (pointed to by BC). The high bits encode the value format: Bit 7 = numeric, Bit 6 = flag-letters.
4E44
INC BC 03
INCrement Register Pair BC by 1 to advance past the dispatch byte, positioning BC at the start of the next keyword entry in the table.
4E45
LD E,(IX+00H) DD 5E 00
Load Register E with the value at IX+00H (the low byte of the parameter value from the current drive's PDRIVE entry field).
4E48
LD D,(IX+01H) DD 56 01
Load Register D with the value at IX+01H (the high byte of the parameter value). Register Pair DE now holds the 16-bit parameter value.
4E4B
PUSH BC C5
Save Register Pair BC (the keyword table pointer positioned at the next entry) onto the stack before branching into the value formatting routines.
4E4C
BIT 7,A CB 7F
Test Bit 7 of Register A (the dispatch byte). If Bit 7 is set, the NZ FLAG is set (numeric parameter — display as a decimal number). If clear, the Z FLAG is set (flag-letter or single-letter parameter).
4E4E
If the NZ FLAG has been set (Bit 7 is set — this is a numeric parameter), JUMP forward to 4E6DH to display the value as a decimal number. [NUMERIC DISPLAY PATH]
4E50
BIT 6,A CB 77
Test Bit 6 of Register A (the dispatch byte). If Bit 6 is set, the NZ FLAG is set (flag-letter parameter — display as a string of letters). If clear, the Z FLAG is set (single-letter parameter).
4E52
If the NZ FLAG has been set (Bit 6 is set — flag-letter parameter like TI=), JUMP forward to 4E5CH to display the value as a series of flag letters. [FLAG-LETTER DISPLAY PATH]

4E54H - DISPLAY SINGLE-LETTER VALUE (TD= TYPE)

Display a single-letter parameter value (e.g., for TD=E). The value in Register E is a zero-based index (0-7) which is converted back to a letter (A-H) and printed.

4E54
LD A,E 7B
Load Register A with Register E (the parameter value — a zero-based drive type index, e.g., 0=A, 1=B, ... 7=H).
4E55
ADD 41H C6 41
ADD 41H (ASCII A) to Register A, converting the zero-based index back to an uppercase letter. Index 0 becomes A (41H), index 4 becomes E (45H), etc.
4E57
GOSUB to 500FH to print the drive type letter (Register A) to the screen.
4E5A
JUMP forward to 4E72H to restore BC and check for the next keyword in the table.

4E5CH - DISPLAY FLAG-LETTER VALUE (TI= TYPE)

Display a flag-letter parameter value (e.g., TI=ADHK). The 16-bit value in DE contains individual flag bits, where each set bit corresponds to a letter A-P. Rotate through all 16 bits and print the letter for each set bit.

Top of Loop to display flag letters

4E5C
LD B,10H 06 10
Load Register B with 10H (decimal 16). This is the loop counter for testing all 16 flag bits (letters A through P).
4E5E
LD C,41H 0E 41
Load Register C with 41H (ASCII A). Register C holds the current letter character, starting with A and incrementing through the alphabet with each loop iteration.
4E60
RR D CB 1A
Rotate Register D Right through Carry. This shifts bit 0 of the high flag byte (D) into the CARRY FLAG, and the old CARRY into bit 7 of D. This is the first half of rotating the 16-bit DE value right by one position.
4E62
RR E CB 1B
Rotate Register E Right through Carry. This shifts bit 0 of the low flag byte (E) into the CARRY FLAG, completing the 16-bit rotation. If the CARRY FLAG is now set, the corresponding flag letter is active.
4E64
LD A,C 79
Load Register A with Register C (the current letter character, A through P). Register A is pre-loaded for the conditional CALL — if the bit was set, this letter will be printed.
4E65
INC C 0C
INCrement Register C by 1 to advance to the next letter character for the next loop iteration (A→B→C→...→P).
4E66
If the CARRY FLAG has been set (the bit that was just rotated out of DE was 1, meaning this flag letter is active), GOSUB to 500FH to print the letter character (Register A) to the screen. If CARRY was clear (flag not set), this CALL is skipped and the letter is not printed.
4E69
DECrement Register B (the bit counter) by 1 and if B is not zero, JUMP back to 4E60H to test the next flag bit.

Bottom of Loop

4E6B
JUMP forward to 4E72H to restore BC and check for the next keyword.

4E6DH - DISPLAY NUMERIC VALUE

Display a numeric parameter value (e.g., TC=40, SPT=10) as a decimal number. The 16-bit value is in DE. Clear the high byte D to 00H (these parameters are all single-byte values despite being loaded as 16-bit), then call the decimal display routine at 5099H.

4E6D
LD D,00H 16 00
Load Register D with 00H, clearing the high byte of the 16-bit value. Numeric PDRIVE parameters (TC, SPT, TSR, GPL, DDSL, DDGA) are all single-byte values that fit in E, so D is forced to zero to ensure correct decimal conversion.
4E6F
GOSUB to 5099H to convert the 16-bit value in DE to decimal digits and print them to the screen. This routine performs repeated subtraction using a divisor table to extract and print each decimal digit.

4E72H - CHECK FOR NEXT KEYWORD IN TABLE

After printing one parameter's value, restore BC (the keyword table pointer) and check whether there are more keywords in the table. If so, print a comma separator and loop back. If the table is exhausted, finish the line and check for drive errors.

4E72
POP BC C1
Restore Register Pair BC (the keyword table pointer, saved at 4E4BH) from the stack. BC now points to the start of the next keyword entry in the table.
4E73
LD A,(BC) 0A
Load Register A with the first byte of the next keyword entry (pointed to by BC). If this byte is 00H, the keyword table is exhausted (no more parameters to display).
4E74
OR A B7
OR Register A with itself to set the Z FLAG. If 00H (end of keyword table), the Z FLAG is set. If non-zero (another keyword exists), the NZ FLAG is set.
4E75
If the Z FLAG has been set (the keyword table is exhausted — all parameters have been displayed), JUMP forward to 4E7EH to finish the display line. [END OF KEYWORD TABLE]
4E77
LD A,2CH 3E 2C
Load Register A with 2CH (ASCII ,). This comma character separates parameter values in the display output.
4E79
GOSUB to 500FH to print the comma separator to the screen.
4E7C
JUMP back to 4E38H to print the next keyword's label and value. [LOOP — display next parameter]

4E7EH - FINISH DISPLAY LINE AND CHECK DRIVE ERRORS

The keyword table is exhausted — all parameters for this drive have been displayed. Call the drive validation routine to check for configuration errors, then print a carriage return to end the display line.

4E7E
GOSUB to 4EB0H to validate the current drive's PDRIVE configuration. This routine checks for errors such as invalid TI/TD combinations, out-of-range SPT values, and other configuration inconsistencies. If errors are found, it prints the warning message and clears the drive's configuration flags at 4302H.
4E81
LD A,(IX+02H) DD 7E 02
Load Register A with the value at IX+02H (byte 02H of the current drive's PDRIVE entry — the configuration flags byte). IX was set by the last call to 4E97H inside 4EB0H.
4E84
AND 1CH E6 1C
AND Register A with 1CH (binary 00011100), masking bits 4, 3, and 2 of the configuration flags. These three bits indicate specific configuration states (density, side, and related settings).
4E86
If the NZ FLAG has been set (at least one of bits 4, 3, or 2 in the configuration flags is set — the drive has valid density/side configuration), JUMP forward to 4E92H to skip the error message and print the carriage return. [VALID CONFIGURATION]

Bits 4, 3, and 2 of the configuration flags are all clear, indicating an invalid or incomplete configuration for this drive. Display the error message and clear the drive's flags.

4E88
LD HL,50CBH 21 CB 50
Load Register Pair HL with 50CBH, the address of the error message string: " ** ERROR ** " (terminated by 0DH). This message warns that the drive's configuration is invalid.
4E8B
GOSUB to the SYS0 string display routine at 4467H to print the error message at 50CBH to the screen.
4E8E
XOR A AF
Set Register A to ZERO and clear all flags. This zero value will be written to the drive's configuration flags byte to mark the drive as unconfigured/invalid.
4E8F
LD (4302H),A 32 02 43
Store 00H (Register A) to memory location 4302H (byte 02H of drive 0's PDRIVE entry — the configuration flags byte). This clears drive 0's configuration, effectively disabling it. [NOTE: This always writes to drive 0's entry at 4302H, not the current drive's entry via IX. This ensures the system drive is marked unconfigured if it has an invalid configuration.]

4E92H - PRINT CARRIAGE RETURN AND EXIT DISPLAY

Print a carriage return (0DH) to end the current drive's display line, then return to the caller.

4E92
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return character). On the TRS-80 Model III, 0DH moves the cursor to the beginning of the next line.
4E94
JUMP to 500FH to print the carriage return character. Since 500FH ends with RET, this effectively returns to the caller after printing. This is a tail-call optimization — JP instead of CALL followed by RET.

4E97H - SET UP IX POINTER TO PDRIVE ENTRY FIELD

Subroutine to calculate the IX pointer to a specific field within the current drive's PDRIVE entry. The dispatch byte at (BC) encodes the field offset in its low nibble. The drive number is read from 4EA2H. IX is set to 4300H + (drive × 16) + offset. Called from 4D4EH (keyword parsing), 4E40H (display), and 4EB4H (validation).

4E97
LD A,(BC) 0A
Load Register A with the dispatch byte from the keyword table (pointed to by BC). The low nibble (bits 3-0) contains the field offset within the 16-byte PDRIVE entry.
4E98
AND 0FH E6 0F
AND Register A with 0FH, masking off the high nibble to isolate the field offset (0-15) from the dispatch byte. Register A now holds the byte offset of the target field within the PDRIVE entry.

4E9AH - CALCULATE IX = PDRIVE BASE + (DRIVE × 16) + OFFSET

Core IX pointer calculation subroutine. On entry, Register A holds the field offset (0-15). The drive number is read from 4EA2H. Calculates IX = 4300H + (drive × 16) + offset. Also called directly from 4D31H (copy path) and 4EB1H (validation) with A pre-loaded.

4E9A
PUSH HL E5
Save Register Pair HL onto the stack. HL will be used as a scratch register for the address calculation.
4E9B
PUSH DE D5
Save Register Pair DE onto the stack. DE will be used as a scratch register for the multiplication.
4E9C
LD HL,4300H 21 00 43
Load Register Pair HL with 4300H, the base address of the PDRIVE table (Drive Configuration Table).
4E9F
LD D,L 55
Load Register D with Register L (which is 00H from the 4300H load). This clears D to prepare for loading the drive number into the low byte of DE.
4EA0
LD E,A 5F
Load Register E with Register A (the field offset, 0-15). DE now holds 00:offset. This value will be added to the computed drive base address.
4EA1
LD A,FFH 3E FF
Load Register A with FFH. [SELF-MODIFYING CODE] — the immediate operand at address 4EA2H is the "current drive number" variable. At entry to the PDRIVE command, the drive number (0-9) is stored here by 4D1CH, 4DA5H, or 4E16H. The value FFH shown here is the initialized/default value; at runtime, Register A receives the actual drive number.
4EA3
RLCA 07
Rotate Register A Left with Carry. First of four RLCA instructions that multiply the drive number by 16 (shift left 4 positions). After this instruction, the drive number has been multiplied by 2.
4EA4
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 4.
4EA5
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 8.
4EA6
RLCA 07
Rotate Register A Left with Carry. The drive number has now been multiplied by 16. Register A holds (drive × 16), the byte offset from 4300H to the drive's PDRIVE entry.
4EA7
ADD A,E 83
ADD Register E (the field offset, 0-15) to Register A (drive × 16). Register A now holds (drive × 16) + field_offset, the combined offset from 4300H to the specific field.
4EA8
LD E,A 5F
Load Register E with Register A (the combined offset). DE now holds 00:(drive × 16 + offset).
4EA9
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL (4300H). HL now holds 4300H + (drive × 16) + field_offset, the absolute address of the target field.
4EAA
PUSH HL E5
Save Register Pair HL (the calculated field address) onto the stack.
4EAB
POP IX DD E1
Restore the top of stack into Register Pair IX. IX now holds the calculated address: 4300H + (drive × 16) + field_offset. This PUSH HL / POP IX sequence is the standard Z80 technique for transferring HL into IX.
4EAD
POP DE D1
Restore Register Pair DE from the stack (the original value saved at 4E9BH).
4EAE
POP HL E1
Restore Register Pair HL from the stack (the original value saved at 4E9AH).
4EAF
RET C9
RETURN to the caller with IX pointing to the target field within the current drive's PDRIVE entry.

4EB0H - VALIDATE SINGLE DRIVE PDRIVE ENTRY

Validation routine for a single drive's PDRIVE configuration. Called from 4DA9H (display-after-modify loop) and 4E7EH (display line finish). First clears unused bits in the configuration flags byte (IX+02H), then checks the drive type (IX+04H) against the interface type (IX+0FH) to verify compatibility. If the drive type is 00H (unconfigured), returns immediately.

4EB0
XOR A AF
Set Register A to ZERO and clear all flags. Register A = 00H will be passed to 4E9AH as a field offset of 0, pointing IX to the start of the current drive's PDRIVE entry (byte 00H).
4EB1
GOSUB to 4E9AH to set up IX pointing to the start (offset 00H) of the current drive's PDRIVE entry. The drive number is read from the self-modifying variable at 4EA2H. On return, IX = 4300H + (drive × 16).
4EB4
LD A,(IX+02H) DD 7E 02
Load Register A with the value at IX+02H (the configuration flags byte for the current drive). This byte contains density, side, and mode flags.
4EB7
AND E3H E6 E3
AND Register A with E3H (binary 11100011), clearing bits 4, 3, and 2 of the configuration flags. These three bits are "computed" flags that will be recalculated by the validation logic below — they are not user-settable.
4EB9
LD (IX+02H),A DD 77 02
Store the cleaned configuration flags (Register A, with bits 4,3,2 cleared) back to IX+02H. The validation code below will set these bits based on the drive type and interface type.
4EBC
LD A,(IX+04H) DD 7E 04
Load Register A with the value at IX+04H (the drive type code, TD= parameter). This is a zero-based index: 0=A (5" SD SS), 1=B (8" SD SS), 2=C (5" SD DS), 3=D (8" SD DS), 4=E (5" DD SS), 5=F (8" DD SS), 6=G (5" DD DS), 7=H (8" DD DS).
4EBF
OR A B7
OR Register A with itself to set the Z FLAG. If the drive type is 00H (type A — or unconfigured), the Z FLAG is set.
4EC0
LD C,A 4F
Load Register C with Register A (the drive type code). Register C will hold the drive type throughout the validation routine for repeated comparisons.
4EC1
RET Z C8
If the Z FLAG has been set (drive type is 0 — type A, the simplest single-density single-sided configuration), RETURN to the caller. Type A drives require no special validation beyond the flag cleanup already performed. [EARLY EXIT — drive type A]

The drive type is not A (index is 1-7). Now check the interface type (IX+0FH) to determine if the drive type is supported by the installed interface. The lookup table at 5106H holds the maximum drive type supported by each interface type.

4EC2
LD A,(IX+0FH) DD 7E 0F
Load Register A with the value at IX+0FH (byte 0FH of the PDRIVE entry). This byte holds a packed value that includes the interface type index and other control flags. The low 3 bits encode the interface type.
4EC5
CP 08H FE 08
Compare Register A (the interface/control byte from IX+0FH) against 08H. If less than 8, the CARRY FLAG is set (valid interface index for the lookup table at 5106H). If 8 or greater, the NO CARRY FLAG is set (skip the table lookup).
4EC7
LD E,A 5F
Load Register E with Register A (the interface/control byte). E preserves this value for later use.
4EC8
LD D,00H 16 00
Load Register D with 00H. Register Pair DE now holds 00:interface_byte, which will be used as an offset into the lookup table.
4ECA
If the NO CARRY FLAG has been set (the interface/control byte is 8 or greater — outside the lookup table range), JUMP forward to 4ED3H to skip the table lookup and proceed with the extended validation. [SKIP TABLE LOOKUP]

The interface index is 0-7, valid for the lookup table. Use it to retrieve the maximum supported drive type for this interface from the table at 5106H.

4ECC
LD HL,5106H 21 06 51
Load Register Pair HL with 5106H, the base address of the interface-to-maximum-drive-type lookup table. This 8-byte table contains one byte per interface type, each holding the maximum drive type code that interface supports.
4ECF
ADD HL,DE 19
ADD Register Pair DE (00:interface_index) to Register Pair HL (5106H). HL now points to 5106H + interface_index, the table entry for this interface type.
4ED0
LD A,(HL) 7E
Load Register A with the maximum drive type code from the lookup table entry at (HL). This value is the highest drive type index (0-7) that the interface supports.
4ED1
CP C B9
Compare Register A (the maximum supported drive type) against Register C (the actual drive type code from IX+04H). If the maximum is less than the drive type, the CARRY FLAG is set (drive type exceeds interface capability). If equal or greater, the NO CARRY FLAG is set (drive type is supported).
4ED2
RET C D8
If the CARRY FLAG has been set (the drive type exceeds the interface's maximum capability — this is an incompatible combination), RETURN to the caller with CARRY set to signal the error. The caller at 4E7EH will detect this and print the error message. [ERROR EXIT — drive type exceeds interface capability]

4ED3H - EXTENDED DRIVE VALIDATION — SPT AND TC CHECKS

The interface supports this drive type (or the table lookup was skipped). Now perform extended validation: check the SPT value (IX+03H) against the drive type, and verify that the drive's track and sector configuration is internally consistent. This calls SYS0 routines at 4C37H and 4C59H for detailed range checking.

4ED3
LD L,C 69
Load Register L with Register C (the drive type code, 0-7). Register L will be used as a working copy of the drive type for subsequent comparisons.
4ED4
LD A,(IX+03H) DD 7E 03
Load Register A with the value at IX+03H (the SPT — sectors per track — value for this drive). This is the user-specified or default sector count.
4ED7
OR A B7
OR Register A with itself to set the Z FLAG. If SPT is 00H, the Z FLAG is set (no sectors per track configured — unconfigured or error).
4ED8
RET Z C8
If the Z FLAG has been set (SPT is zero — drive has no sector configuration), RETURN to the caller. A zero SPT means this drive entry has no meaningful disk geometry. [EARLY EXIT — no SPT configured]
4ED9
GOSUB to the SYS0 routine at 4C37H. This routine performs validation calculations based on the drive type and SPT values. On return, HL holds a computed sector/track boundary value, and DE holds a comparison limit. The exact computation depends on the drive geometry tables in SYS0.
4EDC
BIT 4,(IX+0EH) DD CB 0E 66
Test Bit 4 of the value at IX+0EH (byte 0EH of the PDRIVE entry — additional configuration flags). Bit 4 indicates a special operating mode flag. If set, the NZ FLAG is set; if clear, the Z FLAG is set.
4EE0
LD A,05H 3E 05
Load Register A with 05H (decimal 5). This value represents the standard granule size of 5 sectors per granule used in NEWDOS/80 v2.0.
4EE2
NOP 00
No operation. This NOP is a placeholder — it may have been a patched-out instruction or reserved space for a future modification.
4EE3
If the NZ FLAG has been set (Bit 4 of IX+0EH is set — special mode flag is active), GOSUB to 517EH to perform an additional validation check. The routine at 517EH tests Bit 2 of IX+0FH and returns A=03H if set, or returns Z if clear. This adjusts the granule size for special configurations.
4EE6
GOSUB to the SYS0 routine at 4C59H. This routine uses the granule size (Register A) and the drive geometry computed by 4C37H to validate that the SPT and TC values produce a consistent disk layout. On return, HL and DE hold boundary values, and Z/NZ flags indicate the result.
4EE9
LD A,(IX+09H) DD 7E 09
Load Register A with the value at IX+09H (byte 09H of the PDRIVE entry — the DDSL parameter, the directory start lump number).
4EEC
CP 02H FE 02
Compare Register A (the DDSL value) against 02H. If DDSL is less than 2, the CARRY FLAG is set (DDSL is 0 or 1 — too low for a valid directory position). If 2 or greater, the NO CARRY FLAG is set.
4EEE
LD B,A 47
Load Register B with Register A (the DDSL value). Register B preserves the DDSL value for the range checking loop below.
4EEF
RET C D8
If the CARRY FLAG has been set (DDSL is less than 2 — the directory start lump is too low), RETURN to the caller with CARRY set to signal invalid configuration. [ERROR EXIT — DDSL too low]
4EF0
CP 07H FE 07
Compare Register A (the DDSL value) against 07H. If DDSL is 7 or greater, the NO CARRY FLAG is set (DDSL exceeds the maximum valid range). If less than 7, the CARRY FLAG is set.
4EF2
RET NC D0
If the NO CARRY FLAG has been set (DDSL is 7 or greater — exceeds maximum), RETURN to the caller. This is not flagged as an error with CARRY; the return without CARRY indicates the validation passed (large DDSL values are allowed for large-capacity disks). [EXIT — DDSL is large, skip further checks]

DDSL is in the range 2-6. Now perform detailed cross-validation between DDSL, the granule size (Register A from 4EE0H/4EE3H), and the disk geometry computed by 4C37H/4C59H. Register B holds DDSL, and HL/DE hold boundary values from the SYS0 routines.

4EF3
EX DE,HL EB
Exchange DE and HL. HL now holds the value that was in DE (a boundary/limit from the 4C59H computation), and DE holds the value that was in HL.
4EF4
LD L,(IX+08H) DD 6E 08
Load Register L with the value at IX+08H (byte 08H of the PDRIVE entry — the GPL parameter, granules per lump). Register L now holds the GPL value.
4EF7
LD (IX+00H),L DD 75 00
Store Register L (the GPL value from IX+08H) into IX+00H. [NOTE: IX currently points to the PDRIVE entry base (offset 0 from 4EB0H's setup), so this writes GPL into byte 00H. This appears to temporarily overwrite the TI flags low byte with the GPL value for the calculation that follows.]
4EF9
NOP 00
No operation. Another placeholder NOP, consistent with the one at 4EE2H — reserved space or patched instruction.
4EFA
LD A,(IX+05H) DD 7E 05
Load Register A with the value at IX+05H (byte 05H of the PDRIVE entry — the TC parameter, track count).
4EFD
OR A B7
OR Register A with itself to set the Z FLAG. If TC is 00H, the Z FLAG is set (no track count configured).
4EFE
LD C,A 4F
Load Register C with Register A (the TC value). Register C holds the track count for the loop below.
4EFF
RET Z C8
If the Z FLAG has been set (TC is zero — no track count configured), RETURN to the caller. A zero TC means this drive has no track geometry. [EARLY EXIT — no TC configured]
4F00
CP 09H FE 09
Compare Register A (the TC value) against 09H (decimal 9). If TC is 9 or greater, the NO CARRY FLAG is set. If less than 9, the CARRY FLAG is set.
4F02
RET NC D0
If the NO CARRY FLAG has been set (TC is 9 or greater — a normal track count for real disks), RETURN to the caller. Track counts of 9+ are accepted without further checking. [EXIT — TC is normal range]

TC is in the range 1-8, which is unusually low. Perform a detailed sector-boundary check using the GPL and DDSL values to verify the geometry is internally consistent. Register B holds DDSL, Register C holds TC, HL and DE hold computed boundaries.

4F03
GOSUB to the SYS0 routine at 4C37H again to recompute the geometry boundaries using the current state (which now has GPL written into byte 00H). On return, HL holds an updated sector boundary value.
4F06
INC HL 23
INCrement Register Pair HL by 1. This adjusts the sector boundary value by one for the comparison loop. [LOOP START — count sectors to DDSL boundary]
4F07
DECrement Register B (the DDSL loop counter) by 1 and if B is not zero, JUMP back to 4F06H to increment HL again. This advances HL by DDSL positions, computing the sector offset to the directory start. [LOOP END — DDSL count]
4F09
EX DE,HL EB
Exchange DE and HL. DE now holds the computed directory sector offset, and HL holds the previous boundary value from DE.
4F0A
OR A B7
Clear the CARRY FLAG (OR A always clears carry) to prepare for the SBC instruction that follows. This ensures the subtraction is a pure comparison without a borrow.
4F0B
SBC HL,DE ED 52
SuBtract with Carry Register Pair DE (directory sector offset) from Register Pair HL (the total sector boundary). If HL < DE, the result is negative and the CARRY FLAG is set (directory start exceeds disk capacity). If HL >= DE, no carry (directory fits within disk).
4F0D
RET C D8
If the CARRY FLAG has been set (the directory start sector exceeds the disk's total sector capacity — invalid geometry), RETURN with CARRY set to signal the error. [ERROR EXIT — directory exceeds disk capacity]
4F0E
ADD HL,DE 19
ADD Register Pair DE back to Register Pair HL, restoring HL to the total sector boundary value (undoing the SBC subtraction).
4F0F
LD A,C 79
Load Register A with Register C (the TC value, track count).
4F10
GOSUB to the SYS0 routine at 4C59H with Register A = TC for another geometry computation. This routine validates the TC value against the computed sector boundaries and returns with HL/DE holding updated boundary values and Z/NZ flags.
4F13
If the Z FLAG has been set (the 4C59H computation returned an exact boundary match), JUMP forward to 4F16H to store the result without adjustment. [EXACT MATCH]
4F15
INC HL 23
INCrement Register Pair HL by 1. When 4C59H returned NZ (not an exact match), HL needs a +1 adjustment to account for the partial lump at the boundary.
4F16
LD (IX+00H),L DD 75 00
Store Register L (the low byte of the computed boundary value) into IX+00H. This writes the computed lump count or adjusted value back into the PDRIVE entry's byte 00H (which was temporarily overwritten at 4EF7H).
4F18
LD BC,112BH 01 2B 11
Load Register Pair BC with 112BH. This value serves as a validation constant — B=11H (decimal 17) is the maximum granule count and C=2BH (decimal 43) is a sector boundary limit used in subsequent checks.
4F1B
RET NZ C0
If the NZ FLAG has been set (from the INC HL at 4F15H or the LD at 4F16H — the boundary was not an exact match and required adjustment), RETURN to the caller. The adjusted value has been stored and no further validation is needed for this case. [EXIT — adjusted boundary stored]
4F1C
NOP 00
No operation. Placeholder NOP — reserved space or patched instruction, consistent with the NOPs at 4EE2H and 4EF9H.

4F1DH - DDGA CROSS-VALIDATION

Continue the extended validation. The boundary was an exact match (Z was set at 4F16H and RET NZ at 4F1BH did not return). Now verify that the directory allocation (DDGA) does not exceed the available disk space by comparing the computed boundary in HL against the directory sector offset in DE.

4F1D
OR A B7
Clear the CARRY FLAG (OR A always clears carry) to prepare for the SBC instruction that follows.
4F1E
SBC HL,DE ED 52
SuBtract with Carry Register Pair DE from Register Pair HL. This compares the computed lump boundary (HL) against the directory sector offset (DE). If HL < DE, the CARRY FLAG is set (directory allocation exceeds disk). If HL >= DE, the NO CARRY FLAG is set (directory fits).
4F20
RET NC D0
If the NO CARRY FLAG has been set (HL >= DE — the directory allocation fits within the disk's capacity), RETURN to the caller. Validation passed. [SUCCESS EXIT — DDGA fits]

4F21H - 16-BIT MULTIPLICATION VALIDATION

DDGA exceeds available space. Perform a 16-bit multiplication check to verify the total sector count. Load the DDGA and related parameters from the PDRIVE entry, then multiply to check that sectors_per_granule × granules_per_lump × lumps does not overflow a 16-bit value.

4F21
LD C,(IX+0DH) DD 4E 0D
Load Register C with the value at IX+0DH (byte 0DH of the PDRIVE entry — the DDGA parameter, directory default granule allocation count).
4F24
LD B,(IX+0EH) DD 46 0E
Load Register B with the value at IX+0EH (byte 0EH of the PDRIVE entry — the additional configuration flags byte). Register Pair BC now holds 0E:0D as a 16-bit value combining the flags byte and DDGA for bitfield extraction.
4F27
LD A,C 79
Load Register A with Register C (the DDGA value from IX+0DH).
4F28
AND 7FH E6 7F
AND Register A with 7FH (binary 01111111), masking off bit 7 of the DDGA byte. Bit 7 may be a flag bit rather than part of the numeric value. Register A now holds the DDGA count with bit 7 cleared.
4F2A
LD L,A 6F
Load Register L with Register A (the masked DDGA value). Register L holds the low byte of the multiplicand.
4F2B
LD A,B 78
Load Register A with Register B (the flags byte from IX+0EH).
4F2C
AND 00H E6 00
AND Register A with 00H, which forces Register A to 00H and sets the Z FLAG. This effectively clears the high byte of the multiplicand. [NOTE: AND 00H always produces zero — this may be SELF-MODIFYING CODE where the 00H operand at address 4F2DH is patched at runtime to a different mask value.]
4F2E
LD H,A 67
Load Register H with Register A (00H). Register Pair HL now holds 00:DDGA_masked, the multiplicand for the 16-bit multiplication.

Now perform a 16-bit multiplication by repeated doubling. Register D serves as the loop counter (16 iterations for 16-bit precision). The result accumulates in A:HL where A holds overflow bits.
Top of loop - 16-bit multiply

4F2F
LD D,10H 16 10
Load Register D with 10H (decimal 16), the loop counter for the 16-bit multiplication. Each iteration doubles the accumulator and adds the next bit. [LOOP START — 16-bit multiply]
4F31
XOR A AF
Set Register A to ZERO and clear all flags. Register A is the overflow accumulator for the multiplication — it tracks bits that overflow past the 16-bit result in HL.
4F32
ADD HL,HL 29
ADD Register Pair HL to itself (double HL). This shifts the multiplicand left by one bit position. If the result overflows 16 bits, the CARRY FLAG is set.
4F33
ADC 00H CE 00
ADd Carry to Register A with immediate value 00H. This captures the overflow bit from the ADD HL,HL into Register A. If HL overflowed, A increments by 1.
4F35
DEC D 15
DECrement Register D (the loop counter) by 1.
4F36
If the NZ FLAG has been set (the loop counter D has not reached zero), JUMP back to 4F32H to perform the next doubling iteration.

End of loop for 16-bit multiply. The 16-bit multiplication is complete. Register A holds overflow bits. If A is not exactly 01H (meaning the multiplication overflowed by more than one bit position or didn't overflow at all), the configuration is invalid.

4F38
DEC A 3D
DECrement Register A (the overflow accumulator) by 1. If the multiplication produced exactly one overflow (A was 01H), A becomes 00H and the Z FLAG is set. Any other value means the result did not match the expected single-overflow pattern.
4F39
RET NZ C0
If the NZ FLAG has been set (the overflow was not exactly 1 — the multiplication result is out of the expected range), RETURN to the caller. The configuration is invalid but this returns without CARRY (no error flag set — a silent rejection). [EXIT — overflow mismatch]
4F3A
LD A,C 79
Load Register A with Register C (the original DDGA value from IX+0DH, including bit 7).
4F3B
AND 76H E6 76
AND Register A with 76H (binary 01110110), isolating bits 6,5,4,2,1 of the DDGA byte. These specific bits encode sub-fields within the DDGA configuration.
4F3D
RET NZ C0
If the NZ FLAG has been set (any of bits 6,5,4,2,1 are set in the DDGA byte — unexpected flags are present), RETURN to the caller. [EXIT — invalid DDGA flag bits]
4F3E
LD A,B 78
Load Register A with Register B (the flags byte from IX+0EH).
4F3F
AND E0H E6 E0
AND Register A with E0H (binary 11100000), isolating bits 7,6,5 of the flags byte at IX+0EH. These are the high-order flag bits.
4F41
RET NZ C0
If the NZ FLAG has been set (any of bits 7,6,5 are set in the IX+0EH flags byte — invalid high flags), RETURN to the caller. [EXIT — invalid high flags in byte 0EH]

4F42H - TI FLAG BIT DISPATCH — DECODE INTERFACE FLAGS

All basic range checks have passed. Now decode the TI flag bits (stored in IX+00H/IX+01H as set by the TI= parameter) and set the appropriate configuration bits in the drive's config bytes (IX+02H and IX+07H). This section tests individual TI flag bits (corresponding to flags I, J, K, L, M as documented in the PDRIVE manual) and dispatches to the appropriate encoding logic.

4F42
LD D,14H 16 14
Load Register D with 14H (decimal 20). Register D accumulates configuration bit values. The initial value 14H sets bits 4 and 2 of Register D (binary 00010100), pre-setting the "double density" and "double sided" flags. This is the default for the TI flag K path.
4F44
LD L,(IX+0FH) DD 6E 0F
Load Register L with the value at IX+0FH (the interface/control byte). Individual bits of this byte will be tested to determine which TI flags were set.
4F47
BIT 4,C CB 61
Test Bit 4 of Register C (the DDGA byte from IX+0DH). Bit 4 corresponds to TI flag K (track 0 formatted in opposite density). If set, the NZ FLAG is set.
4F49
If the NZ FLAG has been set (TI flag K is active — track 0 opposite density mode), JUMP forward to 4F6EH to validate and encode the K flag configuration. [FLAG K PATH]
4F4B
LD D,08H 16 08
Load Register D with 08H (decimal 8, binary 00001000). This sets bit 3 of the config accumulator, the value for TI flag J (track numbers start from 1).
4F4D
BIT 3,C CB 59
Test Bit 3 of Register C (the DDGA byte). Bit 3 corresponds to TI flag J (tracks start from 1). If set, the NZ FLAG is set.
4F4F
If the NZ FLAG has been set (TI flag J is active), JUMP forward to 4F6EH to encode the J flag. [FLAG J PATH]
4F51
BIT 1,C CB 49
Test Bit 1 of Register C. Bit 1 corresponds to TI flag I (lowest sector number is 1 instead of 0). If set, the NZ FLAG is set.
4F53
If the Z FLAG has been set (TI flag I is not active), JUMP forward to 4F5BH to check flag L. [SKIP FLAG I]
4F55
LD D,0CH 16 0C
Load Register D with 0CH (decimal 12, binary 00001100). This sets bits 3 and 2, encoding the configuration for TI flag I (sector 1 base) combined with implicit flag J behavior.
4F57
BIT 2,L CB 55
Test Bit 2 of Register L (the interface/control byte from IX+0FH). This bit modifies how flag I interacts with the interface configuration.
4F59
JUMP forward to 4F6DH to test the result and conditionally proceed to 4F6EH. [FLAG I ENCODING]
4F5B
BIT 2,C CB 51
Test Bit 2 of Register C. Bit 2 corresponds to TI flag L (two step pulses between tracks — for 80-track drives reading 40-track disks). If set, the NZ FLAG is set.
4F5D
If the Z FLAG has been set (TI flag L is not active), JUMP forward to 4F65H to check flag M. [SKIP FLAG L]
4F5F
LD D,10H 16 10
Load Register D with 10H (decimal 16, binary 00010000). This sets bit 4, encoding the configuration for TI flag L (double-step mode).
4F61
BIT 0,L CB 45
Test Bit 0 of Register L (the interface/control byte from IX+0FH). This bit modifies how flag L interacts with the interface.
4F63
JUMP forward to 4F6DH to test the result. [FLAG L ENCODING]
4F65
BIT 0,C CB 41
Test Bit 0 of Register C. Bit 0 corresponds to TI flag M (TRSDOS Model III compatibility mode, implies flag I). If set, the NZ FLAG is set.
4F67
RET Z C8
If the Z FLAG has been set (TI flag M is not active — and no other flags I/J/K/L were active either), RETURN to the caller. No special TI configuration flags need to be encoded. [EXIT — no special TI flags]
4F68
LD D,04H 16 04
Load Register D with 04H (decimal 4, binary 00000100). This sets bit 2, encoding the configuration for TI flag M (TRSDOS Model III mode).
4F6A
LD A,L 7D
Load Register A with Register L (the interface/control byte from IX+0FH).
4F6B
AND 01H E6 01
AND Register A with 01H, isolating bit 0 of the interface/control byte. This bit determines whether flag M is compatible with the current interface.
4F6D
RET NZ C0
If the NZ FLAG has been set (the interface compatibility bit was set — the flag is not compatible with this interface), RETURN to the caller without encoding the flag. [EXIT — flag incompatible with interface]

4F6EH - ENCODE TI FLAGS INTO CONFIGURATION BYTES

A TI flag (K, J, I, L, or M) has been identified as active and compatible. Now encode the flag's effects into the drive's configuration bytes IX+02H and IX+07H. Register D holds the config bits to OR into IX+02H. Register E will accumulate additional flag bits for IX+07H based on secondary TI flag tests (flags H, A/D, B/C/E).

4F6E
LD A,L 7D
Load Register A with Register L (the interface/control byte from IX+0FH). This value will be range-checked to ensure it is within the valid interface index range.
4F6F
CP 08H FE 08
Compare Register A (the interface/control byte) against 08H. If 8 or greater, the NO CARRY FLAG is set (outside the valid range for the encoding logic). If less than 8, the CARRY FLAG is set (valid).
4F71
RET NC D0
If the NO CARRY FLAG has been set (interface byte is 8 or greater — out of range for the encoding), RETURN to the caller without encoding. [EXIT — interface out of encoding range]

The interface byte is 0-7. Now build the secondary flag byte in Register E by testing individual bits of the interface/control byte (L) and the DDGA/flags bytes (C and B). Each flag sets a specific bit in Register E.

4F72
LD E,00H 1E 00
Load Register E with 00H, initializing the secondary flag accumulator to zero. Individual bits will be SET as each flag is detected.
4F74
BIT 2,L CB 55
Test Bit 2 of Register L (the interface/control byte). Bit 2 indicates a specific interface capability flag.
4F76
If the Z FLAG has been set (Bit 2 of the interface byte is clear), JUMP forward to 4F7AH to skip setting this flag in E. [SKIP BIT 2]
4F78
SET 0,E CB C3
SET Bit 0 of Register E. This encodes the interface capability indicated by bit 2 of the interface byte into the secondary flag accumulator.
4F7A
BIT 0,L CB 45
Test Bit 0 of Register L (the interface/control byte). Bit 0 indicates another interface capability.
4F7C
If the Z FLAG has been set (Bit 0 is clear), JUMP forward to 4F80H to skip. [SKIP BIT 0]
4F7E
SET 7,E CB FB
SET Bit 7 of Register E. This encodes the interface capability indicated by bit 0 of the interface byte.
4F80
BIT 1,L CB 4D
Test Bit 1 of Register L (the interface/control byte). Bit 1 indicates a third interface capability.
4F82
If the Z FLAG has been set (Bit 1 is clear), JUMP forward to 4F86H to skip. [SKIP BIT 1]
4F84
SET 6,E CB F3
SET Bit 6 of Register E. This encodes the interface capability indicated by bit 1 of the interface byte.
4F86
LD A,(IX+0CH) DD 7E 0C
Load Register A with the value at IX+0CH (byte 0CH of the PDRIVE entry — the TSR parameter, track stepping rate code, value 0-3).
4F89
CP 04H FE 04
Compare Register A (the TSR value) against 04H. If TSR is 4 or greater, the NO CARRY FLAG is set (invalid — TSR must be 0-3). If less than 4, the CARRY FLAG is set (valid).
4F8B
RET NC D0
If the NO CARRY FLAG has been set (TSR is 4 or greater — out of the valid range 0-3), RETURN to the caller. Invalid TSR halts the encoding. [ERROR EXIT — TSR out of range]

TSR is valid (0-3). OR the TSR value into Register D (the primary config accumulator) so that the stepping rate bits are included in the final configuration byte.

4F8C
OR D B2
OR Register A (the TSR value, 0-3) with Register D (the accumulated config bits). This merges the stepping rate into the configuration byte alongside the TI flag bits already in D.
4F8D
LD D,A 57
Load Register D with Register A (the merged config byte). Register D now holds the combined TI flag encoding plus the TSR stepping rate.

Now test additional TI flag bits from the DDGA byte (Register B = IX+0EH) and the flags byte (Register C = IX+0DH) to set more bits in D and E.

4F8E
BIT 4,B CB 60
Test Bit 4 of Register B (the IX+0EH flags byte). Bit 4 corresponds to the special mode flag tested earlier at 4EDCH.
4F90
If the Z FLAG has been set (Bit 4 of IX+0EH is clear — special mode not active), JUMP forward to 4F9CH to skip the special mode encoding.
4F92
SET 5,D CB EA
SET Bit 5 of Register D. This encodes the special mode flag into the primary configuration byte.
4F94
BIT 0,E CB 43
Test Bit 0 of Register E (the secondary flag accumulator). This tests whether a specific interface capability was encoded earlier at 4F78H.
4F96
LD A,06H 3E 06
Load Register A with 06H. This value will be passed to the validation subroutine at 5178H if the interface capability bit is set.
4F98
If the NZ FLAG has been set (Bit 0 of E is set — the interface capability is active), GOSUB to 5178H to perform an additional validation. The routine at 5178H tests Bit 2 of IX+0FH and returns A=03H if set, or Z if clear. This adjusts the configuration for interfaces with special density handling.
4F9B
RET NZ C0
If the NZ FLAG has been set (the 5178H validation returned NZ — the special mode is incompatible with this interface), RETURN to the caller without completing the encoding. [ERROR EXIT — special mode incompatible]
4F9C
BIT 3,B CB 58
Test Bit 3 of Register B (the IX+0EH flags byte). Bit 3 encodes another configuration attribute.
4F9E
If the Z FLAG has been set (Bit 3 is clear), JUMP forward to 4FA2H to skip. [SKIP BIT 3]
4FA0
SET 2,E CB D3
SET Bit 2 of Register E. This encodes the flag indicated by bit 3 of IX+0EH into the secondary flag accumulator.
4FA2
BIT 7,C CB 79
Test Bit 7 of Register C (the DDGA byte from IX+0DH). Bit 7 is a flag that was masked off during the multiplication check at 4F28H but is meaningful here for configuration encoding.
4FA4
If the Z FLAG has been set (Bit 7 of DDGA is clear), JUMP forward to 4FA8H to skip. [SKIP BIT 7]
4FA6
SET 7,D CB FA
SET Bit 7 of Register D. This encodes the flag indicated by bit 7 of IX+0DH into the primary configuration byte.
4FA8
BIT 1,B CB 48
Test Bit 1 of Register B (the IX+0EH flags byte).
4FAA
If the Z FLAG has been set (Bit 1 is clear), JUMP forward to 4FAEH to skip. [SKIP BIT 1]
4FAC
SET 1,E CB CB
SET Bit 1 of Register E.
4FAE
BIT 0,B CB 40
Test Bit 0 of Register B (the IX+0EH flags byte).
4FB0
If the Z FLAG has been set (Bit 0 is clear), JUMP forward to 4FB4H to skip. [SKIP BIT 0]
4FB2
SET 4,E CB E3
SET Bit 4 of Register E.
4FB4
BIT 2,B CB 50
Test Bit 2 of Register B (the IX+0EH flags byte).
4FB6
If the Z FLAG has been set (Bit 2 is clear), JUMP forward to 4FBCH to skip the last two SET instructions. [SKIP BIT 2]
4FB8
SET 6,D CB F2
SET Bit 6 of Register D. Bit 2 of IX+0EH triggers both bit 6 in D and bit 1 in E.
4FBA
SET 1,E CB CB
SET Bit 1 of Register E. This is the companion to the SET 6,D above — both are set when bit 2 of IX+0EH is active.

4FBCH - STORE COMPUTED CONFIGURATION BYTES AND RETURN

All TI flag bits have been tested and encoded. Register D holds the primary configuration byte (to be stored at IX+07H) and Register E holds the secondary flag byte (to be stored at IX+02H). Write both values to the PDRIVE entry and return.

4FBC
LD (IX+07H),E DD 73 07
Store Register E (the secondary flag accumulator) into IX+07H (byte 07H of the PDRIVE entry). This writes the computed secondary configuration flags into the SPT/sector configuration field.
4FBF
LD (IX+02H),D DD 72 02
Store Register D (the primary configuration accumulator with TI flag bits and TSR) into IX+02H (byte 02H of the PDRIVE entry — the main configuration flags byte).
4FC2
RET C9
RETURN to the caller. The PDRIVE entry's configuration bytes IX+02H and IX+07H have been fully computed and stored based on the TI flag settings, TSR value, and interface capabilities.

4FC3H - INITIALIZE DISPLAY FORMAT SUBROUTINE

Short subroutine to initialize the PDRIVE display format variables. Sets the display column count to 2 and points DE to the default parameter template buffer. Called from 4D0BH (entry setup) and 4DD3H (pre-disk-write setup).

4FC3
LD A,02H 3E 02
Load Register A with 02H (decimal 2). This is the display column count — PDRIVE output is formatted in 2-column layout on screen.
4FC5
LD (5118H),A 32 18 51
Store 02H (Register A) to memory location 5118H (the display format control byte). This variable controls how many drives are displayed per screen line.
4FC8
LD DE,510EH 11 0E 51
Load Register Pair DE with 510EH, the address of the default PDRIVE parameter template buffer. This 6-byte buffer at 510EH-5113H contains default parameter values used when initializing new drive entries.
4FCB
RET C9
RETURN to the caller with Register A = 02H, 5118H set to 02H, and DE pointing to 510EH.

4FCCH - COMMAND-LINE SCANNER WRAPPER

Wrapper around the DOS command-line scanner at 4C7AH that adds PDRIVE-specific logic. After scanning, checks whether the PDRIVE invocation is display-only (by testing the flags at 5114H and the self-modifying byte at 4DF6H). If display-only and the user typed a suffix character after the drive number, this routine dispatches to the suffix handler at 51CBH. Returns: CARRY = error/BREAK, Z = end of line, NZ = token found.

4FCC
GOSUB to the SYS0 command-line scanner at 4C7AH. This routine parses the next token from the command line. On return: CARRY set = error or BREAK key pressed; Z set = end of command line; NZ set = token found with HL pointing to its start.
4FCF
RET C D8
If the CARRY FLAG has been set (error or BREAK detected by 4C7AH), RETURN immediately to the caller with CARRY set. [ERROR PATH]
4FD0
RET Z C8
If the Z FLAG has been set (end of command line — no more tokens), RETURN to the caller with Z set. [END OF LINE]

A token was found (NZ). Now check whether this PDRIVE invocation is in display-only mode. If the flags byte at 5114H is non-zero, this is a modification command (not display-only) and we return with NZ to let the caller process the token normally.

4FD1
LD A,(5114H) 3A 14 51
Load Register A with the value at 5114H (the command-line flags byte saved at entry by 4D08H). A non-zero value means parameters were passed that modify drive configuration.
4FD4
OR A B7
OR Register A with itself to set the Z FLAG. If the flags byte is 00H (display-only mode), the Z FLAG is set. If non-zero (modification mode), the NZ FLAG is set.
4FD5
RET NZ C0
If the NZ FLAG has been set (modification mode — the flags byte is non-zero), RETURN to the caller with NZ. The caller will process the token as a keyword=value parameter. [MODIFICATION MODE — return to caller]

Display-only mode (5114H is 00H). Now check the self-modifying byte at 4DF6H which controls whether changes are written to disk. If it is already non-zero, changes are enabled and we return NZ.

4FD6
LD DE,4DF6H 11 F6 4D
Load Register Pair DE with 4DF6H, the address of the self-modifying byte within the LD A,00H instruction at 4DF5H. This byte controls whether the PDRIVE-to-system-area copy executes (00H = display-only, non-zero = write enabled).
4FD9
LD A,(DE) 1A
Load Register A with the value at (DE) (the self-modifying byte at 4DF6H).
4FDA
OR A B7
OR Register A with itself to set the Z FLAG. If 00H (display-only — write not enabled), the Z FLAG is set. If non-zero (write enabled), the NZ FLAG is set.
4FDB
RET NZ C0
If the NZ FLAG has been set (the write-enable byte at 4DF6H is non-zero — changes are already enabled), RETURN to the caller with NZ. [WRITE ALREADY ENABLED]

Both 5114H and 4DF6H are zero — this is a pure display-only invocation. The user typed something after the drive number (e.g., PDRIVE,0,A or PDRIVE,0,B). Dispatch to the suffix handler at 51CBH which checks for the A (save to disk) or B (RAM only) suffix.

4FDC
LD A,(HL) 7E
Load Register A with the next character from the command line (pointed to by HL). This is the suffix character that the user typed (expected to be A or B).
4FDD
JUMP to 51CBH to process the suffix character. The routine at 51CBH checks for A (enable disk writes at 4DF6H and re-enter the scanner) or B (clear the 4DD3H-4DD9H area to disable disk writes and re-enter). [SUFFIX DISPATCH]

4FE0H - SUFFIX HANDLER RETURN POINT

Return point from the suffix handler at 51CBH. After the A suffix is processed, the suffix handler jumps here to continue scanning the command line. If the suffix was valid, HL is advanced past it and scanning resumes. If not valid, the write-enable byte at (DE) is cleared and the routine returns with NZ and A=1.

4FE0
If the NZ FLAG has been set (the character following the suffix was not a valid command-line delimiter — the suffix was part of a longer token), JUMP forward to 4FE8H to clear the write-enable byte and return. [INVALID SUFFIX CONTEXT]
4FE2
INC HL 23
INCrement Register Pair HL by 1 to advance the command-line pointer past the suffix character that was just validated.
4FE3
GOSUB to the SYS0 command-line scanner at 4C7AH to resume scanning from the updated position. This checks for more tokens after the suffix.
4FE6
RET NC D0
If the NO CARRY FLAG has been set (no error — the scanner successfully found end-of-line or another token), RETURN to the caller with the scanner's result (Z for end-of-line, NZ for more tokens). [NORMAL RETURN]
4FE7
DEC HL 2B
DECrement Register Pair HL by 1 to back up the command-line pointer. If the scanner returned CARRY (error), back up so the error position is correctly reported.
4FE8
XOR A AF
Set Register A to ZERO and clear all flags.
4FE9
LD (DE),A 12
Store 00H (Register A) to the address pointed to by DE (4DF6H — the self-modifying write-enable byte). This disables the PDRIVE-to-system-area copy, reverting to display-only mode.
4FEA
INC A 3C
INCrement Register A from 00H to 01H. This sets Register A to a non-zero value and clears the Z FLAG (setting NZ). The NZ return signals to the caller that a token was found (even though it was an invalid suffix context).
4FEB
RET C9
RETURN to the caller with A=01H and NZ set. The write-enable byte has been cleared back to 00H.

4FECH - COMPATIBILITY CHECK ACROSS ALL 10 DRIVES

Scan all 10 PDRIVE entries to check for cross-drive TI flag incompatibilities. Specifically, certain TI flags (B, C, E on Model I) are inter-drive mutually exclusive — if one drive uses flag B, no other drive may use flag C or E, and vice versa. This routine ORs together the relevant flag bits from all drives and checks whether incompatible combinations are present. Called from 4DB2H and 4DE5H after displaying all drives. Returns with CARRY set = compatible (no conflicts), NO CARRY = incompatible (conflicts found). Register C holds the accumulated flag bits.

4FEC
LD HL,430DH 21 0D 43
Load Register Pair HL with 430DH, pointing to byte 0DH of drive 0's PDRIVE entry. Byte 0DH is the DDGA/flags byte that contains the TI flag encoding. HL will walk through all 10 entries.
4FEF
LD BC,0A00H 01 00 0A
Load Register Pair BC with 0A00H. Register B = 0AH (decimal 10, the loop counter for all 10 drives). Register C = 00H (the flag accumulator, initialized to zero).
4FF2
LD DE,0010H 11 00 10
Load Register Pair DE with 0010H (decimal 16). Each PDRIVE entry is 16 bytes, so adding DE to HL advances to the same byte in the next drive's entry. [LOOP START — scan all drives]
4FF5
LD A,(HL) 7E
Load Register A with the DDGA/flags byte (byte 0DH) from the current drive's PDRIVE entry (pointed to by HL).
4FF6
AND 7EH E6 7E
AND Register A with 7EH (binary 01111110), isolating bits 6-1 of the DDGA byte. These are the flag bits relevant to inter-drive mutual exclusivity (bit 7 and bit 0 are excluded from the check).
4FF8
OR C B1
OR Register A (the masked flags from the current drive) with Register C (the accumulated flags from all previously scanned drives). This accumulates all flag bits across all drives into C.
4FF9
LD C,A 4F
Load Register C with Register A (the updated accumulated flags).
4FFA
ADD HL,DE 19
ADD Register Pair DE (0010H) to Register Pair HL, advancing HL by 16 bytes to point at byte 0DH of the next drive's PDRIVE entry.
4FFB
DECrement Register B (the drive counter) by 1 and if B is not zero, JUMP back to 4FF5H to scan the next drive. [LOOP END — scan all drives]

All 10 drives have been scanned. Register C holds the OR of all inter-drive flag bits. Now count how many distinct flag groups are present. If more than 1 group is active, the drives are incompatible.

4FFD
LD B,08H 06 08
Load Register B with 08H (decimal 8), the loop counter for testing all 8 bits of Register C. [LOOP START — count set bits]
4FFF
XOR A AF
Set Register A to ZERO and clear all flags. Register A will count how many flag bits are set in C.
5000
RLC C CB 01
Rotate Register C Left through Carry. This shifts the highest remaining bit of C into the CARRY FLAG. Each iteration tests one flag bit.
5002
If the NO CARRY FLAG has been set (the bit that was rotated out was 0 — this flag is not active), JUMP forward to 5005H to skip the increment. [BIT NOT SET]
5004
INC A 3C
INCrement Register A (the set-bit counter) by 1. A flag bit was active across at least one drive.
5005
DECrement Register B (the bit counter) by 1 and if B is not zero, JUMP back to 5000H to test the next bit. [LOOP END — count set bits]

Register A holds the count of distinct inter-drive flag bits set across all 10 drives. If 0 or 1 flags are set, the configuration is compatible. If 2 or more, there are mutually exclusive flag conflicts.

5007
CP 02H FE 02
Compare Register A (the set-bit count) against 02H (decimal 2). If fewer than 2 flag bits are set, the CARRY FLAG is set (compatible — 0 or 1 flags, no conflict). If 2 or more, the NO CARRY FLAG is set (incompatible — mutually exclusive flags on different drives).
5009
RET C D8
If the CARRY FLAG has been set (fewer than 2 inter-drive flags are active — no conflicts), RETURN to the caller with CARRY set signaling compatibility. [SUCCESS — no conflicts]
500A
XOR A AF
Set Register A to ZERO and clear all flags. The configuration is incompatible. Clear drive 0's configuration flags to disable it.
500B
LD (4302H),A 32 02 43
Store 00H (Register A) to memory location 4302H (byte 02H of drive 0's PDRIVE entry — the configuration flags byte). This clears drive 0's configuration, marking it as unconfigured due to the incompatibility.
500E
RET C9
RETURN to the caller with NO CARRY (CARRY was cleared by XOR A), signaling that inter-drive incompatibility was detected. The caller at 4DE8H/4DEBH will print the warning message.

500FH - CHARACTER OUTPUT WRAPPER SUBROUTINE

Wrapper subroutine that prints the character in Register A to the screen via the ROM routine at 0033H, preserving Register Pairs DE and AF. Called extensively throughout the display routines.

500F
PUSH DE D5
Save Register Pair DE onto the stack. The ROM display routine at 0033H may modify DE, so it must be preserved for the caller.
5010
PUSH AF F5
Save Register A (the character to print) and the flags onto the stack. The flags are preserved so the caller's condition codes are not disturbed.
5011
GOSUB to the ROM character output routine at 0033H to display the character in Register A at the current cursor position and advance the cursor.
5014
POP AF F1
Restore Register A (the original character) and the flags from the stack.
5015
POP DE D1
Restore Register Pair DE from the stack.
5016
RET C9
RETURN to the caller with Register A, DE, and the flags restored to their pre-call values.

5017H - KEYWORD TABLE SCANNER SUBROUTINE

Subroutine to compare the command-line token (pointed to by HL) against keyword entries in the keyword table (pointed to by BC). Each keyword entry is a null-terminated string followed by a dispatch byte. The scanner walks through the table, calling the SYS0 string comparison routine at 4C6AH for each entry. If a match is found, returns NZ with BC pointing to the dispatch byte. If all entries are exhausted without a match, issues error code 34H (parse error). Register D is the skip counter, used to advance past entries in the table. Called from 4D4BH.

5017
GOSUB to the SYS0 string comparison routine at 4C6AH. This routine compares the command-line token (HL) against the current keyword table entry (BC). On return: Z set = match found; NZ set = no match. If a match is found, HL is advanced past the matched portion and BC points past the matched string. [LOOP START — try each keyword]
501A
RET Z C8
If the Z FLAG has been set (the string comparison found a match — the command-line token matches this keyword), RETURN to the caller with Z set. BC now points to the null terminator or dispatch byte of the matched entry. [MATCH FOUND — but note: the caller at 4D4BH expects NZ for a match; Z here means the token comparison succeeded, and the caller proceeds with the dispatch byte]

No match for this keyword entry. Skip past the remaining bytes of this entry's name string (advance BC to the null terminator), then skip the null and the dispatch byte to reach the next entry.

501B
LD A,(BC) 0A
Load Register A with the current byte from the keyword table (pointed to by BC). Walking through the unmatched keyword name to find its null terminator. [LOOP START — skip to null terminator]
501C
CP 00H FE 00
Compare Register A against 00H (the null terminator). If the byte is 00H, the Z FLAG is set (end of keyword name found). If non-zero, the NZ FLAG is set (still within the keyword name).
501E
INC BC 03
INCrement Register Pair BC by 1 to advance to the next byte in the keyword table.
501F
If the NZ FLAG has been set (the byte was not the null terminator — still within the keyword name), JUMP back to 501BH to check the next byte. [LOOP END — skip to null]

BC now points one byte past the null terminator, which is the dispatch byte. Skip past the dispatch byte by advancing BC past D-1 more entries (D was initialized to 1 at 4D49H and tracks how many entries to skip).

5021
LD E,D 5A
Load Register E with Register D (the keyword skip counter). E serves as a local countdown for skipping dispatch bytes.
5022
INC BC 03
INCrement Register Pair BC by 1 to advance past the dispatch byte of the current (unmatched) keyword entry. [LOOP START — skip dispatch bytes]
5023
DEC E 1D
DECrement Register E (the skip countdown) by 1.
5024
If the NZ FLAG has been set (E has not reached zero — more dispatch bytes to skip), JUMP back to 5022H. [LOOP END — skip dispatch bytes]

BC now points to the start of the next keyword entry in the table. Check whether this entry exists (non-zero first byte) or the table is exhausted (zero byte = end of table marker).

5026
LD A,(BC) 0A
Load Register A with the first byte of the next keyword table entry (pointed to by BC).
5027
OR A B7
OR Register A with itself to set the Z FLAG. If 00H (end-of-table marker), the Z FLAG is set (all keywords exhausted, no match). If non-zero (another keyword exists), the NZ FLAG is set.
5028
If the NZ FLAG has been set (another keyword entry exists in the table), JUMP back to 5017H to compare the command-line token against this next keyword. [LOOP — try next keyword]

The keyword table is exhausted — the command-line token did not match any known PDRIVE keyword. Issue a parse error.

502A
LD A,34H 3E 34
Load Register A with 34H (decimal 52, NEWDOS/80 error code for "parse error"). The user-supplied keyword was not recognized.
502C
JUMP forward to 503CH to issue the error via the DOS error handler at 4409H. [ERROR PATH — unrecognized keyword]

502EH - PARSE NUMBER FROM COMMAND LINE (DECIMAL ENTRY)

Entry point for parsing a decimal number from the command line. Calls the core digit-accumulation routine at 503FH (which starts in decimal mode, B=00H), then checks whether the result is valid (non-zero high byte in D means overflow). Called from 4D56H (numeric parameter) and 4D5EH (drive number).

502E
GOSUB to 503FH to parse a decimal number from the command line. On return, Register Pair DE holds the 16-bit parsed value: D = high byte, E = low byte. Register A = E (the low byte).
5031
JUMP forward to 5036H to check the result validity (D must be zero for single-byte parameters).

5033H - PARSE NUMBER FROM COMMAND LINE (HEX ENTRY)

Entry point for parsing a hexadecimal number from the command line. Calls the core digit-accumulation routine at 505DH (which starts in hex mode, B=01H), then checks the result validity.

5033
GOSUB to 505DH to parse a hexadecimal number from the command line. On return, Register Pair DE holds the 16-bit parsed value.

5036H - VALIDATE PARSED NUMBER

Check whether the parsed number's high byte (D) is zero. For PDRIVE parameters, all values must fit in a single byte (0-255). If D is non-zero, the value overflowed. Returns with A = E (the low byte of the result).

5036
LD A,D 7A
Load Register A with Register D (the high byte of the parsed 16-bit number).
5037
OR A B7
OR Register A with itself to set the Z FLAG. If D is 00H (the number fits in a single byte), the Z FLAG is set. If non-zero (overflow — number exceeds 255), the NZ FLAG is set.
5038
LD A,E 7B
Load Register A with Register E (the low byte of the parsed number). This is the return value used by the caller.
5039
RET Z C8
If the Z FLAG has been set (D was zero — the number fits in one byte), RETURN to the caller with A = the parsed value (0-255). [SUCCESS — valid single-byte value]

503AH - ERROR EXIT: PARAMETER NOT VALID (2FH)

Issue error code 2FH ("parameter not valid") via the DOS error handler. Reached when a parsed value overflows or is out of range.

503A
LD A,2FH 3E 2F
Load Register A with 2FH (decimal 47, NEWDOS/80 error code for "parameter not valid").

503CH - COMMON ERROR EXIT VIA DOS ERROR HANDLER

Common error exit point. Register A holds the error code. Jump to the SYS0 DOS error handler at 4409H which displays the error and aborts the command. This routine does not return.

503C
JUMP to the SYS0 DOS error handler at 4409H. Register A contains the error code (e.g., 2AH = general error, 2FH = parameter not valid, 20H = parameter error, 34H = parse error). The error handler displays the error message and returns control to the DOS command prompt. This routine does not return to the PDRIVE code. [ERROR PATH — all errors converge here]

503FH - DECIMAL NUMBER PARSER ENTRY

Parse a decimal number from the command line. First check if the number starts with a hex digit indicator. If the first digit is followed by characters A-H (indicating hexadecimal), redirect to the hex parser. Otherwise, accumulate decimal digits. On return, DE holds the 16-bit result.

503F
PUSH HL E5
Save Register Pair HL (the command-line pointer) onto the stack. HL is preserved in case the number turns out to be hexadecimal and the parse needs to restart.
5040
GOSUB to 5062H to attempt parsing the first digit in decimal mode (B=00H). This routine initializes DE=0000H (the accumulator) and enters the digit accumulation loop at 5067H. On return, DE holds the accumulated value and HL points past the last valid digit.
5043
LD A,(HL) 7E
Load Register A with the character at the current command-line position (pointed to by HL). This is the first character that was NOT a valid decimal digit — it terminated the decimal parse.
5044
SUB 41H D6 41
SUBtract 41H (ASCII A) from Register A. If the terminating character is a letter A-H, this converts it to the range 0-7. If it is not a letter, the result will be negative (CARRY set) or out of range.
5046
CP 08H FE 08
Compare Register A (the letter index) against 08H. If less than 8, the CARRY FLAG is set (the terminating character was one of A-H — this indicates the number is hexadecimal, not decimal). If 8 or greater, the NO CARRY FLAG is set (not a hex letter).
5048
If the NO CARRY FLAG has been set (the terminating character was not A-H — the number is purely decimal), JUMP forward to 5057H to finalize the decimal result. [DECIMAL NUMBER — finalize]

The terminating character was a letter A-H, meaning what was parsed as decimal is actually the start of a hexadecimal number. Discard the decimal result, restore HL to the original position, and re-parse in hex mode.

504A
POP HL E1
Restore Register Pair HL from the stack (the original command-line pointer saved at 503FH). HL is now back at the start of the number.
504B
LD B,01H 06 01
Load Register B with 01H, setting the hex mode flag. When B bit 0 is set, the digit accumulation routine at 5067H will accept hex digits A-F in addition to 0-9, and multiply by 16 instead of 10.
504D
PUSH HL E5
Save Register Pair HL (the original command-line pointer) onto the stack again for the hex parse attempt.
504E
GOSUB to 5064H to parse the number in hex mode (B=01H). The routine initializes DE=0000H and accumulates hex digits (0-9 and A-F) with ×16 multiplication. On return, DE holds the 16-bit hex result.
5051
LD A,(HL) 7E
Load Register A with the character that terminated the hex parse (pointed to by HL).
5052
CP 48H FE 48
Compare Register A against 48H (ASCII H). Hexadecimal numbers in NEWDOS/80 are terminated with a trailing H suffix (e.g., "1AH"). If the terminating character is H, the Z FLAG is set (valid hex number). If not H, the NZ FLAG is set (not a valid hex suffix).
5054
INC HL 23
INCrement Register Pair HL by 1 to advance past the H suffix character (or past the non-H terminator if the parse failed).
5055
If the NZ FLAG has been set (the terminating character was not H — the hex number is missing its required suffix), JUMP back to 503AH to issue error code 2FH ("parameter not valid"). [ERROR PATH — missing H suffix]
5057
BIT 1,B CB 48
Test Bit 1 of Register B. Bit 1 is set by the digit accumulation routine (at 507DH) when at least one valid digit was parsed. If clear, no digits were found (the "number" was empty). If set, the NZ FLAG is set (at least one digit was parsed).
5059
POP BC C1
Restore the top of stack into Register Pair BC (discarding the saved HL from 503FH or 504DH — it is no longer needed). This cleans up the stack.
505A
RET NZ C0
If the NZ FLAG has been set (at least one digit was parsed — the number is valid), RETURN to the caller with DE holding the parsed value. [SUCCESS — valid number parsed]
505B
No digits were found — the input was not a valid number. JUMP to 503AH to issue error code 2FH ("parameter not valid"). [ERROR PATH — no digits]

505DH - HEXADECIMAL NUMBER PARSER ENTRY

Direct entry point for parsing a hexadecimal number. Sets B=01H (hex mode) and calls the digit accumulation routine. Returns via the result check at 5057H.

505D
PUSH HL E5
Save Register Pair HL (the command-line pointer) onto the stack.
505E
LD DE,5057H 11 57 50
Load Register Pair DE with 5057H, the address of the result-check code. This address is pushed onto the stack as a return address, so when the digit accumulation routine returns, it falls through to 5057H for validation.
5061
PUSH DE D5
Save Register Pair DE (5057H) onto the stack. This sets up a synthetic return address — when the accumulation routine at 5062H/5064H/5067H encounters a RET, it will "return" to 5057H.

5062H - DIGIT ACCUMULATION INITIALIZATION (DECIMAL MODE)

Initialize for decimal digit accumulation. Set B=00H (decimal mode flag) and fall through to initialize DE and start the accumulation loop.

5062
LD B,00H 06 00
Load Register B with 00H, setting the mode flag to decimal. When B bit 0 is clear, the accumulation loop multiplies by 10 (decimal). When set, it multiplies by 16 (hex).

5064H - DIGIT ACCUMULATION INITIALIZATION (COMMON)

Common entry point for both decimal and hex parsing. Initialize the 16-bit accumulator DE to zero, then enter the digit processing loop.

5064
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, initializing the 16-bit accumulator to zero. Digits will be accumulated into DE as they are parsed.

5067H - DIGIT ACCUMULATION LOOP

Main digit processing loop. For each character on the command line: convert from ASCII to binary, verify it is a valid digit (0-9 for decimal, 0-F for hex), then multiply the accumulator (DE) by the base (10 or 16) and add the new digit. Exits when a non-digit character is encountered.

5067
LD A,(HL) 7E
Load Register A with the next character from the command line (pointed to by HL). [LOOP START — digit accumulation]
5068
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A, converting the ASCII digit character to its binary value: 0=0, 1=1, ... 9=9. If the character was below 0, the result underflows and the CARRY FLAG is set.
506A
CP 0AH FE 0A
Compare Register A (the converted digit) against 0AH (decimal 10). If less than 10, the CARRY FLAG is set (valid decimal digit 0-9). If 10 or greater, the NO CARRY FLAG is set (not a decimal digit — possibly a hex letter or delimiter).
506C
If the CARRY FLAG has been set (the character is a valid decimal digit 0-9), JUMP forward to 5078H to accumulate this digit into DE. [VALID DECIMAL DIGIT]

The character is not a decimal digit (0-9). Check if we are in hex mode and if the character is a hex letter (A-F).

506E
BIT 0,B CB 40
Test Bit 0 of Register B (the hex mode flag). If set, the NZ FLAG is set (hex mode — hex letters A-F are valid). If clear, the Z FLAG is set (decimal mode — the character is not a valid digit).
5070
RET Z C8
If the Z FLAG has been set (decimal mode and the character is not 0-9), RETURN to the caller. The non-digit character terminates the decimal number. DE holds the accumulated value and HL points to the terminating character. [EXIT — end of decimal number]
5071
SUB 11H D6 11
SUBtract 11H from Register A. After the earlier SUB 30H, the letter A (41H) would be at value 11H (41H-30H=11H). Subtracting 11H converts A=0, B=1, ... F=5. This adjusts hex letters to the range 0-5.
5073
CP 06H FE 06
Compare Register A (the adjusted hex letter index) against 06H. If less than 6, the CARRY FLAG is set (valid hex letter A-F). If 6 or greater, the NO CARRY FLAG is set (not a valid hex letter — e.g., G or higher).
5075
RET NC D0
If the NO CARRY FLAG has been set (the character is not A-F — it is beyond the hex digit range), RETURN to the caller. The non-hex character terminates the hex number. [EXIT — end of hex number]
5076
ADD 0AH C6 0A
ADD 0AH (decimal 10) to Register A, converting the hex letter index (0-5) to its numeric value (10-15). Now A=10 for A, A=11 for B, ... A=15 for F.

5078H - MULTIPLY ACCUMULATOR BY BASE AND ADD DIGIT

A valid digit has been parsed (value in Register A, range 0-15). Multiply the current accumulator (DE) by the base (10 for decimal, 16 for hex), then add the new digit. The multiplication is performed using shifts and adds: ×16 = 4 left shifts; ×10 = (×8 + ×2) via shifts and an intermediate ADD.

5078
PUSH HL E5
Save Register Pair HL (the command-line pointer) onto the stack. HL will be used as a scratch register for the multiplication.
5079
LD H,D 62
Load Register H with Register D (the high byte of the accumulator). HL now holds a copy of the current accumulator value DE.
507A
LD L,E 6B
Load Register L with Register E (the low byte of the accumulator). HL = DE (the accumulator copy).
507B
LD C,A 4F
Load Register C with Register A (the new digit value, 0-15). Register C preserves the digit while the accumulator is shifted.
507C
XOR A AF
Set Register A to ZERO and clear all flags. Register A will track overflow from the 16-bit shifts (if the result exceeds 16 bits, the number is too large).
507D
SET 1,B CB C8
SET Bit 1 of Register B. This flag indicates that at least one valid digit has been processed. It is tested at 5057H to verify that the number was not empty.
507F
ADD HL,HL 29
ADD Register Pair HL to itself (HL = HL × 2). First shift left — accumulator is now ×2.
5080
ADC A,A 8F
ADd Carry to Register A with A (A = A + A + Carry). This captures the overflow bit from the ADD HL,HL into the overflow tracker.
5081
ADD HL,HL 29
ADD Register Pair HL to itself again (HL = HL × 4). Second shift left — accumulator is now ×4.
5082
ADC A,A 8F
ADd Carry to Register A. Captures the second overflow bit.

At this point HL = original_DE × 4. For hex mode (×16), two more shifts are needed. For decimal mode (×10 = ×8 + ×2), add the ×2 copy (in DE) to HL first, then shift once more to get ×8+×2 = ×10.

5083
BIT 0,B CB 40
Test Bit 0 of Register B (the hex mode flag). If set (hex mode), the NZ FLAG is set — skip the decimal ADD and do a plain shift. If clear (decimal mode), the Z FLAG is set — do the decimal ADD.
5085
If the Z FLAG has been set (decimal mode), JUMP forward to 508AH to add ×2 (in DE) before the next shift, producing ×(4+1)×2 = ×10. [DECIMAL ×10 PATH]
5087
ADD HL,HL 29
ADD Register Pair HL to itself (HL = HL × 8). Third shift for hex mode — accumulator is now ×8.
5088
JUMP forward to 508BH to capture the overflow and perform the fourth shift (×16). [HEX ×16 PATH]
508A
ADD HL,DE 19
ADD Register Pair DE (the original accumulator value, ×1) to Register Pair HL (currently ×4). HL now holds ×4 + ×1 = ×5 of the original accumulator. The next shift will double this to ×10.
508B
ADC A,A 8F
ADd Carry to Register A. Captures overflow from the preceding ADD HL,HL (hex path) or ADD HL,DE (decimal path).
508C
ADD HL,HL 29
ADD Register Pair HL to itself. For decimal: ×5 × 2 = ×10. For hex: ×8 × 2 = ×16. The accumulator has now been multiplied by the correct base.
508D
ADC A,A 8F
ADd Carry to Register A. Captures the final overflow bit from the base multiplication.

HL now holds (original DE × base). Add the new digit (in C) to complete the accumulation: result = (old_value × base) + new_digit.

508E
LD E,C 59
Load Register E with Register C (the new digit value, 0-15).
508F
LD D,00H 16 00
Load Register D with 00H. Register Pair DE now holds 00:digit, the 16-bit representation of the new digit.
5091
ADD HL,DE 19
ADD Register Pair DE (the new digit) to Register Pair HL (the shifted accumulator). HL = (old × base) + digit.
5092
ADC A,A 8F
ADd Carry to Register A. If the digit addition overflowed 16 bits, this captures it.
5093
EX DE,HL EB
Exchange DE and HL. DE now holds the updated accumulator value (old × base + digit). HL is free.
5094
POP HL E1
Restore Register Pair HL (the command-line pointer) from the stack.
5095
RET NZ C0
If the NZ FLAG has been set (the overflow tracker A is non-zero after the ADC A,A — the 16-bit accumulator overflowed), RETURN to the caller. The overflow is detected by the validation code at 5036H which checks D. [OVERFLOW EXIT]
5096
INC HL 23
INCrement Register Pair HL by 1 to advance the command-line pointer past the digit character that was just accumulated.
5097
JUMP back to 5067H to process the next digit character from the command line. [LOOP — accumulate next digit]

5099H - DECIMAL NUMBER DISPLAY SUBROUTINE

Convert the 16-bit unsigned value in DE to decimal digits and print them to the screen. Uses a divisor table at 50C3H containing the values 10000, 1000, 100, and 10 (as 16-bit big-endian pairs). For each divisor, performs repeated subtraction to extract the digit, then prints it. Leading zeros are suppressed. Called from 4E6FH to display numeric PDRIVE parameters.

5099
LD BC,0400H 01 00 04
Load Register Pair BC with 0400H. Register B = 04H (decimal 4, the number of divisors in the table — for 10000, 1000, 100, 10). Register C = 00H (the leading-zero suppression flag — 00H means leading zeros are still being suppressed).
509C
LD HL,50C3H 21 C3 50
Load Register Pair HL with 50C3H, the base address of the divisor table. The table contains four 16-bit values in big-endian byte order: 10000 (2710H stored as 10H,27H), 1000, 100, 10. [LOOP START — extract each decimal digit]
509F
PUSH BC C5
Save Register Pair BC (B=remaining divisor count, C=leading-zero flag) onto the stack.
50A0
LD C,(HL) 4E
Load Register C with the low byte of the current divisor from the table (pointed to by HL).
50A1
INC HL 23
INCrement Register Pair HL by 1 to point to the high byte of the current divisor.
50A2
LD B,(HL) 46
Load Register B with the high byte of the current divisor. Register Pair BC now holds the 16-bit divisor value.
50A3
INC HL 23
INCrement Register Pair HL by 1 to advance to the next divisor entry in the table. HL is saved across the division loop.
50A4
EX DE,HL EB
Exchange DE and HL. HL now holds the value being converted (the dividend), and DE holds the divisor table pointer (saved for later).
50A5
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII /, which is one less than ASCII 0). Register A is the digit counter — it starts at / so that after the first successful subtraction it becomes 0. [LOOP START — repeated subtraction]
50A7
INC A 3C
INCrement Register A (the digit counter) by 1. On the first iteration, A goes from 2FH to 30H (ASCII 0).
50A8
ADD HL,BC 09
ADD Register Pair BC (the divisor, stored as a negative value — see table note below) to Register Pair HL. This effectively subtracts the divisor from the dividend. If HL underflows (goes below zero), CARRY is set.
50A9
If the CARRY FLAG has been set (the subtraction did not underflow — the dividend is still greater than or equal to the divisor), JUMP back to 50A7H to increment the digit and subtract again. [LOOP — count subtractions]

The subtraction underflowed — the dividend is now negative. Undo the last subtraction to restore the remainder, then print the digit.

50AB
SBC HL,BC ED 42
SuBtract with Carry Register Pair BC from Register Pair HL. Since CARRY is clear after the failed ADD (JR C did not jump), this undoes the last subtraction, restoring HL to the correct remainder. [LOOP END — repeated subtraction]
50AD
POP BC C1
Restore Register Pair BC (B=remaining divisor count, C=leading-zero flag) from the stack.
50AE
EX DE,HL EB
Exchange DE and HL. DE now holds the remainder (for the next divisor), and HL holds the divisor table pointer.

Register A holds the ASCII digit for this position. Check for leading zero suppression — if C is 00H and the digit is 0, skip printing it.

50AF
CP 30H FE 30
Compare Register A (the digit character) against 30H (ASCII 0). If equal, the Z FLAG is set (the digit is zero). If not equal (non-zero digit), the NZ FLAG is set.
50B1
If the NZ FLAG has been set (the digit is not zero — it should be printed), JUMP forward to 50B7H to mark the leading-zero flag and print. [NON-ZERO DIGIT]
50B3
INC C 0C
INCrement Register C (temporary test). This combined with the DEC C below tests whether C is zero without modifying it.
50B4
DEC C 0D
DECrement Register C back to its original value. The INC/DEC pair sets the Z FLAG based on C's value: if C was 00H, the INC makes it 01H, and the DEC makes it 00H again with Z set. If C was non-zero, NZ is set.
50B5
If the Z FLAG has been set (C is 00H — leading zeros are still being suppressed AND the current digit is zero), JUMP forward to 50BBH to skip printing this leading zero. [SUPPRESS LEADING ZERO]
50B7
INC C 0C
INCrement Register C to a non-zero value, disabling leading-zero suppression for all subsequent digits. Once a non-zero digit is printed, all following zeros must also be printed.
50B8
GOSUB to 500FH to print the digit character (Register A) to the screen.
50BB
DECrement Register B (the remaining divisor count) by 1 and if B is not zero, JUMP back to 509FH to process the next divisor (next decimal position). [LOOP END — extract each digit]

All four divisors (10000, 1000, 100, 10) have been processed. The remainder in E is the ones digit. Print it unconditionally (no leading-zero suppression for the last digit).

50BD
LD A,E 7B
Load Register A with Register E (the final remainder — the ones digit, value 0-9).
50BE
ADD 30H C6 30
ADD 30H (ASCII 0) to Register A, converting the binary ones digit to its ASCII character.
50C0
JUMP to 500FH to print the ones digit character and return. Tail-call optimization — JP instead of CALL followed by RET.

50C3H - DIVISOR TABLE FOR DECIMAL DISPLAY

Table of four 16-bit divisor values used by the decimal display routine at 5099H. Each entry is stored in low-byte/high-byte order. The values are stored as NEGATIVE numbers (two's complement) because the repeated-subtraction loop at 50A7H uses ADD HL,BC instead of SBC HL,BC.

50C3
DEFW F0D8H D8 F0
Divisor entry 1: F0D8H = -10000 (two's complement of 2710H). Adding F0D8H is equivalent to subtracting 10000. Stored little-endian: D8H (low), F0H (high).
50C5
DEFW FC18H 18 FC
Divisor entry 2: FC18H = -1000 (two's complement of 03E8H). Stored little-endian: 18H (low), FCH (high).
50C7
DEFW FF9CH 9C FF
Divisor entry 3: FF9CH = -100 (two's complement of 0064H). Stored little-endian: 9CH (low), FFH (high).
50C9
DEFW FFF6H F6 FF
Divisor entry 4: FFF6H = -10 (two's complement of 000AH). Stored little-endian: F6H (low), FFH (high).

50CBH - ERROR MESSAGE STRING

ASCII error message displayed when a drive's configuration flags (byte 02H, bits 4,3,2) are all clear, indicating an invalid or incomplete configuration. Referenced by 4E88H.

50CB
DEFM " ** ERROR **" 20 20 2A 2A 20 45 52 52 4F 52 20 2A 2A
ASCII string: two leading spaces, then "** ERROR **". This message is appended to the end of a drive's display line when the drive configuration is invalid.
50D8
DEFB 0DH 0D
Carriage return character (0DH) — terminates the message string. The SYS0 string display routine at 4467H prints characters until it encounters 0DH or 03H.

50D9H - PADDING BYTES

Three padding bytes between the error message terminator and the incompatibility warning message.

50D9
DEFB 00H,00H,00H 00 00 00
Three zero bytes — unused padding between message strings.

50DCH - INCOMPATIBILITY WARNING MESSAGE STRING

ASCII warning message displayed when inter-drive TI flag incompatibilities are detected by the compatibility check routine at 4FECH. Referenced by 4DE8H.

50DC
DEFM "*** TI= SPEC BETWEEN DRIVES INCOMPATIBLE" 2A 2A 2A 20 54 49 3D 20 53 50 45 43 20 42 45 54 57 45 45 4E 20 44 52 49 56 45 53 20 49 4E 43 4F 4D 50 41 54 49 42 4C 45
ASCII string: "*** TI= SPEC BETWEEN DRIVES INCOMPATIBLE". This message warns that mutually exclusive TI interface flags (B, C, E on Model I) are assigned to different drives simultaneously.
5105
DEFB 0DH 0D
Carriage return character (0DH) — terminates the warning message string.

5106H - INTERFACE-TO-MAX-DRIVE-TYPE LOOKUP TABLE

Eight-byte lookup table mapping each interface type index (0-7) to the maximum drive type code supported by that interface. Referenced by 4ECCH during validation. Each byte is the maximum TD= value (0=A through 7=H) that the corresponding TI= interface can handle.

5106
DEFB 0AH 0A
Interface index 0: max drive type 0AH (decimal 10). This exceeds the valid range A-H (0-7), meaning this interface supports all drive types.
5107
DEFB 11H,14H,22H 11 14 22
Interface indices 1-3: max drive types 11H, 14H, 22H. These values encode additional information in the upper nibble beyond the simple drive type index.
510A
DEFB 12H,1AH,24H,34H 12 1A 24 34
Interface indices 4-7: max drive types 12H, 1AH, 24H, 34H. These packed values encode both the maximum drive type and interface capability flags used by the validation logic at 4ED1H.

510EH - DEFAULT PDRIVE PARAMETER TEMPLATE

Six-byte default parameter template buffer. Pointed to by DE after the initialization routine at 4FC3H. These values serve as default parameters for new or uninitialized drive entries.

510E
DEFB 82H 82
Default configuration flags: 82H
510F
DEFB 60H 60
Default interface/mode byte: 60H
5110
DEFB 00H 00
Unused
5111
DEFB 00H 00
Unused
5112
DEFB 43H 43
Default Parameter — ASCII C or value 67: 43H.
5113
DEFB 00H 00
Terminator/Padding: 00H.

5114H - PDRIVE VARIABLE AREA

Local variable storage area used by the PDRIVE command. These bytes are read and written at runtime by the various PDRIVE routines.

5114
DEFB 00H 00
Variable at 5114H: command-line flags byte. Stored by 4D08H from Register B at entry. 00H = display-only invocation; non-zero = modification mode. Tested by 4FD1H.
5115
DEFB FFH FF
Variable at 5115H: initialized to FFH. Exact usage not referenced in the main PDRIVE code — may be used by SYS0 routines or reserved.
5116
DEFB 00H,00H 00 00
Variables at 5116H-5117H: two zero bytes. Reserved or used as scratch storage by called routines.
5118
DEFB 02H 02
Variable at 5118H: display format control byte (column count). Set to 02H by 4FC5H. Controls how many drives are displayed per screen row.
5119
DEFB 00H 00
Variable at 5119H: zero byte. Reserved or scratch.
511A
DEFB FFH,FFH FF FF
Variables at 511AH-511BH: initialized to FFH. Reserved or used as sentinel values by routines.

511CH - PDRIVE KEYWORD TABLE

Keyword table for the PDRIVE command. Each entry consists of a null-terminated ASCII keyword string followed by a dispatch byte. The dispatch byte encodes: Bit 7 = numeric value expected, Bit 6 = flag-letter value expected, Bits 3-0 = field offset within the 16-byte PDRIVE entry. The table is terminated by a 00H byte. Referenced by 4D46H (keyword matching), 4E35H (display), and 5017H (scanner). Per the NEWDOS/80 manual, the keywords are: TI= (interface type flags), TD= (drive type), TC= (track count), SPT= (sectors per track), TSR= (track stepping rate), GPL= (granules per lump), DDSL= (directory start lump), DDGA= (directory granule allocation), DSL= (alias for DDSL), NLD= (alias for a numeric parameter), and LLD= (alias).

511C
DEFM "TI=" 54 49 3D
Keyword: "TI=" — Type of Interface. Specifies the disk drive interface flags (one or more letters A-M).
511F
DEFB 00H 00
Null terminator for "TI=" keyword string.
5120
DEFB 4DH 4D
Dispatch byte for TI=: 4DH (binary 01001101). Bit 7=0 (not numeric), Bit 6=1 (flag-letter parameter), Bits 3-0 = 0DH (field offset 0DH within the PDRIVE entry — the DDGA/flags byte at IX+0DH).
5121
DEFM "TD=" 54 44 3D
Keyword: "TD=" — Type of Drive. Specifies the drive type letter (A through H).
5124
DEFB 00H 00
Null terminator for "TD=" keyword string.
5125
DEFB 0FH 0F
Dispatch byte for TD=: 0FH (binary 00001111). Bit 7=0, Bit 6=0 (single-letter parameter), Bits 3-0 = 0FH (field offset 0FH — but this is actually used differently: the low nibble 0FH causes the IX setup at 4E97H to point to IX+0FH, the interface/control byte, where the drive type letter index is stored as part of the packed format). [NOTE: The dispatch byte 0FH maps to offset 0FH but the actual drive type is stored at IX+04H. The 4E97H routine uses the nibble to index into the entry, and the parse/store logic at 4D93H/4D9BH writes the letter index to IX+00H after 4E97H repositions IX.]
5126
DEFM "TC=" 54 43 3D
Keyword: "TC=" — Track Count. Specifies the number of tracks on the disk.
5129
DEFB 00H 00
Null terminator for "TC=" keyword string.
512A
DEFB 83H 83
Dispatch byte for TC=: 83H (binary 10000011). Bit 7=1 (numeric parameter), Bits 3-0 = 03H (field offset 03H — the SPT byte at IX+03H). [NOTE: The mapping of TC= to offset 03H and SPT= to offset 04H reflects the PDRIVE entry layout where byte 03H holds the SPT value and byte 05H holds TC — the dispatch encodes which field receives the parsed value after IX is repositioned.]
512B
DEFM "SPT=" 53 50 54 3D
Keyword: "SPT=" — Sectors Per Track. Specifies the number of sectors per track.
512F
DEFB 00H 00
Null terminator for "SPT=" keyword string.
5130
DEFB 84H 84
Dispatch byte for SPT=: 84H (binary 10000100). Bit 7=1 (numeric), Bits 3-0 = 04H (field offset 04H).
5131
DEFM "TSR=" 54 53 52 3D
Keyword: "TSR=" — Track Stepping Rate. Specifies the stepping pulse rate code (0-3).
5135
DEFB 00H 00
Null terminator for "TSR=" keyword string.
5136
DEFB 8CH 8C
Dispatch byte for TSR=: 8CH (binary 10001100). Bit 7=1 (numeric), Bits 3-0 = 0CH (field offset 0CH).
5137
DEFM "GPL=" 47 50 4C 3D
Keyword: "GPL=" — Granules Per Lump. Specifies the granule-to-lump ratio (2-8).
513B
DEFB 00H 00
Null terminator for "GPL=" keyword string.
513C
DEFB 85H 85
Dispatch byte for GPL=: 85H (binary 10000101). Bit 7=1 (numeric), Bits 3-0 = 05H (field offset 05H).
513D
DEFM "DDSL=" 44 44 53 4C 3D
Keyword: "DDSL=" — Directory Data Start Lump. Specifies the lump number where the directory starts.
5142
DEFB 00H 00
Null terminator for "DDSL=" keyword string.
5143
DEFB 88H 88
Dispatch byte for DDSL=: 88H (binary 10001000). Bit 7=1 (numeric), Bits 3-0 = 08H (field offset 08H).
5144
DEFM "DDGA=" 44 44 47 41 3D
Keyword: "DDGA=" — Directory Default Granule Allocation. Specifies the number of granules allocated to the directory at format time (2-6).
5149
DEFB 00H 00
Null terminator for "DDGA=" keyword string.
514A
DEFB 89H 89
Dispatch byte for DDGA=: 89H (binary 10001001). Bit 7=1 (numeric), Bits 3-0 = 09H (field offset 09H).

The following entries are padding or reserved keyword slots. Addresses 514BH through 516AH contain 32 bytes of 00H, forming empty/unused keyword table entries.

514B
DEFB 00H × 32 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
32 bytes of 00H padding (514BH-516AH). Reserved space for additional keyword entries that were never populated in this version.
516B
DEFM "LLD=" 4C 4C 44 3D
Keyword: "LLD=" — an alias keyword (possibly "Logical Lump Directory" or similar). This appears after the padding block.
516F
DEFB 00H 00
Null terminator for "LLD=" keyword string.
5170
DEFB 8AH 8A
Dispatch byte for LLD=: 8AH (binary 10001010). Bit 7=1 (numeric), Bits 3-0 = 0AH (field offset 0AH).
5171
DEFM "NLD=" 4E 4C 44 3D
Keyword: "NLD=" — another alias keyword (possibly "Number of Lump Directory" or similar).
5175
DEFB 00H 00
Null terminator for "NLD=" keyword string.
5176
DEFB 8BH 8B
Dispatch byte for NLD=: 8BH (binary 10001011). Bit 7=1 (numeric), Bits 3-0 = 0BH (field offset 0BH).
5177
DEFB 00H 00
End-of-table marker. The keyword scanner at 5017H tests for 00H to detect the end of the keyword table.

5178H - SECONDARY VALIDATION SUBROUTINE

Short utility subroutine called from 4EE3H and 4F98H during TI flag validation. Sets bit 4 of Register E, then compares the value at IX+05H (the TC parameter) against the value already in Register A. Returns with the flags set from the CP instruction. Called conditionally (CALL NZ) when special mode or interface capability flags are active.

5178
SET 4,E CB E3
SET Bit 4 of Register E. This marks a secondary capability flag in the flag accumulator, indicating that the special validation was triggered.
517A
CP (IX+05H) DD BE 05
Compare Register A against the value at IX+05H (byte 05H of the PDRIVE entry — the TC parameter, track count). The flags are set based on this comparison: Z if equal, CARRY if A < (IX+05H).
517D
RET C9
RETURN to the caller with the flags set from the CP instruction.

517EH - INTERFACE CAPABILITY CHECK SUBROUTINE

Short utility subroutine called from 4EE3H during validation. Tests Bit 2 of the interface/control byte at IX+0FH. If set, returns A=03H with NZ. If clear, returns with Z set. This adjusts the granule size from the default 05H to 03H for interfaces that use a 3-sector granule instead of 5-sector.

517E
BIT 2,(IX+0FH) DD CB 0F 56
Test Bit 2 of the value at IX+0FH (the interface/control byte). Bit 2 indicates whether the interface uses a non-standard granule size. If set, the NZ FLAG is set. If clear, the Z FLAG is set.
5182
RET Z C8
If the Z FLAG has been set (Bit 2 is clear — the interface uses the standard 5-sector granule), RETURN with Z set. The caller's Register A (05H) remains unchanged. [STANDARD GRANULE SIZE]
5183
LD A,03H 3E 03
Load Register A with 03H (decimal 3). This overrides the default granule size from 5 to 3 sectors per granule for interfaces that require it.
5185
RET C9
RETURN to the caller with Register A = 03H and NZ set (from the LD instruction). The caller will use this adjusted granule size in subsequent calculations.

5186H - UNUSED PADDING AREA

Block of 69 NOP bytes (5186H-51CAH). This is unused reserved space within the SYS16 overlay, available for future patches or expansions. The area sits between the utility subroutines and the suffix handler.

5186
DEFB 00H × 69 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 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69 bytes of 00H NOP padding (5186H-51CAH). Unused reserved space within the SYS16 overlay module.

51CBH - PATCHED AREA - NOT NATIVE TO THE OS - SUFFIX HANDLER (,A AND ,B MODES)

Processes the optional suffix character that follows the drive number in a display-only PDRIVE invocation. The suffix controls whether changes are saved to disk. Entered from 4FDDH with Register A holding the suffix character from the command line and Register Pair DE pointing to 4DF6H (the self-modifying write-enable byte). Two valid suffixes are recognized:
,A — Enable disk writes: set the byte at 4DF6H to non-zero, then re-enter the command-line scanner to process remaining parameters.
,B — RAM-only mode: clear the 7-byte area at 4DD3H-4DD9H (which contains the disk-write CALL sequence) to NOPs, disabling the disk write. Then re-enter the scanner.
Any other character is rejected.

51CB
CP 41H FE 41
Compare Register A (the suffix character from the command line) against 41H (ASCII A). If Register A equals 41H, the Z FLAG is set (the user typed ,A — enable disk writes). If not equal, the NZ FLAG is set. [LOOP START — suffix check]
51CD
LD (DE),A 12
Store Register A (the suffix character) to the address pointed to by DE (4DF6H — the self-modifying write-enable byte inside the LD A,00H instruction at 4DF5H). If the suffix was A (41H), this writes 41H (non-zero) to 4DF6H, enabling the PDRIVE-to-system-area copy at 4DF5H. If the suffix was something else, a non-zero value is also stored — but the validation below may undo this. [SELF-MODIFYING CODE — writes to 4DF6H]
51CE
If the NZ FLAG has been set (the suffix character was not A), JUMP forward to 51D3H to check if it is B. [NOT 'A' — check for 'B']

The suffix was A. The write-enable byte at 4DF6H has been set to 41H (non-zero). Jump to 4FE0H to resume the command-line scanner. The routine at 4FE0H validates that the character following the suffix is a proper delimiter, then continues parsing.

51D0
JUMP to 4FE0H (the suffix handler return point) to validate the suffix context and resume command-line scanning. [SUFFIX 'A' ACCEPTED — enable writes and continue]
51D3
DEC A 3D
DECrement Register A by 1. If the suffix character was B (42H), Register A becomes 41H. This is a compact way to test for B without a separate CP instruction.
51D4
CP 41H FE 41
Compare Register A (the decremented suffix character) against 41H. If the original character was B (42H), the decrement made it 41H and this comparison sets the Z FLAG. If the original was any other character, the NZ FLAG is set.
51D6
If the NZ FLAG has been set (the suffix character was not A and not B — it is an unrecognized character), JUMP back to 51D0H which jumps to 4FE0H. At 4FE0H, the NZ flag causes the routine to clear the write-enable byte at 4DF6H back to 00H and return with NZ, effectively rejecting the invalid suffix. [INVALID SUFFIX — rejected]

The suffix was B (RAM-only mode). Save the current register state, then clear the 7-byte area at 4DD3H-4DD9H to 00H. This area contains the CALL 4FC3H and CALL 443CH instruction sequence that writes the PDRIVE table to disk. Overwriting it with NOPs (00H) prevents the disk write from executing, so changes remain in RAM only.

51D8
PUSH BC C5
Save Register Pair BC onto the stack. BC will be used as the loop counter and fill value for the clear operation.
51D9
PUSH HL E5
Save Register Pair HL onto the stack. HL will point to the area being cleared.
51DA
LD BC,0700H 01 00 07
Load Register Pair BC with 0700H. Register B = 07H (decimal 7, the number of bytes to clear). Register C = 00H (the fill value — NOP opcode 00H).
51DD
LD HL,4DD3H 21 D3 4D
Load Register Pair HL with 4DD3H, the start address of the disk-write code sequence. This 7-byte area (4DD3H-4DD9H) contains: CALL 4FC3H (3 bytes at 4DD3H-4DD5H) followed by CALL 443CH (3 bytes at 4DD6H-4DD8H) followed by RET NZ (1 byte at 4DD9H). [SELF-MODIFYING CODE — target area for NOP patching]
51E0
LD (HL),C 71
Store Register C (00H — NOP opcode) to the memory location pointed to by HL. This overwrites one byte of the disk-write code with a NOP. [LOOP START — clear disk-write code]
51E1
INC HL 23
INCrement Register Pair HL by 1 to advance to the next byte in the disk-write code area.
51E2
DECrement Register B (the byte counter) by 1 and if B is not zero, JUMP back to 51E0H to clear the next byte. After 7 iterations, addresses 4DD3H through 4DD9H are all 00H (NOPs). [LOOP END — disk-write code cleared]

The disk-write code at 4DD3H-4DD9H has been replaced with 7 NOP bytes. When the PDRIVE command reaches 4DD3H after processing parameters, it will execute 7 NOPs instead of CALL 4FC3H / CALL 443CH / RET NZ, causing the code to fall through to 4DDAH without writing to disk. Changes remain in RAM only for this session.

51E4
POP HL E1
Restore Register Pair HL (the command-line pointer) from the stack.
51E5
POP BC C1
Restore Register Pair BC from the stack.
51E6
JUMP back to 51CBH to re-enter the suffix handler loop. After clearing the disk-write area for the B suffix, the code loops back to process the A suffix check again. On re-entry, Register A still holds the decremented value (41H from the B check), so the CP 41H at 51CBH will match, and the LD (DE),A at 51CDH will write 41H to the write-enable byte at 4DF6H — but since the disk-write code has been NOP'd out, the non-zero write-enable byte only enables the PDRIVE-to-system-area copy at 4DF5H, not the disk write. The JP 4FE0H then resumes command-line scanning. [SUFFIX 'B' COMPLETE — RAM-only mode engaged, re-enter to set write-enable and continue]