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

Page Customization

Introduction/Summary:

This module implements the DIR DOS command for NEWDOS/80 v2.0 on the TRS-80 Model I. The DIR command displays directory information for files on a diskette, with extensive filtering and display options.

Functionality:

  • Displays file listings with optional detailed information (EOF, LRL, RECS, GRANS, EXTS)
  • Supports filtering by file type: system files (S), invisible files (I), updated files (U)
  • Allows filtering by file extension using /ext syntax
  • Calculates and displays disk statistics: free granules, free tracks, free directory entries
  • Supports output to printer (P option) or screen
  • Supports diskette swap mode ($) for single-drive systems
  • Handles two entry points: J command (4D0A) for directory jumping and * command (4D50) for standard DIR

Command Line Options Parsed (stored in Register B):

  • Bit 0: A = Show all/full file attributes
  • Bit 1: S = Include system files
  • Bit 2: I = Include invisible files
  • Bit 3: P = Output to printer
  • Bit 4: /ext = Filter the directory listing by file extension
  • Bit 5: U = Show only updated files
  • Bit 6: $ = Diskette swap mode

Variables:

AddressBytesPurpose
4D33H1Directory sector counter (self-modifying code location)
4D47H1CALL opcode storage - modified to CDH to enable swap mode prompts
4E0E-4E10H3Extension filter buffer (stores /ext characters to match)
4F35H1Granule count limit for directory scan (self-modified)
50A8H1Output mode flag: 33H=display, 3BH=printer
5090H1Output routine selector (modified for printer output)
5109-5117H15Numeric conversion divisor table for decimal output
5118-513CH37Text: "MOUNT" / " DISKETTE ON DRIVE 0 (ENTER)" + CR
513D-514AH14Text: "SYSTEM" + 03H + "TARGET" + 03H
514B-514DH3Positioning bytes (1CH, 1FH, 03H)
514E-5152H5Text: "DRIVE"
5153-518BH57Directory display template line 1 (filename and info)
518C-51BBH48Direcftory display template line 2 (full attributes)
51BC-51E6H43Text: "EOF", "LRL", "RECS", "GRANS", "EXTS", attribute flags template

Disassembly:

4D00H - DIR Command Entry Point and Initial Command Check

The DIR command begins here. Register A contains the first character after the command name from the command line. HL points to the remainder of the command line. The code first sets up IY to point to the DOS parameter area at 4280H, then checks which command variant was invoked.

4D00
LD IY,4280H FD 21 80 42
Point Index Register IY to 4280H, the DOS parameter block area used for file operations.
4D04
CP 2AH FE 2A
Compare Register A against * (2AH). If Register A equals 2AH, the Z FLAG is set; otherwise the NZ FLAG is set. This checks if the user typed "DIR*" or just "DIR".
4D06
If the Z FLAG (Zero) has been set (command is DIR*), JUMP to 4D50H to process the full directory command with parameters.
4D08
CP 4AH FE 4A
Compare Register A against J (4AH). This checks if the command is "DIRJ" - the directory jump variant.
4D0A
LD A,2AH 3E 2A
Load Register A with * (2AH) to be returned as the wildcard character for the next parsing stage.
4D0C
RET NZ C0
If the NZ FLAG is set (command was neither DIR* nor DIRJ), RETURN to caller. Register A contains 2AH as a default wildcard.

If execution reaches here, the command is DIRJ (Directory Jump). This allows the user to select a file from the directory by cursor position.

4D0D
GOSUB to 5058H to check for the P (printer) option and advance HL past it if present.
4D10
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Checks if no filename was specified after DIRJ.
4D12
If the NZ FLAG is set (a filename was provided), JUMP to 4D3DH to generate error 34H (parse error).

No filename after DIRJ - set up the interactive directory jump selection screen.

4D14
LD C,00H 0E 00
Load Register C with 0 to initialize the column counter for screen positioning.
4D16
GOSUB to 5086H to output a space (20H) followed by carriage return (0DH) - moves to a new line.
4D19
LD B,0DH 06 0D
Load Register B with 13 (0DH) - the number of lines to display on screen for directory selection.
4D1B
GOSUB to 4FDBH to display one directory entry line. Returns Z flag if successful, NZ if end of directory or error.
4D1E
If the Z FLAG is set (directory entry displayed successfully), JUMP to 4D2AH to continue the loop.
4D20
CP 20H FE 20
Compare Register A against 20H (space). Checks if the return code indicates end of directory with completion.
4D22
If the Z FLAG is set (directory scan complete), JUMP to 4FB8H to finish and return with success.
4D25
CP 08H FE 08
Compare Register A against 08H (backspace). Checks if an I/O error occurred during directory read.
4D27
If the NZ FLAG is set (some other error), JUMP to 4D43H to process and display the error code.
4D29
INC B 04
INCrement Register B by 1. Compensates for the entry that failed to display.
4D2A
INC C 0C
INCrement Register C by 1 to track the current directory position.
4D2B
DECrement Register B and Jump if Not Zero. [LOOP] Continue displaying directory entries until 13 lines are shown.
4D2D
GOSUB to 506BH to wait for user input - displays "?" prompt and waits for ENTER or BREAK.
4D30
JUMP back to 4D19H to display the next page of directory entries. [LOOP]

4D32H - Directory Sector Counter Management

These routines manage the directory sector counter used during directory scanning. The value at 4D33H is self-modified during execution.

4D32
LD A,00H 3E 00
Load Register A with 0. This is the initial value for the directory sector counter.
4D34
LD (4D33H),A 32 33 4D
Store Register A at address 4D33H (the immediate operand of the previous instruction). This is self-modifying code that updates the directory sector counter.
4D37
GOSUB to SYS0 routine at 48D4H to read the next directory sector into the buffer.
4D3A
RET Z C8
If the Z FLAG is set (directory sector read successfully), RETURN to caller.
4D3B
JUMP to 4D43H to handle the error if directory read failed.

4D3DH - Error Exit Routines

These routines handle various error conditions and exit points. Each loads an error code into A and jumps to the common error handler.

4D3D
LD A,34H 3E 34
Load Register A with error code 34H (52 decimal = Parse Error).
4D3F
JUMP to 4D43H to process the error.
4D41
LD A,2FH 3E 2F
Load Register A with error code 2FH (47 decimal = File Specification Error).
4D43
PUSH AF F5
Save the error code in Register A onto the stack for later use.
4D44
LD HL,513DH 21 3D 51
Point HL to 513DH - the "SYSTEM" text string address. (This instruction is overwritten by the next.)
4D47
LD HL,4F96H 21 96 4F
Point HL to 4F96H - the default exit routine address. Note: The opcode at 4D47H (21H) may be changed to CDH (CALL) during disk swap mode to invoke the prompt routine.
4D4A
POP AF F1
Restore the error code from the stack into Register A.
4D4B
OR A B7
OR Register A with itself to set flags. If A is zero, Z flag is set (no error).
4D4C
RET Z C8
If the Z FLAG is set (no error occurred), RETURN to caller with success.
4D4D
JUMP to SYS0 error handler at 4409H to display the error message and return to DOS Ready.

4D50H - Main DIR Command Parameter Parser

This is the main entry point when DIR* is invoked. It parses the command line parameters and sets up flags in Register B for the directory scan options.

