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

Page Customization

SYS16/SYS - PDRIVE Command:

SYS16/SYS implements the PDRIVE (Physical Drive) command for NEWDOS/80 v2.0. This system utility allows users to view and modify the physical drive configuration parameters stored in the Drive Configuration Table (DCT) at 4300H-439FH. Each of the 10 possible drives (0-9) has a 16-byte parameter block containing settings such as:

  • TI= (Time Interval) - Drive motor-on time
  • TD= (Track Density) - Not commonly used
  • TC= (Track Count) - Total tracks on disk (typically 35 or 40)
  • SPT= (Sectors Per Track) - Number of sectors per track (typically 10 or 18)
  • TSR= (Track Stepping Rate) - Head stepping speed
  • GPL= (Granules Per Lump) - Allocation unit size
  • DDSL= (Directory Sectors per Lump) - Directory structure
  • DDGA= (Directory Granule Allocation) - Directory space allocation

The command syntax is: PDRIVE [source=dest] [param=value...]

When invoked without parameters, PDRIVE displays the current configuration of all active drives. With parameters, it can copy drive configurations or modify individual settings. The utility validates all parameter changes and warns if incompatible settings are detected between drives (particularly the TI= specification).

Variables:

AddressBytesPurpose
4300H-439FH160Drive Configuration Table - 10 drives × 16 bytes each
43A0H1Maximum active drive number
4EA2H1Current drive number being processed (0-9)
50CEH-50DBH14Error message: "*** ERROR ***" + 03H terminator
50DCH-5105H42Warning message: "**** TI= SPEC BETWEEN DRIVES INCOMPATIBLE" + 0DH
5106H-510DH8TI= lookup table for drive timing validation
510EH-5113H6PDRIVE parameter storage area
5114H1Source drive copy flag (nonzero = copy mode active)
5118H1Parse state flag
511CH+variesParameter name strings: TI=, TD=, TC=, SPT=, TSR=, GPL=, DDSL=, DDGA=
4DF6H1Self-modifying code flag - controls "A" prefix processing

Disasembly:

4D00H - PDRIVE Entry Point / SVC Handler:

This is the entry point for the PDRIVE command, called when the user types PDRIVE at the DOS prompt or when invoked via SVC 32H. Register A contains the SVC function code on entry. The routine first validates the function code, then parses command line parameters to either display drive configurations or modify them.

The SVC dispatcher has placed the function code in Register A. For PDRIVE, this should be 32H (50 decimal) which identifies SYS16 as the handler.

4D00
CP 32H FE 32
Compare Register A against 32H (50 decimal, the PDRIVE function code). If Register A equals 32H, the Z FLAG is set; otherwise the NZ FLAG is set.
4D02
LD A,2AH 3E 2A
Preload Register A with 2AH (error code 42 = "General Error") in case the function code was incorrect.
4D04
If the NZ FLAG (Not Zero) has been set (meaning the function code was not 32H), JUMP to 503CH to trigger an error via the error handler at 4409H.

Function code validated. Now save the source drive number (in Register B) if this is a drive copy operation.

4D07
LD A,B 78
Copy the value from Register B (contains source drive number from command line parsing, or 0 if none specified) into Register A.
4D08
LD (5114H),A 32 14 51
Store Register A into the source drive copy flag at 5114H. A nonzero value indicates copy mode is active (copying parameters from one drive to another).
4D0B
GOSUB to 4FC3H to initialize the parse state: sets 5118H to 02H and points DE to the parameter storage area at 510EH.
4D0E
GOSUB to SYS0 routine at 4436H to check for end of command line. Returns Z flag set if no more parameters.
4D11
RET NZ C0
If the NZ FLAG has been set (meaning more command line text exists to parse), RETURN to let SYS0 continue command processing.

No parameters after command - check if we should display drive info or just exit.

4D12
GOSUB to 4FCCH to check for additional parameters and handle the "A" drive prefix processing for parameter input.
4D15
RET C D8
If the CARRY FLAG is set (indicating an error or early termination condition), RETURN immediately.
4D16
If the Z FLAG (Zero) has been set (meaning no parameters - just "PDRIVE" was entered), JUMP to 4DDAH to display the current drive configurations for all drives.

4D19H - Parse Destination Drive Number:

When PDRIVE is invoked with a parameter like "0=1" (copy drive 1 config to drive 0), this section parses the destination drive number before the equals sign.

4D19
GOSUB to 4D5EH to parse a decimal number from the command line. Returns the value in Register A (0-9 for valid drive number).
4D1C
LD (4EA2H),A 32 A2 4E
Store the parsed drive number into the current drive variable at 4EA2H. This is the destination drive for copy operations.
4D1F
LD A,(HL) 7E
Fetch the next character from the command line buffer (HL points to current parse position).
4D20
CP 3DH FE 3D
Compare Register A against 3DH (ASCII =). If it matches, we have "dest=source" syntax for copying drive configurations.
4D22
If the NZ FLAG has been set (no equals sign - this is a parameter modification, not a drive copy), JUMP to 4D3FH to process parameter assignments.

