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

Page Customization

Introduction:

SYS3/SYS - NEWDOS/80 v2.0 System Utility Functions

SYS3 is a system overlay file for NEWDOS/80 v2.0 that provides several utility functions accessed via RST 28H supervisor calls. The file loads at address 4D00H and contains handlers for disk space management, file deletion, system configuration, and debugging utilities.

Primary Functions:

  • FREE Command (Function 25H) - Calculates and displays the free space available on a disk. It walks through all directory entries, counts allocated granules by examining the extent tables, builds an allocation bitmap, and reports the remaining free space. The bitmap is also used to verify and repair the disk's Granule Allocation Table (GAT).
  • PURGE Command (Function 45H) - Deletes files matching a filespec. Similar to FREE, it scans directory entries but marks matching files for deletion and updates the allocation bitmap to free the granules.
  • KILL Command (Sub-function E5H/C=6) - Interactive file deletion with user confirmation. Supports wildcards, extension filtering via /ext syntax, and the USR keyword to include system files. For each matching file, displays the filename and prompts "KILL IT? (Y/N/Q)" allowing the user to confirm deletion, skip, or quit.
  • SETHOOK (Function 65H) - Inserts a new entry into the system hook chain at 4584H. Hooks are used to intercept system calls and extend DOS functionality. The new hook is inserted at the head of a linked list.
  • RELHOOK (Function 85H) - Removes a hook entry from the chain by unlinking it from the linked list.
  • DEBUG/DUMP (Function A5H) - Displays memory contents on screen in a readable format, replacing non-printable characters with periods. Used for debugging and memory examination.
  • File Access Check (Function C5H) - Validates whether a file can be accessed by parsing the filespec and checking directory entries.

System Configuration Sub-functions (E5H)

A collection of toggles and settings:

  • C=1: SCREEN mode toggle (video output control at 401CH)
  • C=2: Display configuration (calls ROM routines)
  • C=3: FORMS mode toggle (printer formatting at 4289H bit 7)
  • C=4: SKIP mode configuration (self-modifying code at 4A2DH)
  • C=5: DEBUG hook enable/disable (JP vs RET at 4478H)
  • C=7: File position/EOF marker update
  • C=10: TRACE mode toggle (execution tracing at 4019H)

Technical Notes:

SYS3 uses self-modifying code extensively, particularly for storing operation state (4EA1H, 4FB8H, 5130H) and configuring system hooks.

The granule allocation bitmap at 4D00H-4DBFH temporarily overwrites the start of SYS3's own code space during FREE/PURGE operations, which is safe since the code has already executed past that point.

Hook chain management disables interrupts during list modifications to prevent corruption.

The N/Y parameter parser at 4DD1H accepts either character and returns Z flag for N, NZ for Y.

Variables:

AddressBytesPurpose
4019H1TRACE mode flag (bit 0: 1=enabled, 0=disabled)
401CH1SCREEN mode flag (bit 0: 1=enabled, 0=disabled)
427EH1Current drive number
4288H1Status flag (cleared during FREE operation)
4289H1FORMS mode flag (bit 7: 1=enabled, 0=disabled)
428BH1System flags byte (bit 2: display suppression)
4290H1Character display upper limit for DEBUG dump
431FH1System parameter - last directory sector number
4478H1DEBUG hook instruction byte (C3H=JP enabled, C9H=RET disabled)
4479H-447AH2DEBUG hook jump target address (4546H when enabled)
4480H-449FH32FCB template/buffer for file operations
4487H1Current directory entry identifier for KILL
4584H-4585H2Hook chain head pointer (linked list of installed hooks)
4A2DH1SKIP mode self-modifying code byte 1
4A2EH-4A2FH2SKIP mode self-modifying code bytes 2-3
4D00H-4DBFH192Granule allocation bitmap buffer (1 bit per granule)
4DC0H-4DDFH32Granule tracking area for FREE/PURGE operations
4EA1H1Directory entry offset storage (self-modifying code location)
4FB8H1Operation mode flag (00H=FREE, 01H=PURGE)
5130H1End sector limit for KILL directory scan (self-modifying)
5140H1KILL options flags (bit 0: extension filter, bit 1: USR mode)
5141H-5143H3Extension filter buffer for KILL command
5144H-515EH27Prompt string: " KILL IT? (Y/N/Q) " with terminator

Disassembly

4D00H - SYS3 Main Function Dispatcher

SYS3 is entered with the function code in Register A. This dispatcher examines the function code and routes execution to the appropriate handler. The low bits of the function code encode which SYS file (SYS3 = directory sector 7, function 0) and the high bits encode the specific function within that file. Valid function codes for SYS3 are: 25H, 45H, 65H, 85H, A5H, C5H, and E5H. The E5H function has sub-functions determined by Register C.

4D00
CP 25H FE 25
Compare Register A against 25H (function code for FREE command). If A equals 25H, the Z FLAG is set.
4D02
If the Z FLAG is set (function code = 25H), JUMP to 4E02H to handle the FREE command.
4D05
CP 45H FE 45
Compare Register A against 45H (function code for PURGE command). If A equals 45H, the Z FLAG is set.
4D07
If the Z FLAG is set (function code = 45H), JUMP to 4DE6H to handle the PURGE command.
4D0A
CP 65H FE 65
Compare Register A against 65H (function code for SETHOOK - insert hook into chain). If A equals 65H, the Z FLAG is set.
4D0C
If the Z FLAG is set (function code = 65H), JUMP to 4D47H to insert a new hook into the hook chain.
4D0E
CP 85H FE 85
Compare Register A against 85H (function code for RELHOOK - remove hook from chain). If A equals 85H, the Z FLAG is set.
4D10
If the Z FLAG is set (function code = 85H), JUMP to 4D55H to remove a hook from the hook chain.
4D12
CP A5H FE A5
Compare Register A against A5H (function code for DEBUG/DUMP screen memory display). If A equals A5H, the Z FLAG is set.
4D14
If the Z FLAG is set (function code = A5H), JUMP to 515FH to display memory contents on screen.
4D17
CP C5H FE C5
Compare Register A against C5H (function code for file access check). If A equals C5H, the Z FLAG is set.
4D19
If the Z FLAG is set (function code = C5H), JUMP to 502DH to check file access/validity.
4D1C
CP E5H FE E5
Compare Register A against E5H (function code for system configuration sub-functions). If A equals E5H, the Z FLAG is set.
4D1E
If the NZ FLAG is set (function code is not E5H and none of the above), JUMP to 4D43H to return error code 2AH (invalid function).

[E5H SUB-FUNCTION DISPATCHER] The E5H function code has multiple sub-functions. Register C contains the sub-function number (1-10). Each DEC C tests for the next sub-function number.

4D20
DEC C 0D
DECrement Register C. If C was 1, it becomes 0 and Z FLAG is set (sub-function 1 = SCREEN mode toggle).
4D21
If Z FLAG is set (C=1), JUMP to 4D88H to handle SCREEN mode toggle at 401CH.
4D24
DEC C 0D
DECrement Register C. If C was 2, it becomes 0 and Z FLAG is set (sub-function 2 = display configuration).
4D25
If Z FLAG is set (C=2), JUMP to 4D70H to handle display configuration.
4D27
DEC C 0D
DECrement Register C. If C was 3, it becomes 0 and Z FLAG is set (sub-function 3 = FORMS mode toggle).
4D28
If Z FLAG is set (C=3), JUMP to 4D95H to handle FORMS mode toggle at 4289H.
4D2B
DEC C 0D
DECrement Register C. If C was 4, it becomes 0 and Z FLAG is set (sub-function 4 = SKIP mode configuration).
4D2C
If Z FLAG is set (C=4), JUMP to 4DA2H to handle SKIP mode configuration.
4D2F
DEC C 0D
DECrement Register C. If C was 5, it becomes 0 and Z FLAG is set (sub-function 5 = DEBUG hook configuration).
4D30
If Z FLAG is set (C=5), JUMP to 4DB8H to configure the DEBUG hook at 4478H.
4D33
DEC C 0D
DECrement Register C. If C was 6, it becomes 0 and Z FLAG is set (sub-function 6 = KILL command handler).
4D34
If Z FLAG is set (C=6), JUMP to 503AH to handle the KILL command.
4D37
DEC C 0D
DECrement Register C. If C was 7, it becomes 0 and Z FLAG is set (sub-function 7 = file position update).
4D38
If Z FLAG is set (C=7), JUMP to 4FF5H to update file position/EOF marker.
4D3B
DEC C 0D
DECrement Register C. If C was 8, it becomes 0 and Z FLAG is set (sub-function 8 = invalid/error).
4D3C
If Z FLAG is set (C=8), JUMP to 4D43H to return error (sub-function 8 is invalid).
4D3F
DEC C 0D
DECrement Register C. If C was 9, it becomes 0 and Z FLAG is set (sub-function 9 reserved).
4D40
If Z FLAG is set (C=9), JUMP to 4D7BH but actually falls through on next (sub-function 10 = TRACE mode toggle).

4D43H - Invalid Function Error Return

This routine returns an error code when an invalid function code was passed to SYS3. Error code 2AH indicates "general error" or invalid parameter.

