TRS-80 DOS - TRSDOS v1.3 - SYS10/SYS Disassembled

General:

SYS10/SYS handles DISPLAY DIR ($DSPDIR) and BASIC Error Messages.

Program Overview

SYS10/SYS is a transient TRSDOS 1.3 overlay loaded into the SYSLOW overlay area at 4E00H. It is invoked via the system vector mechanism using two service codes:

Vector 80H — DODIR (Display Directory): entered by Disk BASIC's CMD"D" directive. SYS10 reads the directory track of the requested drive, sector by sector, into the disk I/O buffer at 4300H (BUFF1) and prints the visible filenames four per screen line, skipping any directory entry whose first byte is zero or whose attribute byte indicates a SYSTEM or INVISIBLE file. The drive number originates from D10SAV (4271H), masked against TOPDRV-1 (03H) to retain only the drive bits.

Vector 90H — DOERR (BASIC Error Message Display): entered when Disk BASIC encounters an error condition. SYS10 looks up the error code (passed in Register E) in the embedded ERRTAB string table, walks past the appropriate number of zero-terminated message strings, and then jumps to BASIC's error handler at 1A01H with HL pointing at the chosen message.

Memory Map

Address RangeLabelContents
4E00HSTARTEntry point — masks the request vector and dispatches to DODIR (80H) or DOERR (90H)
4E07H–4E29HDODIR / DIRGETDirectory display setup: validates the drive number, clears the screen, turns the cursor on, and falls through to DIRLOP
4E2AH–4E45HDIRLOPPer-drive directory loop: locates the directory track via TRKGET, formats the drive header line, and prints "DRIVE :n"
4E46H–4E63HDIRLO1 / DIRLO2Per-sector loop: reads each directory sector into BUFF1 by calling XREAD; bails to ERROR (4409H) on read failure
4E64H–4ED9HNOERR / LOOP0 / LOOP1 / LOOP2 / LOOP3Per-entry loop: skips empty/system/invisible entries, prints up to 8 filename characters, optional "/EXT", and pads to 15 columns; ends a screen line every 4 names
4EDAH–4EEFHDRIVE / TRK / DRVMSG / DRV / SAVE3 / S10SEC / NUMWorkspace area for the directory display: drive byte, track byte, "DRIVE :0 \x03" printable header, sector counter, line-count tracker, and pointer into BUFF1
4EF0H–4F10HDOERR / START1 / START2 / START3 / START4Error-message dispatcher: classifies the error code into three ranges (≥8BH unprintable, ≥63H disk error, <2FH BASIC error), computes a 1-based table index, walks ERRTAB by counting zero-terminators, and JPs to the BASIC error handler at 1A01H
4F11H–51D1HERRTABEmbedded BASIC error message table — 47 zero-terminated strings indexed by adjusted error code

Complete Variable List

SYS10 has one self-modifying-code target and seven workspace storage bytes/words. Per the JSON conventions used across this site, self-modifying targets within transient overlays (SYS10 lives at 4E00H–51D1H and is overwritten when other SYSn overlays load) are documented here in the HTML but are not added to the global RAM-addresses JSON.

AddressLabelDescription
4E56HSAVTRKSelf-modifying target (declared SAVTRK EQU $+1): the operand byte of LD D,0 at 4E55H. Patched by LD (SAVTRK),A at 4E32H to inject the directory-track number returned by TRKGET into the subsequent XREAD call.
4EDAHDRIVEStorage byte for the drive number currently being displayed (0–3).
4EDBHTRKStorage byte for the directory track of the current drive (declared but not actively used in the shipped code path).
4EDCHDRVMSGStart of the printable drive-header literal "DRIVE :".
4EE3HDRVThe single ASCII digit slot inside DRVMSG — patched at 4E38H with LD (DRV),A to display the current drive number.
4EECHSAVE3Word-sized pointer into BUFF1; tracks the current 30H-byte directory entry being processed.
4EEEHS10SECCurrent directory-sector number being read (initialized to 02H, incremented through 13H).
4EEFHNUMCounter for filenames already displayed on the current screen line; resets every 4 names so a CR can be emitted.

Major Routine List

