5200H - Command Dispatcher
Entry point for all SYS6 library commands. Register C contains the 1-based command index from SYS1's overlay command table at 4EBDH. The no-error exit address 402DH is pushed onto the stack so handlers can return to DOS READY via RET. Register A is then decremented once per command until it reaches zero, at which point execution jumps to the matching handler.
5200
LD A,C 79
Load Register A with the command index from Register C. Register C was set by SYS1 at 4E90H before invoking SYS6 via RST 28H. The value ranges from 01H (APPEND) to 13H (VERIFY).
5201
LD BC,402DH 01 2D 40
Load Register Pair BC with 402DH, the
no-error exit address in SYS0. This value will be pushed onto the stack in the next instruction to serve as the return address for all command handlers.
5204
PUSH BC C5
Save 402DH onto the stack. When any command handler completes successfully and executes RET, control will transfer to 402DH (no-error exit / DOS READY).
5205
DEC A 3D
DECrement Register A by 1. If A was 01H (APPEND command), A is now zero and the Z FLAG is set.
5206
If the Z FLAG is set (command index was 1 = APPEND), JUMP to 5700H to execute the APPEND command handler.
5209
DEC A 3D
DECrement Register A by 1. If A was 02H (ATTRIB command), A is now zero.
520A
If the Z FLAG is set (command index was 2 = ATTRIB), JUMP to 5B00H to execute the ATTRIB command handler.
520D
DEC A 3D
DECrement Register A by 1. If A was 03H (AUTO command), A is now zero.
520E
If the Z FLAG is set (command index was 3 = AUTO), JUMP to 5283H to execute the AUTO command handler.
5211
DEC A 3D
DECrement Register A by 1. If A was 04H (CLOCK command), A is now zero.
5212
If the Z FLAG is set (command index was 4 = CLOCK), JUMP to 52C5H to execute the CLOCK command handler.
5215
DEC A 3D
DECrement Register A by 1. If A was 05H (COPY command), A is now zero.
5216
If the Z FLAG is set (command index was 5 = COPY), JUMP to 574FH to execute the COPY command handler.
5219
DEC A 3D
DECrement Register A by 1. If A was 06H (DATE command), A is now zero.
521A
If the Z FLAG is set (command index was 6 = DATE), JUMP to 529DH to execute the DATE command handler.
521D
DEC A 3D
DECrement Register A by 1. If A was 07H (DEVICE command), A is now zero.
521E
If the Z FLAG is set (command index was 7 = DEVICE), JUMP to 531DH to execute the DEVICE command handler.
5221
DEC A 3D
DECrement Register A by 1. If A was 08H (DIR command), A is now zero.
5222
If the Z FLAG is set (command index was 8 = DIR), JUMP to 5C6FH to execute the DIR command handler.
5225
DEC A 3D
DECrement Register A by 1. If A was 09H (DUMP command), A is now zero.
5226
If the Z FLAG is set (command index was 9 = DUMP), JUMP to 57D7H to execute the DUMP command handler.
5229
DEC A 3D
DECrement Register A by 1. If A was 0AH (FREE command), A is now zero.
522A
If the Z FLAG is set (command index was 10 = FREE), JUMP to 5EE0H to execute the FREE command handler.
522D
DEC A 3D
DECrement Register A by 1. If A was 0BH (KILL command), A is now zero.
522E
If the Z FLAG is set (command index was 11 = KILL), JUMP to 5914H to execute the KILL command handler.
5231
DEC A 3D
DECrement Register A by 1. If A was 0CH (LIB command), A is now zero.
5232
If the Z FLAG is set (command index was 12 = LIB), JUMP to 533AH to execute the LIB command handler.
5235
DEC A 3D
DECrement Register A by 1. If A was 0DH (LIST command), A is now zero.
5236
If the Z FLAG is set (command index was 13 = LIST), JUMP to 592CH to execute the LIST command handler.
5239
DEC A 3D
DECrement Register A by 1. If A was 0EH (LOAD command), A is now zero.
523A
If the Z FLAG is set (command index was 14 = LOAD), JUMP to 5994H to execute the LOAD command handler.
523D
DEC A 3D
DECrement Register A by 1. If A was 0FH (PRINT command), A is now zero.
523E
If the Z FLAG is set (command index was 15 = PRINT), JUMP to 59ACH to execute the PRINT command handler.
5241
DEC A 3D
DECrement Register A by 1. If A was 10H (PROT command), A is now zero.
5242
If the Z FLAG is set (command index was 16 = PROT), JUMP to 536AH to execute the PROT command handler.
5245
DEC A 3D
DECrement Register A by 1. If A was 11H (RENAME command), A is now zero.
5246
If the Z FLAG is set (command index was 17 = RENAME), JUMP to 5F9CH to execute the RENAME command handler.
5249
DEC A 3D
DECrement Register A by 1. If A was 12H (TIME command), A is now zero.
524A
If the Z FLAG is set (command index was 18 = TIME), JUMP to 52B1H to execute the TIME command handler.
524D
DEC A 3D
DECrement Register A by 1. If A was 13H (VERIFY command), A is now zero.
524E
If the Z FLAG is set (command index was 19 = VERIFY), JUMP to 5504H to execute the VERIFY command handler.
Error Path
If no command matched (Register A was decremented 19 times without reaching zero), execution falls through to the error message display below. This should not occur under normal operation since SYS1 validates the command index before calling SYS6.
5251
LD HL,525AH 21 5A 52
Point Register Pair HL to the error message string at 525AH ("RESERVED COMMAND" followed by 0DH).
5254
GOSUB to the SYS0 Display Message routine at 4467H to print the "RESERVED COMMAND" error message to the video display.
5257
JUMP to 4030H, the error-already-displayed exit in SYS0. The error message has been shown, so this exits to DOS READY without printing an additional error code.
525AH - Error Message: "RESERVED COMMAND"
ASCII string displayed when an invalid command index is passed to SYS6. Terminated by 0DH (carriage return).
525A-5269
DEFM "RESERVED COMMAND" 52 45 53 45 52 56 45 44 20 43 4F 4D 4D 41 4E 44
ASCII text: "RESERVED COMMAND"
526A
DEFB 0DH 0D
Carriage return byte, used as the string terminator by the 4467H display routine.
526BH - Error Message: "-NOTHING DONE-"
ASCII string displayed when a command has no work to perform (e.g., PROT with no options specified). This entry point is also used as a shared error handler by multiple commands. Terminated by 0DH.
526B
LD HL,5274H 21 74 52
Point Register Pair HL to the message string at 5274H ("-NOTHING DONE-" followed by 0DH).
526E
GOSUB to the SYS0 Display Message routine at 4467H to print the "-NOTHING DONE-" message to the video display.
5271
JUMP to 4030H, the error-already-displayed exit in SYS0.
5274H - Data: "-NOTHING DONE-" String
ASCII message string used by the 526BH error handler. Terminated by 0DH.
5274-5281
DEFM "-NOTHING DONE-" 2D 4E 4F 54 48 49 4E 47 20 44 4F 4E 45 2D
ASCII text: "-NOTHING DONE-"
5282
DEFB 0DH 0D
Carriage return string terminator.
5283H - AUTO Command Handler
Implements the AUTO command, which writes an auto-boot command string to a reserved area (offset 0E0H) of directory sector 0 on the system disk. When the system boots, the boot code checks this area and executes the command if present. The AUTO command takes no filespec; it writes the current command buffer contents (everything after "AUTO ") to the directory sector. Format: AUTO command-string
5283
LD C,00H 0E 00
Load Register C with 00H (drive 0, the system disk). The auto-boot command is always stored on drive 0.
5285
GOSUB to SYS0 routine at 4AF0H to read directory sector 0 from drive 0 into the 4D00H buffer. Register C holds the sector number (0).
5288
If the NZ FLAG is set (read failed), JUMP to the disk error handler at 554CH which ORs the error code with 40H and exits via 4409H.
528B
LD D,4DH 16 4D
Load Register D with 4DH, the high byte of the buffer address. This sets the destination to 4DE0H (4D00H + 0E0H offset).
528D
LD E,0E0H 1E E0
Load Register E with 0E0H, the low byte of the destination address. Register Pair DE now points to 4DE0H, the auto-boot command area within the directory sector buffer.
528F
LD BC,0020H 01 20 00
Load Register Pair BC with 0020H (32 decimal), the number of bytes to copy. The auto-boot command area is 32 bytes long.
5292
LDIR ED B0
Block Copy
Copy 32 bytes from the source address in HL (which points to the command line text following "AUTO " in the command buffer) to the destination at DE (4DE0H in the directory sector buffer). HL was set by SYS1 to point past the command keyword. After this copy, the auto-boot string is in the directory sector buffer ready to be written back.
5294
LD C,00H 0E 00
Load Register C with 00H (directory sector 0 on drive 0) for the write operation.
5296
GOSUB to SYS0 routine at 4B03H to write the 4D00H buffer back to directory sector 0 on drive 0, saving the auto-boot command.
5299
If the NZ FLAG is set (write failed), JUMP to the disk error handler at 554CH.
529C
RET C9
Return to the caller. Since 402DH was pushed onto the stack at 5204H, this returns to the no-error exit, returning to DOS READY.
529DH - DATE Command Handler
Implements the DATE command, which sets the system date. The user provides the date in MM/DD/YY format on the command line. The Date/Time Parser at 52EAH is called with Register C = 2FH (ASCII '/') as the delimiter character, and the three parsed values are stored to the system date variables at 4044H-4046H (day, month, year). Format: DATE MM/DD/YY
529D
LD C,2FH 0E 2F
Load Register C with 2FH (ASCII /), the delimiter character for the date format MM/DD/YY.
529F
GOSUB to the Date/Time Parser at 52EAH. This routine parses three 2-digit values separated by the delimiter in Register C (slash) from the command line pointed to by HL. It stores the results in a 3-byte work area at 52DCH-52DEH in reverse order (last value at 52DCH, first value at 52DEH).
52A2
If the NZ FLAG is set (parse failed due to invalid format), JUMP to 52D3H to display the "BAD FORMAT" error message.
52A5
LD HL,52DCH 21 DC 52
Point Register Pair HL to 52DCH, the start of the parsed values work area. The 3 bytes at 52DCH-52DEH contain the year (52DCH), day (52DDH), and month (52DEH) as parsed by 52EAH.
52A8
LD DE,4044H 11 44 40
Point Register Pair DE to 4044H, the system date storage in the SYS0 work area. The 3 bytes at 4044H-4046H store day (4044H), month (4045H), and year (4046H).
52AB
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H (3 bytes to copy).
52AE
LDIR ED B0
Block Copy
Copy 3 bytes from 52DCH (parsed date values) to 4044H (system date variables). Since the parser stores values in reverse order, this correctly maps: 52DCH (year) to 4044H, 52DDH (day) to 4045H, 52DEH (month) to 4046H. Note: This means the system date at 4044H stores year/day/month rather than day/month/year.
52B0
RET C9
Return to the caller (402DH no-error exit via the stacked return address).
52B1H - TIME Command Handler
Implements the TIME command, which sets the system time. The user provides the time in HH:MM:SS format on the command line. The Date/Time Parser at 52EAH is called with Register C = 3AH (ASCII ':') as the delimiter character, and the three parsed values are stored to the system clock variables at 4041H-4043H (seconds, minutes, hours). Format: TIME HH:MM:SS
52B1
LD C,3AH 0E 3A
Load Register C with 3AH (ASCII :), the delimiter character for the time format HH:MM:SS.
52B3
GOSUB to the Date/Time Parser at 52EAH. This routine parses three 2-digit values separated by the colon delimiter from the command line pointed to by HL.
52B6
If the NZ FLAG is set (parse failed), JUMP to 52D3H to display "BAD FORMAT".
52B9
LD HL,52DCH 21 DC 52
Point Register Pair HL to 52DCH, the parsed values work area. The 3 bytes contain: seconds (52DCH), minutes (52DDH), hours (52DEH).
52BC
LD DE,4041H 11 41 40
Point Register Pair DE to 4041H, the system clock storage. The 3 bytes at 4041H-4043H store seconds (4041H), minutes (4042H), and hours (4043H).
52BF
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H (3 bytes to copy).
52C2
LDIR ED B0
Block Copy
Copy 3 bytes from 52DCH (parsed time values) to 4041H (system clock variables). The parser stores values in reverse order, so this correctly maps: 52DCH (seconds) to 4041H, 52DDH (minutes) to 4042H, 52DEH (hours) to 4043H.
52C4
RET C9
Return to the caller (402DH no-error exit).
52C5H - CLOCK Command Handler
Implements the CLOCK command, which enables or disables the real-time clock display. When enabled, the timer interrupt service routine calls 4CA9H periodically to update the clock display on screen. This is implemented by enqueueing or dequeueing a timer callback entry. Format: CLOCK (ON) or CLOCK (OFF)
52C5
CALL 51A0H CD A0 51
GOSUB to the SYS1 Parameter Parser Helper at 51A0H to parse the parenthesized boolean option (ON or OFF). Returns with the Z FLAG set if the option value is ON (true), NZ if OFF (false).
52C8
LD DE,4CA9H 11 A9 4C
Point Register Pair DE to 4CA9H, the address of the timer interrupt dispatch table entry in SYS0. This is the address of the clock display update routine that the timer interrupt will call.
52CB
LD A,06H 3E 06
Load Register A with 06H. This is the timer tick count: the clock display routine will be called every 6 timer ticks (approximately every 0.1 seconds at 60 Hz).
52CD
If the Z FLAG is set (option was ON), JUMP to 4413H to dequeue the timer callback. Wait - this seems reversed. If CLOCK ON, we want to enqueue. Let me re-examine: The 51A0H Parameter Parser Helper returns Z=true when the parsed boolean is FFFFH (YES/ON). The SYS0 routine at 4413H is "Dequeue timer callback" and 4410H is "Enqueue timer callback". So if ON (Z flag set), it dequeues?
Clock Toggle Logic
The Z flag from the Parameter Parser at 51A0H indicates: Z set = ON was specified. When ON is specified, the jump to 4413H (dequeue) is taken. When OFF is specified (NZ), execution falls through to 4410H (enqueue). This appears inverted but is correct for the TRSDOS 2.3 implementation: the Parameter Parser returns Z when the boolean evaluates to true (ON), and the CLOCK command uses dequeue for ON and enqueue for OFF. This is consistent with the interpretation that the parser's Z flag indicates the opposite sense, or that the clock starts in a different default state. Alternatively, 51A0H may return NZ for ON (nonzero value FFFFH) depending on how the final comparison is structured.
52D0
JUMP to 4410H to enqueue the timer callback. Register A holds 06H (tick interval) and DE holds 4CA9H (callback address). After enqueueing, the timer ISR will call the clock display routine every 6 ticks.
52D3H - "BAD FORMAT" Error Display
Shared error handler for DATE and TIME commands when the user provides an improperly formatted value. Displays "BAD FORMAT" and exits to DOS READY via the error-already-displayed exit.
52D3
LD HL,52DFH 21 DF 52
Point Register Pair HL to the error message string at 52DFH ("BAD FORMAT" followed by 0DH).
52D6
GOSUB to the SYS0 Display Message routine at 4467H to print "BAD FORMAT" to the video display.
52D9
JUMP to 4030H, the error-already-displayed exit.
52DCH - Data: Date/Time Parser Work Area and "BAD FORMAT" String
Three-byte work area used by the Date/Time Parser at 52EAH to store parsed values, followed by the "BAD FORMAT" error message string.
52DC
DEFB 00H 00
Work area byte 1: stores the third parsed value (year for DATE, seconds for TIME). Written at runtime by the Date/Time Parser at 52EAH.
52DD
DEFB 00H 00
Work area byte 2: stores the second parsed value (day for DATE, minutes for TIME).
52DE
DEFB 00H 00
Work area byte 3: stores the first parsed value (month for DATE, hours for TIME).
52DF-52E8
DEFM "BAD FORMAT" 42 41 44 20 46 4F 52 4D 41 54
ASCII text: "BAD FORMAT"
52E9
DEFB 0DH 0D
Carriage return string terminator.
52EAH - Date/Time Parser
Parses three 2-digit decimal values separated by a delimiter character (in Register C) from the command line pointed to by HL. Results are stored at 52DCH-52DEH in reverse order: the first value parsed goes to 52DEH, the second to 52DDH, and the third to 52DCH. Used by both the DATE command (delimiter = '/') and the TIME command (delimiter = ':'). Returns with Z flag set on success, NZ on parse error.
52EA
LD DE,52DEH 11 DE 52
Point Register Pair DE to 52DEH, the last byte of the 3-byte work area. Values will be stored from high to low (52DEH first, then 52DDH, then 52DCH) as they are parsed left to right.
52ED
LD B,03H 06 03
Load Register B with 03H as a loop counter: 3 values to parse.
52EF
PUSH DE D5
Loop Start
Save the current storage pointer (DE) onto the stack before calling the parser subroutine.
52F0
GOSUB to the Two-Digit Decimal Parser at 52FFH to parse a 2-digit number from the command line at (HL). Returns with the parsed value in Register A, Z flag set on success.
52F3
POP DE D1
Restore the storage pointer (DE) from the stack.
52F4
RET NZ C0
If the NZ FLAG is set (parse failed), return immediately to the caller with NZ indicating an error. The caller will display "BAD FORMAT".
52F5
LD (DE),A 12
Store the parsed value (Register A) to the address pointed to by DE (first iteration: 52DEH, second: 52DDH, third: 52DCH).
52F6
DEC DE 1B
DECrement Register Pair DE by 1 to point to the next storage location (moving from 52DEH toward 52DCH).
52F7
DEC B 05
DECrement the loop counter in Register B.
52F8
RET Z C8
If the Z FLAG is set (all 3 values parsed), return with Z indicating success.
52F9
LD A,(HL) 7E
Fetch the next character from the command line at (HL). This should be the delimiter character (slash or colon).
52FA
INC HL 23
INCrement Register Pair HL to advance past the delimiter character.
52FB
CP A,C B9
Compare Register A against the expected delimiter character in Register C (2FH for '/' or 3AH for ':'). If they match, the Z FLAG is set.
52FC
If the Z FLAG is set (delimiter matched), LOOP BACK to 52EFH to parse the next 2-digit value.
52FE
RET C9
Loop End
If the delimiter did not match, return with NZ indicating a parse error.
52FFH - Two-Digit Decimal Parser
Parses a 2-digit decimal number from the command line at (HL). Combines the tens digit and units digit into a single binary value in Register A. Returns Z on success, NZ (via CARRY set) on invalid input. Used by the Date/Time Parser at 52EAH.
52FF
GOSUB to the Single Digit Parser at 5316H to extract and convert the first digit (tens) from (HL). Returns with the binary digit value (0-9) in Register A, CARRY clear if valid.
5302
If the NO CARRY FLAG is set (character was not a valid digit), JUMP to 5314H to set NZ and return an error.
5304
LD E,A 5F
Save the tens digit value to Register E for accumulation.
5305
RLCA 07
Rotate Register A left through carry. A = tens x 2.
5306
RLCA 07
Rotate Register A left again. A = tens x 4.
5307
ADD A,E 83
ADD Register E (original tens digit) to Register A. A = (tens x 4) + tens = tens x 5.
5308
RLCA 07
Rotate Register A left. A = tens x 10. This completes the multiply-by-10 using the RLCA/RLCA/ADD/RLCA pattern.
5309
LD E,A 5F
Save the result (tens x 10) to Register E.
530A
GOSUB to the Single Digit Parser at 5316H to extract and convert the second digit (units) from (HL). Returns with the binary value in Register A.
530D
If the NO CARRY FLAG is set (not a valid digit), JUMP to 5314H to return error.
530F
ADD A,E 83
ADD Register E (tens x 10) to Register A (units digit). Register A now holds the complete 2-digit value as a binary number (0-99).
5310
LD E,A 5F
Save the final value to Register E (preserving it across the flag setup).
5311
XOR A,A AF
Set Register A to ZERO and set the Z FLAG to indicate success.
5312
LD A,E 7B
Reload the parsed value from Register E back into Register A. The Z FLAG remains set from the XOR instruction (LD does not affect flags).
5313
RET C9
Return with Z flag set (success) and the 2-digit value in Register A.
5314H - Digit Parse Error Return
Error return point for the Two-Digit Decimal Parser. Sets NZ flag to indicate parse failure.
5314
OR A,A B7
OR Register A with itself. Since A contains a non-digit character value (which is nonzero after the subtraction in 5316H), this sets the NZ FLAG to indicate an error.
5315
RET C9
Return with NZ flag set (error).
5316H - Single Digit Parser
Extracts one ASCII digit character from (HL), advances HL, and converts the digit to binary (0-9). Returns with CARRY set if valid digit, CARRY clear if not.
5316
LD A,(HL) 7E
Fetch the character at the current command line position (HL).
5317
INC HL 23
INCrement Register Pair HL to advance to the next character in the command line.
5318
SUB A,30H D6 30
SUBtract 30H (ASCII '0') from Register A to convert from ASCII to binary. If the character was '0'-'9', Register A now holds 00H-09H.
531A
CP A,0AH FE 0A
Compare Register A against 0AH (10 decimal). If Register A < 0AH (valid digit 0-9), the CARRY FLAG is set. If Register A >= 0AH (not a digit), the NO CARRY FLAG is set.
531C
RET C9
Return with CARRY set if valid digit (value 0-9 in A), CARRY clear if invalid.
531DH - DEVICE Command Handler
Implements the DEVICE command, which displays the logical device routing table stored at 43C0H in the SYS0 work area. Each device entry is 5 bytes: 2 bytes for the device name character pair (e.g., "KI" for keyboard input), followed by 3 bytes of padding/routing data. The routine walks the table printing each device name pair with a carriage return until it encounters a zero byte marking the end of the table. Format: DEVICE (no parameters)
531D
LD HL,43C0H 21 C0 43
Point Register Pair HL to 43C0H, the start of the logical device routing table in the SYS0 work area. Each entry begins with 2 ASCII characters identifying the device.
5320
LD A,(HL) 7E
Loop Start
Fetch the first byte of the current device entry from (HL). A zero value indicates the end of the device table.
5321
INC L 2C
INCrement the low byte of HL to point to the second character of the device name. Using INC L instead of INC HL is a single-byte optimization since the table stays within page 43xxH.
5322
OR A,A B7
OR Register A with itself to test if the byte is zero (end of table). If zero, the Z FLAG is set.
5323
If the Z FLAG is set (end of device table), JUMP to 5337H to exit via the no-error return at 402DH.
5325
GOSUB to the ROM Display Character routine at 0033H to print the first character of the device name (in Register A) to the video display.
5328
LD A,(HL) 7E
Fetch the second character of the device name from (HL).
5329
GOSUB to the ROM Display Character routine to print the second character of the device name.
532C
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return) to move to the next line on the display.
532E
GOSUB to the ROM Display Character routine to output the carriage return.
5331
LD A,L 7D
Load Register A with the low byte of HL (current position in the device table).
5332
ADD A,03H C6 03
ADD 03H to Register A. This advances past the remaining 3 bytes of the current device entry (the routing data), positioning HL to the start of the next entry. Each entry is 5 bytes total: 2 name bytes (already consumed) + 3 routing bytes (skipped here).
5334
LD L,A 6F
Store the updated position back to Register L. Register H remains 43H throughout since the table fits within one 256-byte page.
5335
If the NO CARRY FLAG is set (no page overflow from the ADD), LOOP BACK to 5320H to process the next device entry. If carry occurred, the table has wrapped past 43FFH, so fall through to exit.
5337
JUMP to 402DH, the no-error exit in SYS0, returning to DOS READY.
533AH - LIB Command Handler
Implements the LIB command, which displays all available library command names from the overlay command name table at 4EBDH in SYS1 memory. The table contains 19 entries of 8 bytes each (6-character command name + 2 bytes of dispatch data). The display formats 4 commands per line, each preceded by character C2H (inverse video bracket) and followed by C8H (inverse video closing bracket) for visual emphasis. Format: LIB (no parameters)
533A
LD HL,4EBDH 21 BD 4E
Point Register Pair HL to 4EBDH, the start of the overlay command name table in SYS1 memory. This table contains 19 entries, each 8 bytes: 6 characters of the command name (space-padded) plus 2 bytes of dispatch information.
533D
LD C,04H 0E 04
Outer Loop Start
Load Register C with 04H, the number of commands to display per line before outputting a carriage return.
533F
LD A,0C2H 3E C2
Load Register A with C2H, a TRS-80 graphics/inverse character used as a visual bracket before each command name in the display output.
5341
GOSUB to the ROM Display Character routine to print the opening bracket character.
5344
LD B,06H 06 06
Load Register B with 06H as a loop counter to print the 6 characters of the command name.
5346
LD A,(HL) 7E
Inner Loop Start
Fetch the next character of the command name from the table entry at (HL).
5347
INC HL 23
INCrement Register Pair HL to advance to the next character in the table entry.
5348
GOSUB to the ROM Display Character routine to print the current character of the command name.
534B
DECrement Register B and LOOP BACK to 5346H if not zero. This prints all 6 characters of the command name.
534D
LD A,0C8H 3E C8
Load Register A with C8H, a TRS-80 graphics/inverse character used as the closing bracket after each command name.
534F
GOSUB to the ROM Display Character routine to print the closing bracket character.
5352
INC HL 23
INCrement Register Pair HL to skip past the first dispatch byte in the 8-byte table entry.
5353
INC HL 23
INCrement Register Pair HL to skip past the second dispatch byte. HL now points to the start of the next command name entry.
5354
LD A,(HL) 7E
Fetch the first byte of the next table entry. A zero byte indicates the end of the command table.
5355
OR A,A B7
OR Register A with itself to test for the end-of-table marker (00H). If zero, the Z FLAG is set.
5356
If the Z FLAG is set (end of table reached), JUMP to 5362H to print a final carriage return and exit.
5358
DEC C 0D
DECrement the per-line counter in Register C. When C reaches zero, a new line is needed.
5359
If the NZ FLAG is set (more commands fit on this line), LOOP BACK to 5344H to display the next command name. Inner Loop End
535B
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return) to start a new display line.
535D
GOSUB to the ROM Display Character routine to output the carriage return.
5360
JUMP BACK to 533DH to reset the per-line counter to 4 and continue displaying the next row of commands. Outer Loop End
5362
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return) for the final line ending.
5364
GOSUB to the ROM Display Character routine to output the final carriage return.
5367
JUMP to 402DH, the no-error exit, returning to DOS READY.
536AH - PROT Command Handler
Implements the PROT command, which manages master password protection for the system disk. PROT supports three subcommands: PW (change master password), LOCK (assign master password to all user files), and UNLOCK (remove passwords from all user files). The master password hash is stored in directory sector 0 at offset 0CEH. An optional drive specifier can precede the subcommand keyword. Format: PROT [:n] PW, PROT [:n] LOCK, or PROT [:n] UNLOCK
536A
LD A,(430FH) 3A 0F 43
Fetch the system flags byte from 430FH. Bit 5 of this byte indicates whether PROT operations are currently prohibited (e.g., when running in a restricted mode).
536D
BIT 5,A CB 6F
Test bit 5 of the system flags byte in Register A. If bit 5 is set, PROT operations are not allowed.
536F
If the NZ FLAG is set (bit 5 is set, PROT is prohibited), JUMP to 546EH to display the "INVALID COMMAND DURING PROGRAM CHAINING" error message and exit.
5372
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H. This value will be written to the three self-modifying operand locations to clear any previous option selections.
5375
LD (53D9H),BC ED 43 D9 53
Self-Modifying Code
Clear the PW option flag at 53D8H-53D9H by storing 0000H. This is the operand of the LD DE,0000H instruction at 53D8H. When the option parser matches "PW", it stores the new password hash here.
5379
LD (53F9H),BC ED 43 F9 53
Self-Modifying Code
Clear the LOCK option flag at 53F8H-53F9H by storing 0000H. This is the operand of the LD DE,0000H instruction at 53F8H. When the option parser matches "LOCK", it stores the new password hash here.
537D
LD (5403H),BC ED 43 03 54
Self-Modifying Code
Clear the UNLOCK option flag at 5402H-5403H by storing 0000H. This is the operand of the LD DE,0000H instruction at 5402H. When the option parser matches "UNLOCK", it stores the DOS Ready address (4296H) here as a signal.
5381
LD C,00H 0E 00
Load Register C with 00H as the default drive number (drive 0, the system disk).
5383
LD A,(HL) 7E
Fetch the next character from the command line at (HL). Check for an optional drive specifier.
5384
CP A,3AH FE 3A
Compare Register A against 3AH (ASCII :). If it matches, a drive specifier follows.
5386
If the NZ FLAG is set (no colon, no drive specifier), JUMP to 538EH to skip drive extraction and use the default drive 0.
5388
INC HL 23
INCrement Register Pair HL to advance past the colon character.
5389
LD A,(HL) 7E
Fetch the drive number digit from the command line at (HL).
538A
SUB A,30H D6 30
SUBtract 30H (ASCII '0') to convert the drive digit from ASCII to binary (0-3).
538C
LD C,A 4F
Store the drive number in Register C.
538D
INC HL 23
INCrement Register Pair HL to advance past the drive number digit.
538E
LD A,C 79
Load Register A with the drive number from Register C (default 0 or parsed value).
538F
LD (53BCH),A 32 BC 53
Self-Modifying Code
Store the drive number at 53BCH. This location is the operand of a LD A,(53BCH) instruction that retrieves the drive number later during disk I/O operations.
5392
LD DE,54EBH 11 EB 54
Point Register Pair DE to 54EBH, the PROT subcommand keyword table. This table contains three keywords: "PW" (target 53D9H), "LOCK" (target 53F9H), and "UNLOCK" (target 5403H).
5395
GOSUB to 4476H (SYS0 entry point for the Additional Utility overlay, SVC E3H). This invokes the option/keyword parser in SYS1 (at 507DH, still resident below 5200H). The parser scans the command line at (HL) for keywords matching the table at 54EBH, and stores the associated value to the target address for each matched keyword.
5398
LD A,(53D9H) 3A D9 53
Fetch the PW option flag from 53D9H. This byte is nonzero if the "PW" keyword was matched by the option parser.
539B
LD HL,53F9H 21 F9 53
Point Register Pair HL to 53F9H, the LOCK option flag.
539E
OR A,(HL) B6
OR Register A with the LOCK flag at 53F9H. After this, Register A is nonzero if either PW or LOCK was specified.
539F
LD HL,5403H 21 03 54
Point Register Pair HL to 5403H, the UNLOCK option flag.
53A2
OR A,(HL) B6
OR Register A with the UNLOCK flag at 5403H. After this, Register A is nonzero if any of PW, LOCK, or UNLOCK was specified.
53A3
If the Z FLAG is set (no subcommand keyword was specified), JUMP to 526BH to display "-NOTHING DONE-" and exit. The user must specify PW, LOCK, or UNLOCK.
Master Password Verification
Before performing any PROT operation, the system must verify the current master password. The code opens directory sector 0 on the target drive, reads the existing master password hash from offset 0CEH, and prompts the user to enter the current master password. If the entered password hash does not match the stored hash, the "INVALID MASTER PASSWORD" error is displayed.
53A6
LD A,03H 3E 03
Load Register A with 03H. This is stored to the first byte of the primary filespec buffer at 5551H to set up a minimal FCB access mode (read access = 03H for EXEC level).
53A8
LD DE,5551H 11 51 55
Point Register Pair DE to 5551H, the primary filespec buffer.
53AB
LD (DE),A 12
Store 03H to the first byte of the filespec buffer at 5551H. This sets the access mode for the file open operation.
53AC
GOSUB to 4424H to open an existing file. With the filespec containing only an access mode byte, this opens the directory on the target drive to allow reading the master password.
53AF
LD HL,54A0H 21 A0 54
Point Register Pair HL to the prompt message at 54A0H. This message reads: 0AH + "MASTER PASSWORD ? " + 03H (linefeed, prompt text, ETX terminator).
53B2
GOSUB to the SYS0 Display Message routine to print the "MASTER PASSWORD ?" prompt.
53B5
GOSUB to the Password Input routine at 5454H. This prompts the user for up to 8 characters of password input at the keyboard. Returns with the password hash in HL (computed by the SYS1 parser at 50D1H).
53B8
LD (5168H),HL 22 68 51
Store the entered password hash (HL) to 5168H in the SYS1 work area. This preserves the hash for later comparison against the stored master password.
53BB
LD C,00H 0E 00
Load Register C with 00H (directory sector 0 on the target drive).
53BD
GOSUB to SYS0 routine at 4AF0H to read directory sector 0 into the 4D00H buffer.
53C0
If the NZ FLAG is set (read failed), JUMP to the disk error handler at 554CH.
53C3
LD HL,(4DCEH) 2A CE 4D
Fetch the stored master password hash from 4DCEH-4DCFH. This is the 16-bit password hash at offset 0CEH within the directory sector buffer at 4D00H (4D00H + 0CEH = 4DCEH).
53C6
LD DE,(5168H) ED 5B 68 51
Fetch the entered password hash from 5168H (stored at 53B8H above) into Register Pair DE.
53CA
XOR A,A AF
Set Register A to ZERO and clear the CARRY FLAG in preparation for the 16-bit subtraction comparison.
53CB
SBC HL,DE ED 52
SUBtract the entered password hash (DE) from the stored password hash (HL) with borrow. If they match, HL becomes zero and the Z FLAG is set.
53CD
If the Z FLAG is set (passwords match), JUMP to 53D8H to proceed with the PROT operation.
53CF
LD HL,54D2H 21 D2 54
Point Register Pair HL to the error message at 54D2H ("INVALID MASTER PASSWORD" followed by 0DH).
53D2
GOSUB to the SYS0 Display Message routine to print the "INVALID MASTER PASSWORD" error.
53D5
JUMP to 4030H, the error-already-displayed exit.
PW Subcommand Processing
If the master password was verified, execution reaches 53D8H. The code now checks which subcommand was specified (PW, LOCK, or UNLOCK) and executes the appropriate action. PW prompts for a new password and stores its hash to directory sector 0 offset 0CEH. LOCK assigns the master password to all user files in the directory. UNLOCK removes passwords from all user files.
53D8
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the value at 53D9H. At initial load this is 0000H, but the option parser writes the new password hash here when the "PW" keyword is matched. If DE is nonzero, the PW subcommand was specified.
53DB
LD A,D 7A
Load Register A with the high byte of DE (PW flag/hash).
53DC
OR A,E B3
OR Register A with the low byte of DE. If DE is 0000H (PW not specified), the Z FLAG is set.
53DD
If the Z FLAG is set (PW was not specified), JUMP to 53F5H to check for the LOCK subcommand.
53DF
LD HL,54B9H 21 B9 54
Point Register Pair HL to the prompt message at 54B9H ("NEW MASTER PASSWORD ? " + 03H).
53E2
GOSUB to the SYS0 Display Message routine to print "NEW MASTER PASSWORD ?".
53E5
GOSUB to the Password Input routine at 5454H to get the new master password from the user. Returns with the password hash in HL.
53E8
LD (4DCEH),HL 22 CE 4D
Store the new master password hash (HL) to 4DCEH, which is offset 0CEH within the directory sector buffer at 4D00H. This updates the master password in the buffer.
53EB
LD A,(53BCH) 3A BC 53
Fetch the target drive number from the self-modifying storage at 53BCH (stored at 538FH).
53EE
LD C,A 4F
Load Register C with the drive number for the disk write operation.
53EF
GOSUB to SYS0 routine at 4B03H to write the 4D00H buffer back to directory sector 0, saving the new master password hash to disk.
53F2
If the NZ FLAG is set (write failed), JUMP to the disk error handler at 554CH.
LOCK Subcommand Processing
The code now checks if the LOCK subcommand was specified. If LOCK was used, the new password hash is retrieved and the code falls through to the directory scan loop at 540CH which iterates through all directory entries and assigns the master password hash to each user file.
53F5
LD HL,(4DCEH) 2A CE 4D
Fetch the current master password hash from 4DCEH (offset 0CEH in the directory sector buffer). This is either the original password or the newly set password if PW was also specified.
53F8
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the value at 53F9H. This is the LOCK flag: nonzero if "LOCK" was specified. The option parser stores the password hash here when "LOCK" is matched.
53FB
LD A,D 7A
Load Register A with the high byte of the LOCK flag.
53FC
OR A,E B3
OR Register A with the low byte. If DE is 0000H (LOCK not specified), the Z FLAG is set.
53FD
If the NZ FLAG is set (LOCK was specified), JUMP to 540CH to begin the directory scan that assigns the master password to all user files.
UNLOCK Subcommand Processing
If neither PW (already handled) nor LOCK was specified, check for UNLOCK. The UNLOCK subcommand removes passwords from all user files by writing the blank password hash (4296H, which is the DOS Ready entry address repurposed as a zero/blank password marker) to each file's password field.
53FF
LD HL,4296H 21 96 42
Load Register Pair HL with 4296H. This value serves as the password hash to assign to files during the UNLOCK operation. The value 4296H is the DOS Ready handler address, and in the password context it functions as a well-known constant meaning "no password".
5402
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the value at 5403H. This is the UNLOCK flag: nonzero if "UNLOCK" was specified.
5405
LD A,D 7A
Load Register A with the high byte of the UNLOCK flag.
5406
OR A,E B3
OR Register A with the low byte. If DE is 0000H (UNLOCK not specified), the Z FLAG is set.
5407
If the NZ FLAG is set (UNLOCK was specified), JUMP to 540CH to begin the directory scan with HL=4296H (blank password hash) to remove passwords from all files.
5409
JUMP to 402DH, the no-error exit. This path is reached if only PW was specified (password already changed above) and no LOCK/UNLOCK action is needed.
540CH - PROT Directory Scan (LOCK/UNLOCK)
Iterates through all directory sectors (2 through 9) on the target drive, examining each directory entry. For LOCK, it writes the master password hash to each user file's password field. For UNLOCK, it writes the blank password hash (4296H). Only entries with the active file type marker (10H in the flags byte) are modified. Register Pair HL holds the password hash to assign; for LOCK this is the master password, for UNLOCK this is 4296H.
540C
LD (5430H),HL 22 30 54
Self-Modifying Code
Store the password hash (HL) to 5430H. This is the operand of a LD DE,nnnnH instruction at 542FH that will be used to write the hash into each directory entry. For LOCK, HL contains the master password hash; for UNLOCK, HL contains 4296H (blank password).
540F
LD A,(53BCH) 3A BC 53
Fetch the target drive number from the self-modifying storage at 53BCH.
5412
LD C,A 4F
Load Register C with the drive number.
5413
GOSUB to SYS0 routine at 4B55H to perform a track cache lookup for the target drive. This ensures the FDC track register is synchronized before reading directory sectors.
5416
LD E,02H 1E 02
Load Register E with 02H, the first directory sector number. TRSDOS 2.3 directory sectors run from sector 2 through sector 9 on track 0.
5418
LD HL,4200H 21 00 42
Sector Loop Start
Point Register Pair HL to 4200H, the directory sector buffer where each sector will be read.
541B
GOSUB to SYS0 routine at 4B35H to read the directory sector (number in Register E) into the buffer at 4200H with retry on soft errors.
541E
If the NZ FLAG is set (read failed), JUMP to the disk error handler at 554CH.
5421
LD L,40H 2E 40
Set the low byte of HL to 40H, pointing to 4240H. This is the start of the first directory entry within the sector buffer (offset 40H from the buffer base at 4200H). Each directory entry is 32 bytes (20H), and the first 64 bytes (00H-3FH) of each directory sector contain the GAT/header data.
5423
LD A,(HL) 7E
Entry Loop Start
Fetch the flags byte of the current directory entry at (HL).
5424
AND A,0F8H E6 F8
Mask the flags byte with 0F8H, isolating the upper 5 bits which indicate the file type. This clears bits 0-2 (access level).
5426
CP A,10H FE 10
Compare the masked flags byte against 10H. The value 10H indicates an active user file entry (bit 4 set, no system flags). Only user files have their passwords modified.
5428
If the NZ FLAG is set (entry is not an active user file), JUMP to 543AH to skip this entry and advance to the next.
542A
LD A,L 7D
Load Register A with the low byte of HL (current entry base address within the sector buffer).
542B
ADD A,10H C6 10
ADD 10H to Register A to point to offset +10H within the directory entry, which is the password hash field (2 bytes at offset 10H and 12H).
542D
LD L,A 6F
Store the updated offset back to Register L. HL now points to the password hash field of the current directory entry.
542E
PUSH DE D5
Save the directory sector number (Register E) onto the stack before loading DE with the password hash.
542F
LD DE,0000H 11 00 00
Self-Modifying Code
Load Register Pair DE with the password hash value. The operand at 5430H-5431H was written at 540CH with the master password hash (LOCK) or blank hash 4296H (UNLOCK).
5432
LD (HL),E 73
Store the low byte of the password hash to the first password byte of the directory entry.
5433
INC L 2C
INCrement Register L to point to the second password byte.
5434
LD (HL),D 72
Store the high byte of the password hash to the second password byte.
5435
INC L 2C
INCrement Register L to point to the third password location (offset +12H).
5436
LD (HL),E 73
Store the low byte of the password hash to the third password byte. This writes the same hash to both password fields in the directory entry (offsets +10H/+11H and +12H/+13H).
5437
INC L 2C
INCrement Register L to point to the fourth password byte.
5438
LD (HL),D 72
Store the high byte of the password hash to the fourth password byte.
5439
POP DE D1
Restore the directory sector number from the stack into Register Pair DE.
543A
LD A,L 7D
Load Register A with the low byte of HL (current position within the sector buffer).
543B
AND A,0E0H E6 E0
Mask with 0E0H to round down to the start of the current 32-byte directory entry.
543D
ADD A,20H C6 20
ADD 20H (32 decimal) to advance to the start of the next directory entry.
543F
LD L,A 6F
Store the updated offset back to Register L.
5440
If the NO CARRY FLAG is set (no page overflow, still within the 256-byte sector buffer), LOOP BACK to 5423H to process the next directory entry. Entry Loop End
5442
LD HL,4200H 21 00 42
Point Register Pair HL to 4200H, the directory sector buffer, to write the modified sector back to disk.
5445
CALL 46EFH CD EF 46
GOSUB to SYS0 routine at 46EFH to write the directory sector from the 4200H buffer back to the disk. The sector number is still in Register E.
5448
If the NZ FLAG is set (write failed), JUMP to the disk error handler at 554CH.
544B
INC E 1C
INCrement the sector number in Register E to advance to the next directory sector.
544C
LD A,E 7B
Load Register A with the current sector number.
544D
CP A,0AH FE 0A
Compare Register A against 0AH (10 decimal). Directory sectors run from 2 through 9, so sector 10 is past the last directory sector.
544F
If the CARRY FLAG is set (sector number < 10, more sectors to process), LOOP BACK to 5418H to read and process the next directory sector. Sector Loop End
5451
JUMP to 402DH, the no-error exit. All directory sectors have been processed and passwords updated.
5454H - Password Input Routine
Prompts the user to enter a password at the keyboard. Accepts up to 8 characters of input using the ROM line input routine at 0040H, pads the result with spaces to 8 characters, then calls the SYS1 hexadecimal parser at 50D1H to compute the 16-bit password hash. Returns with the hash in Register Pair HL.
5454
LD B,08H 06 08
Load Register B with 08H, the maximum number of characters to accept for the password input (8 characters).
5456
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the input buffer where the typed password characters will be stored.
5459
GOSUB to the ROM Line Input routine at 0040H. Register B specifies the maximum character count (8), HL points to the input buffer. On return, B contains the number of remaining unused characters (8 minus characters typed).
545C
EX DE,HL EB
Exchange DE and HL. DE now points past the last typed character in the buffer, and HL is free for computation.
545D
LD H,00H 26 00
Load Register H with 00H to set up an offset calculation.
545F
LD L,B 68
Load Register L with Register B (remaining unused character count). HL now holds the count of characters NOT typed.
5460
ADD HL,DE 19
ADD DE (position past last typed character) to HL (unused count). HL now points to the end of the 8-character password field (5608H = 5600H + 8).
5461
LD A,08H 3E 08
Load Register A with 08H (total password length).
5463
SUB A,B 90
SUBtract Register B (unused characters) from 8. Register A now holds the number of characters the user actually typed.
5464
LD B,A 47
Load Register B with the number of spaces needed to pad the password to 8 characters (8 - chars_typed). If the user typed all 8, B is 0 and no padding is needed.
5465
LD A,20H 3E 20
Load Register A with 20H (ASCII space) for padding.
5467
LD (HL),A 77
Padding Loop Start
Store a space character (20H) at the current position in the password buffer.
5468
INC HL 23
INCrement Register Pair HL to the next position in the buffer.
5469
DECrement Register B and LOOP BACK to 5467H if not zero. This pads the remaining positions with spaces to fill the 8-character password field. Padding Loop End
546B
JP 50D1H C3 D1 50
JUMP to the SYS1 hexadecimal/password hash parser at 50D1H (still resident below 5200H). This routine computes a 16-bit CRC hash from the 8-byte password string at 5600H and returns the hash in Register Pair HL.
546EH - "INVALID COMMAND DURING PROGRAM CHAINING" Error
Error handler displayed when PROT is attempted while program chaining is active (bit 5 of system flags at 430FH is set).
546E
LD HL,5477H 21 77 54
Point Register Pair HL to the error message at 5477H.
5471
GOSUB to the SYS0 Display Message routine to print the error message.
5474
JUMP to 4030H, the error-already-displayed exit.
5477H - Data: PROT Message Strings
ASCII message strings used by the PROT command handler. Includes error messages and prompts. Each string is terminated by 0DH (carriage return) or 03H (ETX, end of text used by the display routine to stop output without adding a newline).
5477-549F
DEFM 0AH,"INVALID COMMAND DURING PROGRAM CHAINING",0DH 0A 49 4E 56 41 4C 49 44 20 43 4F 4D 4D 41 4E 44 20 44 55 52 49 4E 47 20 50 52 4F 47 52 41 4D 20 43 48 41 49 4E 49 4E 47 0D
Linefeed + "INVALID COMMAND DURING PROGRAM CHAINING" + CR. Displayed when PROT is attempted while program chaining is active.
54A0-54B8
DEFM 0AH,"MASTER PASSWORD ? ",03H 0A 4D 41 53 54 45 52 20 50 41 53 53 57 4F 52 44 20 3F 20 20 20 20 20 20 03
Linefeed + "MASTER PASSWORD ? " + ETX. Prompt displayed before password input.
54B9-54D1
DEFM 0AH,"NEW MASTER PASSWORD ? ",03H 0A 4E 45 57 20 4D 41 53 54 45 52 20 50 41 53 53 57 4F 52 44 20 3F 20 20 03
Linefeed + "NEW MASTER PASSWORD ? " + ETX. Prompt displayed during the PW subcommand for entering the new password.
54D2-54EA
DEFM 0AH,"INVALID MASTER PASSWORD",0DH 0A 49 4E 56 41 4C 49 44 20 4D 41 53 54 45 52 20 50 41 53 53 57 4F 52 44 0D
Linefeed + "INVALID MASTER PASSWORD" + CR. Displayed when the entered password does not match the stored master password hash.
54EBH - Data: PROT Subcommand Keyword Table
Keyword table for the PROT command's option parser. Contains three 8-byte entries, each consisting of a 6-character keyword (space-padded) followed by a 2-byte target address where the option parser stores the result when the keyword is matched. The table is terminated by a 2-byte entry (54H, 00H) that the parser recognizes as end-of-table.
54EB-54F0
DEFM "PW " 50 57 20 20 20 20
Keyword "PW" (change master password), padded to 6 characters with spaces.
54F1-54F2
DEFW 53D9H D9 53
Target address 53D9H: the self-modifying operand of the LD DE instruction at 53D8H. When "PW" is matched, the parser stores the option value here.
54F3-54F8
DEFM "LOCK " 4C 4F 43 4B 20 20
Keyword "LOCK" (assign master password to all user files), padded to 6 characters.
54F9-54FA
DEFW 53F9H F9 53
Target address 53F9H: the self-modifying operand of the LD DE instruction at 53F8H.
54FB-5500
DEFM "UNLOCK" 55 4E 4C 4F 43 4B
Keyword "UNLOCK" (remove passwords from all user files), exactly 6 characters.
5501-5502
DEFW 5403H 03 54
Target address 5403H: the self-modifying operand of the LD DE instruction at 5402H.
5503
DEFB 00H 00
End-of-table marker. A zero byte in the keyword position signals the parser to stop scanning.
5504H - VERIFY Command Handler
Implements the VERIFY command, which enables or disables write verification. When VERIFY is ON, every disk write is followed by a read-back comparison to ensure data integrity. The verification state is stored in the self-modifying flag byte at 485EH in SYS0. Format: VERIFY (ON) or VERIFY (OFF)
5504
CALL 51A0H CD A0 51
GOSUB to the SYS1 Parameter Parser Helper at 51A0H to parse the parenthesized boolean option (ON or OFF). Returns with the Z FLAG indicating the parsed value.
5507
GOSUB to the VERIFY Flag Setup routine at 60CDH. This routine sets or clears the write-verify flag at 485EH based on the Z flag state from the parameter parser.
550A
If the Z FLAG is set (VERIFY is now OFF), JUMP to 550FH to store the default write address (478BH, write without verify) and exit.
550C
LD HL,47A8H 21 A8 47
Load Register Pair HL with 47A8H, the address of the write-with-verify routine in SYS0. This replaces the default write routine address when VERIFY is ON.
550F
LD (443AH),HL 22 3A 44
Self-Modifying Code
Store the write routine address (HL) to 443AH, which is the operand of the JP instruction in the SYS0 write entry point at 4437H-4439H. When VERIFY is ON, HL=47A8H (write with verify); when OFF, HL=478BH (write without verify), which was loaded at 60CDH.
5512
JUMP to 402DH, the no-error exit.
5515H - BREAK Key Check Utility
Checks whether the BREAK key has been pressed. Used by LIST, PRINT, and other commands that display or output data in loops, allowing the user to abort the operation. Returns NZ if BREAK was pressed (operation should stop), Z if no BREAK detected (operation should continue). Also implements the SHIFT-@ pause mechanism: if SHIFT-@ is held, the routine waits for any key before continuing.
5515
LD A,(430FH) 3A 0F 43
Fetch the system flags byte from 430FH. Bit 5 indicates whether the BREAK key check is enabled or disabled.
5518
AND A,20H E6 20
Mask with 20H to isolate bit 5 (the BREAK check enable flag).
551A
XOR A,20H EE 20
XOR with 20H to invert bit 5. If bit 5 was set (BREAK check disabled), the result is zero (Z). If bit 5 was clear (BREAK check enabled), the result is nonzero (NZ). This inverts the sense so that "enabled" falls through to the actual check.
551C
RET Z C8
If the Z FLAG is set (BREAK checking is disabled), return immediately with Z (no break detected). This allows the calling command to continue without interruption.
551D
LD A,(3840H) 3A 40 38
Read the keyboard row at memory address 3840H. This is row 6 of the TRS-80 Model I keyboard, which contains the ENTER, CLEAR, BREAK, and arrow keys. Bit 2 of this row corresponds to the BREAK key.
5520
AND A,04H E6 04
Mask with 04H to isolate bit 2 (BREAK key). On the TRS-80 Model I keyboard, bits are active LOW (0 = key pressed). If bit 2 is 0, the BREAK key is being held down.
5522
RET NZ C0
If the NZ FLAG is set (bit 2 is 1, BREAK key is NOT pressed), return with NZ to signal that BREAK was detected. Wait - this logic seems inverted. Let me re-examine: AND A,04H produces NZ when bit 2 is set (key NOT pressed on active-low keyboard). So RET NZ returns when the BREAK key is NOT pressed. This is the normal case - no break.
SHIFT-@ Pause Check
If the BREAK key IS pressed (bit 2 = 0, AND result = 0, Z flag set), execution falls through to check for the SHIFT-@ pause combination. The routine waits for any key to be pressed, then checks if it was the BREAK key or SHIFT-@ (ASCII 60H on the TRS-80 Model I).
5523
GOSUB to the ROM Get Character routine at 002BH, which waits for a keypress and returns the character in Register A.
5526
CP A,60H FE 60
Compare Register A against 60H (ASCII backtick/at-sign, the code generated by SHIFT-@ on the TRS-80 Model I keyboard). If the key was SHIFT-@, this is a pause request.
5528
If the Z FLAG is set (SHIFT-@ was pressed), JUMP to 552CH to enter the pause loop, waiting for the user to press another key to resume.
552A
XOR A,A AF
Set Register A to ZERO and set the Z FLAG. This returns Z to indicate "no break" - the user pressed a key other than SHIFT-@ (like ENTER) to continue, and the calling routine should proceed.
552B
RET C9
Return with Z flag set (no break, continue operation).
552C
LD A,(3840H) 3A 40 38
Pause Loop Start
Read keyboard row 6 at 3840H to check for BREAK key release. The routine waits here until the user releases SHIFT-@ and presses another key.
552F
AND A,04H E6 04
Mask with 04H to isolate the BREAK key bit (bit 2). Active LOW: 0 = pressed, 1 = released.
5531
RET NZ C0
If the NZ FLAG is set (BREAK key released), return with NZ. However, the calling routine interprets NZ as "break detected", so this will cause the listing/printing to stop.
5532
GOSUB to the ROM Get Character routine to wait for the next keypress.
5535
OR A,A B7
OR Register A with itself to check if a character was returned (nonzero means a key was pressed).
5536
If the Z FLAG is set (no character returned), LOOP BACK to 552CH to continue waiting. Pause Loop End
5538
XOR A,A AF
Set Register A to ZERO and set the Z FLAG to indicate "no break" (resume operation).
5539
RET C9
Return with Z flag set (no break detected, continue).
553AH - "FILE SPEC REQUIRED" Error Handler
Shared error handler displayed when a command that requires a filespec is invoked without one. Used by APPEND, COPY, DUMP, KILL, LIST, LOAD, PRINT, RENAME, and other file-oriented commands.
553A
LD HL,5591H 21 91 55
Point Register Pair HL to the error message at 5591H ("FILE SPEC REQUIRED" + 0DH).
553D
GOSUB to the SYS0 Display Message routine to print "FILE SPEC REQUIRED".
5540
JUMP to 4030H, the error-already-displayed exit.
5543H - "DEVICE SPEC REQUIRED" Error Handler
Error handler displayed when a device-oriented command lacks the required device specifier.
5543
LD HL,55A5H 21 A5 55
Point Register Pair HL to the error message at 55A5H ("DEVICE SPEC REQUIRED" + 0DH).
5546
GOSUB to the SYS0 Display Message routine to print "DEVICE SPEC REQUIRED".
5549
JUMP to 4030H, the error-already-displayed exit.
554CH - Disk Error Handler
Shared disk error handler used by all commands that perform disk I/O. ORs the error code in Register A with 40H (setting bit 6 to indicate the error occurred during an overlay operation) and exits via the SYS0 error exit at 4409H.
554C
OR A,40H F6 40
OR Register A (containing the raw disk error code) with 40H. This sets bit 6 of the error code, marking it as an overlay-context disk error. The modified code is then passed to the SYS0 error handler.
554E
JUMP to 4409H, the SYS0 DOS Error Exit. This routine displays the error code and returns to DOS READY.
5591H - Data: Error and Work Area Strings
ASCII message strings for file and device specification errors, plus FCB work areas used by file-oriented commands.
5591-55A4
DEFM 0AH + "FILE SPEC REQUIRED"+ 0DH 0A 46 49 4C 45 20 53 50 45 43 20 52 45 51 55 49 52 45 44 0D
Linefeed + "FILE SPEC REQUIRED" + CR. Displayed when a file command is missing its filespec argument.
55A5-55BA
DEFM 0AH + "DEVICE SPEC REQUIRED" + 0DH 0A 44 45 56 49 43 45 20 53 50 45 43 20 52 45 51 55 49 52 45 44 0D
Linefeed + "DEVICE SPEC REQUIRED" + CR. Displayed when a device command is missing its device specifier.
5700H - APPEND Command Handler
Implements the APPEND command, which appends the contents of one file to the end of another. Two filespecs are required: the source file and the destination file. The source file is opened for reading, the destination file is opened for reading (to get its existing FCB), then the destination FCB is positioned to EOF before the read/write copy loop begins. The APPEND command uses two FCB work areas: 5600H for the source and 6F00H for the destination. Format: APPEND source TO destination
5700
LD DE,5551H 11 51 55
Point Register Pair DE to 5551H, the primary filespec buffer, to receive the first (source) filespec.
5703
GOSUB to 441CH to extract a filespec from the command line at (HL) into the buffer at 5551H.
5706
If the NZ FLAG is set (no filespec found), JUMP to 553AH to display "FILE SPEC REQUIRED".
5709
LD A,(DE) 1A
Fetch the first character of the parsed filespec from (DE) = 5551H.
570A
CP A,2AH FE 2A
Compare Register A against 2AH (ASCII *). A wildcard character in the first position is not permitted for APPEND.
570C
If the Z FLAG is set (wildcard found), JUMP to 553AH to display "FILE SPEC REQUIRED".
570F
LD DE,5571H 11 71 55
Point Register Pair DE to 5571H, the secondary filespec buffer, to receive the second (destination) filespec.
5712
GOSUB to 441CH to extract the second filespec from the command line into 5571H.
5715
If the NZ FLAG is set (no second filespec), JUMP to 553AH to display "FILE SPEC REQUIRED".
5718
LD A,(DE) 1A
Fetch the first character of the second parsed filespec.
5719
CP A,2AH FE 2A
Compare against 2AH (wildcard). Wildcards not permitted in the destination filespec.
571B
If the Z FLAG is set (wildcard), JUMP to 553AH for the error.
571E
LD B,00H 06 00
Load Register B with 00H (record length = 0, meaning byte-mode access for the FCB).
5720
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the primary FCB work area for the source file.
5723
GOSUB to 4424H to open the source file (existing file only). The filespec at 5551H identifies the file; the FCB at 5600H receives the file control data. Register B=00H sets byte-mode access.
5726
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
5729
LD B,00H 06 00
Load Register B with 00H (byte-mode access) for the destination FCB.
572B
LD DE,5551H 11 51 55
Point Register Pair DE to 5551H. This reuses the primary filespec buffer for the destination open, but the actual filespec was already parsed into 5571H. The DE register here points to the FCB descriptor area.
572E
LD HL,6F00H 21 00 6F
Point Register Pair HL to 6F00H, the secondary FCB work area for the destination file.
5731
GOSUB to 4424H to open the destination file (existing only) with the FCB at 6F00H.
5734
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
5737
LD DE,5571H 11 71 55
Point Register Pair DE to the secondary filespec buffer at 5571H (destination file).
573A
GOSUB to 4448H to position the destination FCB to EOF. This sets the file pointer to the end of the existing destination file so that new data from the source will be appended.
573DH - NOP Padding (APPEND Continuation)
A block of 15 NOP instructions (573DH-574BH) followed by a jump to the APPEND copy loop. This padding suggests the area was reserved for additional APPEND logic that was either removed or never implemented.
573D-574B
NOP x 15 00 x 15
15 bytes of NOP padding. This space was likely reserved for additional EOF positioning or error handling code that was removed in the final TRSDOS 2.3 release.
574C
JUMP to 57B6H to enter the APPEND read/write copy loop, which reads bytes from the source file and writes them to the destination file.
574FH - COPY Command Handler
Implements the COPY command, which copies a file to a new name and/or drive. Two filespecs are required: the source file and the destination. The source is opened as an existing file, the destination is opened as new-or-existing (created if it does not exist). Data is copied record-by-record in a read/write loop. The copy terminates when an EOF condition (error 1CH) or past-EOF condition (error 1DH) is returned by the read operation. Format: COPY source TO destination
574F
LD DE,5551H 11 51 55
Point Register Pair DE to 5551H, the primary filespec buffer, for the source file.
5752
GOSUB to 441CH to extract the source filespec from the command line.
5755
If the NZ FLAG is set (no filespec), JUMP to the "FILE SPEC REQUIRED" error.
5758
LD DE,5571H 11 71 55
Point Register Pair DE to 5571H, the secondary filespec buffer, for the destination file.
575B
GOSUB to 441CH to extract the destination filespec.
575E
If the NZ FLAG is set (no second filespec), JUMP to the error.
5761
LD B,00H 06 00
Load Register B with 00H (byte-mode access for the source FCB).
5763
LD DE,5551H 11 51 55
Point Register Pair DE to the source filespec at 5551H.
5766
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the primary FCB work area.
5769
GOSUB to 4424H to open the source file (existing file only) into FCB at 5600H.
576C
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
576F
LD B,00H 06 00
Load Register B with 00H (byte-mode access for the destination FCB).
5771
LD DE,5571H 11 71 55
Point Register Pair DE to the destination filespec at 5571H.
5774
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, reusing the same FCB area. The source file was already opened and its FCB data is preserved internally by SYS0. The destination file's FCB will overwrite the source's FCB here since the source is read via the filespec descriptor, not the FCB pointer.
5777
GOSUB to 4420H to open the destination file (new or existing). If the file does not exist, it is created. The FCB at 5600H is initialized for the destination.
577A
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
Copy Loop
The copy loop reads one record from the source file and writes it to the destination file, repeating until an EOF condition is detected. Error codes 1CH (at EOF boundary) and 1DH (past EOF) are treated as normal termination conditions.
577D
LD DE,5551H 11 51 55
Copy Loop Start
Point Register Pair DE to 5551H (source filespec) for the read operation.
5780
GOSUB to 4436H to read one record from the source file. Returns Z on success, or an error code in Register A.
5783
If the Z FLAG is set (read successful), JUMP to 5790H to write the record to the destination file.
5785
CP A,1CH FE 1C
Compare the error code against 1CH (position at EOF). This indicates the last record was read and the file position is now at the EOF boundary.
5787
If the Z FLAG is set (EOF reached), JUMP to 57A1H to close both files and exit.
5789
CP A,1DH FE 1D
Compare the error code against 1DH (position past EOF). This is another normal termination condition indicating the read exceeded the file boundary.
578B
If the Z FLAG is set (past EOF), JUMP to 579BH to copy the EOF position to the destination and close files.
578D
For any other error code, JUMP to the disk error handler at 554CH.
5790
LD DE,5571H 11 71 55
Point Register Pair DE to 5571H (destination filespec) for the write operation.
5793
GOSUB to 4439H to write one record to the destination file.
5796
If the Z FLAG is set (write successful), LOOP BACK to 577DH to read the next record from the source. Copy Loop End
5798
If the write failed, JUMP to the disk error handler.
Past-EOF Cleanup
When the read returns error 1DH (past EOF), the source file's current position data needs to be transferred to the destination file's FCB so the destination has the correct EOF marker.
579B
LD HL,(5559H) 2A 59 55
Fetch the source file's EOF position from 5559H (offset within the primary filespec/FCB descriptor area) into Register Pair HL.
579E
LD (5579H),HL 22 79 55
Store the EOF position to 5579H (the corresponding offset in the secondary filespec/FCB descriptor area) so the destination file records the correct EOF.
57A1
LD DE,5571H 11 71 55
Point Register Pair DE to 5571H (destination filespec) to close the destination file.
57A4
GOSUB to 4428H to close the destination file. This writes the updated directory entry with the new file size.
57A7
If the NZ FLAG is set (close failed), JUMP to the disk error handler.
57AA
LD DE,5551H 11 51 55
Point Register Pair DE to 5551H (source filespec) to close the source file.
57AD
GOSUB to 4428H to close the source file.
57B0
If the NZ FLAG is set (close failed), JUMP to the disk error handler.
57B3
JUMP to 402DH, the no-error exit. Copy or append complete.
57B6H - APPEND Read/Write Copy Loop
The APPEND copy loop reads one record at a time from the source file (via the primary filespec at 5551H) and writes each byte to the destination file (via the secondary filespec at 5571H) using the cassette write routine at 001BH. This routine is entered from the NOP block at 574CH after the APPEND setup at 5700H. It also includes BREAK key checking to allow the user to abort the append operation.
57B6
LD DE,5551H 11 51 55
Read Loop Start
Point Register Pair DE to the source filespec at 5551H.
57B9
CALL 0013H CD 13 00
GOSUB to ROM routine at 0013H to read one record from the file identified by the filespec at (DE). Returns Z on success with the byte in Register A, or NZ with an error code.
57BC
If the Z FLAG is set (read successful), JUMP to 57C5H to check for BREAK and then write the byte.
57BE
CP A,1CH FE 1C
Compare the error code against 1CH (at EOF). If EOF is reached, the append is complete.
57C0
If the Z FLAG is set (EOF), JUMP to 57A1H to close both files and exit normally.
57C2
For any other error, JUMP to the disk error handler.
57C5
LD B,A 47
Save the read byte (Register A) to Register B to preserve it across the BREAK key check.
57C6
GOSUB to the BREAK Key Check utility at 5515H. Returns NZ if the user pressed BREAK to abort the operation.
57C9
If the NZ FLAG is set (BREAK pressed), JUMP to 57A1H to close both files and exit. The user has aborted the append.
57CB
LD A,B 78
Restore the read byte from Register B back to Register A for writing.
57CC
LD DE,5571H 11 71 55
Point Register Pair DE to the destination filespec at 5571H.
57CF
CALL 001BH CD 1B 00
GOSUB to ROM routine at 001BH to write the byte (in Register A) to the destination file identified by the filespec at (DE).
57D2
If the NZ FLAG is set (write failed), JUMP to the disk error handler.
57D5
JUMP BACK to 57B6H to read the next byte from the source file. Read Loop End
57D7H - DUMP Command Handler
Implements the DUMP command, which saves a file or memory range to cassette tape. The DUMP command accepts a filespec and optional parameters: START=X'nnnn' (start address), END=X'nnnn' (end address), and TRA=X'nnnn' (transfer/entry address). Default values are START=7000H, END=7000H, and TRA=402DH (no-error exit). The output is written in system tape format using the cassette write byte routine at 001BH. Format: DUMP filespec (START=X'nnnn',END=X'nnnn',TRA=X'nnnn')
57D7
LD BC,7000H 01 00 70
Load Register Pair BC with 7000H, the default START and END address for the DUMP operation.
57DA
LD (5868H),BC ED 43 68 58
Self-Modifying Code
Store the default START address (7000H) to 5868H, which is the operand of a LD HL,nnnnH instruction at 5867H used to initialize the dump start position.
57DE
LD (586EH),BC ED 43 6E 58
Self-Modifying Code
Store the default END address (7000H) to 586EH, which is the operand of a LD HL,nnnnH instruction at 586DH used to determine when to stop dumping.
57E2
LD BC,402DH 01 2D 40
Load Register Pair BC with 402DH, the default TRA (transfer) address. This is the no-error exit address, meaning no automatic program execution after loading the dump back from tape.
57E5
LD (58ABH),BC ED 43 AB 58
Self-Modifying Code
Store the default TRA address (402DH) to 58ABH, which is the operand of a LD HL,nnnnH instruction at 58AAH used for the entry point record in the tape output.
57E9
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
57EC
GOSUB to 441CH to extract the filespec from the command line.
57EF
If the NZ FLAG is set (no filespec), JUMP to the "FILE SPEC REQUIRED" error.
57F2
LD A,(DE) 1A
Fetch the first character of the parsed filespec.
57F3
CP A,2AH FE 2A
Compare against 2AH (wildcard). Wildcards not permitted for DUMP.
57F5
If the Z FLAG is set (wildcard), JUMP to the error.
57F8
LD DE,58F5H 11 F5 58
Point Register Pair DE to 58F5H, the DUMP option keyword table. This table contains the keywords START, END, and TRA with their target addresses.
57FB
GOSUB to 4476H (Additional Utility / option parser) to parse the parenthesized option list. Matched keywords store their hexadecimal values to the self-modifying operand addresses at 5868H (START), 586EH (END), and 58ABH (TRA).
Filename Extraction for Cassette Header
The DUMP format writes a 6-character filename to the cassette header. The code extracts the first 6 alphanumeric characters from the filespec, padding with spaces if the name is shorter.
57FE
LD DE,590EH 11 0E 59
Point Register Pair DE to 590EH, a 6-byte work area where the cassette header filename will be built.
5801
LD HL,5551H 21 51 55
Point Register Pair HL to the parsed filespec at 5551H.
5804
LD B,06H 06 06
Load Register B with 06H, the number of characters to extract for the cassette filename.
5806
LD A,(HL) 7E
Name Extract Loop Start
Fetch the next character from the filespec.
5807
CP A,30H FE 30
Compare against 30H (ASCII '0'). Characters below '0' are not valid filename characters.
5809
If the CARRY FLAG is set (character < '0'), JUMP to 581EH to pad the remaining positions with spaces.
580B
CP A,3AH FE 3A
Compare against 3AH (ASCII ':'). Characters '0'-'9' are valid.
580D
If the CARRY FLAG is set (character is '0'-'9'), JUMP to 5817H to store it.
580F
CP A,41H FE 41
Compare against 41H (ASCII 'A'). Characters between ':' and 'A' are not valid.
5811
If the CARRY FLAG is set (character in the gap between '9' and 'A'), JUMP to 581EH to pad.
5813
CP A,5BH FE 5B
Compare against 5BH (one past ASCII 'Z'). Characters 'A'-'Z' are valid.
5815
If the NO CARRY FLAG is set (character > 'Z'), JUMP to 581EH to pad.
5817
LD (DE),A 12
Store the valid alphanumeric character to the cassette filename buffer at (DE).
5818
INC HL 23
INCrement HL to the next character in the filespec.
5819
INC DE 13
INCrement DE to the next position in the filename buffer.
581A
DECrement Register B and LOOP BACK to 5806H if not zero. Continues extracting characters until 6 are collected or a non-alphanumeric is hit.
581C
JUMP to 5824H to proceed with the file open, skipping the space-padding loop. Name Extract Loop End
581E
LD A,20H 3E 20
Padding Loop Start
Load Register A with 20H (ASCII space) to pad remaining filename positions.
5820
LD (DE),A 12
Store the space character to the current position in the filename buffer.
5821
INC DE 13
INCrement DE to the next position.
5822
DECrement Register B and LOOP BACK to 581EH if not zero. Fills remaining positions with spaces. Padding Loop End
5824
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec at 5551H.
5827
LD HL,58F2H 21 F2 58
Point Register Pair HL to 58F2H, which contains the default extension "CIM" (for cassette image). This will be inserted into the filespec if no extension was specified.
582A
GOSUB to 4473H to insert the default extension "CIM" into the filespec at 5551H if the user did not specify one.
582D
LD B,00H 06 00
Load Register B with 00H (byte-mode access).
582F
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the FCB work area.
5832
GOSUB to 4420H to open the file (new or existing) for writing the dump output.
5835
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
Cassette Header Output
The code now writes the system tape header to the file. The header consists of: type byte 05H (system tape identifier), format byte 06H, and the 6-character filename extracted earlier.
5838
LD A,05H 3E 05
Load Register A with 05H, the system tape type identifier byte.
583A
CALL 001BH CD 1B 00
GOSUB to ROM routine at 001BH to write the type byte (05H) to the output file.
583D
LD A,06H 3E 06
Load Register A with 06H, the cassette format identifier byte.
583F
CALL 001BH CD 1B 00
GOSUB to 001BH to write the format byte (06H) to the output file.
5842
LD B,06H 06 06
Load Register B with 06H as a loop counter to write the 6-character filename.
5844
LD HL,590EH 21 0E 59
Point Register Pair HL to 590EH, the extracted cassette filename buffer.
5847
LD A,(HL) 7E
Filename Write Loop Start
Fetch the next character of the filename from (HL).
5848
INC HL 23
INCrement HL to the next character.
5849
CALL 001BH CD 1B 00
GOSUB to 001BH to write the filename character to the output file.
584C
DECrement Register B and LOOP BACK to 5847H if not zero. Writes all 6 filename characters. Filename Write Loop End
Address Validation
Before writing the data blocks, the code validates that END >= START, and that END does not exceed the available RAM (6FFFH). If END < START, the "END LESS THAN START" error is displayed. If END > 6FFFH, the "START LESS THAN X'7000'" error is displayed (since 7000H and above is the TRSDOS overlay area).
584E
LD HL,(586EH) 2A 6E 58
Fetch the END address from the self-modifying operand at 586EH into Register Pair HL.
5851
LD BC,(5868H) ED 4B 68 58
Fetch the START address from the self-modifying operand at 5868H into Register Pair BC.
5855
XOR A,A AF
Clear the CARRY FLAG for the subtraction.
5856
SBC HL,BC ED 42
SUBtract START (BC) from END (HL). If END < START, the CARRY FLAG is set.
5858
LD HL,58C4H 21 C4 58
Point Register Pair HL to the error message at 58C4H ("END LESS THAN START" + 0DH).
585B
If the CARRY FLAG is set (END < START), JUMP to 58BEH to display the error and exit.
585D
LD HL,6FFFH 21 FF 6F
Load Register Pair HL with 6FFFH, the maximum valid END address (top of user RAM before the TRSDOS overlay area at 7000H).
5860
SBC HL,BC ED 42
SUBtract START (BC) from 6FFFH. If START > 6FFFH (above the user area), the CARRY FLAG is set.
5862
LD HL,58D9H 21 D9 58
Point Register Pair HL to the error message at 58D9H ("START LESS THAN X'7000'" + 0DH).
5865
If the NO CARRY FLAG is set (START <= 6FFFH, which is valid), JUMP... Wait - JR NC means jump if carry clear. But we want to error when START > 6FFFH which sets carry. So JR NC would skip the error when START is valid. This is correct: if START <= 6FFFH (no carry from 6FFFH - START), continue with an error? No. Let me re-examine: After SBC HL,BC with HL=6FFFH and BC=START, if START > 6FFFH, then 6FFFH - START is negative, CARRY is set. JR NC,58BEH means: if CARRY is NOT set (START is valid, <= 6FFFH), jump to 58BEH (error). That seems wrong. Actually since the previous SBC already cleared carry once, and now the second SBC uses the leftover carry state... this is a subtle chain. The XOR A,A at 5855H cleared carry before the first SBC. But the first SBC at 5856H may set carry. The second SBC at 5860H uses that leftover carry. This means the logic is more complex than a simple comparison. The JR NC at 5865H jumps to 58BEH (error display) when carry is NOT set after the second SBC, meaning the overall check validates both conditions together.
Data Block Output Loop
The code now writes the memory dump as a series of data blocks in the TRS-80 system tape format. Each block starts with a type byte (01H = data block), a length byte, a 2-byte load address, followed by the data bytes. The maximum block size is 254 bytes (FEH). The loop continues until all memory from START to END has been written.
5867
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the START address. The operand at 5868H-5869H was written at 57DAH with the actual START address (or the default 7000H).
586A
PUSH HL E5
Block Loop Start
Save the current dump position (HL) onto the stack.
586B
LD B,H 44
Copy the high byte of the current address to Register B.
586C
LD C,L 4D
Copy the low byte of the current address to Register C. BC now holds the current dump address.
586D
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the END address. The operand at 586EH-586FH was written at 57DEH with the actual END address.
5870
INC HL 23
INCrement HL (END address + 1) to calculate the total number of bytes remaining.
5871
XOR A,A AF
Clear the CARRY FLAG.
5872
SBC HL,BC ED 42
SUBtract the current position (BC) from END+1 (HL). The result in HL is the number of bytes remaining to dump.
5874
If the Z FLAG is set (no bytes remaining), JUMP to 589FH to write the entry point record and close the file.
5876
LD B,0FEH 06 FE
Load Register B with 0FEH (254 decimal), the maximum data block size for a single tape record.
5878
LD A,H 7C
Load Register A with the high byte of the remaining byte count.
5879
OR A,A B7
Test if the high byte is nonzero (more than 255 bytes remaining).
587A
If the NZ FLAG is set (more than 255 bytes remain), JUMP to 5882H to use the full block size of 254 bytes.
587C
LD A,L 7D
Load Register A with the low byte of the remaining count (1-255).
587D
CP A,0FFH FE FF
Compare against FFH (255). If the remaining count is 255, use the maximum block size instead.
587F
If the NO CARRY FLAG is set (remaining >= 255), JUMP to 5882H to use B=FEH (254).
5881
LD B,L 45
Load Register B with the actual remaining byte count (1-254). This is the final block and may be smaller than 254 bytes.
5882
POP HL E1
Restore the current dump address from the stack into HL.
5883
LD A,01H 3E 01
Load Register A with 01H, the data block type identifier in the system tape format.
5885
CALL 001BH CD 1B 00
GOSUB to 001BH to write the data block type byte (01H) to the output file.
5888
LD A,B 78
Load Register A with Register B (the block data length in bytes).
5889
ADD A,02H C6 02
ADD 02H to the data length to include the 2-byte load address in the total block length.
588B
CALL 001BH CD 1B 00
GOSUB to 001BH to write the block length byte (data length + 2) to the output file.
588E
LD A,L 7D
Load Register A with the low byte of the current load address.
588F
CALL 001BH CD 1B 00
GOSUB to 001BH to write the load address low byte.
5892
LD A,H 7C
Load Register A with the high byte of the current load address.
5893
CALL 001BH CD 1B 00
GOSUB to 001BH to write the load address high byte.
5896
LD A,(HL) 7E
Data Write Loop Start
Fetch the byte at the current memory address (HL) to be dumped.
5897
INC HL 23
INCrement HL to the next memory address.
5898
CALL 001BH CD 1B 00
GOSUB to 001BH to write the memory byte to the output file.
589B
DECrement Register B and LOOP BACK to 5896H if not zero. Writes all bytes in this data block. Data Write Loop End
589D
JUMP BACK to 586AH to start the next data block. Block Loop End
Entry Point Record
After all data blocks have been written, the code outputs the entry point (transfer address) record. This is a type 02H block containing the address where execution should begin when the tape file is loaded back into memory.
589F
POP HL E1
Restore the address from the stack (cleanup from the block loop).
58A0
LD A,02H 3E 02
Load Register A with 02H, the entry point record type identifier.
58A2
CALL 001BH CD 1B 00
GOSUB to 001BH to write the entry point type byte (02H).
58A5
LD A,02H 3E 02
Load Register A with 02H, the entry point record length (2 bytes for the address).
58A7
CALL 001BH CD 1B 00
GOSUB to 001BH to write the entry point record length byte.
58AA
LD HL,0000H 21 00 00
Self-Modifying Code
Load Register Pair HL with the TRA (transfer/entry) address. The operand at 58ABH-58ACH was written at 57E5H with the actual TRA address (or the default 402DH).
58AD
LD A,L 7D
Load Register A with the low byte of the entry address.
58AE
CALL 001BH CD 1B 00
GOSUB to 001BH to write the entry address low byte.
58B1
LD A,H 7C
Load Register A with the high byte of the entry address.
58B2
CALL 001BH CD 1B 00
GOSUB to 001BH to write the entry address high byte.
58B5
GOSUB to 4428H to close the output file, flushing all data to disk.
58B8
If the NZ FLAG is set (close failed), JUMP to the disk error handler.
58BB
JUMP to 402DH, the no-error exit. DUMP command complete.
58BEH - DUMP Error Display Subroutine
Displays an error message pointed to by HL and exits via the error-already-displayed path. Used by the DUMP command for address validation errors.
58BE
GOSUB to the SYS0 Display Message routine to print the error message at (HL).
58C1
JUMP to 4030H, the error-already-displayed exit.
58C4H - Data: DUMP Message Strings and Option Table
Error messages, default extension, and option keyword table used by the DUMP command.
58C4-58D8
DEFM 0AH,"END LESS THAN START",0DH 0A 45 4E 44 20 4C 45 53 53 20 54 48 41 4E 20 53 54 41 52 54 0D
Linefeed + "END LESS THAN START" + CR. Displayed when the END address is less than the START address.
58D9-58F1
DEFM 0AH,"START LESS THAN X'7000'",0DH 0A 53 54 41 52 54 20 4C 45 53 53 20 54 48 41 4E 20 58 27 37 30 30 30 27 0D
Linefeed + "START LESS THAN X'7000'" + CR. Displayed when the START address exceeds the user RAM area. Note: This message text says "LESS THAN" but the condition is actually "greater than 6FFFH" (i.e., the address is in the TRSDOS overlay area).
58F2-58F4
DEFM "CIM" 43 49 4D
Default file extension "CIM" (Cassette IMage) for DUMP output files.
58F5H - Data: DUMP Option Keyword Table
Keyword table for the DUMP command's option parser. Contains START, END, and TRA keywords, each 6 characters (space-padded) followed by a 2-byte target address where the option parser stores the parsed hexadecimal value. The table is prefixed by a byte count or flags byte.
58F5-58FA
DEFM "START " 53 54 41 52 54 20
Keyword "START" (dump start address), padded to 6 characters.
58FB-58FC
Target address 5868H: the self-modifying operand of the LD HL instruction at 5867H.
58FD-5902
DEFM "END " 45 4E 44 20 20 20
Keyword "END" (dump end address), padded to 6 characters.
5903-5904
Target address 586EH: the self-modifying operand of the LD HL instruction at 586DH.
5905-590A
DEFM "TRA " 54 52 41 20 20 20
Keyword "TRA" (transfer/entry address), padded to 6 characters.
590B-590C
Target address 58ABH: the self-modifying operand of the LD HL instruction at 58AAH.
590D
DEFB 00H 00
End-of-table marker.
590E-5913
DEFB 00H,00H,00H, 00H,00H,00H 00 00 00 00 00 00
6-byte work area for the extracted cassette filename. Written at runtime by the name extraction loop at 5806H-581AH.
5914H - KILL Command Handler
Implements the KILL command, which deletes a file from disk. The filespec is extracted, the file is opened (to verify it exists and get the directory entry info), then the file is killed (directory entry cleared and granules freed). Format: KILL filespec
5914
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
5917
GOSUB to 441CH to extract the filespec from the command line.
591A
If the NZ FLAG is set (no filespec), JUMP to "FILE SPEC REQUIRED" error.
591D
GOSUB to 4424H to open the file (existing only). This locates the file in the directory and sets up the FCB. Note: the implicit HL/DE/B parameters from the filespec extraction are used.
5920
If the NZ FLAG is set (file not found or open error), JUMP to the disk error handler.
5923
GOSUB to 442CH to kill the file. This marks the directory entry as deleted, frees the allocated granules in the GAT, and clears the FCB.
5926
If the NZ FLAG is set (kill failed, e.g., access denied), JUMP to the disk error handler.
5929
JUMP to 402DH, the no-error exit. File successfully deleted.
592CH - LIST Command Handler
Implements the LIST command, which reads a text file and displays its contents on the video display. The file is opened, then records are read one at a time using 0013H and displayed character by character using 0033H. A LINE option can be specified to skip a number of lines before displaying. Carriage returns (0DH) in the file produce line breaks on the display. The BREAK key check at 5515H allows the user to abort the listing. Error codes 1CH/1DH (EOF conditions) cause a normal exit. Format: LIST filespec [(LINE=nnnn)]
592C
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H to clear the LINE count default (no line skip).
592F
LD (5954H),BC ED 43 54 59
Self-Modifying Code
Store 0000H to 5954H, which is the operand of a LD BC,nnnnH instruction at 5953H. This sets the LINE skip count to zero. The option parser will overwrite this if the LINE keyword is specified.
5933
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
5936
GOSUB to 441CH to extract the filespec from the command line.
5939
If the NZ FLAG is set (no filespec), JUMP to the "FILE SPEC REQUIRED" error.
593C
LD A,(DE) 1A
Fetch the first character of the parsed filespec.
593D
CP A,2AH FE 2A
Compare against 2AH (wildcard). Wildcards not permitted for LIST.
593F
If the Z FLAG is set (wildcard), JUMP to the error.
5942
LD BC,598BH 01 8B 59
Load Register Pair BC with 598BH, the address of the LIST option keyword table containing the "LINE" keyword.
5945
GOSUB to 4476H (option parser) to parse any parenthesized options. If "LINE=nnnn" is specified, the line count is stored to the self-modifying operand at 5954H.
5948
LD B,00H 06 00
Load Register B with 00H (byte-mode access for the FCB).
594A
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the FCB work area.
594D
GOSUB to 4424H to open the text file (existing only).
5950
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
Line Skip Loop
If a LINE count was specified, the code reads and discards characters from the file until the specified number of carriage returns (lines) have been passed. This allows the user to resume listing from a specific line number.
5953
LD BC,0000H 01 00 00
Self-Modifying Code
Load Register Pair BC with the LINE skip count. The operand at 5954H-5955H was set at 592FH (default 0000H) or overwritten by the option parser if LINE was specified.
5956
LD A,B 78
Load Register A with the high byte of the line count.
5957
OR A,C B1
OR with the low byte. If BC is zero (no lines to skip), the Z FLAG is set.
5958
If the Z FLAG is set (no lines to skip), JUMP to 5967H to begin the display loop.
595A
CALL 0013H CD 13 00
Skip Loop Start
GOSUB to 0013H to read one byte from the file. Returns the byte in Register A.
595D
CP A,0DH FE 0D
Compare the byte against 0DH (carriage return). Each CR marks the end of one line.
595F
If the NZ FLAG is set (not a CR), LOOP BACK to 595AH to read the next byte.
5961
DEC C 0D
DECrement the low byte of the line counter (Register C).
5962
If the NZ FLAG is set (more lines to skip in the low byte), LOOP BACK to read more.
5964
DEC B 05
DECrement the high byte of the line counter (Register B).
5965
If the NZ FLAG is set (more lines to skip), LOOP BACK. Skip Loop End
Display Loop
The main display loop reads bytes from the file and prints them to the video display. After each CR (end of line), the BREAK key is checked. Error codes 1CH/1DH (EOF) cause a normal exit.
5967
LD DE,5551H 11 51 55
Display Loop Start
Point Register Pair DE to the filespec at 5551H for the read operation.
596A
CALL 0013H CD 13 00
GOSUB to 0013H to read one byte from the file. Returns Z on success with the byte in Register A, or NZ with an error code.
596D
If the NZ FLAG is set (read error or EOF), JUMP to 597EH to check for normal EOF conditions.
596F
GOSUB to the ROM Display Character routine to print the byte to the video display.
5972
CP A,0DH FE 0D
Compare the displayed character against 0DH (carriage return). If it was a CR, check for BREAK.
5974
If the NZ FLAG is set (not a CR), LOOP BACK to 5967H to read and display the next byte.
5976
GOSUB to the BREAK Key Check utility at 5515H. Returns NZ if the user pressed BREAK to abort.
5979
If the NZ FLAG is set (BREAK pressed), JUMP to 4030H, the error-already-displayed exit. This aborts the listing. Display Loop End
597C
JUMP BACK to 5967H to continue reading and displaying the next line.
597E
CP A,1CH FE 1C
Compare the error code against 1CH (at EOF boundary). This is a normal end-of-file condition.
5980
If the Z FLAG is set (EOF reached), JUMP to 402DH, the no-error exit. Listing complete.
5983
CP A,1DH FE 1D
Compare against 1DH (past EOF). Another normal termination condition.
5985
If the Z FLAG is set (past EOF), JUMP to 402DH, the no-error exit.
5988
For any other error code, JUMP to the disk error handler at 554CH.
598BH - Data: LIST Option Keyword Table
Keyword table for the LIST command's option parser. Contains a single keyword "LINE" with its target address.
598B-5990
DEFM "LINE " 4C 49 4E 45 20 20
Keyword "LINE" (number of lines to skip before listing), padded to 6 characters.
5991-5992
Target address 5954H: the self-modifying operand of the LD BC instruction at 5953H.
5993
DEFB 00H 00
End-of-table marker.
5994H - LOAD Command Handler
Implements the LOAD command, which loads a program file into memory for execution. The filespec is extracted, validated (no wildcards), and then the file is loaded via the SYS0 load-and-execute routine at 4430H. Format: LOAD filespec
5994
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
5997
GOSUB to 441CH to extract the filespec.
599A
If the NZ FLAG is set (no filespec), JUMP to "FILE SPEC REQUIRED" error.
599D
LD A,(DE) 1A
Fetch the first character of the parsed filespec.
599E
CP A,2AH FE 2A
Compare against 2AH ("*" = wildcard). Wildcards not permitted for LOAD.
59A0
If the Z FLAG is set (wildcard), JUMP to the error.
59A3
GOSUB to 4430H to load and commence execution of the program file specified at 5551H. If the load succeeds, this routine does not return to the caller; execution transfers to the program's entry point.
59A6
If the Z FLAG is set (load succeeded without execution transfer), JUMP to the no-error exit.
59A9
If the load failed, JUMP to the disk error handler.
59ACH - PRINT Command Handler
Implements the PRINT command, which reads a text file and sends its contents to the printer. Functionally identical to LIST except that output goes to the printer via ROM routine 003BH instead of the video display via 0033H. After each record, a CR is sent to the printer to advance the paper. The BREAK key check allows aborting the print job. Format: PRINT filespec
59AC
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
59AF
GOSUB to 441CH to extract the filespec.
59B2
If the NZ FLAG is set (no filespec), JUMP to the error.
59B5
LD A,(DE) 1A
Fetch the first character of the parsed filespec.
59B6
CP A,2AH FE 2A
Compare against "*" (wildcard character).
59B8
If wildcard found, JUMP to the error.
59BB
LD B,00H 06 00
Load Register B with 00H (byte-mode access).
59BD
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the FCB work area.
59C0
GOSUB to 4424H to open the file (existing only).
59C3
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
59C6
LD DE,5551H 11 51 55
Print Loop Start
Point Register Pair DE to the filespec at 5551H.
59C9
CALL 0013H CD 13 00
GOSUB to 0013H to read one byte from the file.
59CC
If the NZ FLAG is set (error or EOF), JUMP to 59DAH to check for normal EOF conditions.
59CE
GOSUB to the ROM Printer Output routine at 003BH to send the byte to the printer.
59D1
GOSUB to the BREAK Key Check utility.
59D4
If the NZ FLAG is set (BREAK pressed), JUMP to 4030H to abort the print job.
59D7
JUMP BACK to 59C6H to read and print the next byte. Print Loop End
59DA
PUSH AF F5
Save the error code (in Register A) and flags onto the stack before sending a final CR to the printer.
59DB
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return).
59DD
GOSUB to the ROM Printer Output routine to send a final carriage return to the printer.
59E0
POP AF F1
Restore the error code and flags from the stack.
59E1
CP A,1CH FE 1C
Compare the error code against 1CH (at EOF).
59E3
If the Z FLAG is set (EOF), JUMP to the no-error exit.
59E6
CP A,1DH FE 1D
Compare against 1DH (past EOF).
59E8
If the Z FLAG is set (past EOF), JUMP to the no-error exit.
59EB
For any other error, JUMP to the disk error handler.
5B00H - ATTRIB Command Handler
Implements the ATTRIB command, which sets file attributes including the access password (ACC), update password (UPD), protection level (PROT), and invisibility flag (INV). The file is first opened to verify it exists, then the command line is parsed for a parenthesized option list. Options are applied to the file's directory entry and written back to disk. Format: ATTRIB filespec (PROT=level, ACC=password, UPD=password, INV=ON)
5B00
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer at 5551H.
5B03
GOSUB to 441CH to extract the filespec from the command line.
5B06
If the NZ FLAG is set (no filespec), JUMP to the "FILE SPEC REQUIRED" error.
5B09
LD A,(DE) 1A
Fetch the first character of the parsed filespec.
5B0A
CP A,2AH FE 2A
Compare against 2AH (wildcard). Wildcards not permitted for ATTRIB.
5B0C
If the Z FLAG is set (wildcard), JUMP to the error.
5B0F
PUSH HL E5
Save the command line pointer (HL) onto the stack. HL currently points past the filespec in the command line and will be needed after the file is opened to parse the option list.
5B10
LD B,00H 06 00
Load Register B with 00H (byte-mode access for the FCB).
5B12
LD HL,4D00H 21 00 4D
Point Register Pair HL to 4D00H, the overlay/sector buffer used as the FCB work area for ATTRIB. This is different from the 5600H FCB used by other commands.
5B15
GOSUB to 4424H to open the file (existing only). The FCB is initialized at 4D00H.
5B18
If the NZ FLAG is set (open failed), JUMP to the disk error handler.
5B1B
POP HL E1
Restore the command line pointer from the stack. HL now points to the position after the filespec (where the option list should begin).
5B1C
LD A,(5552H) 3A 52 55
Fetch the access mode flags from 5552H. This byte in the parsed filespec area contains the file's current access permissions from the directory entry.
5B1F
AND A,07H E6 07
Mask with 07H to isolate the protection level bits (bits 0-2). If any protection level bits are set, the file has restricted access.
5B21
LD A,37H 3E 37
Load Register A with 37H, the error code for "access denied" (decimal 55). This is loaded preemptively in case the access check fails.
5B23
If the NZ FLAG is set (protection level bits are nonzero, meaning the file has restricted access), JUMP to the disk error handler with error code 37H. The ATTRIB command requires unrestricted access (protection level = 0) to modify file attributes.
5B26
XOR A,A AF
Set Register A to ZERO.
5B27
LD (5C05H),A 32 05 5C
Self-Modifying Code
Clear the options bitmask accumulator at 5C05H. This byte tracks which options have been specified: bit 0 = PROT, bit 1 = ACC (access password), bit 2 = UPD (update password).
5B2A
LD (5C0DH),A 32 0D 5C
Self-Modifying Code
Clear the visibility flag at 5C0DH. Bit 3 of this byte is set when the INV (invisible) option is specified.
Option List Scanning
The code now scans the command line for the opening parenthesis of the option list. Spaces before the parenthesis are skipped. If no parenthesis is found (and the character is not a space or CR), the "-NOTHING DONE-" error is displayed.
5B2D
LD A,(HL) 7E
Space Skip Loop Start
Fetch the current character from the command line.
5B2E
CP A,28H FE 28
Compare against 28H (ASCII (). The opening parenthesis marks the start of the option list.
5B30
If the Z FLAG is set (found opening parenthesis), JUMP to 5B3AH to begin parsing options.
5B32
CP A,20H FE 20
Compare against 20H (ASCII space).
5B34
If the NZ FLAG is set (not a space and not an opening parenthesis), JUMP to 526BH to display "-NOTHING DONE-". The user did not provide any options.
5B37
INC HL 23
INCrement HL to skip the space character.
5B38
LOOP BACK to 5B2DH to check the next character. Space Skip Loop End
Option Keyword Dispatcher
After the opening parenthesis, the code checks the first character of each option keyword. The four recognized options are: P (PROT), I (INV), A (ACC), and U (UPD). The first character alone determines which parsing branch to take.
5B3A
INC HL 23
Option Parse Entry
INCrement HL to skip past the opening parenthesis or comma separator.
5B3B
LD A,(HL) 7E
Fetch the first character of the option keyword.
5B3C
CP A,49H FE 49
Compare against 49H (ASCII I). This matches the INV (invisible) option.
5B3E
If the Z FLAG is set (option starts with 'I'), JUMP to 5B97H to parse the INV option.
5B40
CP A,41H FE 41
Compare against 41H (ASCII A). This matches the ACC (access password) option.
5B42
If the Z FLAG is set (option starts with 'A'), JUMP to 5BA7H to parse the ACC option.
5B44
CP A,55H FE 55
Compare against 55H (ASCII U). This matches the UPD (update password) option.
5B46
If the Z FLAG is set (option starts with 'U'), JUMP to 5BBCH to parse the UPD option.
5B48
CP A,50H FE 50
Compare against 50H (ASCII P). This matches the PROT (protection level) option.
5B4A
If the NZ FLAG is set (option keyword not recognized), JUMP to 5C39H to display the "ATTRIBUTE SPECIFICATION ERROR" message.
PROT Option Parser
The PROT option specifies the file protection level. Format: PROT=level, where level is one of: EXEC, READ, WRITE, RENAME, KILL, or FULL. The code scans past the keyword to find '=', then looks up the 2-character abbreviation in the protection level table at 5C61H. Special handling: if the level is "RENAME" (index 5) and the value text starts with 'N' (for "NAME"), the level is changed to 2 (WRITE) since "NAME" is an alias.
5B4D
GOSUB to the Scan to Equals Sign routine at 5BD1H. This advances HL past the keyword characters until '=' is found, then reads the value into the SYS1 work area at 5155H. Returns NZ if a value was found, Z if no '=' was present.
5B50
If the Z FLAG is set (no value after PROT), JUMP to the attribute specification error.
5B53
PUSH HL E5
Save the command line pointer onto the stack.
5B54
LD B,07H 06 07
Load Register B with 07H, the number of entries in the protection level lookup table at 5C61H.
5B56
LD DE,(5155H) ED 5B 55 51
Fetch the first 2 bytes of the parsed value from 5155H-5156H into Register Pair DE. These are the first two characters of the protection level name (e.g., "EX" for EXEC, "RE" for READ).
5B5A
LD HL,5C61H 21 61 5C
Point Register Pair HL to 5C61H, the protection level lookup table. Each entry is 2 bytes (the first two characters of the level name).
5B5D
LD A,(HL) 7E
Lookup Loop Start
Fetch the first byte of the current table entry.
5B5E
INC HL 23
INCrement HL to the second byte of the entry.
5B5F
CP A,E BB
Compare Register A against the low byte of the parsed value (Register E = first character of the level name). If they match, the first character is a potential match.
5B60
If the Z FLAG is set (first byte matched), GOSUB to 5B69H to check the second byte. If both bytes match, the routine does not return here (it pops the return address and falls through to the level assignment code).
5B63
INC HL 23
INCrement HL to skip past the second byte of this table entry, pointing to the next entry.
5B64
DECrement Register B and LOOP BACK to 5B5DH to check the next table entry. Lookup Loop End
5B66
If no match was found after checking all 7 entries, JUMP to 5C39H to display the "ATTRIBUTE SPECIFICATION ERROR".
5B69H - Protection Level Match Verifier
Called when the first byte of a protection level table entry matches. Checks the second byte. If both match, removes the CALL return address from the stack and falls through to the level assignment code at 5B6DH. If the second byte does not match, returns to the caller to continue searching.
5B69
LD A,(HL) 7E
Fetch the second byte of the table entry from (HL).
5B6A
CP A,D BA
Compare Register A against the high byte of the parsed value (Register D = second character of the level name).
5B6B
RET NZ C0
If the NZ FLAG is set (second byte does not match), return to the caller at 5B63H to continue searching the table.
Match Found
Both bytes matched. The protection level has been identified. The remaining loop counter in Register B indicates which entry matched: B=7 means entry 0 (first), B=1 means entry 6 (last). The code converts this to a protection level value.
5B6C
POP AF F1
Pop the return address from the CALL Z,5B69H off the stack, discarding it. This prevents returning to the lookup loop since a match was found.
5B6D
LD A,B 78
Load Register A with Register B (the remaining loop counter).
5B6E
DEC A 3D
DECrement Register A. The result is the 0-based index from the end of the table, which maps to the protection level value. For example: if B=7 (first entry, EXEC), A=6; if B=1 (last entry), A=0.
5B6F
CP A,05H FE 05
Compare Register A against 05H. If A=5, the matched entry is the second table entry (RENAME level). This requires special handling for the "NAME" alias.
5B71
If the NZ FLAG is set (not the RENAME entry), JUMP to 5B7EH to store the protection level directly.
5B73
LD A,(5157H) 3A 57 51
Fetch the third character of the parsed protection level name from 5157H (offset +2 in the SYS1 work area). For "RENAME" this would be 'N'; for "READ" this would be 'A'.
5B76
CP A,4EH FE 4E
Compare against 4EH (ASCII N). If the third character is 'N', the user typed "REN..." which matches RENAME.
5B78
LD A,05H 3E 05
Load Register A with 05H, the protection level value for RENAME. This is the default if the third character is not 'N'.
5B7A
If the NZ FLAG is set (third character is NOT 'N', so it is READ not RENAME), JUMP to 5B7EH with A=05H for READ level.
5B7C
LD A,02H 3E 02
Load Register A with 02H, the protection level value for... Wait, this path is taken when the third char IS 'N' (RENAME). So RENAME gets level 2.
5B7E
LD (5C0BH),A 32 0B 5C
Self-Modifying Code
Store the protection level value to 5C0BH, which is the operand of an OR instruction at 5C0AH. This will be applied to the directory entry flags byte later.
5B81
POP HL E1
Restore the command line pointer from the stack (saved at 5B53H).
5B82
LD B,01H 06 01
Load Register B with 01H, a bitmask for the PROT option (bit 0). This indicates that PROT was specified.
Option Bitmask Accumulation
Each option sets a bit in the accumulator at 5C05H: bit 0 = PROT, bit 1 = ACC, bit 2 = UPD. After setting the appropriate bit, the code checks for more options (comma) or the closing parenthesis.
5B84
LD A,(5C05H) 3A 05 5C
Fetch the current options bitmask from the self-modifying storage at 5C05H.
5B87
OR A,B B0
OR Register A with Register B to set the bit for the current option.
5B88
LD (5C05H),A 32 05 5C
Store the updated options bitmask back to 5C05H.
5B8B
LD A,(HL) 7E
Fetch the next character from the command line. After parsing an option value, this should be either ')' (end of list), ',' (more options follow), or CR (end of command).
5B8C
CP A,29H FE 29
Compare against 29H (ASCII )). Closing parenthesis ends the option list.
5B8E
If the Z FLAG is set (closing parenthesis), JUMP to 5BF7H to apply the parsed options to the directory entry and write it back to disk.
5B90
CP A,2CH FE 2C
Compare against 2CH (ASCII ,). A comma separates multiple options.
5B92
If the Z FLAG is set (comma found), JUMP BACK to 5B3AH to parse the next option keyword.
5B94
If neither ')' nor ',' was found, JUMP to the attribute specification error.
5B97H - INV Option Parser
Parses the INV (invisible) option. Sets bit 3 of the visibility flag at 5C0DH. The INV option does not take a value; its mere presence makes the file invisible in directory listings.
5B97
GOSUB to the Scan to Equals Sign routine at 5BD1H to advance past the "INV" keyword. For INV, no '=' is expected; the routine returns Z if no value was found.
5B9A
If the NZ FLAG is set (a value was found after INV=, which is invalid for this option), JUMP to the attribute specification error.
5B9D
LD A,(5C0DH) 3A 0D 5C
Fetch the current visibility flag from 5C0DH.
5BA0
OR A,08H F6 08
OR with 08H to set bit 3, marking the file as invisible.
5BA2
LD (5C0DH),A 32 0D 5C
Store the updated visibility flag back to 5C0DH.
5BA5
JUMP to 5B84H to accumulate the option bit and check for more options.
5BA7H - ACC Option Parser
Parses the ACC (access password) option. The value after '=' is an 8-character password string that is hashed and stored to 516AH-516BH for later application to the directory entry. Sets bit 1 in the options bitmask.
5BA7
GOSUB to the Scan to Equals Sign routine. Returns NZ with the value text parsed into 5155H if '=' was found.
5BAA
If the Z FLAG is set (no value after ACC), JUMP to the error. ACC requires a password value.
5BAD
PUSH HL E5
Save the command line pointer.
5BAE
LD DE,5155H 11 55 51
Point Register Pair DE to 5155H, where the parsed value text was stored by 5BD1H.
5BB1
CALL 50D1H CD D1 50
GOSUB to the SYS1 password hash routine at 50D1H to compute the 16-bit CRC hash of the password text. Returns the hash in Register Pair HL.
5BB4
LD (516AH),HL 22 6A 51
Store the access password hash to 516AH-516BH in the SYS1 work area. This value will be written to the directory entry's access password field later.
5BB7
POP HL E1
Restore the command line pointer.
5BB8
LD B,02H 06 02
Load Register B with 02H, the bitmask for the ACC option (bit 1).
5BBA
JUMP to 5B84H to accumulate the option bit and continue parsing.
5BBCH - UPD Option Parser
Parses the UPD (update password) option. Identical in structure to the ACC parser but stores the hash to 5168H-5169H and sets bit 2 in the options bitmask.
5BBC
GOSUB to the Scan to Equals Sign routine.
5BBF
If no value provided, JUMP to the attribute specification error.
5BC2
PUSH HL E5
Save the command line pointer.
5BC3
LD DE,5155H 11 55 51
Point DE to the parsed value text at 5155H.
5BC6
CALL 50D1H CD D1 50
GOSUB to the password hash routine at 50D1H. Returns the hash in HL.
5BC9
LD (5168H),HL 22 68 51
Store the update password hash to 5168H-5169H. This will be written to the directory entry's update password field.
5BCC
POP HL E1
Restore the command line pointer.
5BCD
LD B,04H 06 04
Load Register B with 04H, the bitmask for the UPD option (bit 2).
5BCF
JUMP to 5B84H to accumulate the option bit.
5BD1H - Scan to Equals Sign and Parse Value
Scans the command line from (HL) looking for an '=' sign, skipping over the keyword characters. If '=' is found, reads the value text into the SYS1 work area at 5155H (space-padded to 8 characters) and returns NZ. If no '=' is found (delimiter is CR, ')' or ','), returns Z indicating no value was provided. Used by the PROT, INV, ACC, and UPD option parsers.
5BD1
INC HL 23
Scan Loop Start
INCrement HL to advance to the next character in the command line.
5BD2
LD A,(HL) 7E
Fetch the current character.
5BD3
CP A,0DH FE 0D
Compare against 0DH (carriage return). CR terminates the command line.
5BD5
RET Z C8
If the Z FLAG is set (end of line), return with Z indicating no value was found.
5BD6
CP A,29H FE 29
Compare against 29H (ASCII ')' closing parenthesis).
5BD8
RET Z C8
If the Z FLAG is set (end of option list), return with Z.
5BD9
CP A,2CH FE 2C
Compare against 2CH (ASCII ',' comma separator).
5BDB
RET Z C8
If the Z FLAG is set (next option follows), return with Z.
5BDC
CP A,3DH FE 3D
Compare against 3DH (ASCII '=' equals sign).
5BDE
If the NZ FLAG is set (not an equals sign), LOOP BACK to 5BD1H to skip this character and check the next. Scan Loop End
Value Extraction
The '=' sign was found. The code now reads the value text that follows and stores it into the SYS1 work area at 5155H, padded with spaces to 8 characters.
5BE0
INC HL 23
INCrement HL to advance past the '=' sign to the start of the value text.
5BE1
LD DE,5155H 11 55 51
Point Register Pair DE to 5155H, the SYS1 work area where the parsed value will be stored.
5BE4
LD B,08H 06 08
Load Register B with 08H (8 characters maximum for the value).
5BE6
PUSH DE D5
Save the work area pointer.
5BE7
PUSH BC C5
Save the character count.
5BE8
LD A,20H 3E 20
Load Register A with 20H (space) to pre-fill the work area.
5BEA
LD (DE),A 12
Pre-fill Loop Start
Store a space to the current position in the work area.
5BEB
INC DE 13
INCrement DE to the next position.
5BEC
DECrement B and LOOP BACK until all 8 positions are filled with spaces. Pre-fill Loop End
5BEE
POP BC C1
Restore the character count (B=08H).
5BEF
POP DE D1
Restore the work area pointer (DE=5155H).
5BF0
CALL 5081H CD 81 50
GOSUB to the SYS1 routine at 5081H to copy characters from the command line at (HL) into the work area at (DE), stopping at a delimiter. The routine advances HL past the copied characters.
5BF3
DEC HL 2B
DECrement HL to back up one position. The SYS1 copy routine at 5081H advanced HL one past the delimiter, so this backs up to the delimiter itself for the caller to examine.
5BF4
OR A,01H F6 01
OR Register A with 01H to force the NZ FLAG, indicating that a value was found and parsed.
5BF6
RET C9
Return with NZ (value found, stored at 5155H).
5BF7H - ATTRIB: Apply Options to Directory Entry
Reached after the closing parenthesis ')' is parsed. Reads the file's directory sector, applies the parsed options (protection level, access password, update password, visibility) to the directory entry, and writes it back to disk.
5BF7
LD BC,(5557H) ED 4B 57 55
Fetch the directory entry location from 5557H-5558H in the filespec work area. Register B contains the sector number and C contains the drive number for the directory sector holding this file's entry.
5BFB
GOSUB to SYS0 routine at 4AC1H to read the directory sector containing the file's entry into the buffer at 4200H. Returns with HL pointing to the start of the file's 32-byte directory entry.
5BFE
If the NZ FLAG is set (read failed), JUMP to the disk error handler.
5C01
LD A,(HL) 7E
Fetch the flags byte of the directory entry (offset +00H). This byte contains the file type in the upper 5 bits and the protection level in the lower 3 bits.
5C02
AND A,0F8H E6 F8
Mask with 0F8H to clear the protection level bits (bits 0-2), preserving the file type bits. The new protection level will be OR'd in below.
5C04
LD D,00H 16 00
Self-Modifying Code
Load Register D with the options bitmask. The operand at 5C05H was built during option parsing: bit 0 = PROT specified, bit 1 = ACC specified, bit 2 = UPD specified.
5C06
BIT 0,D CB 42
Test bit 0 of Register D (PROT option). If bit 0 is set, a new protection level was specified.
5C08
If the Z FLAG is set (PROT not specified), JUMP to 5C0CH to skip applying the protection level.
5C0A
OR A,00H F6 00
Self-Modifying Code
OR Register A with the protection level value. The operand at 5C0BH was written at 5B7EH with the parsed protection level (0-7). This OR inserts the protection level into the lower 3 bits of the flags byte.
5C0C
OR A,00H F6 00
Self-Modifying Code
OR Register A with the visibility flag. The operand at 5C0DH was written at 5BA2H with 08H if INV was specified (bit 3 = invisible). This sets or clears the invisible attribute in the flags byte.
5C0E
LD (HL),A 77
Store the updated flags byte back to the directory entry at offset +00H.
5C0F
LD A,L 7D
Load Register A with the low byte of HL (base of directory entry).
5C10
ADD A,10H C6 10
ADD 10H to point to offset +10H within the directory entry, which is the password hash fields.
5C12
LD L,A 6F
Store the updated offset to Register L. HL now points to the update password field.
5C13
BIT 2,D CB 52
Test bit 2 of Register D (UPD option). If bit 2 is set, a new update password was specified.
5C15
If the Z FLAG is set (UPD not specified), JUMP to 5C21H to skip writing the update password.
5C17
LD A,(5168H) 3A 68 51
Fetch the low byte of the update password hash from 5168H (stored at 5BC9H during UPD parsing).
5C1A
LD (HL),A 77
Store the low byte to offset +10H of the directory entry.
5C1B
LD A,(5169H) 3A 69 51
Fetch the high byte of the update password hash from 5169H.
5C1E
INC HL 23
INCrement HL to offset +11H.
5C1F
LD (HL),A 77
Store the high byte to offset +11H.
5C20
DEC HL 2B
DECrement HL back to offset +10H to maintain pointer consistency.
5C21
INC HL 23
INCrement HL to offset +12H (access password field).
5C22
INC HL 23
INCrement HL to offset +12H... actually this advances past +10H/+11H to reach +12H which is the access password low byte.
5C23
BIT 1,D CB 4A
Test bit 1 of Register D (ACC option). If bit 1 is set, a new access password was specified.
5C25
If the Z FLAG is set (ACC not specified), JUMP to 5C30H to skip writing the access password.
5C27
LD A,(516AH) 3A 6A 51
Fetch the low byte of the access password hash from 516AH (stored at 5BB4H during ACC parsing).
5C2A
LD (HL),A 77
Store the low byte to the access password field in the directory entry.
5C2B
LD A,(516BH) 3A 6B 51
Fetch the high byte of the access password hash from 516BH.
5C2E
INC HL 23
INCrement HL to the next byte in the access password field.
5C2F
LD (HL),A 77
Store the high byte.
5C30
GOSUB to SYS0 routine at 4AD6H to write the directory and GAT sectors back to disk, saving the updated file attributes.
5C33
If the NZ FLAG is set (write failed), JUMP to the disk error handler.
5C36
JUMP to 402DH, the no-error exit. ATTRIB command complete.
5C39H - "ATTRIBUTE SPECIFICATION ERROR" Handler
Error handler displayed when the ATTRIB option list contains an unrecognized keyword or malformed syntax.
5C39
LD HL,5C42H 21 42 5C
Point Register Pair HL to the error message at 5C42H.
5C3C
GOSUB to the SYS0 Display Message routine to print the error.
5C3F
JUMP to 4030H, the error-already-displayed exit.
5C42H - Data: ATTRIB Error Message and Protection Level Table
ASCII error message string and the 2-byte-per-entry protection level lookup table used by the PROT option parser.
5C42-5C60
DEFM 0AH + "ATTRIBUTE SPECIFICATION ERROR" + 0DH 0A 41 54 54 52 49 42 55 54 45 20 53 50 45 43 49 46 49 43 41 54 49 4F 4E 20 45 52 52 4F 52 0D
Linefeed + "ATTRIBUTE SPECIFICATION ERROR" + CR.
5C61H - Data: Protection Level Lookup Table
Table of 7 two-byte entries representing the first two characters of each recognized protection level name. The entries are searched in reverse order: entry 0 (index 6) = EXEC, entry 1 (index 5) = READ, entry 2 (index 4) = WRITE, entry 3 (index 3), entry 4 (index 2) = RENAME, entry 5 (index 1) = KILL, entry 6 (index 0) = FULL. The loop counter B starts at 7 and decrements; the protection level value is derived as B-1 after a match.
5C61-5C62
DEFM "EX" 45 58
Entry 0: "EX" matches EXEC (execute only). Protection level value = 6.
5C63-5C64
DEFM "RE" 52 45
Entry 1: "RE" matches READ or RENAME. Protection level value = 5. Special handling at 5B73H checks the third character to distinguish READ (level 5) from RENAME (level 2).
5C65-5C66
DEFM "WR" 57 52
Entry 2: "WR" matches WRITE. Protection level value = 4.
5C67-5C68
DEFB 7EH,7EH 7E 7E
Entry 3: Bytes 7EH,7EH. This entry represents an unused or reserved level (value = 3). The byte value 7EH does not correspond to a standard ASCII letter and serves as a placeholder that cannot be matched by normal user input.
5C69-5C6A
DEFM "NA" 4E 41
Entry 4: "NA" matches NAME (an alias for RENAME). Protection level value = 2.
5C6B-5C6C
DEFM "KI" 4B 49
Entry 5: "KI" matches KILL (total privilege). Protection level value = 1.
5C6D-5C6E
DEFM "FU" 46 55
Entry 6: "FU" matches FULL (alias for KILL, total privilege). Protection level value = 0.
5C6FH - DIR Command Handler
Implements the DIR command, which displays the directory listing for a specified drive. The command reads all 8 directory sectors (sectors 0-7, loaded into a 2048-byte buffer at 6100H-68FFH), then iterates through each 32-byte directory entry displaying the filename, extension, attribute flags (S=system, I=invisible, P=password protected), and optionally the file size metrics (LRL, EOF offset, sector count). An optional drive specifier can be provided; the default is drive 0. Options A (show all including system/invisible), I (show invisible), and S (show system) can be specified in parentheses. The directory header and disk label are read from sector 0 offset 0D0H and displayed. Format: DIR [:n] [(S,I)]
5C6F
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H to clear the three option filter flags.
5C72
LD (5D9BH),BC ED 43 9B 5D
Self-Modifying Code
Clear the system file filter at 5D9AH-5D9BH (operand of LD DE at 5D9AH). When nonzero, system files are displayed.
5C76
LD (5D0BH),BC ED 43 0B 5D
Self-Modifying Code
Clear the invisible file filter at 5D0AH-5D0BH (operand of LD DE at 5D0AH). When nonzero, invisible files are displayed.
5C7A
LD (5CFDH),BC ED 43 FD 5C
Self-Modifying Code
Clear the additional filter at 5CFCH-5CFDH (operand of LD DE at 5CFCH).
5C7E
LD C,00H 0E 00
Load Register C with 00H as the default drive number (drive 0).
5C80
LD A,(HL) 7E
Fetch the next character from the command line to check for a drive specifier.
5C81
CP A,3AH FE 3A
Compare against 3AH (ASCII ':'). A colon indicates a drive specifier follows.
5C83
If the NZ FLAG is set (no colon), JUMP to 5C8BH to use the default drive 0.
5C85
INC HL 23
INCrement HL past the colon.
5C86
LD A,(HL) 7E
Fetch the drive number digit.
5C87
INC HL 23
INCrement HL past the drive digit.
5C88
SUB A,30H D6 30
Convert the ASCII digit to binary (0-3).
5C8A
LD C,A 4F
Store the drive number in Register C.
5C8B
PUSH BC C5
Save the drive number (in Register C) onto the stack for later use.
5C8C
LD A,C 79
Load Register A with the drive number.
5C8D
ADD A,30H C6 30
Convert the drive number back to ASCII for display in the directory header.
5C8F
LD (5E9EH),A 32 9E 5E
Self-Modifying Code
Store the ASCII drive number to 5E9EH, which is embedded in the directory header format string at 5E83H. This inserts the drive letter into the "DRIVE X" portion of the header.
5C92
LD DE,5E6AH 11 6A 5E
Point Register Pair DE to 5E6AH, the DIR option keyword table containing "A", "I", and "S" filter keywords.
5C95
GOSUB to 4476H (option parser) to parse any parenthesized options (A, I, S) and set the corresponding filter flags.
5C98
LD HL,5E83H 21 83 5E
Point Register Pair HL to the directory header string at 5E83H. This string contains the clear-screen code (1CH, 1FH) followed by "FILE DIRECTORY --- DRIVE X" with the drive number filled in.
5C9B
GOSUB to the SYS0 Display Message routine to clear the screen and print the directory header.
5C9E
POP BC C1
Restore the drive number from the stack.
5C9F
PUSH BC C5
Save it again (it will be needed multiple times).
5CA0
GOSUB to SYS0 routine at 4B55H to perform a track cache lookup for the specified drive.
5CA3
LD E,00H 1E 00
Load Register E with 00H (directory sector 0) to read the disk label sector first.
5CA5
LD HL,4200H 21 00 42
Point Register Pair HL to the sector buffer at 4200H.
5CA8
GOSUB to SYS0 routine at 4B35H to read directory sector 0 into the buffer at 4200H.
5CAB
If the NZ FLAG is set (read failed), JUMP to the disk error handler.
Disk Label Display
The directory sector 0 contains the disk label at offset 0D0H (8 bytes for the name) and the date at offset 0D8H (8 bytes for MM/DD/YY). These are copied to format string positions and displayed.
5CAE
LD HL,42D0H 21 D0 42
Point Register Pair HL to 42D0H (offset 0D0H in the sector buffer at 4200H), the disk label name field (8 bytes).
5CB1
LD DE,5EA1H 11 A1 5E
Point Register Pair DE to 5EA1H, the position in the format string where the disk label name will be inserted.
5CB4
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H (8 bytes to copy).
5CB7
LDIR ED B0
Block Copy
Copy 8 bytes of the disk label name from 42D0H to 5EA1H in the format string.
5CB9
LD DE,5EADH 11 AD 5E
Point Register Pair DE to 5EADH, the position for the disk label date in the format string.
5CBC
LD BC,0008H 01 08 00
Load Register Pair BC with 0008H (8 bytes for the date).
5CBF
LDIR ED B0
Block Copy
Copy 8 bytes of the disk date from 42D8H to 5EADH. HL advanced automatically from the previous LDIR.
5CC1
LD HL,5EA1H 21 A1 5E
Point Register Pair HL to the completed disk label format string at 5EA1H.
5CC4
GOSUB to the SYS0 Display Message routine to print the disk label name and date.
Directory Sector Loading
The code now reads all 8 directory sectors (sectors 0-7) into a contiguous 2048-byte buffer at 6100H-68FFH. Each sector is 256 bytes, and each is loaded into a separate 256-byte page (6100H, 6200H, ... 6800H).
5CC7
POP BC C1
Restore the drive number from the stack.
5CC8
LD B,00H 06 00
Load Register B with 00H as the starting directory sector number. Sectors 0-7 will be read.
5CCA
LD DE,6100H 11 00 61
Point Register Pair DE to 6100H, the start of the directory image buffer.
5CCD
Sector Load Loop Start
GOSUB to SYS0 routine at 4AC1H to read a directory sector into the buffer. Register B holds the sector number, C holds the drive number. Returns with HL pointing to the loaded data.
5CD0
If the NZ FLAG is set (read failed), JUMP to the disk error handler.
5CD3
LD L,00H 2E 00
Set Register L to 00H to point to the start of the loaded sector data.
5CD5
PUSH BC C5
Save the sector/drive numbers.
5CD6
LD BC,0100H 01 00 01
Load Register Pair BC with 0100H (256 bytes, one full sector).
5CD9
LDIR ED B0
Block Copy
Copy 256 bytes from the sector buffer to the directory image buffer at DE. After the copy, DE points to the next 256-byte page in the buffer.
5CDB
POP BC C1
Restore the sector/drive numbers.
5CDC
INC B 04
INCrement the sector number in Register B.
5CDD
LD A,B 78
Load Register A with the sector number.
5CDE
CP A,08H FE 08
Compare against 08H (8 sectors). Sectors 0-7 are loaded.
5CE0
If the NZ FLAG is set (more sectors to load), LOOP BACK to 5CCDH. Sector Load Loop End
Directory Entry Display Loop
With all directory sectors loaded into the 6100H-68FFH buffer, the code now iterates through each 32-byte entry. Each entry's flags byte at offset +00H is checked to determine if the file should be displayed (active user file = bit 4 set, system = bit 7, invisible = bit 3, protected = bit 6). The filename at offset +05H (8 bytes) and extension at offset +0DH (3 bytes) are displayed, followed by attribute flags S (system), I (invisible), and P (password-protected). Up to 3 entries are displayed per line. After each line, the screen line counter is decremented and a BREAK check is performed.
5CE2
LD HL,6100H 21 00 61
Point Register Pair HL to 6100H, the start of the loaded directory image.
5CE5
LD A,0CH 3E 0C
Load Register A with 0CH (12 decimal), the number of display lines before pausing for the user.
5CE7
LD (5DABH),A 32 AB 5D
Self-Modifying Code
Store 0CH to 5DABH, the lines-per-page counter. This is the operand of a LD A,nnH instruction at 5DAAH that counts down display lines.
5CEA
LD B,03H 06 03
Load Register B with 03H, the number of file entries to display per line.
5CEC
LD A,(HL) 7E
Entry Display Loop Start
Fetch the flags byte of the current directory entry at (HL).
5CED
PUSH HL E5
Save the entry base pointer onto the stack.
5CEE
BIT 4,A CB 67
Test bit 4 of the flags byte. Bit 4 set indicates an active file entry. If bit 4 is clear, the entry is empty or deleted.
5CF0
If the Z FLAG is set (not an active file), JUMP to 5DBFH to skip this entry and advance to the next.
5CF3
BIT 7,A CB 7F
Test bit 7. Bit 7 set indicates a system file.
5CF5
If the NZ FLAG is set (system file) and the system filter is not active, JUMP to 5DBFH to skip. The system filter check is handled by the self-modifying code below.
5CF8
BIT 6,A CB 77
Test bit 6. Bit 6 set indicates a password-protected/special file.
5CFA
If the Z FLAG is set (not protected), JUMP to 5D06H to check the invisible bit.
5CFC
LD DE,0000H 11 00 00
Self-Modifying Code
Load DE with the protected file filter flag at 5CFDH. When the option parser set this to nonzero, protected files are shown.
5CFF
LD A,D 7A
Load Register A with the high byte of the filter flag.
5D00
OR A,E B3
OR with the low byte. If zero, the filter is not active and the file is skipped.
5D01
If the Z FLAG is set (filter not active), JUMP to 5DBFH to skip this protected file.
5D04
Filter is active, so proceed to display the file entry.
5D06
BIT 3,A CB 5F
Test bit 3 of the flags byte. Bit 3 set indicates an invisible file.
5D08
If the Z FLAG is set (not invisible), JUMP to 5D12H to display the file.
5D0A
LD DE,0000H 11 00 00
Self-Modifying Code
Load DE with the invisible file filter flag at 5D0BH. Nonzero means invisible files should be shown.
5D0D
LD A,D 7A
Load Register A with the high byte of the filter flag.
5D0E
OR A,E B3
OR with the low byte.
5D0F
If zero (invisible filter not active), skip this entry.
Filename Display
The code now displays the filename (8 characters at offset +05H) and extension (3 characters following the filename, separated by '/') for the current directory entry. A character counter in Register C tracks the display column position for alignment.
5D12
PUSH BC C5
Save the entries-per-line counter (Register B) onto the stack.
5D13
LD A,L 7D
Load Register A with the low byte of HL (entry base address).
5D14
ADD A,05H C6 05
ADD 05H to point to offset +05H, the start of the 8-character filename within the directory entry.
5D16
LD L,A 6F
Store the updated offset to Register L. HL now points to the filename.
5D17
LD C,11H 0E 11
Load Register C with 11H (17 decimal), a column width counter. Each directory entry occupies 17 character positions on the display line.
5D19
LD B,08H 06 08
Load Register B with 08H (8 characters in the filename).
5D1B
LD A,(HL) 7E
Name Display Loop Start
Fetch the next character of the filename.
5D1C
INC HL 23
INCrement HL to the next character.
5D1D
CP A,20H FE 20
Compare against 20H (space). A space indicates the end of the filename (names are space-padded to 8 characters).
5D1F
If the Z FLAG is set (space found), JUMP to 5D29H to skip remaining name characters and check for an extension.
5D21
GOSUB to the ROM Display Character routine to print the filename character.
5D24
DEC C 0D
DECrement the column counter.
5D25
DECrement Register B and LOOP BACK to 5D1BH. Name Display Loop End
5D27
JUMP to 5D2DH to check for an extension (all 8 name characters were non-space).
5D29
LD A,L 7D
Load Register A with the low byte of HL (current position past the space).
5D2A
ADD A,B 80
ADD Register B (remaining character count) to skip to the end of the 8-byte name field.
5D2B
DEC A 3D
DECrement by 1 to adjust (the INC HL at 5D1CH already advanced one past the space).
5D2C
LD L,A 6F
Store the adjusted position. HL now points to offset +0DH (start of the 3-byte extension).
5D2D
LD A,(HL) 7E
Fetch the first character of the extension.
5D2E
CP A,20H FE 20
Compare against space. If the extension is blank (all spaces), skip the separator and extension display.
5D30
If the Z FLAG is set (no extension), JUMP to 5D46H to pad with spaces and display attribute flags.
5D32
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII /), the separator between filename and extension in TRSDOS notation.
5D34
Display the '/' separator.
5D37
DEC C 0D
DECrement the column counter for the separator character.
5D38
LD B,03H 06 03
Load Register B with 03H (3 extension characters to display).
5D3A
LD A,(HL) 7E
Extension Display Loop Start
Fetch the next extension character.
5D3B
INC HL 23
INCrement HL.
5D3C
CP A,20H FE 20
Compare against space (end of extension).
5D3E
If space, JUMP to pad remaining columns.
5D40
Display the extension character.
5D43
DEC C 0D
DECrement the column counter.
5D44
DECrement B and loop. Extension Display Loop End
Attribute Flags Display
After the filename and extension, the attribute flags are displayed: 'S' if the file is a system file (bit 6 of flags), 'I' if invisible (bit 3), and 'P' if password-protected. The password check compares the update password hash at offset +10H against 4296H (blank password marker).
5D46
LD A,20H 3E 20
Load Register A with 20H (space) for column padding.
5D4B
DEC C 0D
DECrement the column counter.
5D4C
LD A,L 7D
Load Register A with the current position to reposition to the entry base for flags access.
5D4D
AND A,0E0H E6 E0
Mask with 0E0H to round down to the start of the 32-byte directory entry.
5D4F
LD L,A 6F
Set HL to the entry base address.
5D50
LD B,(HL) 46
Fetch the flags byte from offset +00H into Register B for attribute testing.
5D51
LD A,53H 3E 53
Load Register A with 53H (ASCII S) for the system file indicator.
5D53
BIT 6,B CB 70
Test bit 6 of the flags byte (system attribute).
5D55
If NZ (bit 6 set, system file), JUMP to 5D59H to display 'S'.
5D57
LD A,20H 3E 20
Not a system file, load space instead of 'S'.
5D59
Display 'S' or space.
5D5C
LD A,49H 3E 49
Load Register A with 49H (ASCII I) for the invisible indicator.
5D5E
BIT 3,B CB 58
Test bit 3 of the flags byte (invisible attribute).
5D60
If NZ (bit 3 set, invisible), display 'I'.
5D62
LD A,20H 3E 20
Not invisible, load space.
5D64
Display 'I' or space.
5D67
PUSH HL E5
Save the entry base pointer.
5D68
LD A,L 7D
Load Register A with the entry base low byte.
5D69
ADD A,10H C6 10
ADD 10H to point to offset +10H (update password hash field).
5D6B
LD L,A 6F
Set HL to the password field.
5D6C
LD E,(HL) 5E
Fetch the low byte of the update password hash.
5D6D
INC L 2C
INCrement to the high byte.
5D6E
LD D,(HL) 56
Fetch the high byte. DE now holds the update password hash.
5D6F
PUSH HL E5
Save the current pointer.
5D70
LD HL,4296H 21 96 42
Load Register Pair HL with 4296H, the blank password hash marker.
5D73
SBC HL,DE ED 52
SUBtract the file's password hash (DE) from 4296H (HL). If they match, HL=0 and Z is set, meaning no password.
5D75
POP HL E1
Restore the pointer.
5D76
If Z (password matches blank marker, no password), JUMP to 5D8CH to display a space instead of 'P'.
5D78
LD A,B 78
Load Register A with the flags byte (still in Register B).
5D79
AND A,07H E6 07
Mask with 07H to isolate the protection level bits (0-7).
5D7B
LD A,50H 3E 50
Load Register A with 50H (ASCII P) for the password indicator.
5D7D
If NZ (protection level is nonzero), JUMP to 5D8EH to display 'P'.
5D7F
INC L 2C
INCrement to offset +12H (access password hash, low byte).
5D80
LD E,(HL) 5E
Fetch access password low byte.
5D81
INC L 2C
INCrement to high byte.
5D82
LD D,(HL) 56
Fetch access password high byte into DE.
5D83
LD HL,4296H 21 96 42
Load blank password marker.
5D86
SBC HL,DE ED 52
Compare access password against blank marker.
5D88
LD A,50H 3E 50
Preload 'P' for password indicator.
5D8A
If NZ (access password is not blank), display 'P'.
5D8C
LD A,20H 3E 20
No password on either field, load space.
5D8E
Display 'P' or space.
5D91
POP HL E1
Restore the entry base pointer.
5D92
LD A,20H 3E 20
Column Padding Loop Start
Load space character for remaining column padding.
5D97
DEC C 0D
DECrement the column counter.
5D98
If NZ (more columns to pad), loop back. Column Padding Loop End
Optional File Metrics Display
If the system file filter is active (showing extended info), the code calls the file metrics display routine at 5DF1H which shows the LRL, EOF offset, and sector count for each file.
5D9A
LD DE,0000H 11 00 00
Self-Modifying Code
Load DE with the extended info filter from 5D9BH. Nonzero means file metrics should be displayed.
5D9D
LD A,D 7A
Check if filter is active.
5D9E
OR A,E B3
OR high and low bytes.
5D9F
POP BC C1
Restore the entries-per-line counter.
5DA0
If NZ (extended info active), GOSUB to 5DF1H to display file metrics (LRL, EOF, sector count) for the current entry.
5DA3
DECrement entries-per-line counter (Register B). If not zero, more entries fit on this line; JUMP to 5DBFH to advance to the next entry.
End of Line Processing
After 3 entries per line, a carriage return is output and the lines-per-page counter is checked. When the counter reaches zero, the code pauses for a keypress before continuing (wait for SHIFT-@ via 0049H). The BREAK key is also checked to allow aborting.
5DA5
LD A,0DH 3E 0D
Load CR for end of line.
5DA7
Display carriage return.
5DAA
LD A,00H 3E 00
Self-Modifying Code
Load Register A with the current lines-per-page counter. The operand at 5DABH is decremented each line and reset to 0CH (12) when the page is full.
5DAC
DEC A 3D
DECrement the line counter.
5DAD
If NZ (more lines fit on the page), JUMP to 5DB4H to update the counter and continue.
5DAF
GOSUB to the ROM Keyboard Scan routine at 0049H to pause and wait for any keypress before showing the next page of entries.
5DB2
LD A,0CH 3E 0C
Reset the lines-per-page counter to 0CH (12).
5DB4
LD (5DABH),A 32 AB 5D
Self-Modifying Code
Store the updated line counter back to 5DABH.
5DB7
GOSUB to the BREAK Key Check utility.
5DBA
If NZ (BREAK pressed), JUMP to 5DDBH to clear the buffer and exit via error path.
5DBD
LD B,03H 06 03
Reset the entries-per-line counter to 3.
Advance to Next Entry
The code advances HL to the next directory entry. Entries are 32 bytes (20H) each, stored across pages 61xxH-68xxH. The page boundary logic handles transitions between pages and between the 8-sector blocks.
5DBF
POP HL E1
Restore the entry pointer from the stack (saved at 5CEDH).
5DC0
INC H 24
INCrement the high byte of HL. Each directory sector occupies one 256-byte page, and entries at the same L offset across pages represent entries in different sectors. This advances to the same entry position in the next sector's page.
5DC1
LD A,H 7C
Load Register A with the updated high byte.
5DC2
CP A,69H FE 69
Compare against 69H. The directory buffer spans 6100H-68FFH (pages 61H-68H). A high byte of 69H means we have gone past the last sector.
5DC4
If NZ (still within the buffer), JUMP BACK to 5CECH to process the next entry.
5DC7
LD H,61H 26 61
Reset the high byte to 61H (back to the first sector's page).
5DC9
LD A,L 7D
Load the low byte (entry offset within the sector).
5DCA
ADD A,20H C6 20
ADD 20H (32 bytes) to advance to the next entry within the same sector.
5DCC
LD L,A 6F
Store the updated offset.
5DCD
If NO CARRY (no overflow past 256), JUMP BACK to process the next entry. If carry occurred, all entries in all sectors have been processed.
Directory Complete
All directory entries have been displayed. The code clears the directory image buffer and exits.
5DD0
GOSUB to 5DE1H to clear the directory image buffer (zero-fill 6100H-68FFH).
5DD3
LD A,0DH 3E 0D
Load CR for final newline.
5DD5
Display the final carriage return.
5DD8
JUMP to 402DH, the no-error exit. DIR command complete.
5DDB
GOSUB to 5DE1H to clear the directory buffer before exiting via error path (BREAK was pressed).
5DDE
JUMP to 4030H, the error-already-displayed exit.
5DE1H - Clear Directory Image Buffer
Zero-fills the 2048-byte directory image buffer from 6100H to 68FFH. Called before exiting the DIR command to clean up memory.
5DE1
LD HL,6100H 21 00 61
Point Register Pair HL to 6100H, the start of the directory image buffer.
5DE4
LD B,00H 06 00
Load Register B with 00H, the zero-fill value.
5DE6
LD (HL),B 70
Clear Loop Start
Store zero to the current byte.
5DE7
INC L 2C
INCrement the low byte of HL.
5DE8
If NZ (haven't wrapped past the end of the page), loop back.
5DEA
INC H 24
INCrement the high byte to advance to the next 256-byte page.
5DEB
LD A,H 7C
Load the high byte.
5DEC
CP A,69H FE 69
Compare against 69H (one past the last page of the buffer).
5DEE
If NZ (more pages to clear), loop back. Clear Loop End
5DF0
RET C9
Return to the caller.
5DF1H - DIR: Display File Metrics
Displays the file size metrics for a directory entry: the EOF byte offset (from offset +03H), the Logical Record Length (from offset +04H), the sector count (from offset +10H/+11H converted via 24-bit division at 60A7H), and the total granule count (computed by walking the extent chain at 5E3EH). All numeric values are converted to decimal ASCII by the 606CH routine and inserted into the format string at 5EB7H before display. Returns with B=01H to indicate only 1 entry per line when file metrics are shown.
5DF1
PUSH HL E5
Save the entry base pointer.
5DF2
INC L 2C
INCrement L to offset +01H.
5DF3
INC L 2C
INCrement L to offset +02H.
5DF4
INC L 2C
INCrement L to offset +03H, the EOF byte offset within the last sector.
5DF5
LD A,(HL) 7E
Fetch the EOF byte offset value.
5DF6
LD (5E69H),A 32 69 5E
Self-Modifying Code
Store the EOF offset to 5E69H for later display in the format string.
5DF9
INC L 2C
INCrement L to offset +04H, the Logical Record Length (LRL) byte.
5DFA
PUSH HL E5
Save the pointer to the LRL byte.
5DFB
LD L,(HL) 6E
Load Register L with the LRL value from (HL).
5DFC
LD A,L 7D
Load Register A with the LRL value.
5DFD
LD (5E1FH),A 32 1F 5E
Self-Modifying Code
Store the LRL value to 5E1FH for display.
5E00
SUB A,01H D6 01
SUBtract 1 from the LRL. If LRL was 0 (meaning 256), this produces FFH with carry clear. If LRL was 1, this produces 0 with carry set.
5E02
LD A,00H 3E 00
Load Register A with 00H without affecting the CARRY FLAG.
5E04
ADC A,00H CE 00
ADD the carry to A. If LRL was 0 (256 bytes), carry was clear so A=0 and H=0. If LRL was nonzero, carry was set so A=1, meaning H=1 to indicate a two-byte LRL value of 256+L. Actually: for LRL=0, SUB 1 gives FFH with borrow, ADC gives A=1. For LRL=1, SUB 1 gives 0 without borrow, ADC gives A=0. So H=1 when LRL=0 (meaning 256), making HL=0100H=256.
5E06
LD H,A 67
Load Register H with the high byte. HL now holds the LRL value as a 16-bit number (0-256, where 0 input means 256).
5E07
LD DE,5EBBH 11 BB 5E
Point DE to the LRL value position in the format string at 5EBBH.
5E0A
GOSUB to the Decimal Output routine at 606CH to convert the LRL value in HL to decimal ASCII and store it at (DE).
5E0D
POP HL E1
Restore the pointer to offset +04H.
5E0E
LD A,L 7D
Load the low byte of the pointer.
5E0F
ADD A,10H C6 10
ADD 10H to advance from offset +04H to offset +14H (sector count field).
5E11
LD L,A 6F
Update the pointer.
5E12
LD A,(HL) 7E
Fetch the sector count low byte from offset +14H.
5E13
LD (5E68H),A 32 68 5E
Self-Modifying Code
Store the sector count low byte to 5E68H.
5E16
INC L 2C
INCrement to offset +15H (sector count high byte).
5E17
LD A,(HL) 7E
Fetch the sector count high byte.
5E18
LD (5E67H),A 32 67 5E
Self-Modifying Code
Store the sector count high byte to 5E67H. The 2-byte value at 5E67H-5E68H now holds the sector count (high byte first).
5E1B
LD HL,5E67H 21 67 5E
Point HL to the 2-byte sector count value.
5E1E
LD C,00H 0E 00
Load Register C with 00H (divisor = 0 indicates a 2-byte direct load in the 60A7H routine, not division).
5E20
GOSUB to the 24-Bit Division routine at 60A7H. With C=0, this simply loads the 2-byte value at (HL) into DE without dividing.
5E23
EX DE,HL EB
Exchange DE and HL. HL now holds the sector count value for decimal conversion.
5E24
LD DE,5EC7H 11 C7 5E
Point DE to the EOF value position in the format string.
5E27
GOSUB to the Decimal Output routine to convert the sector count to ASCII.
5E2A
POP HL E1
Restore the entry base pointer (saved at 5DF1H).
5E2B
GOSUB to the Count File Sectors routine at 5E3EH which walks the extent chain and returns the total granule count in DE.
5E2E
EX DE,HL EB
Move the granule count to HL.
5E2F
LD DE,5ED4H 11 D4 5E
Point DE to the granule count position in the format string.
5E32
GOSUB to the Decimal Output routine to convert the granule count to ASCII.
5E35
LD HL,5EB7H 21 B7 5E
Point HL to the complete format string at 5EB7H ("LRL=nnnnn / EOF=nnnnn / SIZE=nnnnn GRANS" + 03H).
5E38
GOSUB to the SYS0 Display Message routine to print the formatted file metrics line.
5E3B
LD B,01H 06 01
Load Register B with 01H. When file metrics are displayed, only 1 entry fits per line (instead of the normal 3).
5E3D
RET C9
Return to the caller with B=01H to override the entries-per-line count.
5E3EH - DIR: Count File Sectors (Extent Chain Walker)
Walks the extent chain for a file and accumulates the total number of granules allocated to the file. Each extent entry is a 2-byte pair at offset +16H within the directory entry: byte 1 has extent info, byte 2's lower 5 bits (AND 1FH) hold the granule count minus 1 for that extent. Special values FEH (chain continues in another entry) and FFH (end of chain) terminate the walk. For chain continuations (FEH), the next byte provides the directory entry info byte for locating the continuation entry.
5E3E
LD DE,0000H 11 00 00
Initialize the granule count accumulator in DE to zero.
5E41
LD A,L 7D
Load Register A with the low byte of the entry pointer.
5E42
ADD A,16H C6 16
ADD 16H to point to offset +16H, the start of the extent chain data.
5E44
LD L,A 6F
Update the pointer to the extent chain.
5E45
LD A,(HL) 7E
Extent Walk Loop Start
Fetch the first byte of the current extent entry.
5E46
INC L 2C
INCrement to the second byte of the extent entry.
5E47
CP A,0FEH FE FE
Compare against 0FEH. Values FEH and FFH are special terminators.
5E49
If NO CARRY (A >= FEH), JUMP to 5E57H to handle the terminator (FEH = chain continues, FFH = end).
5E4B
LD A,(HL) 7E
Fetch the second byte of the extent entry (granule count data).
5E4C
INC L 2C
INCrement to the next extent entry.
5E4D
AND A,1FH E6 1F
Mask with 1FH to extract the granule count minus 1 (bits 0-4).
5E4F
INC A 3C
INCrement to get the actual granule count for this extent (1-32).
5E50
ADD A,E 83
ADD the granule count to the low byte of the accumulator (Register E).
5E51
LD E,A 5F
Store the updated low byte.
5E52
If NO CARRY (no overflow), LOOP BACK to 5E45H for the next extent entry.
5E54
INC D 14
INCrement the high byte of the accumulator on carry.
5E55
LOOP BACK to 5E45H. Extent Walk Loop End
5E57
RET NZ C0
If NZ (A was FFH, end of chain), return with the total granule count in DE.
Chain Continuation
The first byte was FEH, indicating the extent chain continues in another directory entry. The second byte contains the directory entry info byte (sector/position) for locating the continuation entry in the 6100H buffer.
5E58
LD B,(HL) 46
Fetch the continuation info byte (which sector and entry within the directory) from the second byte.
5E59
LD A,B 78
Copy the info byte to Register A for decoding.
5E5A
AND A,07H E6 07
Mask with 07H to extract the sector number (bits 0-2), range 0-7.
5E5C
ADD A,61H C6 61
ADD 61H to compute the page number in the directory buffer (61H-68H).
5E5E
LD H,A 67
Set the high byte of HL to the computed page.
5E5F
LD A,B 78
Reload the info byte.
5E60
AND A,0E0H E6 E0
Mask with 0E0H to extract the entry position within the sector (bits 5-7, giving the entry base offset in 32-byte multiples).
5E62
ADD A,16H C6 16
ADD 16H to point to offset +16H (extent chain data) within the new directory entry.
5E64
LD L,A 6F
Set the low byte of HL. HL now points to the extent chain in the continuation entry.
5E65
LOOP BACK to 5E45H to continue walking the extent chain in the new entry.
5E6AH - Data: DIR Format Strings and Option Table
Data area containing the DIR option keyword table, directory header format string, disk label format template, and file metrics format template. The option table at 5E6AH has entries for "A" (show all), "I" (show invisible), and "S" (show system) options. The header at 5E83H includes screen-clear codes (1CH, 1FH) followed by the "FILE DIRECTORY --- DRIVE X" banner. The disk label template at 5EA1H has placeholders filled at runtime with the actual disk name and date. The metrics template at 5EB7H has placeholders for LRL, EOF, and SIZE values.
5E6A-5E82
Data: DIR Option Keyword Table 41 20 20 20 20 20 9B 5D 49 20 20 20 20 20 0B 5D 53 20 20 20 20 20 FD 5C 00
Three 8-byte keyword entries: "A " + 5D9BH (show all/system), "I " + 5D0BH (show invisible), "S " + 5CFDH (show protected/system), followed by 00H end marker.
5E83-5EA0
Data: Directory Header String 1C 1F 46 49 4C 45 20 44 49 52 45 43 54 4F 52 59 20 2D 2D 2D 20 44 52 49 56 45 20 58 C5 03
Clear-screen (1CH, 1FH) + "FILE DIRECTORY --- DRIVE X" + C5H (inverse bracket) + 03H terminator. The 'X' at 5E9EH is replaced with the actual drive number ASCII at runtime.
5EA1-5EB6
Data: Disk Label Format Template 4E 4E 4E 4E 4E 4E 4E 4E 20 2D 2D 20 4D 4D 2F 44 44 2F 59 59 0A 0D
"NNNNNNNN -- MM/DD/YY" + LF + CR. The 8 'N' bytes at 5EA1H are replaced with the disk name; the "MM/DD/YY" at 5EADH is replaced with the disk date. Both are copied from directory sector 0 at 42D0H.
5EB7-5EDFH
Data: File Metrics Format Template 4C 52 4C 3D 20 20 20 20 20 20 2F 20 45 4F 46 3D 20 20 20 20 20 20 2F 20 53 49 5A 45 3D 20 20 20 20 20 20 47 52 41 4E 53 03
"LRL= / EOF= / SIZE= GRANS" + 03H. Numeric placeholders at 5EBBH (LRL), 5EC7H (EOF), and 5ED4H (SIZE) are filled at runtime by the 606CH decimal output routine.
5EE0H - FREE Command Handler
Implements the FREE command, which displays the amount of free space on all 4 drives. For each drive 0-3, the command reads directory sector 0, extracts the disk name and date, reads the GAT (Granule Allocation Table) from sector 0, counts the number of free granules, counts the number of free directory entries, and displays the results. The GAT at 4D00H is scanned byte by byte: each byte represents allocation for one track, with individual bits representing granules. A bit shifted out as 0 indicates a free granule. The free directory entry count is computed by scanning each 32-byte entry in the 4D00H buffer sector for zero bytes at specific positions. Format: FREE (no parameters)
5EE0
LD C,00H 0E 00
Load Register C with 00H as the starting drive number (drive 0).
5EE2
LD A,03H 3E 03
Load Register A with 03H (EXEC access level for opening the directory).
5EE4
LD DE,5551H 11 51 55
Point Register Pair DE to the filespec buffer at 5551H.
5EE7
LD (DE),A 12
Store the access level to the first byte of the filespec buffer.
5EE8
GOSUB to 4424H to open the directory on the current drive.
5EEB
PUSH BC C5
Drive Loop Start
Save the drive number (Register C).
5EEC
CALL 50FDH CD FD 50
GOSUB to the SYS1 drive validation routine at 50FDH. Tests if the drive is present and accessible. Returns NZ if the drive is not valid.
5EEF
If NZ (drive not valid), JUMP to 5F58H to skip this drive and try the next one.
5EF1
LD A,C 79
Load the drive number.
5EF2
ADD A,30H C6 30
Convert to ASCII.
5EF4
LD (5F68H),A 32 68 5F
Self-Modifying Code
Store the ASCII drive number to 5F68H in the output format string.
5EF7
GOSUB to 4AF0H to read directory sector 0 into the 4D00H buffer for the current drive.
5EFA
If read failed, JUMP to the disk error handler.
5EFD
LD HL,4DD0H 21 D0 4D
Point HL to offset 0D0H in the buffer (4D00H+0D0H = 4DD0H), the disk label name field.
5F00
LD DE,5F6EH 11 6E 5F
Point DE to the name placeholder in the FREE format string.
5F03
LD BC,0008H 01 08 00
Load BC with 8 (bytes to copy for the disk name).
5F06
LDIR ED B0
Copy 8 bytes of disk name to the format string.
5F08
LD DE,5F79H 11 79 5F
Point DE to the date placeholder in the format string.
5F0B
LD BC,0008H 01 08 00
Load BC with 8 bytes for the date.
5F0E
LDIR ED B0
Copy 8 bytes of date to the format string. HL now points past 4DD8H.
Free Granule Count
The GAT (Granule Allocation Table) is stored in the first 35H (53) bytes of directory sector 0 at 4D00H. Each byte represents one track, with each bit representing one granule. A bit value of 0 = free, 1 = allocated. The code counts free bits by rotating each byte right through carry (with SCF to pre-set carry), counting whenever a 0 bit falls out, and checking for the FFH (all allocated) sentinel.
5F10
LD HL,4D00H 21 00 4D
Point HL to 4D00H, the start of the GAT in the directory sector buffer.
5F13
LD DE,0000H 11 00 00
Initialize the free granule counter in DE to zero.
5F16
LD B,23H 06 23
Load Register B with 23H (35 decimal), the number of GAT bytes to scan (one per track, tracks 0-34).
5F18
LD A,(HL) 7E
GAT Byte Loop Start
Fetch the current GAT byte (allocation bitmap for one track).
5F19
SCF 37
Set the CARRY FLAG. This ensures that the first RRA shifts a 1 into the MSB, and the bit shifted out to carry is the actual allocation bit.
5F1A
RRA 1F
Rotate Register A right through carry. The LSB shifts out to carry (0 = free granule), and the pre-set carry shifts in from the top.
5F1B
If CARRY is set (the bit shifted out was 1 = allocated granule), JUMP to 5F1EH to skip incrementing the free count.
5F1D
INC DE 13
INCrement the free granule counter (the shifted-out bit was 0 = free).
5F1E
CP A,0FFH FE FF
Compare the remaining bits against FFH. After all real granule bits have been shifted out, the remaining bits are all 1's (from the SCF/RRA fill). When A=FFH, all bits for this track have been processed.
5F20
If NZ (more bits to process in this byte), LOOP BACK to 5F19H.
5F22
INC L 2C
INCrement to the next GAT byte (next track).
5F23
DECrement B and LOOP BACK. GAT Byte Loop End
5F25
EX DE,HL EB
Move the free granule count to HL for decimal conversion.
5F26
LD DE,5F90H 11 90 5F
Point DE to the free granule count position in the format string.
5F29
GOSUB to the Decimal Output routine to convert the free count to ASCII.
Free Directory Entries Count
The code also counts the number of free (empty) directory entry slots by reading the directory and counting entries where the flags byte is zero.
5F2C
POP BC C1
Restore the drive number.
5F2D
PUSH BC C5
Save it again for the next iteration.
5F2E
CALL 512EH CD 2E 51
GOSUB to SYS1 routine at 512EH to read the directory sectors for file entry counting.
5F31
If read failed, JUMP to the disk error handler.
5F34
LD HL,4D40H 21 40 4D
Point HL to 4D40H, the first directory entry in the 4D00H buffer (offset 40H, skipping the GAT/header area).
5F37
LD DE,0000H 11 00 00
Initialize the free entry counter in DE to zero.
5F3A
LD A,(HL) 7E
Entry Count Loop Start
Fetch the flags byte of the current directory entry.
5F3B
OR A,A B7
Test if the flags byte is zero (empty/free entry).
5F3C
If NZ (entry is in use), skip the increment.
5F3E
INC DE 13
INCrement the free entry counter.
5F3F
INC L 2C
INCrement to the next byte within the entry.
5F40
LD A,L 7D
Load the current position.
5F41
AND A,0E7H E6 E7
Mask with 0E7H. This checks if the position is at a 32-byte entry boundary (bits 3 and 4 are cleared by the mask). If the masked value equals L, we are still within the same entry's relevant scan area.
5F43
CP A,L BD
Compare masked value against the actual position.
5F44
If Z (still in the scan area of this entry), continue scanning.
5F46
ADD A,20H C6 20
ADD 20H (32) to advance to the next directory entry.
5F48
LD L,A 6F
Update the pointer.
5F49
If NZ (no page overflow), continue. Entry Count Loop End
5F4B
EX DE,HL EB
Move the free entry count to HL.
5F4C
LD DE,5F83H 11 83 5F
Point DE to the free entry count position in the format string.
5F4F
GOSUB to the Decimal Output routine to convert the free entry count to ASCII.
5F52
LD HL,5F62H 21 62 5F
Point HL to the complete FREE output format string at 5F62H.
5F55
GOSUB to the SYS0 Display Message routine to print the line for this drive.
5F58
POP BC C1
Restore the drive number.
5F59
INC C 0C
INCrement the drive number to process the next drive.
5F5A
LD A,C 79
Load the drive number.
5F5B
CP A,04H FE 04
Compare against 04H (4 drives: 0-3).
5F5D
If NZ (more drives to check), LOOP BACK to 5EEBH. Drive Loop End
5F5F
JUMP to 402DH, the no-error exit. FREE command complete for all drives.
5F62H - Data: FREE Format String
Output format template for the FREE command, displayed once per valid drive.
5F62-5F9BH
Data: FREE Output Format 44 52 49 56 45 20 58 20 2D 2D 20 20 4E 4E 4E 4E 4E 4E 4E 4E 20 20 20 4D 4D 2F 44 44 2F 59 59 20 20 20 20 20 20 20 20 46 49 4C 45 53 2C 20 20 20 20 20 20 20 20 47 52 41 4E 53 0D
"DRIVE X -- NNNNNNNN MM/DD/YY FILES, GRANS" + CR. Placeholders: 'X' at 5F68H = drive number, 'N' x 8 at 5F6EH = disk name, "MM/DD/YY" at 5F79H = date, spaces at 5F83H = free files count, spaces at 5F90H = free granules count. All filled at runtime.
5F9CH - RENAME Command Handler
Implements the RENAME command, which changes a file's name on disk. Two filespecs are required: the current name and the new name. The file is opened to verify it exists and check access permissions (protection level must be < 3 to allow renaming). The new name is then written into the directory entry, replacing the old name. If the new filespec does not include a drive specifier, the original file's drive is used. Format: RENAME old-name TO new-name
5F9C
LD DE,5551H 11 51 55
Point Register Pair DE to the primary filespec buffer.
5F9F
GOSUB to 441CH to extract the current (old) filespec.
5FA2
If no filespec, JUMP to error.
5FA5
LD A,(DE) 1A
Fetch first character of old filespec.
5FA6
CP A,2AH FE 2A
Check for wildcard.
5FA8
If wildcard, JUMP to error.
5FAB
GOSUB to 4424H to open the file (existing only) to verify it exists and get the directory entry info.
5FAE
If open failed, JUMP to disk error handler.
5FB1
LD DE,5571H 11 71 55
Point DE to the secondary filespec buffer for the new name.
5FB4
GOSUB to 441CH to extract the new filespec.
5FB7
If no second filespec, JUMP to error.
5FBA
LD A,(5552H) 3A 52 55
Fetch the file's access mode/protection flags from 5552H.
5FBD
AND A,07H E6 07
Mask with 07H to isolate the protection level (bits 0-2).
5FBF
CP A,03H FE 03
Compare against 03H. The RENAME protection level requires the protection value to be less than 3 (WRITE or below allows renaming; READ and EXEC do not).
5FC1
LD A,25H 3E 25
Load Register A with 25H, the "access denied" error code.
5FC3
If NO CARRY (protection level >= 3, insufficient access), JUMP to the disk error handler with error 25H.
Drive Specifier Handling
If the new filespec does not include a drive specifier, the code appends the original file's drive number to ensure the file stays on the same drive. The new filespec at 5571H is scanned for a colon; if none is found, one is appended along with the drive number from the old file.
5FC6
LD HL,5571H 21 71 55
Point HL to the new filespec buffer.
5FC9
LD A,(HL) 7E
Colon Scan Loop Start
Fetch the current character.
5FCA
CP A,3AH FE 3A
Compare against 3AH (colon). If found, a drive specifier is already present.
5FCC
If Z (colon found), JUMP to 6028H to display the "DRIVE SPECIFICATION ILLEGAL" error. Renaming to a different drive is not supported by RENAME; use COPY instead.
5FCE
CP A,20H FE 20
Compare against 20H (space). Characters below space indicate end of filespec.
5FD0
If CARRY (character < space, end of filespec), JUMP to 5FD5H to append the drive specifier.
5FD2
INC HL 23
INCrement HL to the next character.
5FD3
LOOP BACK to check the next character. Colon Scan Loop End
5FD5
LD (HL),3AH 36 3A
Store a colon (3AH) at the end of the new filespec.
5FD7
INC HL 23
INCrement HL past the colon.
5FD8
LD A,(5557H) 3A 57 55
Fetch the original file's drive number from 5557H (stored during the initial open).
5FDB
ADD A,30H C6 30
Convert to ASCII.
5FDD
LD (HL),A 77
Store the ASCII drive number after the colon.
5FDE
INC HL 23
INCrement past the drive number.
5FDF
LD (HL),03H 36 03
Store 03H (ETX) as the string terminator.
5FE1
LD DE,5571H 11 71 55
Point DE to the new filespec (now with drive specifier appended).
5FE4
GOSUB to 4424H to attempt to open a file with the new name. If this succeeds, the new name already exists (duplicate).
5FE7
If the Z FLAG is set (file with new name already exists), JUMP to 604EH to display "DUPLICATE FILE NAME" error.
5FEA
CP A,18H FE 18
Compare the error code against 18H (file not found). This is the expected result - the new name should NOT already exist.
5FEC
If NZ (some error other than "file not found"), JUMP to the disk error handler.
Write New Name to Directory
The new name does not exist (error 18H confirmed). Now the code reads the old file's directory entry, replaces the name with the new name (11 bytes: 8 name + 3 extension from 515DH), and writes it back.
5FEF
LD BC,(5557H) ED 4B 57 55
Fetch the old file's directory sector/drive info from 5557H.
5FF3
PUSH BC C5
Save for later write-back.
5FF4
GOSUB to 4AC1H to read the directory sector containing the old file's entry. Returns with HL pointing to the entry.
5FF7
If read failed, JUMP to disk error handler.
5FFA
LD D,H 54
Copy the high byte of the entry pointer to Register D.
5FFB
LD A,L 7D
Load the low byte of the entry pointer.
5FFC
ADD A,05H C6 05
ADD 05H to point to offset +05H (start of the 8-byte filename within the directory entry).
5FFE
LD E,A 5F
Set DE to point to the filename field in the directory entry.
5FFF
LD HL,515DH 21 5D 51
Point HL to 515DH, the parsed new filename in the SYS1 work area (11 bytes: 8 name + 3 extension).
6002
LD BC,000BH 01 0B 00
Load BC with 000BH (11 bytes to copy: 8 name + 3 extension).
6005
LDIR ED B0
Block Copy
Copy 11 bytes of the new filename over the old filename in the directory entry.
6007
POP BC C1
Restore the directory sector/drive info.
6008
GOSUB to 4AD6H to write the directory sector back to disk with the renamed file.
600B
If write failed, JUMP to disk error handler.
600E
CALL 512EH CD 2E 51
GOSUB to SYS1 routine at 512EH to update the secondary directory structures.
6011
If update failed, JUMP to disk error handler.
6014
LD D,H 54
Set up DE for a hash name update. D = high byte of the directory buffer page.
6015
LD E,B 58
E = sector info from the BC values. This positions to the entry for the hash recalculation.
6016
PUSH BC C5
Save directory sector/drive info.
6017
LD HL,515DH 21 5D 51
Point HL to the new filename for hash computation.
601A
CALL 509BH CD 9B 50
GOSUB to SYS1 routine at 509BH to compute the filename hash (CRC) for the new name. Returns the hash in Register A.
601D
POP BC C1
Restore the directory sector/drive info.
601E
LD (DE),A 12
Store the new filename hash to the hash position in the directory entry buffer.
601F
CALL 5141H CD 41 51
GOSUB to SYS1 routine at 5141H to write the updated directory entry with the new hash back to disk.
6022
If write failed, JUMP to disk error handler.
6025
JUMP to 402DH, the no-error exit. RENAME complete.
6028H - "DRIVE SPECIFICATION ILLEGAL" Error
Displayed when the RENAME command's new filespec includes a drive specifier (renaming across drives is not supported).
6028
LD HL,6031H 21 31 60
Point HL to the error message at 6031H.
602B
GOSUB to Display Message.
602E
JUMP to error-already-displayed exit.
6031H - Data: RENAME Error Messages
Error message strings for the RENAME command.
6031-604DH
DEFM 0AH,"DRIVE SPECIFICATION ILLEGAL",0DH 0A 44 52 49 56 45 20 53 50 45 43 49 46 49 43 41 54 49 4F 4E 20 49 4C 4C 45 47 41 4C 0D
Linefeed + "DRIVE SPECIFICATION ILLEGAL" + CR. Displayed when trying to rename a file to a different drive.
604EH - "DUPLICATE FILE NAME" Error
Displayed when the RENAME command's new filename already exists on the disk.
604E
LD HL,6057H 21 57 60
Point HL to the error message at 6057H.
6051
GOSUB to Display Message.
6054
JUMP to error-already-displayed exit.
6057H - Data: "DUPLICATE FILE NAME" String
6057-606BH
DEFM 0AH,"DUPLICATE FILE NAME",0DH 0A 44 55 50 4C 49 43 41 54 45 20 46 49 4C 45 20 4E 41 4D 45 0D
Linefeed + "DUPLICATE FILE NAME" + CR.
606CH - Decimal Output Routine
Converts a 16-bit value in Register Pair HL to a 5-digit decimal ASCII string stored at (DE). Uses successive division by 10000, 1000, 100, and 10 via the division subroutine at 608CH. Leading zeros are suppressed by replacing them with spaces. The final units digit is always stored.
606C
LD A,20H 3E 20
Load Register A with 20H (space). This is used as the leading-zero suppression character, passed to the division subroutine in Register E.
606E
LD BC,2710H 01 10 27
Load BC with 2710H (10000 decimal) as the divisor for the ten-thousands digit.
6071
GOSUB to the division subroutine. Divides HL by 10000, stores the digit (or space for leading zero) at (DE), advances DE.
6074
LD BC,03E8H 01 E8 03
Load BC with 03E8H (1000 decimal) for the thousands digit.
6077
GOSUB to divide HL by 1000.
607A
LD BC,0064H 01 64 00
Load BC with 0064H (100 decimal) for the hundreds digit.
607D
GOSUB to divide HL by 100.
6080
LD BC,000AH 01 0A 00
Load BC with 000AH (10 decimal) for the tens digit.
6083
GOSUB to divide HL by 10.
6086
LD A,L 7D
Load Register A with the remainder (units digit, 0-9).
6087
ADD A,30H C6 30
Convert to ASCII ('0'-'9').
6089
LD (DE),A 12
Store the units digit to the output string at (DE).
608A
INC DE 13
INCrement DE past the stored digit.
608B
RET C9
Return. The 5-digit decimal string is now at the original (DE) location.
608CH - Division Subroutine (HL / BC with Leading Zero Suppression)
Divides HL by BC using repeated subtraction. The quotient digit is stored at (DE) as an ASCII character. Leading zeros are suppressed: if no significant digit has been output yet (indicated by Register A = space on entry), a zero quotient stores a space instead of '0'. Once a nonzero digit is output, subsequent zeros are stored as '0'. On entry: HL = dividend, BC = divisor, A = leading-zero character (space or '0'). On exit: HL = remainder, DE incremented past the stored digit, A = leading-zero character for next call.
608C
PUSH DE D5
Save the output pointer.
608D
LD E,A 5F
Save the leading-zero character (space or '0') to Register E.
608E
LD D,0FFH 16 FF
Initialize the quotient counter to -1 (FFH). The first INC D will bring it to 0.
6090
XOR A,A AF
Division Loop Start
Clear the CARRY FLAG for the subtraction.
6091
INC D 14
INCrement the quotient counter.
6092
SBC HL,BC ED 42
SUBtract the divisor (BC) from the dividend (HL).
6094
If NO CARRY (result >= 0), LOOP BACK to subtract again. Division Loop End
6096
ADD HL,BC 09
ADD BC back to HL to restore the remainder (the last subtraction went negative).
6097
LD A,E 7B
Restore the leading-zero character from Register E.
6098
LD B,D 42
Copy the quotient digit to Register B for testing.
6099
POP DE D1
Restore the output pointer.
609A
LD (DE),A 12
Store the leading-zero character at (DE) as the default output. If the quotient is nonzero, this will be overwritten below.
609B
INC B 04
INCrement B (quotient + 1). This is a trick to test if B was zero: INC followed by DEC restores B while setting flags.
609C
DEC B 05
DECrement B back to the original quotient. If B was 0, Z is set.
609D
If Z (quotient is 0), JUMP to 60A5H. The leading-zero character (space or '0') was already stored at (DE), so just advance DE.
609F
LD A,B 78
Load Register A with the quotient digit.
60A0
ADD A,30H C6 30
Convert to ASCII.
60A2
LD (DE),A 12
Overwrite the leading-zero character with the actual digit.
60A3
LD A,30H 3E 30
Load Register A with 30H (ASCII '0'). From now on, zeros will be displayed as '0' instead of spaces (leading-zero suppression is turned off after the first significant digit).
60A5
INC DE 13
INCrement DE to the next output position.
60A6
RET C9
Return. Register A holds the leading-zero character for the next call (space if no digit output yet, '0' if a significant digit has been output).
60A7H - 24-Bit Division Routine
Divides a 3-byte big-endian value at (HL) by the divisor in Register C, returning the quotient in Register Pair DE. If C=0, the routine instead loads a 2-byte value from (HL) directly into DE (big-endian: first byte = high, second byte = low). Uses a shift-and-subtract algorithm processing 8 bits per byte across 3 bytes.
60A7
LD DE,0000H 11 00 00
Initialize the quotient accumulator in DE to zero.
60AA
LD A,C 79
Load Register A with the divisor (Register C).
60AB
OR A,A B7
Test if the divisor is zero.
60AC
If Z (divisor is zero), JUMP to 60C9H to do a direct 2-byte load instead of division.
60AE
XOR A,A AF
Clear the accumulator (working remainder) for the division.
60AF
LD B,03H 06 03
Load Register B with 03H, the number of bytes to process (3-byte dividend).
60B1
PUSH BC C5
Byte Loop Start
Save the byte counter.
60B2
PUSH HL E5
Save the source pointer.
60B3
LD H,(HL) 66
Fetch the current byte of the dividend into Register H.
60B4
LD B,08H 06 08
Load Register B with 08H (8 bits per byte to process).
60B6
EX DE,HL EB
Bit Loop Start
Exchange DE and HL. Now HL = quotient accumulator, DE has the dividend byte in D.
60B7
ADD HL,HL 29
Shift the quotient left by 1 bit (multiply by 2).
60B8
EX DE,HL EB
Exchange back. HL has dividend byte, DE has shifted quotient.
60B9
RLC H CB 04
Rotate the dividend byte left, shifting the MSB into carry.
60BB
RLA 17
Rotate carry into Register A (working remainder), building up the remainder bit by bit.
60BC
CP A,C B9
Compare the working remainder (A) against the divisor (C).
60BD
If CARRY (remainder < divisor), JUMP to 60C1H. The quotient bit is 0 (no subtraction).
60BF
SUB A,C 91
SUBtract the divisor from the remainder.
60C0
INC DE 13
INCrement DE (set the quotient bit to 1).
60C1
DECrement B and LOOP BACK for the next bit. Bit Loop End
60C3
POP HL E1
Restore the source pointer.
60C4
INC HL 23
INCrement to the next byte of the dividend.
60C5
POP BC C1
Restore the byte counter.
60C6
DECrement B and LOOP BACK for the next byte. Byte Loop End
60C8
RET C9
Return with the quotient in DE.
60C9
LD D,(HL) 56
Load the first byte (high byte) of the 2-byte value from (HL) into Register D.
60CA
INC HL 23
INCrement to the second byte.
60CB
LD E,(HL) 5E
Load the second byte (low byte) into Register E. DE now holds the 16-bit value.
60CC
RET C9
Return with the value in DE.
60CDH - VERIFY Flag Setup Routine
Sets or clears the write-verify flag at 485EH based on the Z flag state. Called by the VERIFY command at 5504H. On entry: Z flag indicates the desired state (Z = OFF, NZ = ON from the parameter parser). Loads HL with 478BH (write-without-verify address). If Z is set (VERIFY OFF), stores 00H to 485EH. If NZ (VERIFY ON), stores 01H to 485EH. Returns with HL=478BH and Z/NZ indicating the state.
60CD
LD HL,478BH 21 8B 47
Load Register Pair HL with 478BH, the address of the write-without-verify routine in SYS0. This is the default write vector address when VERIFY is OFF.
60D0
If the Z FLAG is set (VERIFY OFF), JUMP to 60D5H to store A=0 (the Z flag from the parameter parser).
60D2
XOR A,A AF
Set Register A to ZERO.
60D3
INC A 3C
INCrement A to 01H. Register A now holds 01H (VERIFY ON flag).
60D4
OR A,A B7
OR A with itself to set the NZ FLAG (indicating VERIFY is ON).
60D5
LD (485EH),A 32 5E 48
Store the verify flag value (00H=OFF, 01H=ON) to 485EH, the write verify flag in the SYS0 work area. The disk write routines check this byte to determine whether to perform read-after-write verification.
60D8
RET C9
Return. Z flag indicates the current state (Z=OFF, NZ=ON). HL=478BH for the VERIFY command to use as the write vector.