4D50
LD A,(42C0H) 3A C0 42
Load Register A with the default drive number from the DOS parameter area at 42C0H.
4D53
LD C,A 4F
Copy the default drive number to Register C for use later.
4D54
LD B,00H 06 00
Load Register B with 0 to initialize the option flags register.
4D56
LD A,(HL) 7E
Load Register A with the character at the current command line position pointed to by HL.
4D57
CP 3AH FE 3A
Compare Register A against : (3AH). Checks if a drive specification follows.
4D59
If the NZ FLAG is set (not a colon), JUMP to 4D5CH to skip drive parsing.
4D5B
INC HL 23
INCrement HL to skip past the colon separator.
4D5C
LD A,(HL) 7E
Load Register A with the next command line character.
4D5D
CP 24H FE 24
Compare Register A against $ (24H). Checks for the diskette swap option.
4D5F
If the NZ FLAG is set (not $), JUMP to 4D64H to continue parsing.
4D61
SET 6,B CB F0
SET bit 6 of Register B to indicate $ (diskette swap) mode is enabled.
4D63
INC HL 23
INCrement HL to advance past the $ character.

Now parse the drive number if present (0-3 are valid drive numbers).

4D64
LD A,(HL) 7E
Load Register A with the current command line character.
4D65
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A to convert ASCII digit to binary.
4D67
CP 0AH FE 0A
Compare Register A against 10. If A < 10, it was a valid digit (0-9).
4D69
If NO CARRY (not a digit), JUMP to 4D89H to skip drive number parsing.
4D6B
LD C,A 4F
Copy the first digit value to Register C (tentative drive number).
4D6C
INC HL 23
INCrement HL to point to the next character.
4D6D
LD A,(HL) 7E
Load Register A with the second character (possible second digit for two-digit numbers).
4D6E
SUB 30H D6 30
SUBtract 30H from Register A to convert to binary.
4D70
CP 0AH FE 0A
Compare Register A against 10 to check if it is a digit.
4D72
If NO CARRY (not a digit), JUMP to 4D85H - only a single-digit drive number was specified.

Two digits were found - calculate the two-digit drive number (C*10 + A). Uses repeated addition to multiply by 10.

4D74
LD E,A 5F
Save the second digit (units) in Register E.
4D75
LD A,C 79
Load Register A with the first digit (tens) from Register C.
4D76
LD D,09H 16 09
Load Register D with 9 as the loop counter for multiplication.
4D78
ADD A,C 81
ADD Register C to Register A (accumulating the multiply-by-10 result).
4D79
If CARRY is set (overflow occurred), JUMP to 4D81H - drive number is too large.
4D7B
DEC D 15
DECrement the loop counter in Register D.
4D7C
If NZ FLAG is set (loop not complete), JUMP back to 4D78H. [LOOP]
4D7E
ADD A,E 83
ADD the units digit (from Register E) to give final drive number.
4D7F
If NO CARRY (valid result), JUMP back to 4D6BH to store result and check for more digits.
4D81
LD A,20H 3E 20
Load Register A with error code 20H (32 decimal = Drive Not Ready/Invalid Drive).
4D83
JUMP to error handler at 4D43H.
4D85
GOSUB to SYS0 routine at 4C7AH to validate the drive number in C and set up drive parameters.
4D88
RET C D8
If CARRY is set (drive validation failed), RETURN with error.

4D89H - Option Flag Parser

This section parses the single-letter options: A (all), S (system), I (invisible), U (updated), and /ext (extension filter). Each option sets a corresponding bit in Register B.

4D89
GOSUB to 5058H to check for P (printer) option and handle it.
4D8C
If Z FLAG is set (P option was found and processed), JUMP back to 4D85H to continue.
4D8E
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Checks if end of command line.
4D90
If Z FLAG is set (end of line), JUMP to 4DD5H to begin the directory display.
4D92
CP 41H FE 41
Compare Register A against A (41H). Checks for the "All" option to show full file attributes.
4D94
If NZ FLAG is set (not A), JUMP to 4D9AH to check next option.
4D96
SET 0,B CB C0
SET bit 0 of Register B to indicate A (All/Attributes) option is enabled.
4D98
JUMP back to 4D85H to continue parsing.
4D9A
CP 53H FE 53
Compare Register A against S (53H). Checks for the "System files" option.
4D9C
If NZ FLAG is set (not S), JUMP to 4DA2H to check next option.
4D9E
SET 1,B CB C8
SET bit 1 of Register B to indicate S (System) files should be shown.
4DA0
JUMP back to 4D85H to continue parsing.
4DA2
CP 49H FE 49
Compare Register A against I (49H). Checks for the "Invisible files" option.
4DA4
If NZ FLAG is set (not I), JUMP to 4DAAH to check next option.
4DA6
SET 2,B CB D0
SET bit 2 of Register B to indicate I (Invisible) files should be shown.
4DA8
JUMP back to 4D85H to continue parsing.
4DAA
CP 55H FE 55
Compare Register A against U (55H). Checks for the "Updated files only" option.
4DAC
If NZ FLAG is set (not U), JUMP to 4DB2H to check next option.
4DAE
SET 5,B CB E8
SET bit 5 of Register B to indicate U (Updated) filter is enabled.
4DB0
JUMP back to 4D85H to continue parsing.
4DB2
CP 2FH FE 2F
Compare Register A against / (2FH). Checks for extension filter syntax.
4DB4
If NZ FLAG is set (unrecognized option), JUMP to 4D3DH to report parse error.

Parse the extension filter (up to 3 characters after /).

4DB7
SET 4,B CB E0
SET bit 4 of Register B to indicate /ext (Extension filter) is active.
4DB9
PUSH BC C5
Save Register Pair BC (flags and drive number) onto the stack.
4DBA
LD B,03H 06 03
Load Register B with 3 - maximum characters for extension.
4DBC
LD DE,4E0EH 11 0E 4E
Point DE to 4E0EH - the extension filter buffer.
4DBF
LD A,(HL) 7E
Load Register A with the current character from command line.
4DC0
SUB 30H D6 30
SUBtract 30H from Register A to check if it is a digit (0-9).
4DC2
CP 0AH FE 0A
Compare Register A against 10.
4DC4
If CARRY (it was a digit 0-9), JUMP to 4DCCH to store it.
4DC6
SUB 11H D6 11
SUBtract 11H more to check for uppercase letters (A-Z become 00H-19H after total subtraction of 41H).
4DC8
CP 1AH FE 1A
Compare Register A against 26 (number of letters).
4DCA
If NO CARRY (not a letter), JUMP to 4DD2H - end of extension characters.
4DCC
LD A,(HL) 7E
Reload Register A with the original character.
4DCD
LD (DE),A 12
Store the extension character at the buffer pointed to by DE.
4DCE
INC DE 13
INCrement DE to point to the next buffer position.
4DCF
INC HL 23
INCrement HL to point to the next command line character.
4DD0
DECrement B and Jump if Not Zero. [LOOP] Continue until 3 characters are processed or end of extension.
4DD2
POP BC C1
Restore Register Pair BC (flags and drive number) from the stack.
4DD3
JUMP back to 4D85H to continue parsing remaining options.

4DD5H - Begin Directory Display

All command line options have been parsed. Register B contains the option flags, Register C contains the drive number. Now set up for the directory display.

4DD5
BIT 3,B CB 58
Test bit 3 of Register B to check if P (Printer) output mode is enabled.
4DD7
LD HL,514BH 21 4B 51
Point HL to 514BH - the positioning bytes for screen formatting (1CH, 1FH, 03H).
4DDA
If Z FLAG is set (NOT printer mode), GOSUB to 508FH to output the screen positioning codes.
4DDD
BIT 6,B CB 70
Test bit 6 of Register B to check if $ (Swap) mode is enabled.
4DDF
If Z FLAG is set (swap mode NOT enabled), JUMP to 4DF6H to skip swap prompts.

Swap mode ($) is enabled - set up to prompt user for disk changes.