AddressLabelDescription / Entry-Exit
4E00HSTARTOverlay entry. In: A = vector code (80H or 90H), E = error code (DOERR path). Out: dispatches to DODIR or DOERR.
4E07HDODIRDirectory-display setup. Reads D10SAV (4271H), masks against TOPDRV-1, stores the drive into DRIVE.
4E10HDIRGETDrive validation. Compares against MAXDRV (4413H); on out-of-range, jumps to ERROR with code EDNS+0C0H.
4E2AHDIRLOPPer-drive top-of-loop. Calls TRKGET (4B3EH) to find the directory track, patches SAVTRK, and prints the drive header line.
4E46HDIRLO1Initialize sector counter S10SEC to 02H.
4E4BHDIRLO2Per-sector loop. Increments S10SEC, calls XREAD (4675H) to read one sector into BUFF1.
4E64HNOERRSuccessful read: initialize SAVE3 pointer to BUFF1.
4E6AHLOOP0Per-entry top: skip blank/SYSTEM/INVISIBLE entries; otherwise begin printing the filename.
4E7DHLOOP1Print up to 8 filename characters until a SPACE is found.
4E89HOUT0Branch target when LOOP1 terminated early on SPACE.
4E8EHOUT00Skip-spaces sub-loop to position HL at the file extension.
4E91HOUT1Examine the extension's first character; skip the "/EXT" if it's blank.
4E9EHLOOP2Print the 3-character extension after a "/" separator.
4EA6HOUT2Pad the printed name to 15 total columns with spaces.
4EA7HLOOP3Per-pad-character print loop.
4EBCHNXTNAMUpdate the per-line name counter NUM.
4EBFHTOTNXTAdvance SAVE3 by 30H to the next directory entry; loop back to LOOP0 unless the sector is exhausted.
4EF0HDOERRBASIC error-message lookup. In: E = error code. Classifies and computes a 1-based message index in B.
4EFDHSTART1Forced unprintable-error path: A := 5AH.
4EFFHSTART2Disk-error path entry: A := A − 34H.
4F01HSTART3Generic-error path entry: rotate A right then INC A → 1-based table index.
4F07HSTART4Walks ERRTAB skipping (B−1) zero-terminated strings; then JP 1A01H to BASIC.
4F11HERRTABStart of the embedded zero-delimited BASIC error-message table (47 strings, ending at 51D1H).

Cross-references and Analysis Notes

The supplied SYS10.SRC source contains one line — LD C,A ;INTO C ALSO at the source's line 32, between PUSH AF and CALL TRKGET inside DIRLOP — that is not present in the shipped binary. The walker accounts for this 1-byte source-vs-binary difference; without it, every label after DIRLOP would drift by +1, and every label after the DCL macro definition (which itself is a non-emitting MACRO/ENDM block) would drift by +3. With the diff applied and the MACRO/ENDM body excluded, the walker's emit cursor lands exactly at 51D2H, one past the final DEFB 0 of the last error message at 51D1H.

SAVTRK at 4E56H is SYS10's only self-modifying target. It is documented in this page but, per the project conventions, is not added to the site-wide RAM addresses JSON because SYS10 is a transient overlay whose code space is reused by other SYSn overlays.

The source labels the BASIC error-message table ERRTAB; an earlier revision of this HTML labeled it ERRSTR. The source is authoritative, so all references to that table now use ERRTAB.

Three error-message strings in the existing HTML differed from the source text: "Bad field number" (HTML) is "Bad file number" in the source at 50D3H, "Bad filename" (HTML) is "Bad file name" in the source at 5166H, and "Mode mismatch" (HTML) is "Mode-mismatch" in the source at 5174H. The HTML strings have been corrected to match the source.

SYS10 calls one SYS0-resident routine that is not yet present in the site-wide RAM addresses JSON: XREAD at 4675H. It is part of the same SYS0 disk-I/O cluster as the already-tracked READIT (45B8H) and XWRITE (45F7H), so it should be added when the SYS0 session is next revised. It is not added from this SYS10 session because the project conventions reserve SYS0 entries to the SYS0 session.

The earlier HTML at 4E55H displayed the instruction as LD D,(SAVTRK). That form is not a valid Z80 instruction — the actual binary at 4E55H is the 2-byte LD D,nn immediate-load (16 00), and the source writes it as LD D,0 with SAVTRK EQU $+1 on the line above to label the operand byte at 4E56H as the self-modifying target. The displayed mnemonic is now corrected to LD D,00H with the source form preserved in the origrom2 span.