Found "=" character - this is a drive configuration copy operation (e.g., "PDRIVE 0=1" copies drive 1's config to drive 0).

4D24
INC HL 23
INCrement HL to skip past the = character and point to the source drive number.
4D25
GOSUB to 4D5EH to parse the source drive number (the number after the equals sign).

Register A now contains the source drive number (0-9). Multiply by 16 to get the offset into the Drive Configuration Table.

4D28
RLCA 07
Rotate Register A left (×2). First of four rotations to multiply by 16.
4D29
RLCA 07
Rotate Register A left (×4). Second rotation.
4D2A
RLCA 07
Rotate Register A left (×8). Third rotation.
4D2B
RLCA 07
Rotate Register A left (×16). A now contains source_drive × 16, the offset to that drive's DCT entry.
4D2C
PUSH HL E5
Save the command line pointer (HL) onto the stack.
4D2D
LD H,43H 26 43
Load Register H with 43H, the high byte of the DCT base address (4300H).
4D2F
LD L,A 6F
Load Register L with the offset (source_drive × 16). HL now points to the source drive's DCT entry.
4D30
XOR A AF
Set Register A to ZERO (destination drive = 0) and clear all flags for the call to 4E9AH.
4D31
GOSUB to 4E9AH to calculate the destination drive's DCT pointer. The value at 4EA2H (destination drive) is used; IX returns pointing to that drive's DCT entry.
4D34
PUSH IX DD E5
Save the destination DCT pointer (IX) onto the stack.
4D36
POP DE D1
Pop the destination DCT pointer from IX into DE. DE now points to destination drive's DCT entry.
4D37
LD BC,0010H 01 00 10
Load Register Pair BC with 0010H (16 decimal) - the size of one DCT entry in bytes.
4D3A
LDIR ED B0
Block copy 16 bytes from source DCT (HL) to destination DCT (DE). This copies all drive parameters from the source drive to the destination drive.
4D3C
POP HL E1
Restore the command line pointer from the stack back into HL.
4D3D
JUMP to 4D9EH to check for more parameters on the command line.

4D3FH - Parse Parameter Name and Value:

This section handles parameter modifications like "PDRIVE 0,SPT=18" - setting specific drive parameters. It scans the parameter name table to find a match, then applies the value.

4D3F
GOSUB to 4FCCH to continue parsing and check for "A" prefix handling.
4D42
RET C D8
If the CARRY FLAG is set (error condition), RETURN immediately.
4D43
If the Z FLAG is set (end of parameters), JUMP to 4DDAH to display current drive configuration.

More parameters to process. Set up to scan the parameter name table.

4D46
LD BC,511CH 01 1C 51
Point Register Pair BC to 511CH, the start of the parameter name table (TI=, TD=, TC=, SPT=, etc.).
4D49
LD D,01H 16 01
Load Register D with 01H - initialize parameter index counter to 1.
4D4B
GOSUB to 5017H to search the parameter name table for a match with the text at (HL).
4D4E
GOSUB to 4E97H to extract the parameter type flags and set up IX pointing to the current drive's DCT entry.
4D51
LD A,(BC) 0A
Fetch the parameter type byte from the matched table entry at (BC).
4D52
BIT 7,A CB 7F
Test Bit 7 of the type byte. If set, this parameter takes a numeric value.
4D54
If Bit 7 is clear (Z flag set), JUMP to 4D69H to handle non-numeric parameters (letter flags or drive letters).

Bit 7 is set - this parameter takes a numeric value. Parse the number.

4D56
GOSUB to 502EH to parse a decimal number from the command line into DE.
4D59
JUMP to 4D9BH to store the parsed value into the appropriate DCT field.

4D5BH - Parameter Error Handler:

Jump target for invalid parameter syntax errors.

4D5B
JUMP to 503AH to trigger error code 2FH (47 decimal - "Parameter Error").

4D5EH - Parse Drive Number (0-9):

Parses a single decimal digit (0-9) from the command line and returns it in Register A. Returns with CARRY set if the value is 10 or greater (invalid drive number).

4D5E
GOSUB to 502EH to parse a decimal number from the command line. Result returned in DE (E for small numbers).
4D61
CP 0AH FE 0A
Compare Register A (the parsed value) against 0AH (10 decimal). Valid drive numbers are 0-9.
4D63
RET C D8
If the CARRY FLAG is set (value < 10, meaning valid drive number 0-9), RETURN with the drive number in A.

Value is 10 or greater - invalid drive number. Trigger error.

4D64
LD A,20H 3E 20
Load Register A with error code 20H (32 decimal - "Invalid Drive Number").
4D66
JUMP to 503CH to trigger the error via the error handler at 4409H.

4D69H - Handle Non-Numeric Parameters:

Handles parameters that take letter values (like drive letters A-P for the DDGA= parameter which specifies which drives are allocated to the directory granule area).

4D69
BIT 6,A CB 77
Test Bit 6 of the parameter type byte. If set, this parameter accepts multiple drive letters (bitmap format).
4D6B
If Bit 6 is clear, JUMP to 4D93H to handle single letter parameters (A-Z converted to 0-25).

Bit 6 is set - this is a bitmap parameter accepting multiple drive letters (e.g., "DDGA=ABCD" means drives A, B, C, D).

4D6D
XOR A AF
Set Register A to ZERO to initialize the bitmap.
4D6E
LD (IX+00H),A DD 77 00
Clear the first byte of the bitmap field in the DCT entry (drives A-H).
4D71
LD (IX+01H),A DD 77 01
Clear the second byte of the bitmap field in the DCT entry (drives I-P).

[LOOP START] - Process each drive letter in the parameter value.

4D74
PUSH IX DD E5
Save the DCT pointer (IX) onto the stack.
4D76
POP DE D1
Pop the DCT pointer into DE. DE now points to the bitmap field.
4D77
LD A,(HL) 7E
Fetch the next character from the command line.
4D78
SUB 41H D6 41
SUBtract 41H (ASCII A) from the character. Result is 0 for 'A', 1 for 'B', etc.
4D7A
CP 08H FE 08
Compare against 08H (8). If < 8, it's in the first byte (drives A-H).
4D7C
If CARRY FLAG is set (letter A-H), JUMP to 4D85H to set the bit in the first bitmap byte.

Letter is I-P (second byte of bitmap).

4D7E
INC DE 13
INCrement DE to point to the second bitmap byte.
4D7F
SUB 08H D6 08
SUBtract 8 from A to get bit position within the second byte (0-7).
4D81
CP 08H FE 08
Check if result is still ≥ 8 (letter beyond P).
4D83
If NO CARRY (letter beyond P or non-letter), JUMP to 4D9EH to finish this parameter.

Convert bit position (0-7) to a bitmask with that bit set.

4D85
LD B,A 47
Copy the bit position (0-7) to Register B for the rotation count.
4D86
LD A,80H 3E 80
Load Register A with 80H (10000000 binary) - start with bit 7 set.
4D88
INC B 04
INCrement B to convert 0-7 range to 1-8 for DJNZ loop.

[INNER LOOP] - Rotate the bit mask right B times to position the bit correctly.

4D89
RLCA 07
Rotate Register A left through carry. This positions the set bit for the drive letter.
4D8A
DECrement B and Jump if Not Zero. [LOOP] Continue rotating until bit is in correct position.
4D8C
EX DE,HL EB
Exchange DE and HL. HL now points to the bitmap byte, DE points to command line.
4D8D
OR (HL) B6
OR the new bit mask with the existing bitmap byte, setting the bit for this drive letter.
4D8E
LD (HL),A 77
Store the updated bitmap back to the DCT entry.
4D8F
EX DE,HL EB
Exchange back: HL points to command line again.
4D90
INC HL 23
INCrement HL to point to the next character in the parameter value.
4D91
[LOOP] Jump back to 4D74H to process the next drive letter.

4D93H - Handle Single Letter Parameter:

Handles parameters that take a single letter value (A-Z) which is converted to 0-25.

4D93
LD A,(HL) 7E
Fetch the parameter value character from the command line.
4D94
SUB 41H D6 41
SUBtract 41H (ASCII A) to convert letter to numeric value (A=0, B=1, ... Z=25).
4D96
CP 1AH FE 1A
Compare against 1AH (26). If ≥ 26, the character was not A-Z.
4D98
INC HL 23
INCrement HL to skip past the letter character.
4D99
If NO CARRY (invalid character - not A-Z), JUMP to 4D5BH to trigger parameter error.

Valid letter A-Z converted to 0-25 in Register A. Fall through to store it.

4D9B
LD (IX+00H),A DD 77 00
Store the parameter value (in Register A) into the DCT field pointed to by IX.

4D9EH - Check For More Parameters:

After processing one parameter, check if there are more parameters on the command line. If so, loop back to parse them; otherwise proceed to update the drive configuration.

4D9E
GOSUB to 4FCCH to check for more command line parameters.
4DA1
RET C D8
If the CARRY FLAG is set (error condition), RETURN immediately.
4DA2
If the NZ FLAG is set (more parameters found), JUMP back to 4D46H to process the next parameter.

No more parameters. Now loop through all 10 drives to update their calculated fields based on the new settings.

4DA4
XOR A AF
Set Register A to ZERO - start with drive 0.

[LOOP START] - Update each drive's DCT entry (drives 0-9).

4DA5
LD (4EA2H),A 32 A2 4E
Store the current drive number into the current drive variable at 4EA2H.
4DA8
PUSH AF F5
Save the drive counter (AF) onto the stack.
4DA9
GOSUB to 4EB0H to recalculate the derived drive parameters (granule mapping, etc.) for this drive.
4DAC
POP AF F1
Restore the drive counter from the stack.
4DAD
INC A 3C
INCrement Register A to move to the next drive number.
4DAE
CP 0AH FE 0A
Compare against 0AH (10). Have we processed all 10 drives (0-9)?
4DB0
If NZ FLAG is set (not done yet), [LOOP] back to 4DA5H to process the next drive.

All drives updated. Now validate the TI= settings for compatibility between drives.

4DB2
GOSUB to 4FECH to validate that all drives have compatible TI= (Time Interval) settings.
4DB5
LD IX,4300H DD 21 00 43
Point Index Register IX to 4300H, the start of the Drive Configuration Table.
4DB9
LD B,0AH 06 0A
Load Register B with 0AH (10 decimal) - loop counter for 10 drives.

[LOOP START] - Process TSR (Track Stepping Rate) sign extension for each drive.

4DBB
LD E,(IX+07H) DD 5E 07
Fetch the TSR (Track Stepping Rate) value from offset +07H in the current DCT entry.
4DBE
LD D,00H 16 00
Clear Register D (assume positive/no sign extension needed).
4DC0
BIT 3,C CB 59
Test Bit 3 of Register C (contains flags from previous call). If set, sign extension is needed.
4DC2
If Z FLAG is set (bit 3 clear), JUMP to 4DC9H to skip sign extension.

Bit 3 set - perform sign extension for negative TSR values.

4DC4
LD A,E 7B
Copy the TSR value to Register A.
4DC5
RLCA 07
Rotate A left to get the sign bit into the carry.
4DC6
OR FCH F6 FC
OR with FCH (11111100 binary) to set up sign extension pattern.
4DC8
LD D,A 57
Store the sign-extended high byte in Register D.
4DC9
LD (IX+06H),D DD 72 06
Store the sign extension byte (or 00H) at offset +06H in the DCT entry.
4DCC
LD DE,0010H 11 00 10
Load DE with 0010H (16 decimal) - size of one DCT entry.
4DCF
ADD IX,DE DD 19
ADD 16 to IX to point to the next drive's DCT entry.
4DD1
DECrement B and Jump if Not Zero. [LOOP] Continue until all 10 drives processed.

All DCT entries updated. Now save the configuration and check if we should write to disk.

4DD3
GOSUB to 4FC3H to re-initialize the parse state.
4DD6
GOSUB to SYS0 routine at 443CH to check for more command line parameters or perform final validation.
4DD9
RET NZ C0
If NZ FLAG is set (error or more processing needed), RETURN to caller.

4DDAH - Display All Drive Configurations:

Called when PDRIVE is entered without parameters, or after parameters have been processed. Loops through all active drives and displays their current configuration settings.

4DDA
XOR A AF
Set Register A to ZERO - start with drive 0.

[LOOP START] - Display configuration for each drive (0-9).

4DDB
PUSH AF F5
Save the drive counter (AF) onto the stack.
4DDC
GOSUB to 4E16H to display the configuration for drive number in A.
4DDF
POP AF F1
Restore the drive counter from the stack.
4DE0
INC A 3C
INCrement Register A to move to the next drive number.
4DE1
CP 0AH FE 0A
Compare against 0AH (10). Have we displayed all 10 drives (0-9)?
4DE3
If CARRY FLAG is set (A < 10), [LOOP] back to 4DDBH to display the next drive.

All drives displayed. Now validate TI= compatibility and check for warnings.

4DE5
GOSUB to 4FECH to validate TI= (Time Interval) compatibility between all active drives.
4DE8
LD HL,50DCH 21 DC 50
Point HL to 50DCH, the warning message: "**** TI= SPEC BETWEEN DRIVES INCOMPATIBLE".
4DEB
If NO CARRY (TI= settings incompatible), GOSUB to SYS0 routine at 4467H to display the warning message.

Check if any drives are configured (drive 0 has valid settings).

4DEE
LD A,(4302H) 3A 02 43
Fetch the flags byte from drive 0's DCT entry at 4302H.
4DF1
OR A B7
OR Register A with itself to set flags based on the value. Zero means drive 0 is not configured.
4DF2
If Z FLAG is set (no drives configured), JUMP to DOS Ready at 4030H to return to command prompt.

Check if we should copy the DCT to the system area.

4DF5
LD A,00H 3E 00
Load Register A with 00H. This is a self-modifying code location - may be patched to nonzero.
4DF7
OR A B7
OR Register A with itself to test if it's zero.
4DF8
RET Z C8
If Z FLAG is set (A was 00H), RETURN - no DCT copy needed.

Copy the DCT entries to the system work area at 4291H for active use.

4DF9
LD HL,4300H 21 00 43
Point HL to 4300H, the source - Drive Configuration Table.
4DFC
LD DE,4291H 11 91 42
Point DE to 4291H, the destination - active drive parameter area.
4DFF
LD A,(43A0H) 3A A0 43
Fetch the maximum active drive number from 43A0H.
4E02
DEC A 3D
DECrement to get count of drives to copy (max drive - 1).
4E03
CP 04H FE 04
Compare against 04H. Limit to maximum of 4 drives for the work area copy.
4E05
If CARRY FLAG is set (fewer than 4 drives), JUMP to 4E09H to use the actual count.
4E07
LD A,03H 3E 03
Load Register A with 03H - cap at 4 drives (indices 0-3).

[LOOP START] - Copy each drive's parameters to the work area.

4E09
INC A 3C
INCrement A to get the actual number of drives to copy.
4E0A
LD BC,000AH 01 0A 00
Load BC with 000AH (10 decimal) - copy 10 bytes per drive entry.
4E0D
LDIR ED B0
Block copy 10 bytes from (HL) to (DE). Copies essential drive parameters.
4E0F
LD C,06H 0E 06
Load C with 06H (6 decimal) - skip remaining 6 bytes of each 16-byte DCT entry.
4E11
ADD HL,BC 09
ADD 6 to HL to skip to the next DCT entry in the source.
4E12
DEC A 3D
DECrement the drive counter.
4E13
If NZ FLAG is set (more drives to copy), [LOOP] back to 4E0AH.
4E15
RET C9
RETURN to caller.

4E16H - Display Single Drive Configuration:

Displays the configuration for a single drive. Outputs the drive number followed by all parameter names and their current values. Marks inactive drives with an asterisk.

4E16
LD (4EA2H),A 32 A2 4E
Store the drive number (in Register A) into the current drive variable at 4EA2H.
4E19
PUSH AF F5
Save the drive number onto the stack.
4E1A
ADD 30H C6 30
ADD 30H to convert drive number (0-9) to ASCII digit ('0'-'9').
4E1C
GOSUB to 500FH to output the drive number character to the screen.
4E1F
LD B,03H 06 03
Load Register B with 03H - output up to 3 asterisks for inactive drives.
4E21
POP AF F1
Restore the drive number from the stack.
4E22
LD HL,43A0H 21 A0 43
Point HL to 43A0H, the maximum active drive number.
4E25
CP (HL) BE
Compare the current drive number against the maximum active drive.
4E26
If NO CARRY (drive number ≥ max active), JUMP to 4E2EH to output spaces (drive is active).

Drive number is less than maximum active - mark with asterisks to indicate it's beyond the configured range.

4E28
DEC B 05
DECrement B (asterisk counter).
4E29
LD A,2AH 3E 2A
Load Register A with 2AH (ASCII *).
4E2B
GOSUB to 500FH to output an asterisk.

[LOOP] - Output spaces or asterisks as padding.

4E2E
LD A,20H 3E 20
Load Register A with 20H (ASCII space).
4E30
GOSUB to 500FH to output a space character.
4E33
DECrement B and Jump if Not Zero. [LOOP] Output B spaces total.

Now display each parameter for this drive.

4E35
LD BC,511CH 01 1C 51
Point BC to 511CH, the start of the parameter name table (TI=, TD=, etc.).

[OUTER LOOP START] - Process each parameter name.

4E38
LD A,(BC) 0A
Fetch the next character of the parameter name from (BC).
4E39
OR A B7
OR Register A with itself to test if it's zero (null terminator).
4E3A
INC BC 03
INCrement BC to point to the next character or the type byte.
4E3B
If NZ FLAG (not null), GOSUB to 500FH to output the parameter name character.
4E3E
If NZ FLAG (more characters), [LOOP] back to 4E38H to output next character.

Parameter name complete (hit null terminator). Now get the value from the DCT.

4E40
GOSUB to 4E97H to extract parameter flags and set up IX pointing to the current drive's DCT field.
4E43
LD A,(BC) 0A
Fetch the parameter type byte from (BC).
4E44
INC BC 03
INCrement BC past the type byte.
4E45
LD E,(IX+00H) DD 5E 00
Fetch the low byte of the parameter value from the DCT entry.
4E48
LD D,(IX+01H) DD 56 01
Fetch the high byte of the parameter value (or second byte for bitmaps).
4E4B
PUSH BC C5
Save the parameter table pointer (BC) onto the stack.
4E4C
BIT 7,A CB 7F
Test Bit 7 of the type byte. If set, this is a numeric parameter.
4E4E
If Bit 7 is set (numeric), JUMP to 4E6DH to display as decimal number.
4E50
BIT 6,A CB 77
Test Bit 6 of the type byte. If set, this is a bitmap parameter.
4E52
If Bit 6 is set (bitmap), JUMP to 4E5CH to display as drive letters.

Neither bit 7 nor bit 6 set - this is a single letter parameter. Display as A-Z.

4E54
LD A,E 7B
Copy the parameter value (0-25) to Register A.
4E55
ADD 41H C6 41
ADD 41H to convert value to ASCII letter (0='A', 1='B', etc.).
4E57
GOSUB to 500FH to output the letter character.
4E5A
JUMP to 4E72H to continue with the next parameter.

4E5CH - Display Bitmap Parameter As Drive Letters:

Displays a 16-bit bitmap parameter as a list of drive letters (A-P). Each set bit in the bitmap corresponds to a drive letter.

4E5C
LD B,10H 06 10
Load Register B with 10H (16 decimal) - 16 bits to check (drives A-P).
4E5E
LD C,41H 0E 41
Load Register C with 41H (ASCII A) - starting drive letter.

[LOOP START] - Check each bit and output corresponding letter if set.

4E60
RR D CB 1A
Rotate Register D right through carry. Shifts the next bit into carry.
4E62
RR E CB 1B
Rotate Register E right through carry. Together with D, shifts the 16-bit bitmap right.
4E64
LD A,C 79
Copy the current letter (C) to Register A.
4E65
INC C 0C
INCrement C to the next letter for the next iteration.
4E66
If CARRY FLAG is set (bit was 1), GOSUB to 500FH to output the drive letter.
4E69
DECrement B and Jump if Not Zero. [LOOP] Continue for all 16 bits.
4E6B
JUMP to 4E72H to continue with the next parameter.

4E6DH - Display Numeric Parameter:

Displays a numeric parameter value in decimal format.

4E6D
LD D,00H 16 00
Clear Register D (high byte) - parameter is single byte value in E.
4E6F
GOSUB to 5099H to convert the 16-bit value in DE to decimal and display it.

4E72H - Continue Parameter Display:

Checks if there are more parameters to display, and outputs a comma separator between parameters.

4E72
POP BC C1
Restore the parameter table pointer from the stack.
4E73
LD A,(BC) 0A
Fetch the next byte from the parameter table. If 00H, we've reached the end.
4E74
OR A B7
OR Register A with itself to test for end of table (zero).
4E75
If Z FLAG (end of parameter table), JUMP to 4E7EH to finish this drive's display.

More parameters to display - output a comma separator.

4E77
LD A,2CH 3E 2C
Load Register A with 2CH (ASCII ,).
4E79
GOSUB to 500FH to output the comma.
4E7C
[LOOP] Jump back to 4E38H to display the next parameter.

4E7EH - Finish Drive Display Line:

Completes the display line for one drive. Checks for error conditions and outputs a carriage return.

4E7E
GOSUB to 4EB0H to recalculate derived drive parameters and check for errors.
4E81
LD A,(IX+02H) DD 7E 02
Fetch the drive flags byte from offset +02H in the DCT entry.
4E84
AND 1CH E6 1C
AND with 1CH (00011100 binary) to isolate error flag bits.
4E86
If NZ FLAG (no errors), JUMP to 4E92H to output carriage return.

Error flags are set - display error message for this drive.

4E88
LD HL,50CBH 21 CB 50
Point HL to 50CBH, just before the error message "*** ERROR ***" at 50CEH.
4E8B
GOSUB to SYS0 routine at 4467H to display the error message.
4E8E
XOR A AF
Set Register A to ZERO.
4E8F
LD (4302H),A 32 02 43
Clear the flags byte at 4302H to reset error state for drive 0.

Output carriage return to end this line.

4E92
LD A,0DH 3E 0D
Load Register A with 0DH (ASCII carriage return).
4E94
JUMP to 500FH to output the carriage return and return to caller.

4E97H - Get Parameter Type and Set IX to DCT Field:

Extracts the parameter field offset from the type byte and sets IX to point to the corresponding field in the current drive's DCT entry.

4E97
LD A,(BC) 0A
Fetch the parameter type byte from (BC).
4E98
AND 0FHAND 00001111 E6 0F
AND with 0FH to extract the low nibble (field offset within DCT entry, 0-15).

Fall through to 4E9AH to calculate the actual address.

4E9AH - Calculate DCT Field Address:

Calculates the address of a specific field within a drive's DCT entry. Takes the drive number from 4EA2H and the field offset in Register A. Returns with IX pointing to that field.

4E9A
PUSH HL E5
Save HL onto the stack.
4E9B
PUSH DE D5
Save DE onto the stack.
4E9C
LD HL,4300H 21 00 43
Point HL to 4300H, the base address of the Drive Configuration Table.
4E9F
LD D,L 55
Copy L (00H) to D. D will accumulate the high byte of offset.
4EA0
LD E,A 5F
Copy the field offset (0-15) to E.
4EA1
LD A,FFH 3E FF
Load Register A with FFH. This location (4EA2H) is also used as the current drive number storage!

The instruction at 4EA1H loads a value that will be overwritten. 4EA2H is where the drive number is stored by other code, making this a self-modifying code pattern.

4EA2
 
(Address 4EA2H is the storage location for the current drive number, embedded in the previous instruction's operand)
4EA3
RLCA 07
Rotate A left (×2). First of four rotations to multiply drive number by 16.
4EA4
RLCA 07
Rotate A left (×4). Second rotation.
4EA5
RLCA 07
Rotate A left (×8). Third rotation.
4EA6
RLCA 07
Rotate A left (×16). A now contains drive_number × 16.
4EA7
ADD A,E 83
ADD the field offset (E) to the drive offset (A). A = drive×16 + field_offset.
4EA8
LD E,A 5F
Store the combined offset in E.
4EA9
ADD HL,DE 19
ADD DE (the offset) to HL (base 4300H). HL now points to the specific DCT field.
4EAA
PUSH HL E5
PUSH the calculated address onto the stack.
4EAB
POP IX DD E1
POP the address into Index Register IX. IX now points to the DCT field.
4EAD
POP DE D1
Restore DE from the stack.
4EAE
POP HL E1
Restore HL from the stack.
4EAF
RET C9
RETURN to caller with IX pointing to the DCT field.

4EB0H - Recalculate Derived Drive Parameters:

Recalculates the derived parameters for a drive based on its basic settings. This includes granule-to-track mappings and validation of parameter combinations. Sets error flags if invalid combinations are detected.

4EB0
XOR A AF
Set Register A to ZERO (field offset 0 - start of DCT entry).
4EB1
GOSUB to 4E9AH to set IX pointing to the start of the current drive's DCT entry.
4EB4
LD A,(IX+02H) DD 7E 02
Fetch the drive flags byte from offset +02H.
4EB7
AND E3H E6 E3
AND with E3H (11100011 binary) to clear bits 2-4 (error flag bits).
4EB9
LD (IX+02H),A DD 77 02
Store the cleared flags back to the DCT.
4EBC
LD A,(IX+04H) DD 7E 04
Fetch the TC (Track Count) value from offset +04H.
4EBF
OR A B7
OR Register A with itself to check if TC is zero.
4EC0
LD C,A 4F
Copy TC to Register C for later use.
4EC1
RET Z C8
If Z FLAG (TC is zero - drive not configured), RETURN immediately.

Drive has tracks configured. Check TI= parameter for validity.

4EC2
LD A,(IX+0FH) DD 7E 0F
Fetch the TI (Time Interval) value from offset +0FH.
4EC5
CP 08H FE 08
Compare TI against 08H (8). Values 0-7 are standard, 8+ are extended.
4EC7
LD E,A 5F
Copy TI to Register E.
4EC8
LD D,00H 16 00
Clear D for 16-bit offset calculation.
4ECA
If NO CARRY (TI ≥ 8), JUMP to 4ED3H to skip TI lookup table check.

TI is 0-7 - look up maximum track count for this TI value.

4ECC
LD HL,5106H 21 06 51
Point HL to 5106H, the TI lookup table (max tracks per TI value).
4ECF
ADD HL,DE 19
ADD TI offset to HL to get the entry for this TI value.
4ED0
LD A,(HL) 7E
Fetch the maximum track count allowed for this TI setting.
4ED1
CP C B9
Compare against the actual TC value (in C).
4ED2
RET C D8
If CARRY (max < actual TC - TI too small for track count), RETURN to flag error later.

TI is valid for track count. Continue parameter validation.

4ED3
LD L,C 69
Copy TC (track count) to Register L.
4ED4
LD A,(IX+03H) DD 7E 03
Fetch the SPT (Sectors Per Track) value from offset +03H.
4ED7
OR A B7
OR Register A to check if SPT is zero.
4ED8
RET Z C8
If Z FLAG (SPT is zero - invalid), RETURN.
4ED9
GOSUB to SYS0 routine at 4C37H to perform HL = TC × SPT (total sectors on disk).
4EDC
BIT 4,(IX+0EH) DD CB 0E 66
Test Bit 4 of the extended flags at offset +0EH.
4EE0
LD A,05H 3E 05
Load Register A with 05H (default granules per lump = 5).
4EE2
NOP 00
No Operation (placeholder or alignment).
4EE3
If Bit 4 was set, GOSUB to 517EH to check for double-sided disk adjustment.
4EE6
GOSUB to SYS0 routine at 4C59H to calculate granule mapping parameters.
4EE9
LD A,(IX+09H) DD 7E 09
Fetch the DDSL (Directory Sectors per Lump) from offset +09H.
4EEC
CP 02H FE 02
Compare against 02H (minimum of 2 directory sectors).
4EEE
LD B,A 47
Copy DDSL to Register B.
4EEF
RET C D8
If CARRY (DDSL < 2 - invalid), RETURN.
4EF0
CP 07H FE 07
Compare against 07H (maximum of 6 directory sectors).
4EF2
RET NC D0
If NO CARRY (DDSL ≥ 7 - invalid), RETURN.
4EF3
EX DE,HL EB
Exchange DE and HL. DE now has total sectors, HL is free.
4EF4
LD L,(IX+08H) DD 6E 08
Fetch the GPL (Granules Per Lump) from offset +08H.
4EF7
LD (IX+00H),L DD 75 00
Store GPL at offset +00H (copy to working location).
4EF9
NOP 00
No Operation (placeholder).
4EFA
LD A,(IX+05H) DD 7E 05
Fetch the TSR (Track Stepping Rate) from offset +05H.
4EFD
OR A B7
OR Register A to check if TSR is zero.
4EFE
LD C,A 4F
Copy TSR to Register C.
4EFF
RET Z C8
If Z FLAG (TSR is zero - invalid), RETURN.
4F00
CP 09H FE 09
Compare TSR against 09H (maximum value 8).
4F02
RET NC D0
If NO CARRY (TSR ≥ 9 - invalid), RETURN.
4F03
GOSUB to SYS0 routine at 4C37H for multiplication.

[LOOP] - Iterate through calculation.

4F06
INC HL 23
INCrement HL.
4F07
DECrement B and Jump if Not Zero. [LOOP]
4F09
EX DE,HL EB
Exchange DE and HL.
4F0A
OR A B7
Clear carry flag for subtraction.
4F0B
SBC HL,DE ED 52
Subtract DE from HL with borrow.
4F0D
RET C D8
If CARRY (underflow), RETURN.
4F0E
ADD HL,DE 19
ADD DE back to HL.
4F0F
LD A,C 79
Copy C back to Register A.
4F10
GOSUB to SYS0 routine at 4C59H for additional calculation.
4F13
If Z FLAG, JUMP to 4F16H.
4F15
INC HL 23
INCrement HL.
4F16
LD (IX+00H),L DD 75 00
Store result at offset +00H.
4F18
LD BC,112BH 01 2B 11
Load BC with 112BH.
4F1B
RET NZ C0
If NZ FLAG, RETURN.
4F1C
NOP 00
No Operation.
4F1D
OR A B7
Clear carry for subtraction.
4F1E
SBC HL,DE ED 52
Subtract DE from HL.
4F20
RET NC D0
If NO CARRY, RETURN.

4F21H - Extended Parameter Validation:

Continues validation of drive parameters, checking bit flags and setting derived values. This complex section validates the relationships between multiple parameters.

4F21
LD C,(IX+0DH) DD 4E 0D
Fetch parameter from offset +0DH into Register C.
4F24
LD B,(IX+0EH) DD 46 0E
Fetch parameter from offset +0EH into Register B.
4F27
LD A,C 79
Copy C to Register A.
4F28
AND 7FHAND 01111111 E6 7F
AND with 7FH to clear bit 7.
4F2A
LD L,A 6F
Store result in L.
4F2B
LD A,B 78
Copy B to Register A.
4F2C
AND 00H E6 00
AND with 00H - effectively clears A to zero.
4F2E
LD H,A 67
Store zero in H. HL now contains masked value.
4F2F
LD D,10H 16 10
Load D with 10H (16) - loop counter.
4F31
XOR A AF
Clear Register A.

[LOOP START] - 16-bit shift loop for multiplication.

4F32
ADD HL,HL 29
Double HL (shift left).
4F33
ADC 00H CE 00
Add carry to A.
4F35
DEC D 15
DECrement loop counter.
4F36
If NZ FLAG, [LOOP] back to continue shifting.
4F38
DEC A 3D
DECrement A.
4F39
RET NZ C0
If NZ FLAG, RETURN.
4F3A
LD A,C 79
Copy C to Register A.
4F3B
AND 76H E6 76
AND with 76H to isolate specific bits.
4F3D
RET NZ C0
If NZ FLAG, RETURN.
4F3E
LD A,B 78
Copy B to Register A.
4F3F
AND 0E0HAND 11100000 E6 E0
AND with E0H to isolate high bits.
4F41
RET NZ C0
If NZ FLAG, RETURN.

Continue with additional bit testing and flag setting based on parameter combinations.

4F42
LD D,14H 16 14
Load D with 14H (20 decimal).
4F44
LD L,(IX+0FH) DD 6E 0F
Fetch TI value into L.
4F47
BIT 4,C CB 61
Test Bit 4 of C.
4F49
If Bit 4 is set, JUMP to 4F6EH.
4F4B
LD D,08H 16 08
Load D with 08H (8).
4F4D
BIT 3,C CB 59
Test Bit 3 of C.
4F4F
If Bit 3 is set, JUMP to 4F6EH.
4F51
BIT 1,C CB 49
Test Bit 1 of C.
4F53
If Bit 1 is clear, JUMP to 4F5BH.
4F55
LD D,0CH 16 0C
Load D with 0CH (12).
4F57
BIT 2,L CB 55
Test Bit 2 of L.
4F59
JUMP to 4F6DH.
4F5B
BIT 2,C CB 51
Test Bit 2 of C.
4F5D
If Bit 2 is clear, JUMP to 4F65H.
4F5F
LD D,10H 16 10
Load D with 10H (16).
4F61
BIT 0,L CB 45
Test Bit 0 of L.
4F63
JUMP to 4F6DH.
4F65
BIT 0,C CB 41
Test Bit 0 of C.
4F67
RET Z C8
If Bit 0 is clear, RETURN.
4F68
LD D,04H 16 04
Load D with 04H (4).
4F6A
LD A,L 7D
Copy L to Register A.
4F6B
AND 01HAND 00000001 E6 01
AND with 01H to isolate bit 0.
4F6D
RET NZ C0
If NZ FLAG, RETURN.
4F6E
LD A,L 7D
Copy L (TI value) to Register A.
4F6F
CP 08H FE 08
Compare TI against 08H.
4F71
RET NC D0
If NO CARRY (TI ≥ 8), RETURN.

4F72H - Build Drive Configuration Flags:

Builds the drive configuration flags byte based on various parameter settings. This involves checking multiple bit flags and building the result in Register E for the drive flags field.

4F72
LD E,00H 1E 00
Clear Register E - initialize the flags accumulator.
4F74
BIT 2,L CB 55
Test Bit 2 of L (TI value).
4F76
If Bit 2 is clear, JUMP to 4F7AH.
4F78
SET 0,E CB C3
SET Bit 0 of E.
4F7A
BIT 0,L CB 45
Test Bit 0 of L.
4F7C
If Bit 0 is clear, JUMP to 4F80H.
4F7E
SET 7,E CB FB
SET Bit 7 of E.
4F80
BIT 1,L CB 4D
Test Bit 1 of L.
4F82
If Bit 1 is clear, JUMP to 4F86H.
4F84
SET 6,E CB F3
SET Bit 6 of E.
4F86
LD A,(IX+0CH) DD 7E 0C
Fetch parameter from offset +0CH into Register A.
4F89
CP 04H FE 04
Compare against 04H.
4F8B
RET NC D0
If NO CARRY (value ≥ 4), RETURN.
4F8C
OR D B2
OR Register A with D to combine flags.
4F8D
LD D,A 57
Store combined flags in D.
4F8E
BIT 4,B CB 60
Test Bit 4 of B.
4F90
If Bit 4 is clear, JUMP to 4F9CH.
4F92
SET 5,D CB EA
SET Bit 5 of D.
4F94
BIT 0,E CB 43
Test Bit 0 of E.
4F96
LD A,06H 3E 06
Load Register A with 06H.
4F98
If Bit 0 is set, GOSUB to 5178H for additional checking.
4F9B
RET NZ C0
If NZ FLAG, RETURN.
4F9C
BIT 3,B CB 58
Test Bit 3 of B.
4F9E
If Bit 3 is clear, JUMP to 4FA2H.
4FA0
SET 2,E CB D3
SET Bit 2 of E.
4FA2
BIT 7,C CB 79
Test Bit 7 of C.
4FA4
If Bit 7 is clear, JUMP to 4FA8H.
4FA6
SET 7,D CB FA
SET Bit 7 of D.
4FA8
BIT 1,B CB 48
Test Bit 1 of B.
4FAA
If Bit 1 is clear, JUMP to 4FAEH.
4FAC
SET 1,E CB CB
SET Bit 1 of E.
4FAE
BIT 0,B CB 40
Test Bit 0 of B.
4FB0
If Bit 0 is clear, JUMP to 4FB4H.
4FB2
SET 4,E CB E3
SET Bit 4 of E.
4FB4
BIT 2,B CB 50
Test Bit 2 of B.
4FB6
If Bit 2 is clear, JUMP to 4FBCH.
4FB8
SET 6,D CB F2
SET Bit 6 of D.
4FBA
SET 1,E CB CB
SET Bit 1 of E.

Store the computed flags into the DCT entry.

4FBC
LD (IX+07H),E DD 73 07
Store the computed E flags byte at offset +07H in the DCT.
4FBF
LD (IX+02H),D DD 72 02
Store the computed D flags byte at offset +02H in the DCT.
4FC2
RET C9
RETURN to caller.

4FC3H - Initialize Parse State:

Initializes the parsing state variables for processing PDRIVE command parameters. Sets up the parameter storage area pointer and parse state flag.

4FC3
LD A,02H 3E 02
Load Register A with 02H - initial parse state value.
4FC5
LD (5118H),A 32 18 51
Store the parse state into the parse state flag at 5118H.
4FC8
LD DE,510EH 11 0E 51
Point DE to 510EH, the PDRIVE parameter storage area.
4FCB
RET C9
RETURN to caller.

4FCCH - Check For Parameters / Handle "A" Prefix:

Checks the command line for more parameters and handles the special "A" prefix for drive specifications (allowing syntax like "PDRIVE A0,SPT=18").

4FCC
GOSUB to SYS0 routine at 4C7AH to skip whitespace and check for end of command line.
4FCF
RET C D8
If CARRY FLAG is set (error), RETURN immediately.
4FD0
RET Z C8
If Z FLAG is set (end of command line), RETURN.

More text on command line. Check if we should process "A" prefix.

4FD1
LD A,(5114H) 3A 14 51
Fetch the source drive copy flag from 5114H.
4FD4
OR A B7
OR Register A to test if copy mode is active.
4FD5
RET NZ C0
If NZ FLAG (copy mode active), RETURN - don't process "A" prefix.

Not in copy mode. Check for "A" prefix processing flag.

4FD6
LD DE,4DF6H 11 F6 4D
Point DE to 4DF6H, the self-modifying code location that controls "A" prefix behavior.
4FD9
LD A,(DE) 1A
Fetch the flag byte from (DE).
4FDA
OR A B7
OR Register A to test if "A" prefix processing is enabled.
4FDB
RET NZ C0
If NZ FLAG (already processed or disabled), RETURN.

Check if the current character is "A" which might be a prefix for drive letters.

4FDC
LD A,(HL) 7E
Fetch the current character from the command line.
4FDD
JUMP to 51CBH to check if it's an "A" and handle accordingly.

4FE0H - Process After "A" Prefix Check:

Continuation of the "A" prefix handling. If "A" was found and processed, advance the pointer and continue. If not, disable further "A" prefix checking.

4FE0
If NZ FLAG (character was not "A" or second char not digit), JUMP to 4FE8H to disable "A" prefix.
4FE2
INC HL 23
INCrement HL to skip past the "A" character.
4FE3
GOSUB to SYS0 routine at 4C7AH to skip whitespace after the "A".
4FE6
RET NC D0
If NO CARRY (no error), RETURN to continue processing.
4FE7
DEC HL 2B
DECrement HL (restore position if there was an error).

Disable further "A" prefix checking by setting the flag.

4FE8
XOR A AF
Set Register A to ZERO.
4FE9
LD (DE),A 12
Store zero at (DE) to disable "A" prefix processing flag.
4FEA
INC A 3C
INCrement A to 1 (sets NZ flag for return).
4FEB
RET C9
RETURN with NZ flag set (more to process).

4FECH - Validate TI= Compatibility Across Drives:

Scans all 10 drive configurations to validate that the TI= (Time Interval) settings are compatible with each other. Returns with CARRY set if all drives are compatible, NO CARRY if incompatible.

4FEC
LD HL,430DH 21 0D 43
Point HL to 430DH, the first drive's TI field (offset +0DH from 4300H).
4FEF
LD BC,0A00H 01 00 0A
Load BC: B=0AH (10 drives to check), C=00H (accumulator for flags).
4FF2
LD DE,0010H 11 00 10
Load DE with 0010H (16 decimal) - offset between DCT entries.

[LOOP START] - Check each drive's TI-related flags.

4FF5
LD A,(HL) 7E
Fetch the flags byte at offset +0DH from current drive.
4FF6
AND 7EH E6 7E
AND with 7EH (01111110 binary) to isolate TI-related bits.
4FF8
OR C B1
OR with accumulator C to combine all drive TI flags.
4FF9
LD C,A 4F
Store combined flags back in C.
4FFA
ADD HL,DE 19
ADD 16 to HL to point to the next drive's DCT entry.
4FFB
DECrement B and Jump if Not Zero. [LOOP] Continue for all 10 drives.

All drives checked. Now count how many different TI types are present.

4FFD
LD B,08H 06 08
Load B with 08H (8) - number of bits to check.
4FFF
XOR A AF
Clear Register A - counter for number of TI types found.

[LOOP START] - Count set bits in the combined flags.

5000
RLC C CB 01
Rotate C left through carry. Shifts next bit into carry flag.
5002
If NO CARRY (bit was 0), JUMP to 5005H to skip counting.
5004
INC A 3C
INCrement A (count this TI type).
5005
DECrement B and Jump if Not Zero. [LOOP] Continue for all 8 bits.

A now contains the count of different TI types found. If ≥ 2, they're incompatible.

5007
CP 02H FE 02
Compare A against 02H. If 2 or more TI types, incompatible.
5009
RET C D8
If CARRY (fewer than 2 TI types - compatible), RETURN with carry set.

Multiple TI types found - clear drive 0's flags to signal incompatibility warning.

500A
XOR A AF
Clear Register A.
500B
LD (4302H),A 32 02 43
Store 00H to drive 0's flags at 4302H to signal warning condition.
500E
RET C9
RETURN with no carry (incompatible TI settings).

500FH - Output Character:

Outputs a single character (in Register A) to the console via the ROM character output routine. Preserves DE and AF registers.

500F
PUSH DE D5
Save DE onto the stack (preserve during ROM call).
5010
PUSH AF F5
Save AF onto the stack (preserve character and flags).
5011
GOSUB to ROM routine at 0033H to display the character in Register A at the cursor position.
5014
POP AF F1
Restore AF from the stack.
5015
POP DE D1
Restore DE from the stack.
5016
RET C9
RETURN to caller.

5017H - Search Parameter Name Table:

Searches the parameter name table (starting at BC) for a match with the text at (HL). D contains the parameter index. Returns when a match is found or end of table reached.

5017
GOSUB to SYS0 routine at 4C6AH to compare the string at (HL) with the parameter name at (BC).
501A
RET Z C8
If Z FLAG (match found), RETURN.

No match. Skip to the next parameter name in the table.

501B
LD A,(BC) 0A
Fetch the next character from the table entry.
501C
CP 00H FE 00
Compare against 00H (null terminator).
501E
INC BC 03
INCrement BC to next character.
501F
If NZ FLAG (not at end of name), [LOOP] to continue scanning.

Found null terminator. Skip past the type byte following the name.

5021
LD E,D 5A
Copy parameter index (D) to E.

[LOOP] - Skip D entries (type bytes) in the table.

5022
INC BC 03
INCrement BC past the type byte.
5023
DEC E 1D
DECrement E (counter).
5024
If NZ FLAG, [LOOP] to skip more type bytes.

Check if we've reached the end of the table.

5026
LD A,(BC) 0A
Fetch the next byte from the table.
5027
OR A B7
OR Register A to test for end of table (zero byte).
5028
If NZ FLAG (more entries), [LOOP] back to try next parameter name.

End of table reached with no match - trigger parameter error.

502A
LD A,34H 3E 34
Load Register A with error code 34H (52 decimal - "Parse Error").
502C
JUMP to 503CH to trigger the error.

502EH - Parse Decimal Number Entry Point:

Main entry point to parse a decimal number from the command line. Calls the core parsing routine and validates the result.

502E
GOSUB to 503FH to parse a decimal/hex number from the command line into Register DE.
5031
JUMP to 5036H to validate the result (skip alternate entry).

5033H - Parse Decimal Number (Alternate Entry):

Alternate entry point that uses a different parsing routine at 505DH.

5033
GOSUB to 505DH to parse using the alternate entry point.

5036H - Validate Parsed Number:

Validates that the parsed number is within range (D must be zero for single-byte values).

5036
LD A,D 7A
Load Register A with the high byte of the parsed number (Register D).
5037
OR A B7
OR Register A to set flags - tests if D is zero.
5038
LD A,E 7B
Load Register A with the low byte of the parsed number (Register E). This puts the value in A for the caller.
5039
RET Z C8
If Z FLAG (D was zero, number <= 255), RETURN with valid result in A and E.

Number is too large (D != 0). Fall through to trigger parameter error.

503AH - Parameter Error Handler:

Triggers error code 2FH (47 decimal - "Parameter Error") when a parameter value is out of range.

503A
LD A,2FH 3E 2F
Load Register A with error code 2FH (47 decimal - "Parameter Error").

503CH - Jump to Error Handler:

Transfers control to the SYS0 error handler with the error code in Register A.

503C
JUMP to SYS0 error handler at 4409H to process the error code in Register A.

503FH - Parse Decimal/Hex Number (Main Implementation):

Core routine to parse a decimal or hexadecimal number from the command line into Register DE. Supports hex digits A-F when preceded by decimal digits.

503F
PUSH HL E5
Save HL (command line pointer) to the stack.
5040
GOSUB to 5062H to initialize Register B to 00H (decimal mode) and DE to 0000H.

After parsing, check if next character is a hex digit (A-F) indicating this is a hex number.

5043
LD A,(HL) 7E
Fetch the current character from the command line.
5044
SUB 41H D6 41
Subtract 41H (ASCII 'A'). If character is 'A' to 'H', result is 00H-07H.
5046
CP 08H FE 08
Compare against 08H. Tests if character was A-H (potential hex suffix).
5048
If NC FLAG (not a hex letter A-H), JUMP to 5057H to check results.

Character is A-H. Re-parse as hexadecimal number.

504A
POP HL E1
Restore HL (original command line pointer) from the stack.
504B
LD B,01H 06 01
Load Register B with 01H (hex mode flag - bit 0 set enables A-F digits).
504D
PUSH HL E5
Save HL back to the stack for later restoration.
504E
GOSUB to 5064H to re-parse in hexadecimal mode (B=01H allows hex digits).

After hex parsing, verify the number ends with 'H' suffix.

5051
LD A,(HL) 7E
Fetch the character after the parsed number.
5052
CP 48H FE 48
Compare against 48H (ASCII 'H' for hex suffix).
5054
INC HL 23
INCrement HL past the 'H' suffix (or the current character).
5055
If NZ FLAG (no 'H' suffix), JUMP to 503AH to trigger parameter error.

5057H - Validate Parse Results:

Checks that at least one digit was parsed (bit 1 of B is set by the parse loop when digits are found).

5057
BIT 1,B CB 48
Test bit 1 of Register B. This bit is set when at least one valid digit was parsed.
5059
POP BC C1
Restore BC (was HL - original command line pointer) from the stack.
505A
RET NZ C0
If NZ FLAG (digits were found), RETURN with parsed value in DE.

No digits found - trigger parameter error.

505B
JUMP to 503AH to trigger "Parameter Error".

505DH - Parse Number (Alternate Entry):

Alternate entry point that pushes the validation address 5057H onto the stack, then falls into the main parse loop.

505D
PUSH HL E5
Save HL (command line pointer) to the stack.
505E
LD DE,5057H 11 57 50
Load Register DE with address 5057H (validation routine).
5061
PUSH DE D5
PUSH 5057H onto the stack as the return address - RET will jump there for validation.

Fall through to initialize and parse.

5062H - Initialize Parse State:

Initializes Register B to 00H (decimal mode) for parsing.

5062
LD B,00H 06 00
Load Register B with 00H (decimal mode - bit 0 clear means only 0-9 accepted).

Fall through to initialize accumulator.

5064H - Initialize Accumulator and Parse Digits:

Initializes DE to 0000H and begins the digit parsing loop. Each digit is accumulated into DE.

5064
LD DE,0000H 11 00 00
Load Register DE with 0000H - initialize accumulator to zero.

5067H - Parse Digit Loop:

Main digit parsing loop. Reads characters, converts to digit values, and accumulates into DE. Handles both decimal (×10) and hex (×16) multiplication based on mode flag in B.

[LOOP START] - Process each digit character.

5067
LD A,(HL) 7E
Fetch the current character from the command line at (HL).
5068
SUB 30H D6 30
Subtract 30H (ASCII '0'). Converts '0'-'9' to 00H-09H.
506A
CP 0AH FE 0A
Compare against 0AH. Tests if result is a valid decimal digit (0-9).
506C
If C FLAG (valid digit 0-9), JUMP to 5078H to accumulate it.

Not 0-9. Check if hex mode is enabled and character is A-F.

506E
BIT 0,B CB 40
Test bit 0 of Register B (hex mode flag).
5070
RET Z C8
If Z FLAG (decimal mode), RETURN - non-digit ends parsing.

Hex mode. Check for A-F.

5071
SUB 11H D6 11
Subtract 11H. This converts 'A'-'F' (after -30H gives 11H-16H) to 00H-05H.
5073
CP 06H FE 06
Compare against 06H. Tests if result is 0-5 (was 'A'-'F').
5075
RET NC D0
If NC FLAG (not A-F), RETURN - invalid hex digit ends parsing.
5076
ADD 0AH C6 0A
ADD 0AH to convert 00H-05H to 0AH-0FH (hex digit values 10-15).

5078H - Accumulate Digit Into DE:

Multiplies DE by the base (10 for decimal, 16 for hex) and adds the new digit. Uses a clever shift-and-add algorithm.

5078
PUSH HL E5
Save HL (command line pointer) to the stack.
5079
LD H,D 62
Copy Register D to H (high byte of accumulator).
507A
LD L,E 6B
Copy Register E to L (low byte of accumulator). Now HL = DE (current value).
507B
LD C,A 4F
Save the new digit value in Register C.
507C
XOR A AF
Clear Register A to zero (will accumulate overflow bits).
507D
SET 1,B CB C8
SET bit 1 of Register B to flag that at least one digit was parsed.

Multiply HL by base. For decimal: HL = HL×2 + HL×8 = HL×10. For hex: HL = HL×16.

507F
ADD HL,HL 29
ADD HL to itself. HL = HL × 2. (First doubling)
5080
ADC A,A 8F
ADd Carry to A,A - captures any overflow into the high byte (A).
5081
ADD HL,HL 29
ADD HL to itself. HL = HL × 4. (Second doubling)
5082
ADC A,A 8F
ADd Carry to A,A - captures overflow.
5083
BIT 0,B CB 40
Test bit 0 of Register B (hex/decimal mode flag).
5085
If Z FLAG (decimal mode), JUMP to 508AH to add original value (×2+×8=×10).

Hex mode: just continue doubling to get ×16.

5087
ADD HL,HL 29
ADD HL to itself. HL = HL × 8. (Third doubling for hex)
5088
JUMP to 508BH to continue with fourth doubling.

508AH - Add Original Value for Decimal ×10:

For decimal mode, adds the original DE value to HL (currently ×4) to get ×4+×1=×5, then doubles for ×10 total.

508A
ADD HL,DE 19
ADD DE to HL. Now HL = (original×4) + original = original×5.

508BH - Complete Multiplication and Add Digit:

Completes the base multiplication (×10 for decimal, ×16 for hex) and adds the new digit value to the accumulator in HL. This is reached from either decimal path (after ADD HL,DE at 508AH) or hex path (after third doubling at 5087H).

508B
ADC A,A 8F
ADd Carry to A,A - captures any overflow bit from the previous ADD operation into the high byte accumulator (A).
508C
ADD HL,HL 29
ADD HL to itself (final doubling). For decimal: ×5×2=×10. For hex: ×8×2=×16.
508D
ADC A,A 8F
ADd Carry to A,A - captures overflow from the final doubling.

Now add the new digit value (stored in C from 507BH).

508E
LD E,C 59
Load Register E with the digit value from Register C (0-9 for decimal, 0-15 for hex).
508F
LD D,00H 16 00
Load Register D with 00H. Now DE = digit value as a 16-bit number.
5091
ADD HL,DE 19
ADD DE to HL. HL = (old_value × base) + new_digit.
5092
ADC A,A 8F
ADd Carry to A,A - captures any final overflow. A will be non-zero if overflow occurred.
5093
EX DE,HL EB
EXchange DE and HL. Now DE contains the new accumulated value for next iteration.
5094
POP HL E1
Restore HL (command line pointer) from the stack (was pushed at 5078H).
5095
RET NZ C0
If NZ FLAG (A non-zero indicates overflow occurred), RETURN with error condition.
5096
INC HL 23
INCrement HL to point to the next character in the command line.
5097
[LOOP] back to 5067H to process the next digit.

5099H - Convert 16-Bit Number to Decimal Display:

Converts a 16-bit value in DE to decimal ASCII and displays it. Uses repeated subtraction with a table of negative powers of 10 at 50C3H. Suppresses leading zeros.

5099
LD BC,0400H 01 00 04
Load Register BC with 0400H. B=04H (4 digits to process: thousands, hundreds, tens, ones). C=00H (leading zero suppression flag - 0 means suppress).
509C
LD HL,50C3H 21 C3 50
Load Register HL with 50C3H - pointer to the division table containing negative powers of 10.

509FH - Process Each Decimal Place:

Loop to process each decimal place from most significant to least.

[LOOP START] - Process one decimal place.

509F
PUSH BC C5
Save BC to the stack (B=remaining digits, C=zero suppression flag).
50A0
LD C,(HL) 4E
Fetch the low byte of the negative divisor from the table into C.
50A1
INC HL 23
INCrement HL to point to the high byte.
50A2
LD B,(HL) 46
Fetch the high byte of the negative divisor into B. Now BC = negative of power of 10.
50A3
INC HL 23
INCrement HL to point to the next table entry (saved for next digit).
50A4
EX DE,HL EB
EXchange DE and HL. Now HL = number being converted, DE = table pointer.
50A5
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII '0' minus 1). Will be incremented to count subtractions.

[LOOP] - Count how many times we can subtract the divisor.

50A7
INC A 3C
INCrement A (the digit counter). First pass makes it '0'.
50A8
ADD HL,BC 09
ADD BC to HL. Since BC is negative, this subtracts the power of 10.
50A9
If C FLAG (no borrow - subtraction succeeded), [LOOP] to count another subtraction.

Subtraction went too far. Add back once to restore remainder.

50AB
SBC HL,BC ED 42
SuBtract with Carry BC from HL. Since carry is clear, this adds BC back (double negative = add).
50AD
POP BC C1
Restore BC from the stack (B=remaining digits, C=zero suppression flag).
50AE
EX DE,HL EB
EXchange DE and HL. Now DE = remainder, HL = table pointer.

Handle leading zero suppression.

50AF
CP 30H FE 30
Compare A against 30H (ASCII '0'). Check if this digit is zero.
50B1
If NZ FLAG (digit is not '0'), JUMP to 50B7H to display it.

Digit is '0'. Check if we should suppress it (leading zero).

50B3
INC C 0C
INCrement C (test and set the suppression flag).
50B4
DEC C 0D
DECrement C back. If C was 0 (suppressing), Z flag set. If C was non-zero, Z clear.
50B5
If Z FLAG (C was 0, suppress leading zeros), JUMP to 50BBH to skip display.

50B7H - Display Digit:

Displays a non-zero digit (or a zero after a non-zero digit has been displayed).

50B7
INC C 0C
INCrement C to disable zero suppression for subsequent digits.
50B8
GOSUB to 500FH to display the ASCII digit in Register A.

50BBH - Next Decimal Place:

Decrements the digit counter and loops for remaining places, then displays the ones digit.

50BB
Decrement B and [LOOP] to 509FH if not zero (more decimal places to process).

All 4 higher places processed. Display the ones digit (remainder in E).

50BD
LD A,E 7B
Load Register A with the final remainder (ones digit, 0-9) from Register E.
50BE
ADD 30H C6 30
ADD 30H to convert to ASCII ('0'-'9').
50C0
JUMP to 500FH to display the ones digit and return.

50C3H - Division Table (Negative Powers of 10):

Table of 16-bit negative values used for decimal conversion by repeated subtraction. Each entry is the two's complement of a power of 10.

These values are stored little-endian (low byte first).

50C3
DEFB F0H,D8H F0 D8
D8F0H = -10000 (two's complement). For ten-thousands place.
50C5
DEFB 18H,FCH 18 FC
FC18H = -1000 (two's complement). For thousands place.
50C7
DEFB 9CH,FFH 9C FF
FF9CH = -100 (two's complement). For hundreds place.
50C9
DEFB F6H,FFH F6 FF
FFF6H = -10 (two's complement). For tens place.

50CBH - Padding Before Error Message:

Three space characters used as padding or prefix before the error message.

50CB
DEFB 20H,20H,20H 20 20 20
Three ASCII spaces (padding).

50CEH - Error Message String:

The "*** ERROR ***" message displayed when drive parameter validation fails. Terminated with 03H (ETX).

50CE
DEFB 2AH,2AH,2AH 2A 2A 2A
ASCII "***" (asterisks prefix).
50D1
DEFB 20H 20
ASCII space.
50D2
DEFB 45H,52H,52H,4FH,52H 45 52 52 4F 52
ASCII "ERROR".
50D7
DEFB 20H 20
ASCII space.
50D8
DEFB 2AH,2AH,2AH 2A 2A 2A
ASCII "***" (asterisks suffix).
50DB
DEFB 03H 03
03H (ETX) - string terminator.

50DCH - TI= Incompatibility Warning Message:

Warning message displayed when drives have incompatible TI= (Time Interval) specifications. This occurs when different drives require different motor timing that cannot be satisfied simultaneously. Terminated with 0DH (CR).

50DC
DEFB 2AH,2AH,2AH,2AH 2A 2A 2A 2A
ASCII "****" (four asterisks prefix for emphasis).
50E0
DEFB 20H 20
ASCII space.
50E1
DEFB 54H,49H,3DH 54 49 3D
ASCII "TI=".
50E4
DEFB 20H 20
ASCII space.
50E5
DEFB 53H,50H,45H,43H 53 50 45 43
ASCII "SPEC".
50E9
DEFB 20H 20
ASCII space.
50EA
DEFB 42H,45H,54H,57H,45H,45H,4EH 42 45 54 57 45 45 4E
ASCII "BETWEEN".
50F1
DEFB 20H 20
ASCII space.
50F2
DEFB 44H,52H,49H,56H,45H,53H 44 52 49 56 45 53
ASCII "DRIVES".
50F8
DEFB 20H 20
ASCII space.
50F9
DEFB 49H,4EH,43H,4FH,4DH,50H,41H,54H,49H,42H,4CH,45H 49 4E 43 4F 4D 50 41 54 49 42 4C 45
ASCII "INCOMPATIBLE".
5105
DEFB 0DH 0D
0DH (CR) - carriage return / string terminator.

5106H - TI= Lookup Table:

Lookup table for TI= (Time Interval) validation. Each byte represents the maximum track count for that TI= setting, used to verify drive timing compatibility. Index 0-7 corresponds to TI= values 0-7.

5106
DEFB 0AH 0A
TI=0: max 10 tracks (0AH).
5107
DEFB 11H 11
TI=1: max 17 tracks (11H).
5108
DEFB 14H 14
TI=2: max 20 tracks (14H).
5109
DEFB 22H 22
TI=3: max 34 tracks (22H).
510A
DEFB 12H 12
TI=4: max 18 tracks (12H).
510B
DEFB 1AH 1A
TI=5: max 26 tracks (1AH).
510C
DEFB 24H 24
TI=6: max 36 tracks (24H).
510D
DEFB 34H 34
TI=7: max 52 tracks (34H).

510EH - Parameter Storage Area:

Working storage area for parameter parsing. Contains type flags and temporary values during PDRIVE command processing.

510E
DEFB 82H 82
Parameter type/flags byte 1. Bit 7 set indicates numeric parameter.
510F
DEFB 60H 60
Parameter type/flags byte 2.
5110
DEFB 00H,00H 00 00
Working storage (2 bytes).
5112
DEFB 43H 43
Working storage - possibly base address high byte (43H = 4300H base).
5113
DEFB 00H 00
Working storage.

5114H - Control Flag Storage:

Control flags used during PDRIVE command processing.

5114
DEFB 00H 00
Source drive copy flag. Non-zero when processing a drive=source copy operation.
5115
DEFB FFH FF
Flag byte (FFH = -1 or all bits set).
5116
DEFB 00H,00H 00 00
Working storage.

5118H - Parse State Flag:

Parse state indicator for command line processing.

5118
DEFB 02H 02
Parse state flag. 02H indicates initial state before parameter processing.
5119
DEFB 00H 00
Working storage.
511A
DEFB FFH,FFH FF FF
Working storage (FFH = unused/invalid markers).

511CH - Parameter Name Table:

Table of PDRIVE parameter names with their type bytes. Each entry consists of the parameter name (null-terminated) followed by a type byte that encodes: bit 7 = numeric value, bit 6 = bitmap value, low nibble = DCT field offset.

TI= (Time Interval) - Motor-on timing for drive spin-up.

511C
DEFB 54H,49H,3DH,00H 54 49 3D 00
ASCII "TI=" + null terminator.
5120
DEFB 4DH 4D
Type byte: 4DH = bit 6 set (bitmap), offset 0DH into DCT.

TD= (Track Density) - Single or double density indicator.

5121
DEFB 54H,44H,3DH,00H 54 44 3D 00
ASCII "TD=" + null terminator.
5125
DEFB 0FH 0F
Type byte: 0FH = single letter value, offset 0FH into DCT.

TC= (Track Count) - Number of tracks on the disk (typically 35 or 40).

5126
DEFB 54H,43H,3DH,00H 54 43 3D 00
ASCII "TC=" + null terminator.
512A
DEFB 83H 83
Type byte: 83H = bit 7 set (numeric), offset 03H into DCT.

SPT= (Sectors Per Track) - Number of sectors per track (typically 10 or 18).

512B
DEFB 53H,50H,54H,3DH,00H 53 50 54 3D 00
ASCII "SPT=" + null terminator.
5130
DEFB 84H 84
Type byte: 84H = bit 7 set (numeric), offset 04H into DCT.

TSR= (Track Stepping Rate) - Head stepping speed (1-8).

5131
DEFB 54H,53H,52H,3DH,00H 54 53 52 3D 00
ASCII "TSR=" + null terminator.
5136
DEFB 8CH 8C
Type byte: 8CH = bit 7 set (numeric), offset 0CH into DCT.

GPL= (Granules Per Lump) - Allocation unit configuration.

5137
DEFB 47H,50H,4CH,3DH,00H 47 50 4C 3D 00
ASCII "GPL=" + null terminator.
513C
DEFB 85H 85
Type byte: 85H = bit 7 set (numeric), offset 05H into DCT.

DDSL= (Directory Sectors per Lump) - Directory allocation.

513D
DEFB 44H,44H,53H,4CH,3DH,00H 44 44 53 4C 3D 00
ASCII "DDSL=" + null terminator.
5143
DEFB 88H 88
Type byte: 88H = bit 7 set (numeric), offset 08H into DCT.

DDGA= (Directory Granule Allocation) - Directory granule count.

5144
DEFB 44H,44H,47H,41H,3DH,00H 44 44 47 41 3D 00
ASCII "DDGA=" + null terminator.
514A
DEFB 89H 89
Type byte: 89H = bit 7 set (numeric), offset 09H into DCT.

514BH - Reserved/Padding Area:

Padding area filled with NOP bytes (00H). This space may be reserved for future expansion or alignment.

514B
DEFS 20H 00 00 ... (32 bytes)
32 bytes of 00H padding/reserved space.

516BH - Additional Parameter Names:

Additional parameters for extended PDRIVE functionality.

LLD= (Logical to Logical Drive) - Drive mapping parameter.

516B
DEFB 4CH,4CH,44H,3DH,00H 4C 4C 44 3D 00
ASCII "LLD=" + null terminator.
5170
DEFB 8AH 8A
Type byte: 8AH = bit 7 set (numeric), offset 0AH into DCT.

NLD= (Number of Logical Drives) - Logical drive count.

5171
DEFB 4EH,4CH,44H,3DH,00H 4E 4C 44 3D 00
ASCII "NLD=" + null terminator.
5176
DEFB 8BH 8B
Type byte: 8BH = bit 7 set (numeric), offset 0BH into DCT.
5177
DEFB 00H 00
End-of-table marker (null byte).

5178H - Set Error Flag Bit 4:

Small utility that sets bit 4 in Register E (for error flag building).

5178
SET 4,E CB E3
SET bit 4 of Register E (error flag).
517A
CP (IX+05H) DD BE 05
Compare Register A against the byte at IX+05H (GPL parameter).
517D
RET C9
RETURN to caller with comparison result in flags.

517EH - Double-Sided Disk Check:

Checks if the drive is configured for double-sided operation by testing bit 2 of the flag byte at IX+0FH. Returns error code 03H if there's a mismatch.

517E
BIT 2,(IX+0FH) DD CB 0F 56
Test bit 2 of the byte at IX+0FH (double-sided flag in DCT).
5182
RET Z C8
If Z FLAG (bit 2 clear = single-sided), RETURN normally.

Double-sided. Return error code.

5183
LD A,03H 3E 03
Load Register A with error code 03H (double-sided incompatibility error).
5185
RET C9
RETURN with error code in A.

5186H - Reserved/Padding Area 2:

Large padding area filled with NOP bytes (00H). Reserved for future expansion.

5186
DEFS 45H 00 00 ... (69 bytes)
69 bytes of 00H padding from 5186H to 51CAH.

51CBH - "A" Prefix Character Check:

Checks if the current character is "A" (allowing syntax like "PDRIVE A0,SPT=18" where "A" is an optional prefix before the drive number). This is called from 4FDDH when checking for the "A" prefix pattern.

51CB
CP 41H FE 41
Compare Register A against 41H (ASCII 'A').
51CD
LD (DE),A 12
Store Register A at (DE) - save the character for later reference.
51CE
If NZ FLAG (not 'A'), JUMP to 51D3H to check further.

Character is 'A'. Check if valid "A" prefix (jump to processing).

51D0
JUMP to 4FE0H to process the "A" prefix (check if followed by digit).

51D3H - Check For 'A' After Decrement:

Checks if the character (after decrementing) equals 'A'. This handles the case where the original character was 'B' (42H), which becomes 'A' (41H) after DEC A.

51D3
DEC A 3D
DECrement Register A (if was 'B', now is 'A' = 41H).
51D4
CP 41H FE 41
Compare against 41H (ASCII 'A').
51D6
If NZ FLAG (not a drive letter pattern), JUMP back to 51D0H (4FE0H).

Special case handling - clear the flag area at 4DD3H.

51D8
PUSH BC C5
Save BC to the stack.
51D9
PUSH HL E5
Save HL to the stack.
51DA
LD BC,0700H 01 00 07
Load BC with 0700H. B=07H (7 bytes to clear), C=00H (value to store).
51DD
LD HL,4DD3H 21 D3 4D
Load HL with 4DD3H - address of flag area to clear (self-modifying code area in SYS16).

[LOOP] - Clear 7 bytes at 4DD3H-4DD9H.

51E0
LD (HL),C 71
Store 00H (from C) at (HL).
51E1
INC HL 23
INCrement HL to next byte.
51E2
Decrement B and [LOOP] to 51E0H if not zero.
51E4
POP HL E1
Restore HL from the stack.
51E5
POP BC C1
Restore BC from the stack.
51E6
[LOOP] back to 51CBH to continue checking.