4DE1
LD A,C 79
Load Register A with the drive number from Register C.
4DE2
OR A B7
OR Register A with itself to test if drive is 0.
4DE3
If NZ FLAG is set (drive is not 0), JUMP to 4DEAH - swap mode only valid for drive 0.
4DE5
LD A,CDH 3E CD
Load Register A with CDH (the CALL opcode).
4DE7
LD (4D47H),A 32 47 4D
Store CDH at 4D47H, converting the LD HL instruction there into a CALL instruction. This enables the disk swap prompts at exit.
4DEA
LD A,C 79
Load Register A with the drive number.
4DEB
ADD 30H C6 30
ADD 30H to convert the drive number to ASCII digit.
4DED
LD (5132H),A 32 32 51
Store the ASCII drive number at 5132H in the "DRIVE 0" display string template.
4DF0
LD HL,5144H 21 44 51
Point HL to 5144H - the "TARGET" text string.
4DF3
GOSUB to 4F96H to display the "MOUNT TARGET DISKETTE ON DRIVE n (ENTER)" prompt and wait for ENTER.
4DF6
GOSUB to 4FDBH to display the disk header line (disk name, date, free space info).
4DF9
If NZ FLAG is set (error reading disk info), JUMP to error handler at 4D43H.
4DFC
XOR A AF
Set Register A to ZERO and clear all flags.
4DFD
GOSUB to 4D34H to initialize the directory sector counter to 0 and read the first directory sector.
4E00
GOSUB to 5086H to output a space and carriage return (start new line).
4E03
LD D,0DH 16 0D
Load Register D with 13 - the number of lines per screen page.
4E05
GOSUB to 4FC7H to output the header line with column titles (if A option is enabled).
4E08
PUSH DE D5
Save Register Pair DE (line counter and flags) onto the stack.
4E09
LD C,05H 0E 05
Load Register C with 5 - the number of file entries per line in compact mode.
4E0B
JUMP to 4F3BH to begin processing directory entries.

4E0E - Extension Filter Buffer and Directory Entry Processing

The three bytes at 4E0EH serve as the extension filter buffer. The bytes shown (20 20 D5) are initial values that get overwritten when /ext is specified. The code at 4E11H processes each directory entry for display.

4E0E
JR NZ,4E30H 20 20
DATA: Extension filter buffer bytes 1-2 (spaces = 20H 20H). When executed as code: If NZ, branch to 4E30H (not normally executed as code).
4E10
JR NZ,4DE7H 20 D5
DATA: Extension filter buffer byte 3 (space) and next opcode. The D5 is PUSH DE which begins the main entry processing.
4E12
PUSH BC C5
Save Register Pair BC (option flags and file counter) onto the stack.
4E13
PUSH HL E5
Save Register Pair HL (pointer to directory entry) onto the stack.
4E14
EX DE,HL EB
Exchange DE and HL. Now DE points to the directory entry.
4E15
LD HL,51AFH 21 AF 51
Point HL to 51AFH - the 12-character flag display area in the output template.
4E18
LD B,0BH 06 0B
Load Register B with 11 - number of flag positions to initialize.
4E1A
PUSH HL E5
Save the current flag position pointer.
4E1B
LD (HL),2EH 36 2E
Store . (2EH) at the current position as a placeholder for inactive flags.
4E1D
INC HL 23
INCrement HL to the next flag position.
4E1E
DECrement B and Jump if Not Zero. [LOOP] Initialize all 11 flag positions with dots.

Now extract and store the protection level digit (bits 0-2 of first directory byte).

4E20
LD A,(DE) 1A
Load Register A with the first byte of the directory entry (attribute/status byte).
4E21
AND 07HAND 00000111 E6 07
AND with 07H to isolate the protection level (bits 0-2).
4E23
ADD 30H C6 30
ADD 30H to convert protection level to ASCII digit.
4E25
LD (HL),A 77
Store the protection level digit at HL (the "L" flag position).
4E26
POP HL E1
Restore HL to point back to 51AFH (start of flag area).

Now check each attribute bit and set the corresponding flag character if active.

4E27
LD A,(DE) 1A
Reload Register A with the first directory entry byte.
4E28
BIT 6,A CB 77
Test bit 6 of Register A - the System file flag.
4E2A
If Z FLAG is set (not a system file), JUMP to 4E2EH.
4E2C
LD (HL),53H 36 53
Store S (53H) to indicate System file.
4E2E
INC HL 23
INCrement HL to the next flag position.
4E2F
BIT 3,A CB 5F
Test bit 3 of Register A - the Invisible file flag.
4E31
If Z FLAG is set (not invisible), JUMP to 4E35H.
4E33
LD (HL),49H 36 49
Store I (49H) to indicate Invisible file.
4E35
INC HL 23
INCrement HL to the next flag position.
4E36
INC DE 13
INCrement DE to point to the second directory entry byte.
4E37
LD A,(DE) 1A
Load Register A with the second directory entry byte (more flags).
4E38
BIT 5,A CB 6F
Test bit 5 of Register A - the Updated flag.
4E3A
If Z FLAG is set (not updated), JUMP to 4E3EH.
4E3C
LD (HL),55H 36 55
Store U (55H) to indicate Updated file.
4E3E
INC HL 23
INCrement HL to the next flag position.
4E3F
BIT 7,A CB 7F
Test bit 7 of Register A - the Extent limit (no grow) flag.
4E41
If Z FLAG is set (not limited), JUMP to 4E45H.
4E43
LD (HL),45H 36 45
Store E (45H) to indicate file cannot Extend.
4E45
INC HL 23
INCrement HL to the next flag position.
4E46
BIT 6,A CB 77
Test bit 6 of Register A - the Close without release flag.
4E48
If Z FLAG is set (normal close), JUMP to 4E4CH.
4E4A
LD (HL),43H 36 43
Store C (43H) to indicate Close without release.

4E4CH - Process Filename and Passwords

Now process the filename (8 chars + 3 char extension) and check for passwords.

4E4C
LD HL,0004H 21 04 00
Load HL with offset 4 - offset to filename within directory entry.
4E4F
ADD HL,DE 19
ADD DE (directory entry base + 1) to get pointer to filename field.
4E50
LD C,0FH 0E 0F
Load Register C with 15 - position counter for output formatting.
4E52
LD B,08H 06 08
Load Register B with 8 - length of filename field.
4E54
GOSUB to 509AH to output the 8-character filename, skipping trailing spaces.
4E57
LD A,(HL) 7E
Load Register A with the first character of the extension.
4E58
CP 20H FE 20
Compare Register A against space (20H). Checks if extension exists.
4E5A
LD A,2FH 3E 2F
Load Register A with / (2FH) - the extension separator.
4E5C
If NZ FLAG (extension exists), GOSUB to 50A4H to output the "/" separator.
4E5F
LD B,03H 06 03
Load Register B with 3 - length of extension field.
4E61
GOSUB to 509AH to output the 3-character extension.
4E64
LD B,C 41
Copy remaining column count from Register C to Register B.
4E65
GOSUB to 5092H to output B spaces to pad to column alignment.

Now check for update and access passwords by comparing against stored password hashes.