Disassembly:

 
ORG 4E00H
4E00START
AND 0F0H
On entry, every overlay has a routine request in Register A, which is routinely masked to retain only the high nybble. MASK the value of Register A against 0F0H (1111 0000) to leaving only bits 7, 6, 5, 4 active.
Original Source Code Comment: MASK SYSTEM NUMBER
4E02
CP 90HCP VECT10
Compare the value held in Register A against 90H to see if this was a request to display an error message. If Register A equals 90H, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: ERROR MESSAGES?
4E04
If the entry call was 90H, then the Z FLAG (Zero) will have been set, meaning that this Overlay was involked to display an error; JUMP to 4EF0H to handle it.
Original Source Code Comment: YES
4E07DODIR
XOR A
Set Register A to ZERO and clear all Flags so that we can set the overlay flag to indicate that SYS06/SYS is NOT in memory.
Original Source Code Comment: SHOW SYS 6 NOT IN MEMORY
4E08
LD (442BH),ALD (OVLFLG),A
Store the 0 held in Register A into memory location 442BH.
4E0B
LD A,(4271H)LD A,(D10SAV)
Fetch the drive number from memory location 4271H and store it into Register A.
Original Source Code Comment: GET THE DRIVE NUMBER
4E0E
AND 03HAND TOPDRV-1
The first two bits of Register A hold the drive number, so MASK the value of Register A against 03H to keep only bits 1-0.
Original Source Code Comment: MASK ALL BUT DRIVE
4E10DIRGET
LD (DRIVE),A
Store the drive number (held in Register A) into memory location 4EDAH.
Original Source Code Comment: SAVE THE DRIVE NUMBER
4E13
Clear the screen via a GOSUB to 01C9H.
NOTE: 01C9H is the Model III ROM routine to to CLEAR THE SCREEN and RETurn.
Original Source Code Comment: CLEAR SCREEN
4E16
LD A,0EH
Let Register A equal 0EH which is the ASCII code for CURSOR ON.
Original Source Code Comment: CURSOR ON CHAR
4E18
Turn the cursor on via a GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
Original Source Code Comment: TURN CURSOR BACK ON
4E1B
LD A,(DRIVE)
Fetch the drive number (held in memory location 4EDAH) and store it into Register A.
Original Source Code Comment: GET THE DRIVE NUMBER
4E1E
LD B,A
Copy the drive number from Register A into Register B.
Original Source Code Comment: INTO (B)
4E1F
LD A,(4413H)LD A,(MAXDRV)
Fetch the highest drive number in the system from memory location 4413H and store it into Register A.
NOTE: 4413H is the storage location for the NUMBER OF DISK DRIVES in the system.
Original Source Code Comment: GET THE MAXIMUM DRIVE IN SYSTEM
4E22
CP B
Make sure we actually have the drive by comparing the highest drive number in the system(held in Register A) against the drive number supplied (held in Register B). If if the maximum drive number (A) >= the requested drive number (B), the NO CARRY FLAG will be set.
Original Source Code Comment: WE TRYING FOR A NON-EXISTANT DRIVE?
4E23
If the drive number is valid, then the NC FLAG (No Carry) will have been set, so continue via JUMP to 4E2AH.
Original Source Code Comment: NO, CONTINUE
4E25
LD A,0C2HLD A,EDNS+0C0H
Let Register A equal 0C2H to set up for a DRIVE NOT IN SYSTEM error.
Original Source Code Comment: DRIVE NOT IN SYSTEM ERROR
4E27
JUMP to 4409H, which is the SYS00/SYS routine to process DOS errors.
Original Source Code Comment: REPORT AND RETURN

4E2AH - DIRLOP - Read the directory track into a Buffer in RAM.