4D43
LD A,2AH 3E 2A
Load Register A with 2AH (error code 42 = "general error").
4D45
OR A B7
OR Register A with itself. This sets the NZ FLAG (since A=2AH is non-zero) to indicate an error occurred.
4D46
RET C9
RETURN to caller with error code 2AH in A and NZ FLAG set indicating failure.

4D47H - SETHOOK (Function 65H) - Insert Hook into Chain

This function inserts a new entry into the hook chain stored at 4584H. The hook chain is a linked list where each entry contains a 2-byte address pointing to the next entry. DE contains the address of the new hook entry to insert, which should have space for a 2-byte forward pointer. The new entry is inserted at the head of the chain.

4D47
DI F3
Disable Interrupts to prevent any interrupt from corrupting the linked list while we modify it.
4D48
LD HL,(4584H) 2A 84 45
Load Register Pair HL with the current head of the hook chain stored at 4584H. This is the address of the first hook entry (or 0000H if empty).
4D4B
LD (4584H),DE ED 53 84 45
Store the address in DE (the new hook entry) into 4584H, making it the new head of the chain.
4D4F
EX DE,HL EB
Exchange DE and HL. Now HL points to the new entry and DE contains the old chain head.
4D50
LD (HL),E 73
Store the low byte of the old head (E) into the first byte of the new entry. This sets up the forward link.
4D51
INC HL 23
INCrement HL to point to the second byte of the new entry's forward pointer.
4D52
LD (HL),D 72
Store the high byte of the old head (D) into the second byte of the new entry. The new entry now points to the previous head.
4D53
EI FB
Enable Interrupts now that the list modification is complete.
4D54
RET C9
RETURN to caller. The hook has been successfully inserted at the head of the chain.

4D55H - RELHOOK (Function 85H) - Remove Hook from Chain

This function removes an entry from the hook chain. BC contains the address of the hook entry to remove. The routine searches the chain starting at 4584H, finds the entry matching BC, and unlinks it by updating the previous entry's forward pointer.

4D55
LD B,D 42
Copy Register D to Register B. Now BC contains DE (the address to search for). This preserves the search target.
4D56
LD C,E 4B
Copy Register E to Register C. BC now holds the complete 16-bit address to find and remove.
4D57
LD HL,4584H 21 84 45
Point HL to the hook chain head pointer at 4584H. This is where we start the search.
4D5A
DI F3
Disable Interrupts to protect the linked list during modification.

[LOOP START] Search loop - walk through the chain looking for the entry matching BC.