4E68
LD E,(HL) 5E
Load Register E with the low byte of the update password hash.
4E69
INC HL 23
INCrement HL to point to the high byte.
4E6A
LD D,(HL) 56
Load Register D with the high byte of the update password hash.
4E6B
PUSH DE D5
Save the update password hash on the stack.
4E6C
INC HL 23
INCrement HL to point to the access password hash.
4E6D
LD E,(HL) 5E
Load Register E with the low byte of the access password hash.
4E6E
INC HL 23
INCrement HL to the high byte.
4E6F
LD D,(HL) 56
Load Register D with the high byte of the access password hash.
4E70
LD HL,4296H 21 96 42
Point HL to 4296H - the "blank password" hash value for comparison.
4E73
RST 18H DF
Call RST 18H - compare DE with (HL). Checks if access password is blank.
4E74
If Z FLAG is set (password is blank), JUMP to 4E7BH.
4E76
LD A,41H 3E 41
Load Register A with A (41H) - Access password exists.
4E78
LD (51B9H),A 32 B9 51
Store A at 51B9H in the flag template to show Access password exists.
4E7B
POP DE D1
Restore the update password hash from the stack into DE.
4E7C
RST 18H DF
Call RST 18H - compare DE with (HL). Checks if update password is blank.
4E7D
If Z FLAG is set (password is blank), JUMP to 4E84H.
4E7F
LD A,55H 3E 55
Load Register A with U (55H) - Update password exists.
4E81
LD (51B8H),A 32 B8 51
Store U at 51B8H in the flag template to show Update password exists.
4E84
POP HL E1
Restore HL (original directory entry pointer) from the stack.
4E85
POP BC C1
Restore BC (option flags and counter) from the stack.
4E86
BIT 0,B CB 40
Test bit 0 of Register B - the A (All/Attributes) option.
4E88
If Z FLAG is set (A option NOT enabled), JUMP to 4F28H to skip extended attributes display.

4E8BH - Extended Attributes Display (A Option)

The A (All) option was specified - display extended file information: EOF, LRL, RECS, GRANS, EXTS, and the full flag string.

4E8B
LD C,01H 0E 01
Load Register C with 1 - indicates single file per line in extended mode.
4E8D
PUSH BC C5
Save Register Pair BC onto the stack.
4E8E
PUSH HL E5
Save Register Pair HL onto the stack.
4E8F
INC HL 23
INCrement HL to offset +1 in directory entry.
4E90
INC HL 23
INCrement HL to offset +2.
4E91
INC HL 23
INCrement HL to offset +3 (EOF sector number).
4E92
LD E,(HL) 5E
Load Register E with the EOF sector number (relative sector within file).
4E93
LD D,00H 16 00
Load Register D with 0 to form 16-bit EOF sector in DE.
4E95
INC HL 23
INCrement HL to offset +4 (EOF byte position).
4E96
LD B,D 42
Load Register B with 0.
4E97
LD C,(HL) 4E
Load Register C with the EOF byte offset within the last sector.
4E98
SET 4,L CB E5
SET bit 4 of L to point to offset +14H (record size field) in the parallel directory entry area.
4E9A
LD A,(HL) 7E
Load Register A with the Logical Record Length (LRL).
4E9B
INC HL 23
INCrement HL to point to the EOF high position.
4E9C
PUSH HL E5
Save this pointer onto the stack.
4E9D
LD H,(HL) 66
Load Register H with the high byte of EOF position.
4E9E
LD L,A 6F
Load Register L with LRL (now HL = file size info).
4E9F
LD A,E 7B
Load Register A with the EOF sector number.
4EA0
OR A B7
OR Register A with itself to test if EOF sector is 0.
4EA1
If Z FLAG is set (sector is 0), JUMP to 4EA4H.
4EA3
DEC HL 2B
DECrement HL to adjust for partial sector calculation.
4EA4
INC C 0C
INCrement Register C (EOF byte offset).
4EA5
DEC C 0D
DECrement Register C to test if it was 0 (full sector).
4EA6
If NZ FLAG (EOF byte is non-zero), JUMP to 4EAAH.
4EA8
LD B,01H 06 01
Load Register B with 1 to indicate full 256-byte sector.
4EAA
PUSH DE D5
Save DE (EOF sector) onto the stack.
4EAB
PUSH HL E5
Save HL (LRL and size info) onto the stack.
4EAC
PUSH BC C5
Save BC (EOF byte and flag) onto the stack.
4EAD
If NZ FLAG, JUMP to 4EB2H to calculate record count.
4EAF
LD E,L 5D
Copy L to E for division setup.
4EB0
LD L,H 6C
Copy H to L.
4EB1
LD H,D 62
Copy D to H. Now HLE contains the dividend for record calculation.
4EB2
If NZ FLAG, GOSUB to 50ADH to perform 24-bit division (file size / LRL = record count).
4EB5
OR A B7
OR A with itself to check for remainder.
4EB6
If Z FLAG (no remainder), JUMP to 4EBCH.
4EB8
INC E 1C
INCrement E to account for partial record.
4EB9
If NZ FLAG (no overflow), JUMP to 4EBCH.
4EBB
INC HL 23
INCrement HL if E overflowed to propagate carry.
4EBC
LD A,H 7C
Load Register A with the high byte of record count.
4EBD
LD B,L 45
Load Register B with the middle byte of record count.
4EBE
LD C,E 4B
Load Register C with the low byte of record count. ABC now holds the 24-bit record count.
4EBF
LD HL,519BH 21 9B 51
Point HL to 519BH - the RECS (record count) display position in template.
4EC2
LD DE,5109H 11 09 51
Point DE to 5109H - the divisor table for decimal conversion.
4EC5
GOSUB to 50C8H to convert the 24-bit record count to decimal ASCII and store at HL.
4EC8
POP BC C1
Restore BC (EOF byte position) from the stack.
4EC9
LD HL,5197H 21 97 51
Point HL to 5197H - the EOF byte display position in template.
4ECC
GOSUB to 50BFH to convert BC to decimal ASCII and store at HL.
4ECF
POP BC C1
Restore BC (LRL) from the stack.
4ED0
LD HL,518CH 21 8C 51
Point HL to 518CH - the first numeric display position in template.
4ED3
LD DE,510CH 11 0C 51
Point DE to 510CH - the divisor table for 16-bit conversion.
4ED6
GOSUB to 50C7H to convert BC to decimal ASCII (for LRL display).
4ED9
LD (HL),30H 36 30
Store 0 (30H) at HL - leading zero for formatting.
4EDB
POP BC C1
Restore BC (EOF sector) from the stack.
4EDC
PUSH HL E5
Save current output position.
4EDD
GOSUB to 50BFH to convert EOF sector to decimal ASCII.
4EE0
POP HL E1
Restore output position pointer.
4EE1
LD (HL),2FH 36 2F
Store / (2FH) as the separator between EOF sector and byte.

4EE3H - Granule and Extent Counting

Now count the granules and extents allocated to this file by scanning the extent table in the directory entry.

4EE3
POP HL E1
Restore HL to point to the extent table in the directory entry.
4EE4
INC HL 23
INCrement HL to the start of extent data.
4EE5
LD BC,0000H 01 00 00
Initialize BC to 0 - this will accumulate the granule count.
4EE8
LD D,B 50
Initialize Register D to 0.
4EE9
LD E,C 59
Initialize Register E to 0. DE will count extents.
4EEA
LD A,(HL) 7E
Load Register A with the extent's granule number.
4EEB
CP FEH FE FE
Compare Register A against FEH. FEH indicates end of extent list; FFH indicates continuation.
4EED
INC HL 23
INCrement HL to the extent length byte.
4EEE
If NO CARRY (A >= FEH, meaning end or continuation marker), JUMP to 4F04H.
4EF0
INC DE 13
INCrement the extent count in DE.
4EF1
LD A,(HL) 7E
Load Register A with the extent length (number of granules in this extent - 1).
4EF2
AND 1FHAND 00011111 E6 1F
AND with 1FH to isolate the granule count (bits 0-4).
4EF4
INC HL 23
INCrement HL to the next extent entry.
4EF5
INC A 3C
INCrement A to convert from "granules-1" to actual granule count.
4EF6
ADD A,C 81
ADD the extent's granule count to the running total in C.
4EF7
LD C,A 4F
Store the result back in Register C.
4EF8
If NO CARRY (no overflow), JUMP to 4EFBH.
4EFA
INC B 04
INCrement B to handle overflow from C into the high byte.
4EFB
BIT 4,L CB 65
Test bit 4 of L to check if we've reached the end of this directory entry's extent table.
4EFD
If NZ FLAG (still within extent table), JUMP back to 4EEAH. [LOOP]
4EFF
LD A,2CH 3E 2C
Load Register A with error code 2CH (44 decimal = Directory entry overflow error).
4F01
JUMP to error handler at 4D43H. This should not normally be reached.