4E2ADIRLOP
LD A,(DRIVE)
Fetch the drive number (held in memory location 4EDAH) and store it into Register A.
Original Source Code Comment: GET BINARY DRIVE
4E2D
PUSH AF
Save the drive number to the top of the stack.
Original Source Code Comment: SAVE IT
4E2E
GOSUB to 4B3EH.
NOTE: 4B3EH is the SYS00/SYS routine to identify the track number of the directory. Routine exits with the director track number in Register D.
Original Source Code Comment: GET THE DIRECTORY S10SEC FOR THIS DRIVE
4E31
LD A,D
Copy the directory track number for the given drive (held in Register D) into Register A.
Original Source Code Comment: GET IT
4E32
LD (SAVTRK),A
Store the directory track number for the given drive into memory location 4E56H, which is in the middle of a LD D,0 OPCODE.
Original Source Code Comment: SAVE THE TRACK NUMBER
4E35
POP AF
Restore the drive number from the top of the stack.
4E36
ADD A,30H
LET Register A = Register A + 30H. Note: Adding 30H to from Register A will convert decimal number 0-9 into its ASCII equivalent (i.e., 6 + 30H = 36H, which, in ASCII, is 6.
Original Source Code Comment: MAKE IT ASCII
4E38
LD (DRV),A
Store the ASCII rendition of the drive number (held in Register A) into the middle of the DRIVE MESSAGE at memory location 4EE3H.
Original Source Code Comment: STORE IN DRIVE MESSAGE
4E3B
LD A,01HLD A,1
Let Register A equal 01H.
4E3D
LD (NUM),A
Store a 1 into memory location 4EEFH as the starter value for how many filenames have been displayed on the current screen line.
4E40
LD HL,DRVMSG
Let Register Pair HL equal 4EDCH to point to the drive number message.
Original Source Code Comment: POINT TO DRIVE # MSG
4E43
GOSUB to 021BH.
NOTE: 021BH is the Model III ROM routine to display the character at (HL) until a 03H is found.
Original Source Code Comment: PRINT IT
4E46DIRLO1
LD A,02HLD A,2
Let Register A equal 02H to point to Sector 2.
Original Source Code Comment: SET FOR SECTOR 2
4E48
LD (S10SEC),A
Store the sector number (held in Register A) into memory location 4EEEH.
Original Source Code Comment: STORE FOR USE
4E4BDIRLO2
LD HL,S10SEC
Let Register Pair HL equal to the track pointed to at 4EEEH.
Original Source Code Comment: POINT TO TRACK
4E4E
LD A,(HL)
Fetch the sector number (held in the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET SEC NUM
4E4F
INC (HL)
INCrement the value stored in the memory location pointed to by Register Pair HL by 1 to point to the next sector.
Original Source Code Comment: SET FOR NEXT SEC, NXT LOOP
4E50
LD E,A
Copy the sector number into Register E to prepare for the next call.
Original Source Code Comment: PUT IN E FOR CALL
4E51
LD A,(DRIVE)
Fetch the current drive number (held in memory location 4EDAH) and store it into Register A.
Original Source Code Comment: GET PRESENT DRIVE
4E54
LD C,A
Copy the contents of Register A into Register C for the CALL.
Original Source Code Comment: PUT IN C FOR CALL
4E55
LD D,00HLD D,0
Let Register D equal the directory track (placed into 4E56H at 4E32H).
Original Source Code Comment: DIRECTORY TRACK SAVED HERE
4E57
LD HL,4300HLD HL,BUFF1
Let Register Pair HL equal 4300H.
NOTE: 4300H is a memory buffer (referred to as Memory Buffer 1) where diskette contents are stored in RAM.
NOTE: 4300H is the storage location for the 256 Byte Storage Area for Disk I/O.
Original Source Code Comment: WHERE TO STORE IT
4E5A
Read the directory track into the buffer via a GOSUB to 4675H.
Original Source Code Comment: READ DIR TRACK IN MEM
4E5D
If the Z FLAG (Zero) has been set then there was no error, so JUMP to 4E64H.
Original Source Code Comment: GOOD READ
4E5F
OR 0C0H
If we're here then there was an error reading that track. OR Register A against 0C0H (1100 0000) to prepare to set error codes to detailed messages instead of just numbers.
Original Source Code Comment: SET DETAIL MESSAGE BIT ON
4E61
JUMP to 4409H.
NOTE: 4409H is the SYS00/SYS routine to process DOS errors.
Original Source Code Comment: REPORT ERROR AND EXIT

4E64H - NOERR - Process the directory track now in RAM to find the filename.

4E64NOERR
LD HL,4300HLD HL,BUFF1
Let Register Pair HL equal 4300H.
NOTE: 4300H is a memory buffer (referred to as Memory Buffer 1) where diskette contents are stored in RAM.
NOTE: 4300H is the storage location for the 256 Byte Storage Area for Disk I/O.
Original Source Code Comment: POINT TO BUFFER
4E67
LD (SAVE3),HL
Store the buffer pointer (held in Register Pair HL) into memory location 4EECH.
Original Source Code Comment: SAVE IT
4E6ALOOP0
LD HL,(SAVE3)
Fetch the current pointer to the current buffer (held in memory location 4EECH) and store it into Register Pair HL.
Original Source Code Comment: GET POINTER
4E6D
LD A,(HL)
Fetch a character from the buffer (which is a character from the directory) and store it into Register A.
Original Source Code Comment: GET CHARACTER FROM DIR
4E6E
OR A
We need to see if that first character of the directory entry is 0. Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: BLANK FILE?
4E6F
If the Z FLAG (Zero) has been set, then we have a blank file, so JUMP to 4EBFH to skip the file processing.
Original Source Code Comment: YES
4E71
AND 48H
If we're here then we found a file, but now need to see if it is a SYSTEM or INVISIBLE file. MASK the value of Register A against 48H (0100 1000) leaving only bits 6 and 3 active.
Original Source Code Comment: SYSTEM OR INVISIBLE FILE?
4E73
If the NZ FLAG (Not Zero) has been set, then we have either a SYSTEM or an INVISIBLE file, so JUMP to 4EBFH to skip the file processing.
Original Source Code Comment: SKIP IF SO
4E75
LD B,08HLD B,8
Let Register B equal the maximum length of a filename (i.e., 08H).
Original Source Code Comment: MAX LENGTH OF NAME
4E77
LD C,0FHLD C,15
Let Register C equal the maximum length of a full filespec (i.e., 0FH or 15 characters).
Original Source Code Comment: NAME/EXT+SPACES

The next 3 instructions function as HL = HL + 05H

4E79
LD A,L
LET Register Pair HL = Register Pair HL + 05H so as to push HL to the beginning of the filename. First, put L into A.
Original Source Code Comment: GET LSB INTO A
4E7A
ADD A,05HADD A,5
Next, add 5 to A.
Original Source Code Comment: SET FOR BEGIN OF NAME
4E7C
LD L,A
Finally, put the A+5 back into L.
Original Source Code Comment: PUT BACK FOR ADDRESS
4E7DLOOP1
LD A,(HL)
Fetch a character from the filename (which is what HL is pointing to in the directory in the buffer).
Original Source Code Comment: GET A CHARACTER FROM NAME
4E7E
INC HL
Bump the buffer to point to the next character in the filename.
4E7F
CP 20HCP ' '
We need to see if we are at the end of the filename, so compare that character against a SPACE. Results: If it is a SPACE, the Z FLAG will be set.
Original Source Code Comment: SPACE?
4E81
If it is a SPACE, then we are done processing filename characters so JUMP to 4E89H.
Original Source Code Comment: DONE IF SO
4E83
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
Original Source Code Comment: PRINT OTHERWISE
4E86
DEC C
DECrement the filespec character counter stored in Register C by 1.
Original Source Code Comment: DEC TOTAL COUNTER
4E87
Keep processing characters by LOOPing back to 4E7DH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: PRINT ALL OF NAME
4E89OUT0
LD A,B
Copy the filename counter (held in Register B as the counter for the DJNZ loop) into Register A.
Original Source Code Comment: GET COUNT
4E8A
OR A
Since a LD command does not set any FLAGS, Set FLAGS based on the contents of Register A (and, in all events, clear the CARRY FLAG).
Original Source Code Comment: SET FLAGS
4E8B
If B was zero, then we don't need to fill the remaining characters of a filename (i.e., we got 8), so JUMP to 4E91H.
Original Source Code Comment: NOTHING TO DO
4E8D
DEC HL
Back up the pointer in the directory sector (value stored in Register Pair HL) by 1 in preparation for the following loop which starts by INCrementing it right back.
Original Source Code Comment: BACK POINT UP ONE
4E8EOUT00
INC HL
INCrement the value stored in Register Pair HL by 1.
4E8F
Keep skipping spaces by LOOPing back to 4E8EH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.

At this point, HL is now positioned at the file's EXTENSION in the directory sector.

4E91OUT1
LD A,(HL)
Fetch the first character of where the file's extension is supposed to be in the directory entry held in RAM (pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: NOW AT EXT
4E92
CP 20HCP ' '
Compare the value held in Register A against a SPACE). Results: If Register A equals SPACE, the Z FLAG is set; otherwise the NZ FLAG is set.
Original Source Code Comment: ANY EXT?
4E94
If that very first character is a SPACE, then we know that there is no extension present; so skip processing the extension by JUMPing to 4EA6H.
Original Source Code Comment: IF NOT, SKIP
4E96
LD A,2FHLD A,'/'
We know that there is an extension, so we need to display a /. Let Register A equal 2FH (ASCII: /).
Original Source Code Comment: PRINT A SEPERATOR
4E98
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
4E9B
DEC C
DECrement the total filespec counter (stored in Register C) by 1.
Original Source Code Comment: DEC TOTAL COUNTER
4E9C
LD B,03HLD B,3
Let Register B equal 03H for the length of an extension.
Original Source Code Comment: 3 CHARS IN EXT
4E9ELOOP2
LD A,(HL)
Fetch a character of where the file's extension is supposed to be in the directory entry held in RAM (pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET A CHAR OF EXT
4E9F
INC HL
INCrement the value stored in Register Pair HL by 1 to point to the next character in the extension.
Original Source Code Comment: POINT TO NEXT
4EA0
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
Original Source Code Comment: PRINT IT
4EA3
DEC C
DECrement the total filespec counter (stored in Register C) by 1.
Original Source Code Comment: DEC TOTAL COUNTER
4EA4
Display the entire extension by LOOPing back to 4E9EH, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: PRINT ALL OF EXT
4EA6OUT2
LD B,C
Copy the total number of characters left into Register B.
Original Source Code Comment: GET TOTAL NUMBER
4EA7LOOP3
LD A,20HLD A,' '
Let Register A equal 20H so that we can display the appropriate number of SPACE's.
Original Source Code Comment: OUTPUT SPACES
4EA9
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
4EAC
LOOP back to 4EA7H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
4EAE
LD A,(NUM)
Fetch the number of filenames that have already been displayed on the same line on screen (held in memory location 4EEFH) and store it into Register A.
Original Source Code Comment: GET HOW MANY THIS LINE
4EB1
INC A
INCrement the value stored in Register A by 1 to indicate that one more was just displayed.
Original Source Code Comment: ADD ONE TO IT
4EB2
CP 04HCP 4
Compare the value held in Register A against 04H to see if we already have 4. If A < 04H, the CARRY FLAG will be set.
Original Source Code Comment: 3 NAMES ON SCREEN?
4EB4
If we are less than 4, then we can keep displaying on this line, so JUMP down to 4EBCH.
Original Source Code Comment: IF NOT, KEEP GOING THIS LINE

If we are here, then we have already displayed 4 filenames on a line, so we need to end that line and reset everything that monitors that count and start again.

4EB6
LD A,0DH
Let Register A equal 0DH (ASCII: CARRIAGE RETURN).
Original Source Code Comment: OUT A CR FOR NEXT LINE
4EB8
GOSUB to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position.
4EBB
XOR A
Set Register A to ZERO in preparation for resetting the "how many filenames have appeared on screen on this line" tracker.
Original Source Code Comment: CLEAR NUMBER COUNTER
4EBCNXTNAM
LD (NUM),A
Store the value held in Register A into the "how many filenames have appeared on screen on this line" tracker (held in memory location 4EEFH).
Original Source Code Comment: SAVE COUNTER
4EBFTOTNXT
LD HL,(SAVE3)
Fetch the BUFFER starting location (held in memory location 4EECH) and store it into Register Pair HL.
Original Source Code Comment: GET BUFFER POINTER

The next 3 instructions function as HL = HL + 30H

4EC2
LD A,L
Let Register Pair HL point to the next filename in the buffer in RAM by advancing it 30H more bytes. First, put L into A.
Original Source Code Comment: PUT LSB INTO A
4EC3
ADD A,30H
Next, add 30H to A.
Original Source Code Comment: POINT TO NEXT NAME
4EC5
LD L,A
Finally, put the A+30H back into L.
Original Source Code Comment: PUT BACK FOR ADDRESS
4EC6
LD (SAVE3),HL
Store the revised pointer to the directory sector in RAM into memory location 4EECH.
Original Source Code Comment: PUT ADJUSTED BACK
4EC9
CP 0F0H
Compare the value held in Register A against 0F0H, which is the delimeter for the last entry in a directory sector. If A < 0F0H, the CARRY FLAG will be set.
Original Source Code Comment: WE AT END OF THIS SECTOR?
4ECB
If the C FLAG (Carry) has been set, then we are not yet at the end of the sector, so JUMP back to 4E6AH to process the next filename.
Original Source Code Comment: NEXT NAME IF NOT DONE

If we are here, then we have exhausted all filenames in the current sector, and need to move to the next sector of the directory.

4ECD
LD A,(S10SEC)
Fetch the sector number of the directory which we just worked on from memory location 4EEEH.
Original Source Code Comment: GET PRESENT TRACK
4ED0
CP 13HCP 19
Compare the value held in Register A against 13H (Decimal: 19) to see if we have run out of sectors. If the sector we are on (held in Register A) < 19 sectors, the CARRY FLAG will be set.
Original Source Code Comment: ALL DIR TRACKS YET?
4ED2
If the C FLAG (Carry) has been set then we have not yet hit sector 19, so loop back to 4E4BH to get the next directory sector.
Original Source Code Comment: IF NOT, KEEP GOING
4ED5
LD A,0DH
Let Register A equal 0DH (ASCII: CARRIAGE RETURN).
Original Source Code Comment: NEW LINE PLEASE
4ED7
JUMP to 0033H.
NOTE: 0033H is the Model III ROM character print routine; displays the character held in Register A at the current cursor position. Since this was JUMPED to instead of CALLed, the RET at the end of this ROM routine will then RETurn to the caller of this subroutine instead of returning to this place.
Original Source Code Comment: DISPLAY AND EXIT

4EDAH - DRIVE - BYTE STORAGE.

4EDADRIVE
DEFB 00H
Storage byte for the DRIVE NUMBER being worked on.
4EDBTRK
DEFB 00H
Storage byte for the DIRECTORY TRACK of the disk in the DRIVE.
4EDCDRVMSG
DEFM 'DRIVE :'
4EE3DRV
DEFM '0 ' + 03H
4EECSAVE3
DEFW 0000H
Location of the current pointer in the Directory Buffer in RAM
4EEES10SEC
DEFB 00H
The sector number in the directory being worked on.
4EEFNUM
DEFB 00H
Number of filenames which have already appeared on screen on the current line.

4EF0H - DOERR - Process an Error.

4EF0DOERR
LD A,E
Copy the error code (held in Register E) into Register A.
4EF1
CP 8BH
Compare the value held in Register A against 8BH (Decimal: 139), which is the highest possible error code. If A >= 8BH, the NO CARRY FLAG will be set.
Original Source Code Comment: HIGHER THAN ALLOWABLE ERROR?
4EF3
If the requested error code is higher than the highest possible error code then the NC FLAG (No Carry) will have been set, JUMP to 4EFDH to handle an UNPRINTABLE ERROR.
Original Source Code Comment: YES, FORCE TO 'UNPRINTABLE' ERROR
4EF5
CP 63H
Compare the value held in Register A against 63H (Decimal: 99), which is the start of the DISK ERRORs. If A >= 63H, the NO CARRY FLAG will be set.
Original Source Code Comment: DISK ERROR?
4EF7
If the requested error code is equal to or higher than 63H, then we have a disk error, so JUMP to 4EFFH.
Original Source Code Comment: YES, DO IT
4EF9
CP 2FH
Compare the value held in Register A against 2FH (Decimal: 47). If A < 2FH, the CARRY FLAG will be set.
4EFB
If the C FLAG (Carry) has been set, JUMP to 4F01H.

If we pass through, then we wind up at the UNPRINTABLE ERROR jump point. How clever!

4EFDSTART1
LD A,5AH
As a jump point, this processes an UNPRINTABLE ERROR. Let Register A equal 5AH (Decimal: 90) to set up to force an UNPRINTABLE ERROR after all the math that's coming up.
Original Source Code Comment: FORCE TO 'UNPRINTABLE' ERROR
4EFFSTART2
SUB 34H
As a jump point, this processes disk errors. SUBtract the value 34H (Decimal: 52) from Register A. If passed through, then A now equals 5AH-34H=26H (Decimal 38). If jumped, A is between 63H-34H=2F (Decimal 47) and 8AH-34H=56H (Decimal 86).
4F01START3
RRCA
As a jump point, this is for errors 2EH (46 decimal) and below. Rotate the bits in A right, with Bit 0 being copied to both the CARRY FLAG and Bit 7. If passed from START 1, then 00100110 rotated to 00010011 (13H / 19).
4F02
INC A
INCrement the adjusted error code (stored in Register A) by 1. If this was from START 1, then A now is 20, meaning the 20th error. This is, in fact, 505AH which is UNPRINTABLE ERROR.
4F03
LD B,A
Copy the contents of Register A into Register B.
4F04
LD HL,ERRTAB
Let Register Pair HL equal 4F11H to point to the ERROR MESSAGE TABLE.
Original Source Code Comment: HL => TABLE

At this point, Register B is holding the number of error messages we need to skip before we get to the one we want.

4F07START4
LD A,(HL)
Fetch a character from the error message table (the memory location pointed to by Register Pair HL) and store it into Register A.
Original Source Code Comment: GET A CHARACTER
4F08
INC HL
Point the to next character in the error message table by INCrementing the value stored in Register Pair HL by 1.
Original Source Code Comment: BUMP TO NEXT CHARACTER
4F09
OR A
Set FLAGS based on the contents of Register A.
Original Source Code Comment: END OF THIS ERROR MESSAGE?
4F0A
If we have no 0, then we have not yet reached the end of the error message, so LOOP back to START4.
Original Source Code Comment: NO, LOOP TILL FOUND

We fall through to here when an entire error message has been read and its time to move to the next one.

4F0C
LOOP back to 4F07H, reducing Register B each time, and continue to LOOP until Register B has been reduced to ZERO, in which case, continue with the next instruction.
Original Source Code Comment: LOOP FOR ERROR NUMBER
4F0E
JUMP to the error handler at 1A01H.
Original Source Code Comment: JP TO ERROR HANDLER

4F11H - ERRTAB - ERROR MESSAGE STORAGE AREA.

4F11ERRTAB
DEFB 00H
Delimeter
Original Source Code Comment: START OF TABLE
4F12
DEFM 'NEXT without FOR'
4F22
DEFB 00H
Delimeter
4F23
DEFM 'Syntax Error'
4F2F
DEFB 00H
Delimeter
4F30
DEFM 'RETURN without GOSUB'
4F44
DEFB 00H
Delimeter
4F45
DEFM 'Out of DATA'
4F50
DEFB 00H
Delimeter
4F51
DEFM 'Illegal function call'
4F66
DEFB 00H
Delimeter
4F67
DEFM 'Overflow'
4F6F
DEFB 00H
Delimeter
4F70
DEFM 'Out of memory'
4F7D
DEFB 00H
Delimeter
4F7E
DEFM 'Undefined line number'
4F93
DEFB 00H
Delimeter
4F94
DEFM 'Subscript out of range'
4FAA
DEFB 00H
Delimeter
4FAB
DEFM 'Redimensioned array'
4FBE
DEFB 00H
Delimeter
4FBF
DEFM 'Division by zero'
4FCF
DEFB 00H
Delimeter
4FD0
DEFM 'Illegal direct'
4FDE
DEFB 00H
Delimeter
4FDF
DEFM 'Type mismatch'
4FEC
DEFB 00H
Delimeter
4FED
DEFM 'Out of string space'
5000
DEFB 00H
Delimeter
5001
DEFM 'String too long'
5010
DEFB 00H
Delimeter
5011
DEFM 'String formula too complex'
502B
DEFB 00H
Delimeter
502C
DEFM 'Can't Continue'
503A
DEFB 00H
Delimeter
503B
DEFM 'No RESUME'
5044
DEFB 00H
Delimeter
5045
DEFM 'RESUME without error'
5059
DEFB 00H
Delimeter
505A
DEFM 'Unprintable error'
506B
DEFB 00H
Delimeter
506C
DEFM 'Missing operand'
507B
DEFB 00H
Delimeter
507C
DEFM 'BAD File Data'
5089
DEFB 00H
Delimeter
508A
DEFM 'Disk Basic Feature'
509C
DEFB 00H
Delimeter
509D
DEFM 'Undefined User Function'
50B4
DEFB 00H
Delimeter
50B5
DEFM 'FIELD overflow'
50C3
DEFB 00H
Delimeter
50C4
DEFM 'Internal error'
50D2
DEFB 00H
Delimeter
50D3
DEFM 'Bad file number'
50E2
DEFB 00H
Delimeter
50E3
DEFM 'File not found'
50F1
DEFB 00H
Delimeter
50F2
DEFM 'Bad file mode'
50FF
DEFB 00H
Delimeter
5100
DEFM 'File already open'
5111
DEFB 00H
Delimeter
5112
DEFM '?'
5113
DEFB 00H
Delimeter
5114
DEFM 'Disk I/O error'
5122
DEFB 00H
Delimeter
5123
DEFM 'File already exists'
5136
DEFB 00H
Delimeter
5137
DEFM '?'
5138
DEFB 00H
Delimeter
5139
DEFM '?'
513A
DEFB 00H
Delimeter
513B
DEFM 'Disk full'
5144
DEFB 00H
Delimeter
5145
DEFM 'Input past end'
5153
DEFB 00H
Delimeter
5154
DEFM 'Bad record number'
5165
DEFB 00H
Delimeter
5166
DEFM 'Bad file name'
5173
DEFB 00H
Delimeter
5174
DEFM 'Mode-mismatch'
5181
DEFB 00H
Delimeter
5182
DEFM 'Direct statement in file'
519A
DEFB 00H
Delimeter
519B
DEFM 'Too many files'
51A9
DEFB 00H
Delimeter
51AA
DEFM 'Disk write protected'
51BE
DEFB 00H
Delimeter
51BF
DEFM 'File access DENIED'
51D1
DEFB 00H
Delimeter
 
END 4E00H