4D5B
LD E,(HL) 5E
Load the low byte of the current entry's forward pointer into Register E.
4D5C
INC HL 23
INCrement HL to point to the high byte of the forward pointer.
4D5D
LD D,(HL) 56
Load the high byte of the current entry's forward pointer into Register D. DE now contains the address of the next entry.
4D5E
EX DE,HL EB
Exchange DE and HL. HL now points to the next entry, DE points to where we just read from (previous entry's high byte).
4D5F
LD A,H 7C
Copy Register H to Register A (high byte of current entry address).
4D60
OR L B5
OR Register A with Register L. If HL=0000H (end of chain), Z FLAG is set.
4D61
If Z FLAG is set (reached end of chain without finding the entry), JUMP to 4D53H to enable interrupts and return.
4D63
OR A B7
Clear the CARRY FLAG in preparation for the 16-bit comparison.
4D64
SBC HL,BC ED 42
Subtract BC from HL. If HL equals BC (found the target entry), Z FLAG is set.
4D66
ADD HL,BC 09
ADD BC back to HL to restore the original value (we only wanted to compare, not modify HL).
4D67
If NZ FLAG is set (current entry doesn't match), LOOP BACK to 4D5BH to check the next entry.

[FOUND - UNLINK ENTRY] We found the entry at HL that matches BC. Now we unlink it by copying its forward pointer to the previous entry.

4D69
DEC DE 1B
DECrement DE. DE was pointing to the high byte of the previous entry's forward pointer; now it points to the low byte.
4D6A
LD A,(HL) 7E
Load Register A with the low byte of the found entry's forward pointer (the entry after the one we're removing).
4D6B
INC HL 23
INCrement HL to point to the high byte of the found entry's forward pointer.
4D6C
LD H,(HL) 66
Load Register H with the high byte of the found entry's forward pointer.
4D6D
LD L,A 6F
Load Register L with A (the low byte). HL now contains the address of the entry after the removed one.
4D6E
JUMP to 4D4FH to store HL (the successor) into the previous entry's forward pointer (at DE), unlinking the removed entry.

4D70H - Sub-function E5H/C=2: Display Configuration

This sub-function handles display configuration. It validates parameters and calls ROM routines to set display modes.

4D70
GOSUB to 4DCCH to parse and validate the N/Y parameter from the command line.
4D73
If Z FLAG is set (parameter was N), JUMP to ROM routine at 02A1H (likely a display disable/clear routine).
4D76
GOSUB to ROM routine at 0298H to perform display configuration (likely enable display output).
4D79
XOR A AF
XOR Register A with itself, setting A to 00H and setting the Z FLAG to indicate success.
4D7A
RET C9
RETURN to caller with success (A=0, Z FLAG set).

4D7BH - Sub-function E5H/C=10: TRACE Mode Toggle

This sub-function toggles the TRACE mode flag at address 4019H. This controls whether execution tracing is enabled for debugging.

4D7B
GOSUB to 4DCCH to parse and validate the N/Y parameter.
4D7E
LD HL,4019H 21 19 40
Point HL to 4019H - the TRACE mode flag in the DOS system area.
4D81
SET 0,(HL) CB C6
SET bit 0 of the byte at (HL) to 1, enabling TRACE mode.
4D83
RET Z C8
If Z FLAG is set (parameter was N), RETURN now with TRACE mode enabled (bit was set above).
4D84
RES 0,(HL) CB 86
RESset bit 0 of the byte at (HL) to 0, disabling TRACE mode (parameter was Y to disable).
4D86
XOR A AF
XOR Register A with itself, setting A to 00H and Z FLAG for success.
4D87
RET C9
RETURN to caller with success.

4D88H - Sub-function E5H/C=1: SCREEN Mode Toggle

This sub-function toggles the SCREEN mode flag at address 401CH. This controls video output behavior.

4D88
GOSUB to 4DCCH to parse and validate the N/Y parameter.
4D8B
LD HL,401CH 21 1C 40
Point HL to 401CH - the SCREEN mode flag in the DOS system area.
4D8E
SET 0,(HL) CB C6
SET bit 0 of the byte at (HL) to 1, initially enabling SCREEN mode.
4D90
RET Z C8
If Z FLAG is set (parameter was N), RETURN with SCREEN mode enabled.
4D91
RES 0,(HL) CB 86
RESset bit 0 of the byte at (HL) to 0, disabling SCREEN mode.
4D93
XOR A AF
XOR Register A with itself for success return.
4D94
RET C9
RETURN to caller with success.

4D95H - Sub-function E5H/C=3: FORMS Mode Toggle

This sub-function toggles the FORMS mode flag at address 4289H bit 7. FORMS mode affects printer output formatting.

4D95
GOSUB to 4DCCH to parse and validate the N/Y parameter.
4D98
LD HL,4289H 21 89 42
Point HL to 4289H - the FORMS mode flag byte.
4D9B
RES 7,(HL) CB BE
RESset bit 7 of the byte at (HL) to 0, initially disabling FORMS mode.
4D9D
RET Z C8
If Z FLAG is set (parameter was N), RETURN with FORMS mode disabled.
4D9E
SET 7,(HL) CB FE
SET bit 7 of the byte at (HL) to 1, enabling FORMS mode.
4DA0
XOR A AF
XOR Register A with itself for success return.
4DA1
RET C9
RETURN to caller with success.

4DA2H - Sub-function E5H/C=4: SKIP Mode Configuration

This sub-function configures the SKIP mode. When enabled (Y), special skip code is stored at 4A2DH; when disabled (N), the skip is bypassed.

4DA2
GOSUB to 4DCCH to parse and validate the N/Y parameter.
4DA5
LD A,DDH 3E DD
Load Register A with DDH - this is the first byte of an IX-prefixed instruction (for skip enable).
4DA7
LD HL,017EH 21 7E 01
Load HL with 017EH - additional bytes for the skip-enabled instruction sequence.
4DAA
If Z FLAG is set (parameter was N), JUMP to 4DB0H to store the skip-enable values.
4DAC
XOR A AF
XOR Register A with itself, setting A to 00H (for skip disabled).
4DAD
LD HL,FF3EH 21 3E FF
Load HL with FF3EH - the skip-disabled instruction bytes.
4DB0
LD (4A2DH),A 32 2D 4A
Store Register A into memory location 4A2DH - the first byte of the self-modifying skip code area.
4DB3
LD (4A2EH),HL 22 2E 4A
Store HL into memory location 4A2EH - the second and third bytes of the skip code area.
4DB6
XOR A AF
XOR Register A with itself for success return (A=0, Z FLAG set).
4DB7
RET C9
RETURN to caller with success.

4DB8H - Sub-function E5H/C=5: DEBUG Hook Configuration

This sub-function configures the DEBUG hook at 4478H. When enabled, a JP instruction is written to call the debug routine at 4546H. When disabled, a RET instruction is written to skip the debug hook.

4DB8
GOSUB to 4DCCH to parse and validate the N/Y parameter.
4DBB
LD HL,4546H 21 46 45
Load HL with 4546H - the address of the DEBUG handler routine.
4DBE
LD (4479H),HL 22 79 44
Store HL into 4479H - this is the jump target address (bytes 2-3 of the JP instruction at 4478H).
4DC1
LD A,C3H 3E C3
Load Register A with C3H - the opcode for JP instruction.
4DC3
If Z FLAG is set (parameter was N to disable debug), JUMP to 4DC7H to store C3H (JP) at the hook.
4DC5
LD A,C9H 3E C9
Load Register A with C9H - the opcode for RET instruction (to disable the hook).
4DC7
LD (4478H),A 32 78 44
Store Register A into 4478H - the first byte of the DEBUG hook. This is now either JP (C3H) or RET (C9H).
4DCA
XOR A AF
XOR Register A with itself for success return.
4DCB
RET C9
RETURN to caller with success.

4DCCH - Parameter Validation Wrapper

This is a wrapper routine that calls the actual parameter parser at 4DD1H, then performs additional validation. It expects HL to point to the command line. Returns Z FLAG if parameter was N, NZ if Y.

4DCC
GOSUB to 4DD1H to parse the first character from the command line.
4DCF
JUMP to 4DDDH to perform additional validation and return.

4DD1H - Parse N/Y Parameter from Command Line

This routine parses a single character parameter from the command line pointed to by HL. It expects either N (4EH) or Y (59H). The result is stored in Register B: 00H for N, 0BH for Y.

4DD1
LD A,(HL) 7E
Load Register A with the character at (HL) - the parameter character from the command line.
4DD2
SUB 4EH D6 4E
SUBtract 4EH (ASCII N) from Register A. If the character was N, A becomes 00H.
4DD4
LD B,A 47
Copy the result to Register B for later use. B=00H means N, B=0BH means Y (since 59H-4EH=0BH).
4DD5
INC HL 23
INCrement HL to advance past the parameter character.
4DD6
If Z FLAG is set (character was N), JUMP to 4DE3H to return success.
4DD8
CP 0BH FE 0B
Compare Register A against 0BH. If original character was Y (59H-4EH=0BH), Z FLAG is set.
4DDA
If Z FLAG is set (character was Y), JUMP to 4DE3H to return success.
4DDC
DEC HL 2B
DECrement HL to point back to the invalid character (for error reporting).
4DDD
GOSUB to SYS0 routine at 4C7AH to skip whitespace and delimiters on the command line.
4DE0
If NZ FLAG is set (additional characters found - parse error), JUMP to 4409H to report error.
4DE3
LD A,B 78
Load Register A with the saved result from Register B (00H for N, 0BH for Y).
4DE4
OR A B7
OR Register A with itself. Sets Z FLAG if A=00H (N), sets NZ FLAG if A=0BH (Y).
4DE5
RET C9
RETURN to caller. Z FLAG indicates N was specified, NZ FLAG indicates Y.

4DE6H - PURGE Command Handler (Function 45H)

The PURGE command deletes files matching a filespec. It first parses the filespec, then iterates through matching directory entries, optionally prompting for confirmation before deleting each file.

4DE6
GOSUB to SYS0 routine at 4925H to parse the filespec from the command line.
4DE9
GOSUB to SYS0 routine at 48F0H to validate the parsed filespec and check for wildcards.
4DEC
RET NZ C0
If NZ FLAG is set (filespec parse error), RETURN immediately with the error code.
4DED
LD B,02H 06 02
Load Register B with 02H - a flag value indicating PURGE mode (delete operation).
4DEF
GOSUB to SYS0 routine at 495EH to search for matching files and prepare for iteration.
4DF2
JUMP to 4DF7H to begin the purge iteration loop.

4DF4H - PURGE Loop Continuation Entry

This is the re-entry point for the PURGE loop when continuing to delete additional files.

4DF4
GOSUB to 4925H to re-parse the filespec (since directory may have changed).
4DF7
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H - initialize the sector/counter for directory search.
4DFA
LD A,01H 3E 01
Load Register A with 01H - flag indicating "PURGE in progress".
4DFC
LD (4FB8H),A 32 B8 4F
Store A into 4FB8H - the PURGE/FREE operation mode flag (01H = PURGE active).
4DFF
PUSH BC C5
Save BC onto the stack (sector counter).
4E00
JUMP to 4E27H to begin processing directory entries.

4E02H - FREE Command Handler (Function 25H)

The FREE command displays the free space available on a disk by walking through the directory and calculating space used. It counts allocated granules and reports remaining free space.

4E02
GOSUB to 4925H to parse the drive specification from the command line.
4E05
XOR A AF
XOR Register A with itself, setting A to 00H.
4E06
LD (4FB8H),A 32 B8 4F
Store 00H into 4FB8H - set operation mode flag to FREE (not PURGE).
4E09
GOSUB to 4FEAH to open the directory file for reading.
4E0C
If NO CARRY (directory open failed or is empty), JUMP to 4F5AH to display results anyway.
4E0F
BIT 6,(IX+02H) DD CB 02 76
Test bit 6 of FCB+02H (IX points to FCB). This bit indicates a special file attribute.
4E13
If bit 6 is set (special attribute), JUMP to 4F5AH - skip this entry.
4E16
PUSH HL E5
Save HL onto the stack (points to directory buffer).
4E17
LD A,(IX+08H) DD 7E 08
Load Register A with FCB+08H - the EOF sector number within the last granule.
4E1A
OR A B7
OR Register A with itself. Test if EOF sector is zero.
4E1B
If Z FLAG is set (EOF sector = 0), JUMP to 4E1EH to skip adjustment.
4E1D
NOP 00
No operation (placeholder, possibly removed code).
4E1E
EX DE,HL EB
Exchange DE and HL. DE now has the old HL value.
4E1F
GOSUB to SYS0 routine at 4C57H to perform a calculation (likely buffer address computation).
4E22
OR A B7
OR Register A with itself. Test the result.
4E23
If Z FLAG is set, JUMP to 4E26H.
4E25
INC HL 23
INCrement HL.
4E26
EX (SP),HL E3
Exchange HL with the value on top of the stack. Save current HL, restore original.

4E27H - Directory Entry Processing Loop

This is the main loop that processes directory entries for both FREE and PURGE commands. It walks through each directory entry, counting allocated granules or marking files for deletion.

4E27
LD D,(IX+07H) DD 56 07
Load Register D with FCB+07H - the drive number for the current operation.
4E2A
LD BC,0000H 01 00 00
Load BC with 0000H - initialize the granule counter to zero.
4E2D
LD E,10H 1E 10
Load Register E with 10H (16) - the expected directory entry type flag (10H = active file entry).

[LOOP START] Main directory entry processing loop. Scan through all directory entries.

4E2F
LD A,(HL) 7E
Load Register A with the first byte of the directory entry (file status byte).
4E30
AND 90H E6 90
Mask off all bits except bit 7 and bit 4 (90H). Bit 4 set = active entry, Bit 7 = deleted.
4E32
CP E BB
Compare against E (10H = active entry). If status matches, Z FLAG is set.
4E33
If NZ FLAG (not an active entry), JUMP to 4E52H to skip this entry.
4E35
LD A,L 7D
Load Register A with the low byte of HL (current position in directory buffer).
4E36
LD (4EA1H),A 32 A1 4E
Store A into 4EA1H - save the directory entry offset for later reference.
4E39
ADD 16H C6 16
ADD 16H (22 decimal) to A - offset to the granule allocation table within the directory entry.
4E3B
LD L,A 6F
Load Register L with A. HL now points to the granule allocation table.
4E3C
PUSH DE D5
Save DE onto the stack (D=drive, E=entry type flag).
4E3D
LD E,05H 1E 05
Load Register E with 05H - there are 5 extents to process per directory entry.

[INNER LOOP - EXTENT PROCESSING] Process each of the 5 extents in the directory entry.

4E3F
LD A,(HL) 7E
Load Register A with the current extent byte (granule number or FEH/FFH for end).
4E40
CP FEH FE FE
Compare against FEH. If A >= FEH, this extent is empty (FEH or FFH marks unused).
4E42
INC HL 23
INCrement HL to point to the sector count byte of this extent.
4E43
If NO CARRY (A >= FEH, extent empty), JUMP to 4E64H to handle end of extents.
4E45
LD A,(HL) 7E
Load Register A with the sector count byte (bits 0-4 = sectors, bits 5-7 = granule count MSB).
4E46
AND 1FHAND 00011111 E6 1F
Mask off the upper 3 bits, keeping only the sector count (0-1FH = 0-31 sectors).
4E48
INC HL 23
INCrement HL to point to the next extent entry.
4E49
INC A 3C
INCrement A (sector count is stored as count-1, so add 1 for actual count).
4E4A
ADD A,C 81
ADD the sector count to Register C (accumulating total sectors in BC).
4E4B
LD C,A 4F
Store the sum back into Register C.
4E4C
If NO CARRY (no overflow), JUMP to 4E4FH.
4E4E
INC B 04
INCrement Register B (high byte of sector count) for carry.
4E4F
DEC E 1D
DECrement Register E (extent counter).
4E50
If NZ FLAG (more extents to process), LOOP BACK to 4E3FH.

[ERROR PATH] If we processed all 5 extents without finding an end marker, this is an error condition.

4E52
LD A,2CH 3E 2C
Load Register A with 2CH (error code 44 = "directory full" or allocation error).
4E54
OR A B7
OR Register A with itself to set NZ FLAG (indicate error).
4E55
RET Z C8
RET if Z FLAG set (which it isn't - this is a safety return that won't execute).
4E56
JUMP to SYS0 error handler at 4972H to report the error.

4E59H - Report Drive and Continue

This subroutine reports the drive number and returns to continue processing.

4E59
LD A,D 7A
Load Register A with Register D (the drive number).
4E5A
GOSUB to SYS0 routine at 48D4H to display the drive number.
4E5D
JUMP back to 4E55H to return with appropriate flags.

4E5FH - Write Directory Sector

This subroutine writes the current directory sector back to disk after modifications.

4E5F
GOSUB to SYS0 routine at 48C4H to write the directory sector to disk.
4E62
JUMP to 4E55H to return.

4E64H - End of Extents Handler

This code handles reaching the end of extents (found FEH marker). It either continues to the next directory entry or processes a continuation extent.

4E64
If NZ FLAG (extent byte was FFH not FEH), JUMP to 4E72H - this was the true end.
4E66
DEC E 1D
DECrement the extent counter.
4E67
POP DE D1
Restore DE from the stack (drive number and original entry type).
4E68
If NZ FLAG (more extents were expected but found FEH), JUMP to 4E52H for error.
4E6A
LD D,(HL) 56
Load Register D with (HL) - the continuation sector number for extended entries.
4E6B
LD E,90H 1E 90
Load Register E with 90H - entry type for continuation extent (bit 7 and bit 4 set).
4E6D
GOSUB to 4E59H to report drive and continue.
4E70
LOOP BACK to 4E2FH to continue processing the continuation extent.

4E72H - Finish Entry Processing

This code completes processing of a directory entry and prepares for the next one.

4E72
POP DE D1
Restore DE from the stack.
4E73
EX (SP),HL E3
Exchange HL with stack top. HL gets the saved directory position, stack gets current HL.
4E74
XOR A AF
XOR Register A with itself, clearing the CARRY FLAG.
4E75
SBC HL,BC ED 42
Subtract BC (total sectors counted) from HL. Result is remaining free space indicator.
4E77
LD (4288H),A 32 88 42
Store A (now 00H) into 4288H - a status flag.
4E7A
PUSH HL E5
Save HL (free space value) onto the stack.
4E7B
LD HL,4D00H 21 00 4D
Point HL to 4D00H - the granule allocation bitmap buffer.
4E7E
LD B,C0H 06 C0
Load Register B with C0H (192 decimal) - size of the allocation bitmap (192 bytes = 192 granules max).

[LOOP - CLEAR BITMAP] Initialize the allocation bitmap to all FFH (all granules marked as free).

4E80
LD (HL),FFH 36 FF
Store FFH at (HL) - mark 8 granules as free (each bit = one granule, 1 = free).
4E82
INC HL 23
INCrement HL to the next byte of the bitmap.
4E83
DECrement B and LOOP BACK to 4E80H if not zero. Loop 192 times.
4E85
LD B,20H 06 20
Load Register B with 20H (32 decimal) - size of the extra area.

[LOOP - CLEAR EXTRA AREA] Clear 32 more bytes after the bitmap.

4E87
LD (HL),A 77
Store A (00H) at (HL) - clear this byte.
4E88
INC HL 23
INCrement HL.
4E89
DECrement B and LOOP BACK if not zero. Loop 32 times.
4E8B
POP BC C1
Restore BC (free space count) from the stack.
4E8C
POP HL E1
Restore HL (directory pointer) from the stack.
4E8D
LD A,(4FB8H) 3A B8 4F
Load Register A with the operation mode flag from 4FB8H (00H=FREE, 01H=PURGE).
4E90
OR A B7
OR Register A with itself. Test if this is FREE or PURGE mode.
4E91
If NZ FLAG (PURGE mode), JUMP to 4E9EH to skip free space check.
4E93
LD A,B 78
Load Register A with B (high byte of sector count).
4E94
CP 80H FE 80
Compare against 80H. If sector count >= 8000H, there may be insufficient space.
4E96
PUSH HL E5
Save HL onto the stack.
4E97
If NO CARRY (large sector count), GOSUB to 48C4H to write buffer and report.
4E9A
POP HL E1
Restore HL from the stack.
4E9B
If NZ FLAG (write error), JUMP to 4F0DH for error handling.

4E9EH - Directory Entry Bitmap Processing Loop

This section processes directory entries and updates the granule allocation bitmap. It walks through directory entries, marking allocated granules in the bitmap.

4E9E
DEC L 2D
DECrement Register L (adjust directory pointer back 2 bytes).
4E9F
DEC L 2D
DECrement Register L again.
4EA0
LD E,00H 1E 00
Load Register E with 00H - initialize the entry offset counter.

[MAIN DIRECTORY SCAN LOOP] Scan through all directory entries in the current sector.

4EA1
LD A,E 7B
Load Register A with Register E (current entry offset). Note: Address 4EA1H is used as self-modifying storage for directory entry offset.
4EA2
ADD 16H C6 16
ADD 16H (22 bytes) to A - calculate offset to next directory entry.
4EA4
CP L BD
Compare against L (current position in buffer). If A >= L, we've passed the current entry.
4EA5
If CARRY (next entry offset < current position), JUMP to 4EC5H to process extent info.
4EA7
LD L,E 6B
Load Register L with E. Point HL to start of current entry.
4EA8
BIT 7,(HL) CB 7E
Test bit 7 of the entry status byte. If set, entry is deleted or unused.
4EAA
If Z FLAG (bit 7 clear = active entry), JUMP to 4EFFH to check operation mode.
4EAC
GOSUB to 4FC2H to process this directory entry (mark granules as allocated).
4EAF
GOSUB to 4E59H to report the drive number.
4EB2
LD (4EA1H),A 32 A1 4E
Store A into 4EA1H - save current entry offset (self-modifying code).
4EB5
ADD 1FH C6 1F
ADD 1FH (31) to A - calculate offset to end of this entry.
4EB7
LD L,A 6F
Load Register L with A. Point to end of entry.
4EB8
LD A,(4FB8H) 3A B8 4F
Load Register A with the operation mode flag from 4FB8H.
4EBB
OR A B7
OR Register A with itself. Test FREE (00H) vs PURGE (01H) mode.
4EBC
If NZ FLAG (PURGE mode), LOOP BACK to 4E9EH to continue scanning.
4EBE
DEC A 3D
DECrement A. A becomes FFH.
4EBF
LD (HL),A 77
Store FFH at (HL) - mark end of entry with FFH.
4EC0
DEC HL 2B
DECrement HL.
4EC1
LD (HL),A 77
Store FFH at (HL-1).
4EC2
JUMP back to 4E9FH to continue processing.

4EC5H - Process Extent Information

This section processes the extent information for a directory entry, updating the bitmap for each allocated granule.

4EC5
LD E,(HL) 5E
Load Register E with the byte at (HL) - the extent/granule information.
4EC6
LD A,B 78
Load Register A with B (high byte of counter).
4EC7
OR C B1
OR Register A with C. Test if BC is zero (no more entries to process).
4EC8
If Z FLAG (BC=0, done processing), JUMP to 4EFFH.
4ECA
PUSH DE D5
Save DE onto the stack.
4ECB
PUSH HL E5
Save HL onto the stack.
4ECC
LD D,(HL) 56
Load Register D with (HL) - copy of extent info.
4ECD
DEC (HL) 35
DECrement the value at (HL).
4ECE
DEC HL 2B
DECrement HL to point to previous byte.
4ECF
LD E,(HL) 5E
Load Register E with (HL) - the granule number.
4ED0
DEC E 1D
DECrement Register E (adjust granule number).
4ED1
PUSH BC C5
Save BC onto the stack.
4ED2
LD A,D 7A
Load Register A with D (extent info byte).
4ED3
AND 1FHAND 00011111 E6 1F
Mask off upper bits, keeping sector count (bits 0-4).
4ED5
LD B,A 47
Copy sector count to Register B.
4ED6
PUSH AF F5
Save AF onto the stack.
4ED7
LD A,D 7A
Reload Register A with D.
4ED8
RLCA 07
Rotate A left (bit 7 to bit 0, bit 7 to CARRY).
4ED9
RLCA 07
Rotate A left again.
4EDA
RLCA 07
Rotate A left again. Upper 3 bits now in lower 3 positions.
4EDB
AND 07HAND 00000111 E6 07
Mask off all but lower 3 bits (granule count MSB).
4EDD
ADD A,B 80
ADD sector count to get total sectors.
4EDE
LD B,(IY+05H) FD 46 05
Load Register B with (IY+05H) - sectors per granule from system parameters.

[LOOP - CALCULATE GRANULE NUMBER] Divide total sectors by sectors-per-granule to find granule offset.

4EE1
INC E 1C
INCrement Register E (granule number).
4EE2
SUB B 90
SUBtract sectors-per-granule from A.
4EE3
If NO CARRY (more granules to count), LOOP BACK to 4EE1H.
4EE5
ADD A,B 80
ADD B back to A (undo last subtraction - get remainder).
4EE6
LD B,A 47
Store remainder in B.
4EE7
LD A,7FH 3E 7F
Load Register A with 7FH - bit mask starting value (01111111).
4EE9
LD D,00H 16 00
Load Register D with 00H - clear high byte of offset.

[LOOP - CREATE BIT MASK] Rotate the bit mask to mark the correct bit position.

4EEB
INC B 04
INCrement B (bit position counter).
4EEC
RLCA 07
Rotate A left. Shift the mask bit.
4EED
DECrement B and LOOP BACK if not zero. Creates the correct bit mask.
4EEF
LD HL,4D00H 21 00 4D
Point HL to 4D00H - the start of the granule allocation bitmap.
4EF2
ADD HL,DE 19
ADD DE to HL. Point to the correct byte in the bitmap.
4EF3
AND (HL) A6
AND the bitmap byte with the mask - clear the bit for this granule (mark as allocated).
4EF4
LD (HL),A 77
Store the result back into the bitmap.
4EF5
POP AF F1
Restore AF from the stack.
4EF6
POP BC C1
Restore BC from the stack.
4EF7
POP HL E1
Restore HL from the stack.
4EF8
POP DE D1
Restore DE from the stack.
4EF9
INC BC 03
INCrement BC (entry counter).
4EFA
If NZ FLAG (more entries), LOOP BACK to 4EC6H.
4EFC
LD (HL),E 73
Store E at (HL).
4EFD
JUMP to 4EB9H to continue processing.

4EFFH - Check Operation Mode and Continue

This section checks the operation mode and either writes results (PURGE) or continues scanning (FREE).

4EFF
LD A,(4FB8H) 3A B8 4F
Load Register A with the operation mode from 4FB8H.
4F02
OR A B7
OR Register A with itself. Test FREE vs PURGE mode.
4F03
If Z FLAG (FREE mode), JUMP to 4F0AH.
4F05
GOSUB to 4FC2H to process directory entry for PURGE.
4F08
JUMP to 4F0DH to finalize.
4F0A
GOSUB to 4E5FH to write directory sector for FREE mode.

4F0DH - Finalize and Display Results

This section finalizes the operation, counts free granules, and displays results.

4F0D
GOSUB to 4F5AH to display results or close files.
4F10
LD HL,4D00H 21 00 4D
Point HL to 4D00H - the granule allocation bitmap.
4F13
LD B,C0H 06 C0
Load Register B with C0H (192) - bitmap size in bytes.

[LOOP - COUNT FREE GRANULES] Scan bitmap to find all bytes that are still FFH (all granules free).

4F15
LD A,(HL) 7E
Load Register A with (HL) - current bitmap byte.
4F16
INC A 3C
INCrement A. If byte was FFH, A becomes 00H and Z FLAG is set.
4F17
INC HL 23
INCrement HL to next bitmap byte.
4F18
If NZ FLAG (byte was not FFH, some granules allocated), JUMP to 4F1EH.
4F1A
DECrement B and LOOP BACK if not zero. Continue scanning.
4F1C
JUMP to 4F33H - all granules were FFH (disk is empty or error).

4F1EH - Read and Merge Allocation Bitmap

When non-free granules are found, this code reads the disk's actual allocation bitmap and merges it with the computed bitmap.

4F1E
XOR A AF
XOR Register A with itself, setting A to 00H.
4F1F
GOSUB to SYS0 routine at 48AFH to read the allocation bitmap from disk.
4F22
RET NZ C0
If NZ FLAG (read error), RETURN with error code.
4F23
LD DE,4D00H 11 00 4D
Point DE to 4D00H - our computed bitmap.
4F26
LD B,C0H 06 C0
Load Register B with C0H - bitmap size.

[LOOP - MERGE BITMAPS] AND each byte of the disk bitmap with our computed bitmap.

4F28
LD A,(DE) 1A
Load Register A with byte from our computed bitmap.
4F29
AND (HL) A6
AND with byte from disk bitmap. Result shows granules free in both.
4F2A
LD (HL),A 77
Store merged result back into disk bitmap buffer.
4F2B
INC DE 13
INCrement DE to next byte in computed bitmap.
4F2C
INC HL 23
INCrement HL to next byte in disk bitmap.
4F2D
DECrement B and LOOP BACK if not zero.
4F2F
GOSUB to 4E5FH to write the merged bitmap to disk.
4F32
EX DE,HL EB
Exchange DE and HL.

4F33H - Count and Display Free Granules

This section scans the extra area (4DC0H-4DDFH) and counts/displays the number of free granules.

4F33
LD B,20H 06 20
Load Register B with 20H (32) - size of the extra tracking area.

[LOOP - SCAN EXTRA AREA] Check if any bytes in the extra area are non-zero.

4F35
LD A,(HL) 7E
Load Register A with (HL) - byte from extra area.
4F36
OR A B7
OR Register A with itself. Test if zero.
4F37
INC HL 23
INCrement HL to next byte.
4F38
If NZ FLAG (byte is non-zero), JUMP to 4F3DH to process.
4F3A
DECrement B and LOOP BACK if not zero.
4F3C
RET C9
RETURN - extra area was all zeros, done.

4F3DH - Process Free Granule List

When non-zero entries are found in the extra area, process and display the free granule information.

4F3D
LD A,01H 3E 01
Load Register A with 01H - sector number to read.
4F3F
GOSUB to 48AFH to read the sector.
4F42
RET NZ C0
If NZ FLAG (read error), RETURN with error.
4F43
LD DE,4DBFH 11 BF 4D
Point DE to 4DBFH - the bit position lookup table.
4F46
LD C,20H 0E 20
Load Register C with 20H (32) - number of entries to process.

[OUTER LOOP] Process each byte in the tracking area.

4F48
INC DE 13
INCrement DE to next lookup entry.
4F49
LD B,08H 06 08
Load Register B with 08H - 8 bits per byte.

[INNER LOOP] Check each bit in the current byte.

4F4B
LD A,(DE) 1A
Load Register A with (DE) - the bitmap byte.
4F4C
RLCA 07
Rotate A left. High bit goes to CARRY.
4F4D
If NO CARRY (bit was 0 = allocated), JUMP to 4F51H.
4F4F
LD (HL),00H 36 00
Store 00H at (HL) - mark as cleared/processed.
4F51
INC HL 23
INCrement HL to next output position.
4F52
DECrement B and LOOP BACK for remaining bits.
4F54
DEC C 0D
DECrement C (byte counter).
4F55
If NZ FLAG (more bytes), LOOP BACK to 4F48H.
4F57
JUMP to 4E5FH to write results and return.

4F5AH - Display Results or Skip

This section checks system flags and either displays the FREE results or returns if output is suppressed.

4F5A
LD A,(428BH) 3A 8B 42
Load Register A with the system flags byte at 428BH.
4F5D
BIT 2,A CB 57
Test bit 2 of the flags. This bit controls display suppression.
4F5F
If bit 2 is set (suppress output), JUMP to 4FC0H to skip display.
4F61
LD A,(IX+07H) DD 7E 07
Load Register A with FCB+07H - the drive number.
4F64
GOSUB to 4E5AH to display the drive number.
4F67
EX DE,HL EB
Exchange DE and HL.
4F68
PUSH IX DD E5
Save IX onto the stack.
4F6A
POP HL E1
Pop into HL. HL now contains the FCB address.
4F6B
LD B,08H 06 08
Load Register B with 08H - filename is 8 characters.
4F6D
PUSH HL E5
Save HL (FCB address) onto the stack.
4F6E
INC DE 13
INCrement DE (skip status byte).
4F6F
INC DE 13
INCrement DE again.
4F70
INC DE 13
INCrement DE again.
4F71
INC DE 13
INCrement DE again.
4F72
INC DE 13
INCrement DE. DE now points to filename in directory entry (offset +5).

[LOOP - COPY FILENAME] Copy filename from directory entry to display buffer.

4F73
LD A,(DE) 1A
Load Register A with character from directory entry filename.
4F74
CP 20H FE 20
Compare against 20H (space). Filenames are padded with spaces.
4F76
If Z FLAG (space = end of name), JUMP to 4F7AH.
4F78
LD (HL),A 77
Store character at (HL) in output buffer.
4F79
INC HL 23
INCrement HL to next output position.
4F7A
DECrement B and LOOP BACK for remaining characters.
4F7C
INC DE 13
INCrement DE to extension field.
4F7D
LD A,(DE) 1A
Load first extension character.
4F7E
CP 20H FE 20
Compare against space.
4F80
If Z FLAG (no extension), JUMP to 4F91H.
4F82
LD (HL),2FH 36 2F
Store 2FH (/) as separator character.
4F84
LD B,03H 06 03
Load B with 03H - extension is 3 characters.

[LOOP - COPY EXTENSION]

4F86
INC HL 23
INCrement HL.
4F87
LD A,(DE) 1A
Load extension character.
4F88
CP 20H FE 20
Compare against space.
4F89
INC DE 13
INCrement DE.
4F8A
If space, JUMP to 4F91H.
4F8C
LD (HL),A 77
Store character.
4F8E
INC HL 23
INCrement HL.
4F8F
LOOP for remaining extension chars.
4F91
LD (HL),3AH 36 3A
Store 3AH (:) as drive separator.
4F93
INC HL 23
INCrement HL.
4F94
LD A,(427EH) 3A 7E 42
Load Register A with the drive number from 427EH.
4F97
LD BC,0264H 01 64 02
Load BC with 0264H (B=02H, C=64H=100 decimal) for decimal conversion.
4F9A
LD D,2FH 16 2F
Load D with 2FH (/ character minus 1).

[LOOP - DECIMAL CONVERSION] Convert drive number to ASCII decimal digits.

4F9C
INC D 14
INCrement D (digit counter, starts at 0).
4F9D
SUB C 91
SUBtract divisor from A.
4F9E
If NO CARRY, LOOP BACK - count another digit.
4FA0
ADD A,C 81
ADD C back to A (undo last subtraction).
4FA1
LD E,A 5F
Save remainder in E.
4FA2
LD A,D 7A
Load digit character into A.
4FA3
CP 30H FE 30
Compare against 0. Check for leading zero.
4FA5
If Z FLAG (leading zero), skip storing it.
4FA7
LD (HL),A 77
Store digit character.
4FA8
INC HL 23
INCrement HL.
4FA9
LD A,E 7B
Restore remainder.
4FAA
LD C,0AH 0E 0A
Load C with 0AH (10) for next digit.
4FAC
DECrement B and LOOP BACK for remaining digits.
4FAE
ADD 30H C6 30
ADD 30H to convert last digit to ASCII.
4FB0
LD (HL),A 77
Store final digit.
4FB1
INC HL 23
INCrement HL.
4FB2
LD (HL),03H 36 03
Store 03H (end-of-text marker).
4FB4
POP HL E1
Restore HL (FCB address).
4FB5
LD B,20H 06 20
Load B with 20H (32) - clear 32 bytes.
4FB7
LD A,00H 3E 00
Load Register A with 00H. Note: Address 4FB8H is the operation mode flag storage.

4FB8H - Operation Mode Flag and Clear Loop

4FB8H contains the operation mode flag (00H=FREE, 01H=PURGE). The loop clears the FCB area.

4FB8
LD A,00H 3E 00
Load Register A with 00H. This byte at 4FB8H is modified to store the mode flag.
4FBA
DEC A 3D
DECrement A. If mode was 00H, A becomes FFH; if 01H, A becomes 00H.
4FBB
If NZ FLAG (was not PURGE mode), JUMP to 4FC0H to return.

[LOOP - CLEAR FCB] Clear the FCB area.

4FBC
LD (HL),A 77
Store A (00H) at (HL).
4FBD
INC HL 23
INCrement HL.
4FBE
DECrement B and LOOP BACK if not zero.
4FC0
XOR A AF
XOR Register A with itself - return success (A=0, Z FLAG).
4FC1
RET C9
RETURN to caller.

4FC2H - Process Directory Entry for Bitmap

This subroutine processes a directory entry and updates the tracking area for granule allocation.

4FC2
LD A,(4EA1H) 3A A1 4E
Load Register A with the saved directory entry offset from 4EA1H.
4FC5
LD L,A 6F
Load Register L with A. Point to start of entry.
4FC6
RES 4,(HL) CB A6
RESset bit 4 of the entry status byte - mark entry as processed.
4FC8
LD E,D 5A
Copy D to E.
4FC9
INC HL 23
INCrement HL.
4FCA
LD D,(HL) 56
Load D with next byte.
4FCB
GOSUB to 4E5FH to write the directory sector.
4FCE
LD A,E 7B
Load A with E.
4FCF
RRCA 0F
Rotate A right. Divide by 2.
4FD0
RRCA 0F
Rotate A right. Divide by 4.
4FD1
RRCA 0F
Rotate A right. Divide by 8.
4FD2
AND 1FHAND 00011111 E6 1F
Mask to lower 5 bits (byte offset in tracking area).
4FD4
PUSH BC C5
Save BC.
4FD5
LD HL,4DC0H 21 C0 4D
Point HL to 4DC0H - the tracking area.
4FD8
LD C,A 4F
Copy offset to C.
4FD9
LD B,00H 06 00
Clear B.
4FDB
ADD HL,BC 09
ADD BC to HL. Point to correct byte in tracking area.
4FDC
LD A,E 7B
Reload A with E.
4FDD
AND 07HAND 00000111 E6 07
Mask to lower 3 bits (bit position within byte).
4FDF
LD B,A 47
Copy to B.
4FE0
LD A,01H 3E 01
Load A with 01H - initial bit mask.
4FE2
INC B 04
INCrement B (adjust for loop).

[LOOP - CREATE BIT MASK]

4FE3
RRCA 0F
Rotate A right. Shift bit mask.
4FE4
DECrement B and LOOP BACK if not zero.
4FE6
OR (HL) B6
OR with current tracking byte - set the bit.
4FE7
LD (HL),A 77
Store result back.
4FE8
POP BC C1
Restore BC.
4FE9
RET C9
RETURN.

4FEAH - Open Directory File

This routine sets up and opens the directory file for reading during FREE/PURGE operations.

4FEA
LD HL,E507H 21 07 E5
Load HL with E507H - a parameter for the directory open call.
4FED
PUSH HL E5
Save HL onto the stack.
4FEE
LD HL,497CH 21 7C 49
Load HL with 497CH - return address for SYS0 routine.
4FF1
PUSH HL E5
Save return address onto the stack.
4FF2
JUMP to SYS0 routine at 4A07H to open the directory file.

4FF5H - Sub-function E5H/C=7: File Position/EOF Update

This sub-function updates the file position or EOF marker in an FCB. It validates the file is open and accessible, then modifies the current position and extent information.

4FF5
GOSUB to SYS0 routine at 48F0H to validate the FCB and check if file is open.
4FF8
If NZ FLAG (validation failed), JUMP to 4E56H to report the error.
4FFB
LD A,(IX+01H) DD 7E 01
Load Register A with FCB+01H - the file flags byte.
4FFE
AND 07HAND 00000111 E6 07
Mask off upper bits, keeping only file type (bits 0-2).
5000
CP 05H FE 05
Compare against 05H. File types 0-4 are valid.
5002
RET NC D0
If NO CARRY (file type >= 5), RETURN without modifying - invalid file type.
5003
LD E,(IX+0CH) DD 5E 0C
Load Register E with FCB+0CH - low byte of current record number.
5006
LD D,(IX+0DH) DD 56 0D
Load Register D with FCB+0DH - high byte of current record number.
5009
LD A,(IX+08H) DD 7E 08
Load Register A with FCB+08H - EOF sector within last granule.
500C
OR A B7
OR Register A with itself. Test if EOF sector is zero.
500D
If Z FLAG (EOF sector = 0), JUMP to 5010H.
500F
INC DE 13
INCrement DE (adjust record number for non-zero EOF sector).
5010
PUSH HL E5
Save HL (points to buffer) onto the stack.
5011
INC L 2C
INCrement L (move to next byte in buffer).
5012
INC L 2C
INCrement L again.
5013
INC L 2C
INCrement L. HL now points to offset +3 in buffer.
5014
LD C,(HL) 4E
Load Register C with the byte at (HL) - old sector value.
5015
LD (HL),A 77
Store A (new sector value) at (HL).
5016
SUB C 91
SUBtract old sector value from new. Result shows change.
5017
LD BC,0011H 01 11 00
Load BC with 0011H (17 decimal) - offset to record number field.
501A
ADD HL,BC 09
ADD BC to HL. Point to record number field in buffer.
501B
LD C,(HL) 4E
Load C with low byte of old record number.
501C
INC HL 23
INCrement HL.
501D
LD B,(HL) 46
Load B with high byte of old record number.
501E
LD (HL),D 72
Store new high byte at (HL).
501F
DEC HL 2B
DECrement HL.
5020
LD (HL),E 73
Store new low byte at (HL). Record number is now updated.
5021
If NZ FLAG (sector value changed), JUMP to 5027H.
5023
LD H,D 62
Copy D to H.
5024
LD L,E 6B
Copy E to L. HL = DE (new record number).
5025
SBC HL,BC ED 42
Subtract old record number from new. Check if position changed.
5027
If NZ FLAG (position changed), GOSUB to 4E5FH to write the directory.
502A
POP HL E1
Restore HL from the stack.
502B
SCF 37
Set the CARRY FLAG to indicate success.
502C
RET C9
RETURN to caller with CARRY set.

502DH - File Access Check (Function C5H)

This function checks if a file can be accessed. It validates the filespec and checks file attributes and access permissions.

502D
GOSUB to SYS0 routine at 4925H to parse the filespec from the command line.
5030
GOSUB to 4FEAH to open the directory and find the file.
5033
If CARRY is set (file found and accessible), JUMP to 4FC0H to return success.
5036
LD A,25H 3E 25
Load Register A with 25H (error code 37 = "access denied").
5038
OR A B7
OR Register A with itself. Sets NZ FLAG to indicate error.
5039
RET C9
RETURN with error code 25H and NZ FLAG.

503AH - Sub-function E5H/C=6: KILL Command Handler

The KILL command deletes files matching a filespec, with optional user confirmation. It supports wildcards and can filter by extension using the /ext syntax, and by system file status using USR keyword.

503A
LD A,B 78
Load Register A with B (parameter from caller).
503B
LD C,00H 0E 00
Load Register C with 00H - initialize options flags (no options set).
503D
GOSUB to SYS0 routine at 4791H to set up drive parameters.
5040
RET NZ C0
If NZ FLAG (setup error), RETURN immediately.

[COMMAND PARSING LOOP] Parse the command line for filespec and options.

5041
GOSUB to SYS0 routine at 4C7AH to skip whitespace and get next character.
5044
RET C D8
If CARRY is set (error in parsing), RETURN.
5045
If Z FLAG (end of command line), JUMP to 5081H to execute KILL with parsed options.
5047
LD A,(HL) 7E
Load Register A with the character at (HL).
5048
CP 2FH FE 2F
Compare against 2FH (ASCII /). Check for extension filter option.
504A
If NZ FLAG (not a slash), JUMP to 5069H to check for other options.
504C
SET 0,C CB C1
SET bit 0 of Register C - flag indicating extension filter is specified.
504E
INC HL 23
INCrement HL to skip the slash.
504F
LD DE,5140H 11 40 51
Point DE to 5140H - the extension filter buffer.
5052
LD B,03H 06 03
Load Register B with 03H - maximum 3 characters in extension.

[LOOP - PARSE EXTENSION] Copy up to 3 characters of the extension filter.

5054
LD A,(HL) 7E
Load Register A with current character.
5055
SUB 30H D6 30
SUBtract 30H (ASCII 0). Test if it's a digit 0-9.
5057
CP 0AH FE 0A
Compare against 0AH. If < 0AH, it was a digit.
5059
If CARRY (was a digit), JUMP to 5061H to accept it.
505B
SUB 11H D6 11
SUBtract 11H more. Now testing for letters A-Z.
505D
CP 1AH FE 1A
Compare against 1AH (26). If < 26, it was a letter.
505F
If NO CARRY (not a letter or digit), JUMP back to 5041H - end of extension.
5061
INC DE 13
INCrement DE (extension buffer pointer).
5062
LD A,(HL) 7E
Reload the original character from (HL).
5063
LD (DE),A 12
Store character into extension buffer.
5064
INC HL 23
INCrement HL to next character.
5065
DECrement B and LOOP BACK for remaining extension characters.
5067
JUMP back to 5041H to continue parsing.

5069H - Parse USR Option

Check for the USR keyword option which includes system files in the KILL operation.

5069
CP 55H FE 55
Compare Register A against 55H (ASCII U). First letter of "USR".
506B
If NZ FLAG (not U), JUMP back to 5041H to continue parsing.
506D
LD D,H 54
Copy H to D.
506E
LD E,L 5D
Copy L to E. DE = HL (save current position).
506F
INC DE 13
INCrement DE to next character.
5070
LD A,(DE) 1A
Load Register A with character at (DE).
5071
CP 53H FE 53
Compare against 53H (ASCII S). Second letter of "USR".
5073
INC DE 13
INCrement DE.
5074
If NZ FLAG (not S), JUMP back - not "USR".
5076
LD A,(DE) 1A
Load next character.
5077
CP 52H FE 52
Compare against 52H (ASCII R). Third letter of "USR".
5079
INC DE 13
INCrement DE.
507A
If NZ FLAG (not R), JUMP back - not "USR".
507C
SET 1,C CB C9
SET bit 1 of Register C - flag indicating USR option is active (include system files).
507E
EX DE,HL EB
Exchange DE and HL. Update HL to position after "USR".
507F
JUMP back to 5041H to continue parsing.

5081H - Execute KILL Command

After parsing is complete, this section executes the KILL command by scanning the directory for matching files and prompting for confirmation.

5081
LD A,C 79
Load Register A with C (the accumulated options flags).
5082
LD (5140H),A 32 40 51
Store the options flags at 5140H for later reference.
5085
LD A,01H 3E 01
Load Register A with 01H - sector number to read.
5087
GOSUB to SYS0 routine at 48AFH to read the directory sector.
508A
RET NZ C0
If NZ FLAG (read error), RETURN with error.
508B
LD A,(431FH) 3A 1F 43
Load Register A with the value at 431FH (system parameter - last sector number).
508E
ADD 08H C6 08
ADD 08H to A. Calculate end sector number for directory scan.
5090
LD (5130H),A 32 30 51
Store result at 5130H - this is the comparison value for end-of-directory check.
5093
XOR A AF
XOR Register A with itself, clearing A to 00H.
5094
LD C,A 4F
Load Register C with A - initialize directory entry counter to 0.
5095
GOSUB to SYS0 routine at 48DBH to get the next directory entry.
5098
RET NZ C0
If NZ FLAG (error or end of directory), RETURN.

[DIRECTORY ENTRY CHECK] Examine each directory entry to see if it matches the KILL criteria.

5099
LD A,(HL) 7E
Load Register A with the first byte of the directory entry (status byte).
509A
AND 90H E6 90
Mask to keep only bits 7 and 4 (90H). Bit 4 = active entry.
509C
CP 10H FE 10
Compare against 10H. If status = 10H, it's an active file entry.
509E
If NZ FLAG (not an active entry), JUMP to 5124H to skip this entry.
50A1
LD A,(HL) 7E
Reload the status byte.
50A2
AND 48HAND 01001000 E6 48
Mask to check bits 6 and 3 (48H). These indicate system/protected files.
50A4
LD DE,5140H 11 40 51
Point DE to 5140H - the options flags and extension filter.
50A7
LD A,(DE) 1A
Load Register A with the options flags.
50A8
If Z FLAG (file is not protected), JUMP to 50AEH to continue.
50AA
BIT 1,A CB 4F
Test bit 1 of options (USR flag). Check if system files should be included.
50AC
If NZ FLAG (USR not set and file is protected), JUMP to 5124H to skip this file.
50AE
BIT 0,A CB 47
Test bit 0 of options (extension filter flag).
50B0
If Z FLAG (no extension filter), JUMP to 50C4H to proceed with KILL.
50B2
PUSH HL E5
Save HL (directory entry pointer) onto the stack.
50B3
LD A,L 7D
Load Register A with L (entry offset in buffer).
50B4
ADD 0DH C6 0D
ADD 0DH (13) to A - offset to extension field in directory entry.
50B6
LD L,A 6F
Load L with A. HL now points to the extension.
50B7
LD B,03H 06 03
Load B with 03H - extension is 3 characters.

[LOOP - COMPARE EXTENSION] Compare file extension with filter.

50B9
INC DE 13
INCrement DE (filter buffer pointer).
50BA
LD A,(DE) 1A
Load filter character.
50BB
CP (HL) BE
Compare with file's extension character.
50BC
INC HL 23
INCrement HL.
50BD
If NZ FLAG (mismatch), JUMP to 50C1H.
50BF
DECrement B and LOOP BACK for remaining characters.
50C1
POP HL E1
Restore HL (directory entry pointer).
50C2
If NZ FLAG (extension didn't match), JUMP to 5124H to skip this file.

50C4H - Prompt for KILL Confirmation

After finding a matching file, prompt the user for confirmation before deleting.

50C4
LD A,C 79
Load Register A with C (current sector counter).
50C5
CP 02H FE 02
Compare against 02H. Check if we're past sector 2.
50C7
LD A,L 7D
Load Register A with L (entry offset).
50C8
If NO CARRY (sector >= 2), JUMP to 50CDH.
50CA
OR A B7
OR Register A with itself. Check if entry offset is 0.
50CB
If Z FLAG (first entry of first sector = BOOT/SYS), JUMP to 5124H to skip (never delete BOOT).
50CD
ADD A,C 81
ADD C (sector) to A (offset). Calculate unique entry identifier.
50CE
LD (4487H),A 32 87 44
Store at 4487H - save current entry identifier for deletion.
50D1
PUSH HL E5
Save HL onto the stack.
50D2
LD A,L 7D
Load Register A with L.
50D3
ADD 05H C6 05
ADD 05H - offset to filename in directory entry.
50D5
LD L,A 6F
Update L. HL now points to filename.
50D6
LD B,08H 06 08
Load B with 08H - filename is 8 characters.
50D8
GOSUB to 5136H to display the filename (8 chars).
50DB
LD A,(HL) 7E
Load Register A with first extension character.
50DC
CP 20H FE 20
Compare against 20H (space). Check if extension exists.
50DE
If Z FLAG (no extension), JUMP to 50EAH.
50E0
LD A,2FH 3E 2F
Load A with 2FH (ASCII /) - extension separator.
50E2
GOSUB to ROM routine at 0033H to display the slash character.
50E5
LD B,03H 06 03
Load B with 03H - extension is 3 characters.
50E7
GOSUB to 5136H to display the extension.
50EA
LD HL,5144H 21 44 51
Point HL to 5144H - the " KILL IT? (Y/N/Q) " prompt string.
50ED
GOSUB to SYS0 routine at 4467H to display the prompt string.

[KEYBOARD INPUT LOOP] Wait for user to press Y, N, or Q.

50F0
GOSUB to ROM routine at 0049H to scan the keyboard and get a keypress.
50F3
RES 5,A CB AF
RESset bit 5 of A - convert lowercase to uppercase.
50F5
CP 51H FE 51
Compare against 51H (ASCII Q). Check for Quit.
50F7
If Z FLAG (Q pressed), JUMP to 5101H to process.
50F9
CP 4EH FE 4E
Compare against 4EH (ASCII N). Check for No.
50FB
If Z FLAG (N pressed), JUMP to 5101H to process.
50FD
CP 59H FE 59
Compare against 59H (ASCII Y). Check for Yes.
50FF
If NZ FLAG (not Y, N, or Q), LOOP BACK to 50F0H to wait for valid key.
5101
PUSH AF F5
Save AF (the key pressed) onto the stack.
5102
GOSUB to 0033H to echo the character to the screen.
5105
LD A,0DH 3E 0D
Load A with 0DH (carriage return).
5107
GOSUB to 0033H to output the carriage return (move to next line).
510A
POP AF F1
Restore AF (the key pressed).
510B
POP HL E1
Restore HL (directory entry pointer).
510C
CP 51H FE 51
Compare against Q. Check if user wants to quit.
510E
RET Z C8
If Z FLAG (Q pressed), RETURN immediately - abort KILL operation.
510F
CP 4EH FE 4E
Compare against N. Check if user said No.
5111
If Z FLAG (N pressed), JUMP to 5124H to skip this file and continue.

[DELETE FILE] User pressed Y - proceed with deletion.

5113
LD DE,4480H 11 80 44
Point DE to 4480H - the FCB template/buffer.
5116
LD A,80H 3E 80
Load A with 80H - file open flag.
5118
LD (DE),A 12
Store 80H at FCB - mark file as "open" for deletion.
5119
GOSUB to 4DF4H to perform the actual file deletion (PURGE routine).
511C
RET NZ C0
If NZ FLAG (deletion error), RETURN with error.
511D
PUSH HL E5
Save HL onto the stack.
511E
LD A,C 79
Load Register A with C (sector counter).
511F
GOSUB to 48DBH to get the next directory entry.
5122
POP HL E1
Restore HL.
5123
RET NZ C0
If NZ FLAG (error), RETURN.

5124H - Next Directory Entry

Advance to the next directory entry and continue the KILL scan.

5124
LD A,L 7D
Load Register A with L (current entry offset).
5125
AND 0E0HAND 11100000 E6 E0
Mask to E0H - get base of current entry (entries are 32 bytes).
5127
ADD 20H C6 20
ADD 20H (32) - advance to next entry.
5129
LD L,A 6F
Update L with new offset.
512A
If NO CARRY (still within current sector), JUMP to 5099H to process next entry.
512D
INC C 0C
INCrement C (sector counter) - move to next sector.
512E
LD A,C 79
Load A with C.
512F
CP 00H FE 00
Compare against 00H. Note: Address 5130H contains the end-sector limit stored earlier.
5131
If CARRY (more sectors to scan), JUMP to 5094H to read next sector.
5134
XOR A AF
XOR Register A with itself - return success (no more files).
5135
RET C9
RETURN with success.

5136H - Display Characters Subroutine

This subroutine displays B characters from the buffer pointed to by HL, skipping spaces.

5136
LD A,(HL) 7E
Load Register A with the character at (HL).
5137
CP 20H FE 20
Compare against 20H (ASCII space). If character is a space, Z FLAG is set.
5139
INC HL 23
INCrement HL to point to the next character.
513A
If NZ FLAG (character is not a space), GOSUB to ROM routine at 0033H to display the character.
513D
DECrement B and LOOP BACK to 5136H if not zero. Continue for remaining characters.
513F
RET C9
RETURN to caller.

5140H - Data Area: Options and Prompt String

This area contains the KILL command options flags, extension filter buffer, and the user prompt string. The bytes at 5140H-5143H are used as working storage during KILL operations. The string at 5144H-515EH is the " KILL IT? (Y/N/Q) " prompt displayed to the user.

5140
NOP 00
Options flags storage byte (bit 0: extension filter active, bit 1: USR mode active).
5141
JR NZ,5163H 20 20
Extension filter buffer byte 1 (initialized to spaces 20H 20H). Disassembles as JR NZ but is actually data.
5143
JR NZ,5165H 20 20
Extension filter buffer byte 2-3 (spaces). Disassembles as JR NZ but is actually data.
5145
JR NZ,5167H 20 20
Prompt string starts here: two spaces (20H 20H).
5147
JR NZ,5169H 20 20
Prompt string continues: two spaces.
5149
JR NZ,516BH 20 20
Prompt string continues: two spaces.
514B
JR NZ,5198H 20 4B
Prompt string: space (20H) and K (4BH).
514D
LD C,C 49
Prompt string: I (49H).
514E
LD C,H 4C
Prompt string: L (4CH).
514F
LD C,H 4C
Prompt string: L (4CH).
5150
JR NZ,519BH 20 49
Prompt string: space (20H) and I (49H).
5152
LD D,H 54
Prompt string: T (54H).
5153
CCF 3F
Prompt string: ? (3FH).
5154
JR NZ,517EH 20 28
Prompt string: space (20H) and ( (28H).
5156
LD E,C 59
Prompt string: Y (59H).
5157
CPL 2F
Prompt string: / (2FH).
5158
LD C,(HL) 4E
Prompt string: N (4EH).
5159
CPL 2F
Prompt string: / (2FH).
515A
LD D,C 51
Prompt string: Q (51H).
515B
ADD HL,HL 29
Prompt string: ) (29H).
515C
JR NZ,517EH 20 20
Prompt string: two spaces (20H 20H).
515E
INC BC 03
End-of-string marker (03H = ETX).

515FH - DEBUG/DUMP Memory Display (Function A5H)

This routine displays the contents of memory on the screen, starting at video RAM (3C00H) or RAM (4000H) depending on the BREAK key state. Non-printable characters are replaced with periods. The display continues until the entire region is shown.

515F
LD HL,3C00H 21 00 3C
Point HL to 3C00H - the start of video RAM.
5162
LD A,(3840H) 3A 40 38
Load Register A with the value at 3840H - the keyboard row containing the BREAK key.
5165
AND 04HAND 00000100 E6 04
Mask with 04H to isolate bit 2 (BREAK key). If BREAK is pressed, bit 2 is clear.
5167
If Z FLAG is set (BREAK not pressed), JUMP to 516EH to continue with current address.
5169
LD HL,4000H 21 00 40
Point HL to 4000H - the start of user RAM (BREAK was pressed to select RAM instead of video).
516C
JUMP back to 5162H to re-check BREAK key (allows toggling between video and RAM display).

[DISPLAY LOOP] Main loop to display memory contents character by character.

516E
LD A,L 7D
Load Register A with L (low byte of address).
516F
AND 3FHAND 00111111 E6 3F
Mask with 3FH (63). Check if we're at a 64-byte boundary (start of line).
5171
LD A,0DH 3E 0D
Load A with 0DH (carriage return).
5173
If Z FLAG is set (at line boundary), GOSUB to ROM routine at 003BH to output carriage return.
5176
LD A,H 7C
Load Register A with H (high byte of address).
5177
AND 3FHAND 00111111 E6 3F
Mask with 3FH. Check if we've wrapped past the display region.
5179
RET Z C8
If Z FLAG is set (completed display region), RETURN to caller.
517A
LD A,(HL) 7E
Load Register A with the byte at (HL) - the memory content to display.
517B
CP 20H FE 20
Compare against 20H (space). Check if character is printable (>= 20H).
517D
INC HL 23
INCrement HL to point to the next memory location.
517E
If CARRY is set (character < 20H, non-printable), JUMP to 5188H to substitute a period.
5180
LD B,A 47
Copy the character to Register B for safekeeping.
5181
LD A,(4290H) 3A 90 42
Load Register A with the upper display limit from 4290H.
5184
CP B B8
Compare upper limit against the character. Check if character exceeds printable range.
5185
LD A,B 78
Restore the character from B back to A.
5186
If NO CARRY (character within printable range), JUMP to 518AH to display it.
5188
LD A,2EH 3E 2E
Load A with 2EH (ASCII . period) - substitute for non-printable characters.
518A
GOSUB to ROM routine at 003BH to display the character in A.
518D
JUMP back to 5162H to continue displaying the next character.

518FH-51DFH Unused Area (NOP Padding)