4F04H - Continuation Entry or End of Extent List

Handle FEH (end of extents) or FFH (continuation to next directory entry).

4F04
If NZ FLAG (A was FFH = continuation), JUMP to 4F0FH to process continuation entry.
4F06
LD A,(HL) 7E
Load Register A with the next directory entry link number (for continuation).
4F07
GOSUB to 4D37H to read the continuation directory sector.
4F0A
ADD 16H C6 16
ADD 16H (22 decimal) to calculate offset within the directory buffer.
4F0C
LD L,A 6F
Store the offset in Register L. HL now points to the continuation extent table.
4F0D
JUMP back to 4EEAH to continue counting granules and extents. [LOOP]

This is the normal end of extent processing - display the GRANS and EXTS values.

4F0F
GOSUB to 4D32H to reset the directory sector counter to the original position.
4F12
PUSH DE D5
Save the extent count in DE onto the stack.
4F13
LD HL,51A3H 21 A3 51
Point HL to 51A3H - the GRANS display position in the template.
4F16
GOSUB to 50C4H to convert the granule count BC to decimal ASCII.
4F19
POP BC C1
Restore the extent count from the stack into BC.
4F1A
LD HL,51A9H 21 A9 51
Point HL to 51A9H - the EXTS display position in the template.
4F1D
GOSUB to 50BFH to convert the extent count to decimal ASCII.
4F20
LD HL,518CH 21 8C 51
Point HL to 518CH - the full attribute line template.
4F23
GOSUB to 508FH to output the complete extended attribute line.
4F26
POP HL E1
Restore HL (directory entry pointer) from the stack.
4F27
POP BC C1
Restore BC (option flags) from the stack.

4F28H - Advance to Next Directory Entry

Move to the next directory entry (each entry is 32 bytes = 20H).

4F28
LD A,L 7D
Load Register A with the low byte of the current directory position.
4F29
ADD 20H C6 20
ADD 20H (32 decimal) to advance to the next directory entry.
4F2B
LD L,A 6F
Store the new position back in Register L.
4F2C
If NO CARRY (still within current sector), JUMP to 4F3BH to process the entry.

Crossed into a new directory sector - need to read it first.

4F2E
LD A,(4D33H) 3A 33 4D
Load Register A with the current directory sector counter from 4D33H.
4F31
AND 1FHAND 00011111 E6 1F
AND with 1FH to mask to 5 bits (max 31 directory sectors).
4F33
INC A 3C
INCrement to the next sector number.
4F34
CP 00H FE 00
Compare Register A against 0. This value is modified by code at 5035H to set the actual sector limit.
4F36
If Z FLAG is set (reached end of directory), JUMP to 4FAFH to finish.
4F38
GOSUB to 4D34H to read the next directory sector.

4F3BH - Process Current Directory Entry

Check if the current directory entry should be displayed based on the filter options.

4F3B
LD A,(HL) 7E
Load Register A with the first byte of the directory entry (attribute/status byte).
4F3C
AND 90H E6 90
AND with 90H to isolate bits 7 (deleted) and 4 (active file).
4F3E
CP 10H FE 10
Compare against 10H - valid active file has bit 4 set, bit 7 clear.
4F40
If NZ FLAG (not a valid active file), JUMP to 4F28H to skip to next entry.
4F42
LD A,B 78
Load Register A with the option flags from Register B.
4F43
AND 30H E6 30
AND with 30H to isolate bits 4 (/ext) and 5 (U = updated only).
4F45
If NZ FLAG (one of these filters is active), JUMP to 4F58H to check filters.

No special filters - check if this is a system or invisible file that should be hidden.

4F47
BIT 6,(HL) CB 76
Test bit 6 of the directory entry (System file flag).
4F49
If Z FLAG (not a system file), JUMP to 4F4FH to check invisible flag.
4F4B
BIT 1,B CB 48
Test bit 1 of B (S option - show system files).
4F4D
JUMP to 4F55H to evaluate the result.
4F4F
BIT 3,(HL) CB 5E
Test bit 3 of the directory entry (Invisible file flag).
4F51
If Z FLAG (not invisible), JUMP to 4F58H - file should be shown.
4F53
BIT 2,B CB 50
Test bit 2 of B (I option - show invisible files).
4F55
If Z FLAG (option not set to show this type), JUMP to 4F28H to skip this file.

4F58H - Extension Filter Check

Check if the file matches the extension filter (if /ext was specified).

4F58
BIT 4,B CB 60
Test bit 4 of B (/ext option - filter by extension).
4F5A
If Z FLAG (/ext not specified), JUMP to 4F73H to skip extension check.
4F5C
PUSH HL E5
Save the directory entry pointer onto the stack.
4F5D
PUSH BC C5
Save the option flags onto the stack.
4F5E
LD DE,000DH 11 0D 00
Load DE with 13 - offset to the extension field in the directory entry.
4F61
ADD HL,DE 19
ADD DE to HL to point to the file's extension.
4F62
LD DE,4E0EH 11 0E 4E
Point DE to 4E0EH - the extension filter buffer.
4F65
LD B,03H 06 03
Load Register B with 3 - number of extension characters to compare.
4F67
LD A,(DE) 1A
Load Register A with the filter extension character.
4F68
CP (HL) BE
Compare Register A against the file's extension character at (HL).
4F69
INC DE 13
INCrement DE to the next filter character.
4F6A
INC HL 23
INCrement HL to the next file extension character.
4F6B
If NZ FLAG (mismatch found), JUMP to 4F6FH to exit comparison.
4F6D
DECrement B and Jump if Not Zero. [LOOP] Continue comparing all 3 characters.
4F6F
POP BC C1
Restore option flags from the stack.
4F70
POP HL E1
Restore directory entry pointer from the stack.
4F71
If NZ FLAG (extension did not match), JUMP to 4F28H to skip this file.

4F73H - Updated File Filter Check

Check the "Updated only" filter (U option).

4F73
BIT 5,B CB 68
Test bit 5 of B (U option - show only updated files).
4F75
If Z FLAG (U option not set), JUMP to 4F7DH to display the file.
4F77
INC HL 23
INCrement HL to point to the second byte of the directory entry.
4F78
BIT 5,(HL) CB 6E
Test bit 5 of the second byte (Updated flag).
4F7A
DEC HL 2B
DECrement HL back to the entry start.
4F7B
If Z FLAG (file NOT updated), JUMP to 4F28H to skip this file.

4F7DH - Display File Entry and Screen Management

The file passes all filters - display it and manage screen pagination.

4F7D
POP DE D1
Restore DE from the stack (contains line counter in D, previous state in E).
4F7E
DEC C 0D
DECrement the files-per-line counter in Register C.
4F7F
If NZ FLAG (more files fit on this line), JUMP to 4F93H to display the file.

Line is full - start a new line and check for page break.

4F81
LD C,04H 0E 04
Reset Register C to 4 files per line (will be incremented to 5).
4F83
GOSUB to 5086H to output carriage return (new line).
4F86
DEC D 15
DECrement the lines-remaining counter in Register D.
4F87
If NZ FLAG (more lines fit on screen), JUMP to 4F93H.

Screen is full - wait for user input before continuing.

4F89
LD D,0FH 16 0F
Reset Register D to 15 lines for the next page.
4F8B
GOSUB to 506BH to display "?" prompt and wait for ENTER or BREAK.
4F8E
BIT 3,B CB 58
Test bit 3 of B (P option - printer output).
4F90
If Z FLAG (screen output, not printer), GOSUB to 4FC7H to redisplay column headers.
4F93
JUMP to 4E11H to display the current file entry and continue the loop.

4F96H - Display Disk Swap Prompt

Display the "MOUNT ... DISKETTE ON DRIVE n (ENTER)" prompt and wait for user to press ENTER.

4F96
PUSH HL E5
Save the prompt text pointer (pointing to "TARGET" or "SYSTEM") onto the stack.
4F97
LD HL,5118H 21 18 51
Point HL to 5118H - the "MOUNT" text string.
4F9A
GOSUB to SYS0 routine at 4467H to output the string at HL (terminated by byte < 20H).
4F9D
POP HL E1
Restore the prompt text pointer from the stack.
4F9E
GOSUB to 4467H to output "TARGET" or "SYSTEM".
4FA1
LD HL,511FH 21 1F 51
Point HL to 511FH - the " DISKETTE ON DRIVE 0 (ENTER)" text.
4FA4
GOSUB to 4467H to output the rest of the prompt.
4FA7
GOSUB to ROM routine at 0049H to scan keyboard and return character in A (0 if none).
4FAA
CP 0DH FE 0D
Compare Register A against 0DH (ENTER key).
4FAC
If NZ FLAG (ENTER not pressed), JUMP back to 4FAAH to keep waiting. [LOOP]
4FAE
RET C9
RETURN to caller after user presses ENTER.

4FAFH - End of Directory Listing

Reached end of directory - clean up and check if disk swap prompt needed.

4FAF
GOSUB to 5086H to output final carriage return.
4FB2
POP AF F1
Restore AF from the stack (contains files-per-line counter).
4FB3
CP 04H FE 04
Compare Register A against 4 to check if the last line had any output.
4FB5
If CARRY (last line had output), GOSUB to 506BH to wait for user input.
4FB8
LD A,(50A8H) 3A A8 50
Load Register A with the output mode flag from 50A8H.
4FBB
CP 3BH FE 3B
Compare Register A against 3BH (printer mode indicator).
4FBD
If Z FLAG (printer mode), GOSUB to 5086H for extra line spacing.
4FC0
If Z FLAG (still printer mode), GOSUB again for form feed effect.
4FC3
XOR A AF
Set Register A to ZERO to indicate success (no error).
4FC4
JUMP to 4D43H exit routine with A=0 for successful completion.

4FC7H - Display Column Headers (A Option)

Display column header line when A (All) option is enabled.

4FC7
BIT 0,B CB 40
Test bit 0 of B (A option - show full attributes).
4FC9
RET Z C8
If Z FLAG (A option not set), RETURN - no headers needed.
4FCA
PUSH HL E5
Save Register Pair HL onto the stack.
4FCB
PUSH BC C5
Save Register Pair BC onto the stack.
4FCC
DEC D 15
DECrement line counter to account for header line.
4FCD
LD B,14H 06 14
Load Register B with 20 - number of leading spaces for alignment.
4FCF
GOSUB to 5092H to output B spaces.
4FD2
LD HL,51BCH 21 BC 51
Point HL to 51BCH - the header template "EOF LRL RECS GRANS EXTS SIUEC....UAL".
4FD5
GOSUB to 508FH to output the header line.
4FD8
POP BC C1
Restore Register Pair BC from the stack.
4FD9
POP HL E1
Restore Register Pair HL from the stack.
4FDA
RET C9
RETURN to caller.

4FDBH - Read and Display Disk Information

Read the disk's boot sector and GAT (Granule Allocation Table) to display disk name, date, and free space statistics.

4FDB
LD A,C 79
Load Register A with the drive number from Register C.
4FDC
GOSUB to SYS0 routine at 4791H to select the drive and read the boot sector.
4FDF
RET NZ C0
If NZ FLAG (error occurred), RETURN with error code in A.
4FE0
PUSH BC C5
Save Register Pair BC (option flags) onto the stack.
4FE1
LD B,00H 06 00
Load Register B with 0 to prepare for 16-bit offset.
4FE3
LD HL,5153H 21 53 51
Point HL to 5153H - the disk name display position in template.
4FE6
GOSUB to 50BFH (but this seems to be setting up the display area).
4FE9
LD A,(4283H) 3A 83 42
Load Register A with the disk name pointer from DOS parameter area 4283H.
4FEC
LD C,A 4F
Copy the pointer to Register C.
4FED
LD B,00H 06 00
Clear Register B for 16-bit calculation.
4FEF
LD HL,516CH 21 6C 51
Point HL to 516CH - the date display position in template.
4FF2
GOSUB to 50BFH to convert and display the date information.
4FF5
XOR A AF
Set Register A to ZERO.
4FF6
GOSUB to SYS0 routine at 48AFH to read the GAT (Granule Allocation Table) sector.
4FF9
If NZ FLAG (error reading GAT), JUMP to 5056H to return with error.

Count free granules by scanning the GAT bitmap.

4FFB
LD BC,0000H 01 00 00
Initialize BC to 0 - free granule counter.
4FFE
LD E,(IY+05H) FD 5E 05
Load Register E with the granules per track from DOS parameter block at IY+05H.
5001
LD A,(HL) 7E
Load Register A with the current GAT byte (each bit represents one granule).
5002
INC HL 23
INCrement HL to the next GAT byte.
5003
RRCA 0F
Rotate Register A Right through Carry. If a bit is 0, the granule is free.
5004
If CARRY (bit was 1 = allocated), JUMP to 5007H to skip counting.
5006
INC BC 03
INCrement the free granule counter in BC.
5007
DEC E 1D
DECrement the granules-per-track counter.
5008
If NZ FLAG (more granules on this track), JUMP back to 5003H. [INNER LOOP]
500A
LD A,L 7D
Load Register A with the low byte of HL (current GAT position).
500B
CP (IY+01H) FD BE 01
Compare against the GAT end position at IY+01H.
500E
If CARRY (more tracks to scan), JUMP back to 4FFEH. [OUTER LOOP]

All tracks scanned - display free granule count.

5010
LD HL,5180H 21 80 51
Point HL to 5180H - the GRANS (free granules) display position.
5013
GOSUB to 50C4H to convert BC to decimal ASCII and store at HL.

Copy disk name (8 bytes) and date (8 bytes) from boot sector to display template.

5016
LD HL,43D0H 21 D0 43
Point HL to 43D0H - the boot sector buffer containing disk name.
5019
LD DE,5159H 11 59 51
Point DE to 5159H - the disk name position in display template.
501C
LD BC,0008H 01 08 00
Load BC with 8 bytes to copy (disk name length).
501F
LDIR ED B0
Block copy 8 bytes from (HL) to (DE), incrementing both.
5021
LD DE,5163H 11 63 51
Point DE to 5163H - the date position in display template.
5024
LD C,08H 0E 08
Load C with 8 bytes for date (MM/DD/YY format).
5026
LDIR ED B0
Block copy 8 bytes of date from (HL) to (DE).

5028H - Count Free Tracks and Directory Entries

Read the HIT (Hash Index Table) to count free tracks and directory entries.

5028
LD A,01H 3E 01
Load Register A with 1 to request HIT sector.
502A
GOSUB to SYS0 routine at 48AFH to read the HIT sector.
502D
If NZ FLAG (error reading HIT), JUMP to 5056H to return error.
502F
LD A,(431FH) 3A 1F 43
Load Register A with the tracks per disk from system variable at 431FH.
5032
ADD 08H C6 08
ADD 8 to skip the reserved system tracks (directory area starts at track 8).
5034
LD E,A 5F
Copy to Register E as the HIT entries to scan.
5035
LD (4F35H),A 32 35 4F
Store this value at 4F35H to set the directory sector limit for later comparison. This is self-modifying code.
5038
LD A,(HL) 7E
Load Register A with the current HIT entry (0 = free directory slot).
5039
OR A B7
OR A with itself to test if entry is zero (free).
503A
INC HL 23
INCrement HL to the next HIT entry.
503B
If NZ FLAG (entry is used), JUMP to 503EH.
503D
INC BC 03
INCrement BC to count free directory entries.
503E
DEC E 1D
DECrement the HIT entry counter.
503F
If NZ FLAG (more entries to scan), JUMP back to 5038H. [LOOP]
5041
LD A,L 7D
Load Register A with the low byte of HL (end position).
5042
ADD 1FH C6 1F
ADD 1FH to round up to the next 32-byte boundary.
5044
AND 0E0HAND 11100000 E6 E0
AND with E0H to align to 32-byte boundary.
5046
LD L,A 6F
Store aligned position back in L.
5047
If NZ FLAG (more tracks to process), JUMP back to 502FH. [LOOP]

Display the free track and directory entry counts.

5049
LD HL,5176H 21 76 51
Point HL to 5176H - the free tracks display position.
504C
GOSUB to 50BFH to convert BC to decimal ASCII.
504F
LD HL,514EH 21 4E 51
Point HL to 514EH - the "DRIVE" header text position.
5052
GOSUB to 508FH to output the complete disk information line.
5055
XOR A AF
Set Register A to ZERO to indicate success.
5056
POP BC C1
Restore Register Pair BC (option flags) from the stack.
5057
RET C9
RETURN to caller with Z flag set if A=0 (success).

5058H - Check for Printer Option (P)

Check if the current character is "P" for printer output, and configure the output routines accordingly.

5058
LD A,(HL) 7E
Load Register A with the current command line character.
5059
CP 50H FE 50
Compare Register A against P (50H).
505B
INC HL 23
INCrement HL to the next character (done regardless of match).
505C
RET NZ C0
If NZ FLAG (not P), RETURN with current character still in A.

P option found - configure for printer output.

505D
LD A,3BH 3E 3B
Load Register A with 3BH - printer mode indicator.
505F
LD (50A8H),A 32 A8 50
Store 3BH at 50A8H to mark printer output mode.
5062
LD A,6AH 3E 6A
Load Register A with 6AH - opcode for different output routine.
5064
LD (5090H),A 32 90 50
Store at 5090H to modify the output routine jump. This is self-modifying code.
5067
SET 3,B CB D8
SET bit 3 of Register B to indicate P (Printer) option is active.
5069
LD A,(HL) 7E
Load Register A with the next command line character.
506A
RET C9
RETURN with Z flag set (from earlier CP 50H match).

506BH - Wait for User Input (Pause at Page Break)

Display "?" prompt and wait for user to press ENTER to continue or BREAK to abort.

506B
BIT 5,(IY+09H) FD CB 09 6E
Test bit 5 of DOS system flag at IY+09H to check if auto-mode is active.
506F
RET NZ C0
If NZ FLAG (auto-mode active), RETURN without waiting.
5070
LD A,(50A8H) 3A A8 50
Load Register A with the output mode flag.
5073
CP 33H FE 33
Compare against 33H (screen output mode initial value).
5075
RET NZ C0
If NZ FLAG (printer mode), RETURN without waiting.
5076
LD A,3FH 3E 3F
Load Register A with ? (3FH) - the prompt character.
5078
GOSUB to 50A5H to output the "?" prompt.
507B
LD A,(3840H) 3A 40 38
Load Register A with the keyboard scan for BREAK/CLEAR/ENTER row (memory-mapped at 3840H).
507E
AND 05H E6 05
AND with 05H to isolate ENTER (bit 0) and BREAK (bit 2) keys.
5080
If Z FLAG (neither key pressed), JUMP back to 507BH to keep waiting. [LOOP]
5082
RRCA 0F
Rotate Register A Right. If ENTER was pressed (bit 0), carry is set.
5083
If NO CARRY (BREAK pressed instead of ENTER), JUMP to DOS Ready at 402DH to abort.

5086H - Output Space and Carriage Return

Output a space followed by carriage return (new line).

5086
LD A,20H 3E 20
Load Register A with space (20H).
5088
GOSUB to 50A5H to output the space character.
508B
LD A,0DH 3E 0D
Load Register A with carriage return (0DH).
508D
JUMP to 50A5H to output the carriage return and return to caller.

508FH - Output String at HL

Output a string pointed to by HL. This jumps to the SYS0 string output routine.

508F
JUMP to SYS0 routine at 4467H to output the string at HL (terminated by byte < 20H).

5092H - Output B Spaces

Output B space characters for padding/formatting.

5092
LD A,20H 3E 20
Load Register A with space (20H).
5094
GOSUB to 50A5H to output one space.
5097
DECrement B and Jump if Not Zero. [LOOP] Continue until B spaces are output.
5099
RET C9
RETURN to caller.

509AH - Output Non-Space Characters from Buffer

Output B characters from (HL), skipping trailing spaces but tracking with counter C.

509A
LD A,(HL) 7E
Load Register A with the character at (HL).
509B
CP 20H FE 20
Compare Register A against space (20H).
509D
INC HL 23
INCrement HL to the next character.
509E
If NZ FLAG (not a space), GOSUB to 50A4H to output the character.
50A1
DECrement B and Jump if Not Zero. [LOOP] Continue for all B characters.
50A3
RET C9
RETURN to caller.

50A4H - Output Character with Position Tracking

Decrement position counter C, then output character in A.

50A4
DEC C 0D
DECrement Register C to track remaining column positions.
50A5
PUSH DE D5
Save Register Pair DE onto the stack.
50A6
PUSH AF F5
Save the character to output onto the stack.
50A7
GOSUB to ROM routine at 0033H to display the character in A at the cursor position.
50AA
POP AF F1
Restore Register A (the character) from the stack.
50AB
POP DE D1
Restore Register Pair DE from the stack.
50AC
RET C9
RETURN to caller.

50ADH - 24-Bit Division Routine

Perform 24-bit division: HLE / C. Returns quotient in HLE, remainder in A. Used for calculating record counts.

50AD
LD B,18H 06 18
Load Register B with 24 (18H) - number of bits to process.
50AF
XOR A AF
Set Register A to ZERO to initialize the remainder.
50B0
SLA E CB 23
Shift Left Arithmetic: shift E left one bit, LSB becomes 0, MSB goes to carry.
50B2
ADC HL,HL ED 6A
Add HL to HL with carry (16-bit left shift with carry in from E).
50B4
RLA 17
Rotate Left through Carry: shift A left, carry goes to bit 0, bit 7 goes to carry.
50B5
If CARRY (overflow from A), JUMP to 50BAH to perform subtraction.
50B7
CP C B9
Compare Register A (partial remainder) against divisor C.
50B8
If CARRY (A < C), JUMP to 50BCH to skip subtraction.
50BA
SUB C 91
SUBtract divisor C from remainder A.
50BB
INC E 1C
INCrement E to set quotient bit (since we subtracted).
50BC
DECrement B and Jump if Not Zero. [LOOP] Continue for all 24 bits.
50BE
RET C9
RETURN with quotient in HLE, remainder in A.

50BFH - Convert 16-bit BC to Decimal ASCII

Convert 16-bit value in BC to decimal ASCII and store at (HL). Uses divisor table at 5112H.

50BF
LD DE,5112H 11 12 51
Point DE to 5112H - the 16-bit divisor table (10000, 1000, 100, 10).
50C2
JUMP to 50C7H to perform the conversion.

50C4H - Convert 16-bit BC Using 5-digit Table

Convert 16-bit value using divisor table starting at 510FH (for larger numbers).

50C4
LD DE,510FH 11 0F 51
Point DE to 510FH - alternative divisor table.
50C7
XOR A AF
Set Register A to ZERO (no leading zeros initially).

50C8H - Decimal Conversion Main Loop

Main decimal conversion routine. Input: ABC = 24-bit value (or HL:low in BC for 16-bit), DE = divisor table, HL = output buffer. Converts to decimal ASCII.

50C8
PUSH DE D5
Save divisor table pointer onto the stack.
50C9
PUSH HL E5
Save output buffer pointer onto the stack.
50CA
PUSH BC C5
Save BC (value to convert) onto the stack.
50CB
EX DE,HL EB
Exchange DE and HL. Now HL points to divisor table.
50CC
LD E,(HL) 5E
Load Register E with the low byte of the current divisor.
50CD
INC HL 23
INCrement HL to the high byte.
50CE
LD D,(HL) 56
Load Register D with the high byte of the divisor.
50CF
INC HL 23
INCrement HL to the 24-bit extension byte.
50D0
LD C,(HL) 4E
Load Register C with the extension byte (for 24-bit divisors).
50D1
LD B,2FH 06 2F
Load Register B with 2FH (ASCII '0' - 1). Will be incremented for each successful subtraction.
50D3
POP HL E1
Restore the value being converted into HL.
50D4
INC B 04
INCrement digit counter B (will become '0' to '9').
50D5
ADD HL,DE 19
ADD divisor (negative in two's complement form) to HL.
50D6
ADC A,C 89
Add with carry the extension byte to A.
50D7
If CARRY (subtraction didn't underflow), JUMP back to 50D4H. [LOOP]
50D9
OR A B7
OR A with itself to test if high byte is zero.
50DA
SBC HL,DE ED 52
Subtract with carry to undo the last subtraction (restore remainder).
50DC
SBC A,C 99
Subtract with carry from A to restore.
50DD
EX (SP),HL E3
Exchange HL with top of stack (remainder ↔ output pointer).
50DE
PUSH AF F5
Save the high byte of remainder.
50DF
LD A,(HL) 7E
Load Register A with the current character in output buffer.
50E0
SUB 30H D6 30
SUBtract 30H to check if it is a digit.
50E2
CP 0AH FE 0A
Compare against 10.
50E4
INC HL 23
INCrement HL to next output position.
50E5
LD (HL),B 70
Store the digit character B at the current output position.
50E6
If CARRY (previous char was a digit), JUMP to 50EFH to continue.
50E8
LD A,B 78
Load Register A with the current digit.
50E9
CP 30H FE 30
Compare against '0' to check for leading zero.
50EB
If NZ FLAG (not a leading zero), JUMP to 50EFH.
50ED
LD (HL),20H 36 20
Replace leading zero with space (20H) for formatting.
50EF
LD A,E 7B
Load Register A with the low byte of the divisor.
50F0
CP F6H FE F6
Compare against F6H (the sentinel value for end of divisor table).
50F2
If Z FLAG (reached end of table), JUMP to 50FCH to finish.
50F4
POP AF F1
Restore the high byte of the remainder.
50F5
POP BC C1
Restore the current remainder into BC.
50F6
POP DE D1
Restore divisor table pointer into DE.
50F7
INC DE 13
Advance to the next divisor entry.
50F8
INC DE 13
Each entry is 3 bytes.
50F9
INC DE 13
Point to the next divisor.
50FA
JUMP back to 50C8H to process the next digit. [LOOP]

Finished converting - store the final units digit.

50FC
POP DE D1
Discard saved AF from stack.
50FD
POP BC C1
Discard saved BC from stack.
50FE
POP DE D1
Discard saved DE from stack.
50FF
INC HL 23
INCrement HL to the units digit position.
5100
LD A,C 79
Load Register A with the final remainder (units digit value).
5101
ADD 30H C6 30
ADD 30H to convert to ASCII digit.
5103
LD (HL),A 77
Store the units digit at the output position.
5104
INC HL 23
INCrement HL past the number.
5105
RET C9
RETURN to caller.

5106H - Stack Cleanup Entry

Alternate entry point to clean up stack and return.

5106
POP AF F1
Discard saved AF from stack.
5107
POP AF F1
Discard another saved AF from stack.
5108
RET C9
RETURN to caller.

5109H - Divisor Tables for Decimal Conversion

These are negative divisors used for decimal conversion by repeated subtraction. Each entry is 3 bytes: low, high, extension (for 24-bit). Values are two's complement negatives of powers of 10.

5109
A0
DATA: A0H = low byte of -100000 (for 24-bit conversion).
510A
86
DATA: 86H = middle byte of -100000.
510B
01 F0 D8
DATA: 01H = high byte of -100000; F0H D8H = -10000 (low, high).
510E
FF
DATA: FFH = extension byte for -10000.
510F
18 FC
DATA: 18H FCH = -1000 (low byte, high byte as two's complement).
5111
FF
DATA: FFH = extension byte.
5112
9C
DATA: 9CH = low byte of -100.
5113
FF
DATA: FFH = high byte of -100.
5114
FF
DATA: FFH = extension byte.
5115
F6 FF
DATA: F6H FFH = -10 (low, high).
5117
FF
DATA: FFH = extension byte. F6H is also the sentinel value that marks end of table.

5118H - Text Strings for Prompts and Display Templates

The remainder of the program consists of text strings and display templates used by the DIR command. These are stored as ASCII with control bytes (values < 20H) serving as terminators.

5118
DEFM "MOUNT "+03H 4D 4F 55 4E 54 20 03
511F
DEFM " DISKETTE ON DRIVE 0" 20 44 49 53 4B 45 54 54 45 20 4F 4E 20 44 52 49 56 45 20 30
5133
DEFM " " 20 20
5135
DEFM "(ENTER)"+0DH Terminator28 45 4E 54 45 52 29 0D

Text: "SYSTEM" and "TARGET" (for swap prompts)

513D
DEFM "SYSTEM"+03H 53 59 53 54 45 4D 03
5144
DEFM "TARGET"+03H 54 41 52 47 45 54 03

Screen positioning codes

514B
DEFB 1CH, 1FH, 03H 1C 1F 03

Text: "DRIVE" header and display template line

514E
DEFM "DRIVE 000 XXXXXXXX MM/DD/YY " 44 52 49 56 45 20 30 30 30 20 20 58 58 58 58 58 58 58 58 20 20 4D 4D 2F 44 44 2F 59 59 20 20
516D
DEFM "000 TRKS 000 FDES " 30 30 30 20 54 52 4B 53 20 20 30 30 30 20 46 44 45 53 20 20
5180
DEFM "0000 GRANS"+0DH 30 30 30 30 20 47 52 41 4E 53 0D

Column header template for A (All) option display

51BC
DEFM "EOF LRL RECS GRANS EXTS SIUEC..UAL"+0DH 45 4F 46 20 20 20 20 4C 52 4C 20 20 20 52 45 43 53 20 47 52 41 4E 53 20 45 58 54 53 20 20 53 49 55 45 43 2E 2E 55 41 4C 0D
51E7
NOP 00
Terminator