TRS-80 DOS - VTOS 4.0.2 for the Model I - SYS4/SYS Disassembled

Page Customization

Introduction/Summary:

VTOS 4.0 SYS4/SYS Disassembly - Error Display Handler (Model I)

SYS4/SYS is the error display overlay for VTOS 4.0 (Virtual Technology Operating System v4.0.2 by Randolph Cook). It is loaded into the overlay area at 4E00H-51DDH when an error condition triggers SVC code 86H via RST 28H. SYS4 is a pure display overlay: it contains no disk I/O logic except a single CALL to 4797H to read a directory sector for filename extraction. All error handling decisions are made by the calling overlay before invoking SYS4.

SYS4 uses a dictionary-based message system to convert numeric error codes into human-readable text. The system decomposes 42 error messages (codes 00H-29H) into 55 reusable words stored in a contiguous string pool, referenced through a 3-level lookup: an offset table maps each error code to a descriptor chain, each descriptor byte encodes a word index (bits 0-5) plus continuation/context flags (bits 6-7), and a DEFW address table provides the start address and implied length of each word in the pool. This overlapping-entry scheme reads 4 consecutive bytes per word (current start, next start) and computes word length by subtraction, eliminating the need for stored lengths or delimiters.

The total vocabulary of 55 words occupies 299 bytes in the string pool, plus 112 bytes for the DEFW table, 42 bytes for the offset table, and 160 bytes for the descriptor chains, totaling approximately 613 bytes for the complete error message system. This is roughly 20-25% smaller than storing the 42 messages as individual full-text strings.

SYS4's error display includes three diagnostic components beyond the message text: an error code prefix ("*** ERRCOD=XX, "), a device/file context section showing the drive and filename associated with the error, and a return address display ("REFERENCED AT X'nnnn'") identifying the instruction that triggered the error. The filename can be extracted from either the FCB filespec string (if the FCB contains status 2AH indicating an initialized reference) or from the directory entry (requiring a disk read via 4797H).

The architecture is closely related to TRSDOS 2.3 SYS4, reflecting VTOS's lineage as the direct ancestor of LDOS. VTOS extends the error code range from TRSDOS 2.3's 40 codes (00H-27H) to 42 codes (00H-29H), adding messages for "DEVICE IN USE" (27H) and "PROTECTED SYSTEM DEVICE" (28H). Several messages are also reworded, and the word dictionary is expanded from 53 to 55 entries.

The entry mechanism uses the standard VTOS inline parameter block technique: the CALL to SYS4 is followed by an error code byte in Register A, and the overlay extracts context from the stack (saved return address) and from the caller's FCB pointer. The exit path distinguishes fatal errors (bit 7 of the error code set, causing JP M,0000H cold restart) from recoverable errors (bit 7 clear, falling through to JP 4030H for error-already-displayed exit). Bit 6 controls whether extended context (device, filename, return address) is displayed.

Error Code Bit Flags
Bit 6 of the error code controls whether extended context is displayed: when clear, the full diagnostic output includes the "*** ERRCOD=XX, " prefix, the error message words, and the extended context (device, file, return address). When bit 6 is set, only the error message words are displayed with no prefix or context. Bit 7 is the fatal error flag: when clear, the exit goes to DOS READY via JP 4030H; when set, a cold restart occurs via JP M,0000H.

Descriptor Byte Format
Each byte in a descriptor chain encodes: bits 0-5 = word index (1-55) into the DEFW table at 4FB1H; bit 6 = context flag (on the last byte only: 0 = filename extracted from directory entry, 1 = filename taken from FCB filespec string); bit 7 = last-word flag (0 = more words follow, 1 = this is the final word).

Dictionary System Architecture
SYS4 uses a 3-level lookup to convert error codes to messages: (1) Offset Table at 4F89H (42 bytes): maps error_code to a page offset into 51xxH where the descriptor chain begins; (2) Descriptor Chain at 513EH-51DDH: sequence of bytes, each encoding a word index with continuation and context flags; (3) Word Address Table at 4FB1H (112 bytes): word_index x 2 gives a DEFW pointing to the start of the word in the string pool, with word length computed as next_DEFW minus current_DEFW; (4) String Pool at 5023H-513DH (283 bytes): 55 contiguous ASCII words with no separators, boundaries defined by the DEFW table.


Key Variables

AddressBytesPurpose
4E97H2Self-modified JP M operand: overlay return address stored here during entry (written by 4E01H). For fatal errors (bit 7 set), JP M,0000H performs cold restart; for normal errors, execution falls through to JP 4030H.
430AH2Saved overlay return address (SYS0 context). Read by extended context routine at 4E9EH to load IX with FCB pointer.
430CH2Saved overlay return address (alternate). Read at 4F2EH; subtracted by 3 to compute the caller's SVC stub address for "REFERENCED AT X'nnnn'" display.
430FH1System mode flags. Bit 6 tested at 4E0DH: when set, XOR with error code bit 6 suppresses certain context display modes.
4200H256Message assembly buffer. Error message text is built here character by character before display via CALL 447BH.
4DE7H-SYS0 routine: Hex display for return address (called at 4F38H). Displays HL as 4-digit hexadecimal.
447BH-SYS0 routine: Display message string on screen (called at 4E86H, 4F2BH, 4F3EH). Prints from HL until 03H or 0DH terminator.
4797H-SYS0 routine: Read directory sector by info byte. Used at 4EEAH to load directory entry for filename extraction.
4B10H-SYS0 routine: Directory entry validation. Used at 4EEAH to read and validate directory data.

Self-Modifying Code Locations

WriterTargetPurpose
4E01H4E97HOverlay return address stored as JP M operand. For fatal errors, this becomes the cold restart vector (0000H); for normal errors, execution falls through past it.
4E1FH-4E35H4F42H-4F43HDecimal error code digits written into the "*** ERRCOD=XX, " template string at 4F41H. The tens digit at 4F42H and units digit at 4F43H.
4EB5H4F57H-4F58HFCB drive number and directory info byte stored into the "DEVICE=*XX" template string at 4F4DH.

Major Routines

AddressNamePurpose
4E00HError Display Entry PointContext save, error code extraction, bit 6/7 flag processing, decimal conversion, error code prefix display, message lookup and word printing loop.
4E71HError Display CompletionAppends "*** " closing marker, displays assembled message, conditionally calls extended context routine, restores registers, and exits.
4E9CHExtended Error Context DisplayLoads FCB pointer from 430AH, determines filename source (FCB chain vs directory entry), extracts and formats device/file context, displays return address.
4EBEHFCB Direct Info ExtractionFor FCB with status not equal to 2AH: copies up to 24 bytes from the FCB to the filename buffer for display.
4EE4HDirectory Entry Filename ExtractionReads directory sector via 4B10H, extracts 8-byte filename and 3-byte extension in NAME/EXT:D format.
4F06HDisplay Return AddressShows "REFERENCED AT X'nnnn'" using the overlay return address at 430CH minus 3, pointing back to the caller's SVC stub.

Cross-Reference Notes

SYS4 Calls Into SYS0
447BH (display message string on screen), 4797H (read directory sector by info byte), 4B10H (directory entry validation), 4030H (error-already-displayed DOS exit), 4DE7H (hex display routine).

SYS4 Calls Into ROM
0000H (cold restart, via self-modified JP M target for fatal errors).

SYS4 Called By
Any overlay that triggers SVC code 86H (error display) via RST 28H. Error codes are passed in Register A. The calling overlay's return address and FCB pointer provide context for the diagnostic display.


VTOS 4.0 Error Codes Handled by SYS4

CodeMessage
00HNO ERROR
01HPARITY ERROR DURING HEADER READ
02HSEEK ERROR DURING READ
03HLOST DATA DURING READ
04HPARITY ERROR DURING READ
05HDATA RECORD NOT FOUND DURING READ
06HATTEMPTED TO READ SYSTEM DATA RECORD
07HATTEMPTED TO READ LOCKED/DELETED DATA RECORD
08HDEVICE NOT AVAILABLE
09HPARITY ERROR DURING HEADER WRITE
0AHSEEK ERROR DURING WRITE
0BHLOST DATA DURING WRITE
0CHPARITY ERROR DURING WRITE
0DHDATA RECORD NOT FOUND DURING WRITE
0EHWRITE FAULT ON DISK DRIVE
0FHWRITE PROTECTED DISK
10HILLEGAL LOGICAL FILE NUMBER
11HDIRECTORY READ ERROR
12HDIRECTORY WRITE ERROR
13HILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE
14HPROTECTED FILE
15HREAD LOCKED/DELETED DATA RECORD
16HRECORD
17HLOCKED/DELETED DATA RECORD
18HDEVICE NOT IN DIRECTORY
19HFILE ACCESS DENIED
1AHFULL OR WRITE PROTECTED DISK
1BHDISK SPACE FULL
1CHEND OF FILE ENCOUNTERED
1DHRECORD NUMBER OUT OF RANGE
1EHDIRECTORY FULL - CAN'T EXTEND FILE
1FHPROGRAM NOT FOUND
20HILLEGAL DRIVE NUMBER
21HNO DEVICE SPACE AVAILABLE
22HLOAD FILE FORMAT ERROR
23HMEMORY FAULT
24HATTEMPTED TO LOAD READ ONLY MEMORY
25HILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE
26HFILE NOT OPEN
27HDEVICE IN USE
28HPROTECTED SYSTEM DEVICE
29HUNKNOWN ERROR CODE

Disassembly:

4E00H - Error Display Entry Point

Entry point for the error display overlay. Saves context, extracts and processes the error code from Register A, converts it to decimal for display, builds the error message prefix string, then enters the word lookup and display loop.

The overlay is entered via RST 28H with SVC code 86H. At entry, the stack contains the caller's return address (pointing past the RST 28H instruction) and Register A holds the error code. The EX (SP),HL trick extracts the return address while simultaneously saving HL.

4E00
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack. This swaps the caller's return address (which was on the stack from the RST 28H dispatch) into HL, while simultaneously saving the current HL value onto the stack for later restoration. HL now holds the overlay return address.
4E01
LD (4E97H),HL 22 97 4E
Self-Modifying Code
Store the overlay return address (in Register Pair HL) into the operand field of the JP M instruction at 4E96H. This address becomes the cold restart target if the error is fatal (bit 7 set). The JP M instruction at 4E96H tests the sign flag: if the error code has bit 7 set, the jump is taken to 0000H (cold restart); otherwise execution falls through to JP 4030H.
4E04
POP HL E1
Restore Register Pair HL from the stack. This recovers the original HL value that was pushed by the EX (SP),HL at 4E00H.
4E05
POP AF F1
Restore Register Pair AF from the stack. Register A now contains the error code that was passed by the calling overlay. The error code encodes: bits 0-5 = error number (00H-29H), bit 6 = extended context suppression flag, bit 7 = fatal error flag.
4E06
PUSH HL E5
Save Register Pair HL onto the stack for restoration at the exit path. This preserves the caller's HL value across the entire error display operation.
4E07
PUSH DE D5
Save Register Pair DE onto the stack for restoration at the exit path.
4E08
PUSH BC C5
Save Register Pair BC onto the stack for restoration at the exit path.
4E09
LD B,A 47
Copy the error code from Register A into Register B for safe-keeping. Register A will be modified by the upcoming flag processing, but the full error code is needed later for the bit 6 and bit 7 exit tests.

The next four instructions implement a subtle bit manipulation that merges the system flags byte at 430FH with the error code's bit 6. The effect is: if 430FH bit 6 is set AND the error code's bit 6 is clear, the result forces bit 6 on, suppressing the extended context display. If 430FH bit 6 is clear, the error code's own bit 6 is preserved unchanged.

4E0A
LD A,(430FH) 3A 0F 43
Fetch the system mode flags byte from 430FH into Register A. Bit 6 of this byte controls whether the system is in a mode that suppresses extended error context display.
4E0D
AND 40H E6 40
Mask Register A to isolate bit 6 of the system flags. If the system's bit 6 is set, Register A = 40H; otherwise Register A = 00H.
4E0F
XOR B A8
XOR Register A (isolated system bit 6) with Register B (the full error code). This flips the error code's bit 6 if the system flag's bit 6 was set. The XOR produces a combined flag value where bit 6 reflects the merged state of both flags.
4E10
AND B A0
AND the XOR result with the original error code in Register B. The AND operation with the original error code ensures that only bits present in the original error code survive, with the exception of bit 6 which was conditionally toggled by the XOR. The net effect: if 430FH bit 6 is set, the error code's bit 6 is forced ON (suppressing context display); if 430FH bit 6 is clear, the original error code's bit 6 is preserved.
4E11
LD B,A 47
Store the processed error code (with merged bit 6) back into Register B. This is now the working error code used throughout the rest of the overlay.
4E12
PUSH AF F5
Save Register A (the processed error code) onto the stack. This value will be restored at 4E71H and 4E8AH for the bit 6 and bit 7 exit tests.
4E13
LD DE,4200H 11 00 42
Point Register Pair DE to the message assembly buffer at 4200H. All error message text will be built into this buffer character by character before being displayed as a single string.
4E16
AND 3FH E6 3F
Mask Register A to extract the error code number (bits 0-5), stripping the bit 6 context flag and bit 7 fatal flag. This gives the raw error code value (00H-29H) used for the message lookup.
4E18
LD C,A 4F
Copy the raw error code number into Register C. This will be used as an index into the error code offset table at 4F89H.
4E19
BIT 6,B CB 70
Test bit 6 of Register B (the processed error code). If bit 6 is set, the extended context prefix ("*** ERRCOD=XX, ") is suppressed and only the error message words are displayed. If bit 6 is clear, the full diagnostic prefix is assembled.
4E1B
LD B,00H 06 00
Clear Register B to 00H. This prepares BC as a 16-bit index (with C holding the error code number and B = 00H) for the offset table lookup later at 4E44H.
4E1D
If the NZ FLAG (Not Zero) has been set because bit 6 of the processed error code was set, JUMP to 4E3EH to skip the error code prefix assembly and go directly to the error message word lookup. When bit 6 is set, only the message words are displayed without any "*** ERRCOD=XX, " prefix.

The following block (4E1FH-4E3DH) assembles the "*** ERRCOD=XX, " prefix into the buffer at 4200H. It copies the template string from 4F41H, then overwrites the "XX" placeholder with the actual error code converted to decimal ASCII digits using repeated subtraction.

4E1F
PUSH BC C5
Save Register Pair BC (B=00H, C=error code number) onto the stack. BC will be needed after the template copy and decimal conversion.
4E20
LD HL,4F41H 21 41 4F
Point Register Pair HL to the error code display template string at 4F41H. This template contains the bytes: 0AH (linefeed), "*** ERRCOD=" (11 characters), for a total of 12 bytes to copy.
4E23
LD BC,000CH 01 0C 00
Load Register Pair BC with 000CH (12 decimal). This is the byte count for the LDIR block copy of the template string from 4F41H into the message buffer at 4200H (pointed to by DE).
4E26
LDIR ED B0
Block copy 12 bytes from the template string at 4F41H (source HL) to the message assembly buffer at 4200H (destination DE). After the copy, HL points past the template (to 4F4DH), DE points to 420CH (the position in the buffer after the copied template text), and BC = 0.
4E28
POP BC C1
Restore Register Pair BC from the stack. Register C still holds the raw error code number (00H-29H), and Register B = 00H.
4E29
EX DE,HL EB
Exchange DE and HL. HL now points to position 420CH in the message buffer (where the decimal digits will be written), and DE points to 4F4DH (past the template string, not needed further).
4E2A
LD C,A 4F
Copy Register A (which still holds the raw error code number from 4E16H) into Register C. This prepares the error code for the decimal conversion loop.

The following loop at 4E2BH-4E33H converts the binary error code in Register C to two decimal ASCII digits using repeated subtraction of 10. The tens digit is built at (HL) starting from ASCII '0' (2FH + INC = 30H), and the units digit is recovered by adding back 3AH to the negative remainder.

4E2B
LD (HL),2FH 36 2F
Initialize the tens digit position in the buffer to 2FH (one less than ASCII '0'). The INC at the next instruction will bump this to 30H ('0') on the first iteration, then to 31H ('1'), 32H ('2'), etc., for each successful subtraction of 10.
4E2D
INC (HL) 34
Loop Start
INCrement the tens digit at (HL) by 1. On first entry, this changes 2FH to 30H (ASCII '0'). Each subsequent iteration increments the digit by one, counting how many times 10 can be subtracted from the error code.
4E2E
SUB 0AH D6 0A
SUBtract 10 (0AH) from Register A (the error code number). If the result is non-negative (no borrow), the tens digit is incremented again. If the result goes negative (borrow/carry), the tens digit is complete and the remainder (plus 10) gives the units digit.
4E30
If the NO CARRY FLAG has been set because the subtraction did not underflow, LOOP BACK to 4E2DH to increment the tens digit and subtract another 10. This loop runs once for each full group of 10 in the error code value.
Loop End
4E32
INC L 2C
INCrement Register L by 1 to advance the buffer pointer (HL) to the next byte position (the units digit position). Since the buffer is page-aligned within page 42xxH, incrementing L alone is sufficient.
4E33
ADD A,3AH C6 3A
ADD 3AH (58 decimal) to Register A. After the loop, Register A holds the negative remainder from the last subtraction (a value between -10 and -1, stored as F6H-FFH). Adding 3AH converts this to the ASCII digit for the units value: -10 + 3AH = 30H ('0'), -9 + 3AH = 31H ('1'), ..., -1 + 3AH = 39H ('9').
4E35
LD (HL),A 77
Store the units digit (ASCII '0'-'9') into the buffer at the current HL position. The buffer now contains the two-digit decimal error code at positions that correspond to 4F42H-4F43H in the template.
4E36
INC L 2C
INCrement Register L to advance the buffer pointer past the units digit to the next buffer position.
4E37
LD (HL),2CH 36 2C
Store 2CH (ASCII comma ',') into the buffer at the current position. This places the comma separator after the error code digits, producing the "XX," portion of the prefix.
4E39
INC L 2C
INCrement Register L to advance the buffer pointer past the comma.
4E3A
LD (HL),20H 36 20
Store 20H (ASCII space ' ') into the buffer. This completes the "*** ERRCOD=XX, " prefix with a trailing space before the error message words begin.
4E3C
INC L 2C
INCrement Register L to advance the buffer pointer past the space, positioning DE (via EX at 4E29H; but now HL is the buffer pointer) for the word copy loop that follows.
4E3D
EX DE,HL EB
Exchange DE and HL. DE now points to the current position in the message assembly buffer (past the prefix), and HL is free for use as a source pointer in the upcoming word lookup.

4E3EH - Error Message Lookup and Word Display Loop

Clamps the error code to the maximum supported value (29H), looks up the descriptor chain via the offset table, then enters a loop that reads each descriptor byte, extracts the word index, copies the word text from the string pool into the message buffer, and continues until the last-word flag (bit 7) is set.

At this point, Register C holds the raw error code number (00H-29H), Register B = 00H (so BC is a clean 16-bit index), and Register Pair DE points to the current position in the message assembly buffer at 4200H (either after the "*** ERRCOD=XX, " prefix, or at the very start if bit 6 suppressed the prefix).

4E3E
LD A,29H 3E 29
Load Register A with 29H (41 decimal), the maximum supported error code. Any error code above this value will be clamped to 29H, which maps to the "UNKNOWN ERROR CODE" message.
4E40
CP C B9
Compare Register A (29H) against Register C (the raw error code number). If Register C is less than or equal to 29H, the CARRY FLAG is clear (NC) and the error code is valid. If Register C exceeds 29H, the CARRY FLAG is set, indicating an out-of-range code.
4E41
If the NO CARRY FLAG has been set because the error code in Register C is within range (less than or equal to 29H), JUMP to 4E44H to proceed with the valid error code lookup. If the error code exceeds 29H, fall through to clamp it.
4E43
LD C,A 4F
Clamp the error code: copy Register A (29H) into Register C, replacing the out-of-range value. Error code 29H maps to "UNKNOWN ERROR CODE", which is the default message for any undefined error.

The offset table lookup begins. The table at 4F89H contains one byte per error code (42 entries), where each byte is an offset into page 51xxH where the descriptor chain for that error begins. The code uses BC (with B=00H, C=error code) as a 16-bit index to fetch the correct offset byte.

4E44
LD HL,4F89H 21 89 4F
Point Register Pair HL to the error code offset table at 4F89H. This table contains 42 bytes (one per error code 00H-29H), where each byte is an offset into page 51xxH pointing to the start of the descriptor chain for that error message.
4E47
ADD HL,BC 09
ADD Register Pair BC (the error code index, 0000H-0029H) to HL (4F89H). HL now points to the offset table entry for this specific error code. For example, error 00H reads from 4F89H, error 01H from 4F8AH, error 29H from 4FB2H.
4E48
LD L,(HL) 6E
Fetch the offset byte from the table into Register L. This byte is the low byte of the descriptor chain address. For error 00H, this loads 3EH (pointing to 513EH).
4E49
LD H,51H 26 51
Set Register H to 51H, forming the high byte of the descriptor chain address. Combined with the offset in L, HL now points to the start of the descriptor chain for this error code in page 51xxH (513EH-51DDH).

The main word display loop begins at 4E4BH. For each iteration: (1) read a descriptor byte from the chain at (HL), (2) extract the word index from bits 0-5, (3) look up the word's start address and length from the DEFW table at 4FB1H, (4) copy the word text into the message buffer, (5) append a space separator, (6) check bit 7 of the descriptor to decide whether to continue or exit.

4E4B
LD A,(HL) 7E
Loop Start - Word Display Loop
Fetch the current descriptor byte from the chain at (HL) into Register A. This byte encodes: bits 0-5 = word index into the DEFW table, bit 6 = context flag (meaningful only on the last byte), bit 7 = last-word flag (1 = this is the final word in the message).
4E4C
AND 3FH E6 3F
Mask Register A to extract the word index (bits 0-5), stripping the bit 6 context flag and bit 7 last-word flag. The result is a value from 01H to 37H (1 to 55 decimal) identifying which word to display.
4E4E
ADD A,A 87
Double the word index in Register A (multiply by 2). Each entry in the DEFW table at 4FB1H is 2 bytes wide, so the byte offset into the table is word_index x 2.
4E4F
PUSH HL E5
Save Register Pair HL (the current position in the descriptor chain) onto the stack. HL will be used for the DEFW table lookup, and the descriptor chain position must be preserved for the next iteration.
4E50
LD C,A 4F
Copy the doubled word index from Register A into Register C. With B still 00H from 4E1BH (or cleared by earlier operations), BC = word_index x 2 as a 16-bit offset.
4E51
LD B,00H 06 00
Ensure Register B is 00H so that BC is a clean 16-bit value holding word_index x 2.
4E53
LD HL,4FB1H 21 B1 4F
Point Register Pair HL to the word address (DEFW) table at 4FB1H. This table contains 56 entries of 2 bytes each (little-endian addresses pointing to word strings in the pool at 5023H-513DH).
4E56
ADD HL,BC 09
ADD the doubled word index (in BC) to the DEFW table base (4FB1H). HL now points to the 2-byte entry for this word's start address.

The overlapping-entry scheme reads 4 consecutive bytes: the first 2 bytes (at HL) are the current word's start address, and the next 2 bytes (at HL+2) are the next word's start address. The word length is computed as (next_start - current_start) via SBC HL,BC.

4E57
LD C,(HL) 4E
Fetch the low byte of the current word's start address from the DEFW table into Register C.
4E58
INC HL 23
INCrement HL to point to the high byte of the current word's start address.
4E59
LD B,(HL) 46
Fetch the high byte of the current word's start address into Register B. BC now holds the 16-bit start address of the current word in the string pool (e.g., 5025H for "ERROR").
4E5A
INC HL 23
INCrement HL to point to the low byte of the NEXT word's start address (the overlapping entry).
4E5B
LD A,(HL) 7E
Fetch the low byte of the next word's start address into Register A.
4E5C
INC HL 23
INCrement HL to point to the high byte of the next word's start address.
4E5D
LD H,(HL) 66
Fetch the high byte of the next word's start address into Register H.
4E5E
LD L,A 6F
Load Register L with Register A (the low byte of the next word's start address). HL now holds the next word's start address, and BC holds the current word's start address.
4E5F
OR A B7
OR Register A with itself to clear the CARRY FLAG. This prepares for the SBC instruction that follows, ensuring a clean subtraction without borrow.
4E60
SBC HL,BC ED 42
SUBtract BC (current word start) from HL (next word start) with borrow. The result in HL is the word length in bytes. For example, if the current word starts at 5025H and the next at 502AH, the length is 5 (the word "ERROR").
4E62
PUSH BC C5
Save Register Pair BC (the current word's start address in the string pool) onto the stack. The EX (SP),HL trick at the next instruction will swap this with the word length.
4E63
EX (SP),HL E3
Exchange HL (word length) with the top of the stack (word start address). After this: HL = word start address in the string pool, and the word length is on the stack.
4E64
POP BC C1
Restore Register Pair BC from the stack. BC now holds the word length (the number of bytes to copy from the string pool into the message buffer).
4E65
LDIR ED B0
Block copy BC bytes from the word string (source HL in the string pool) to the message assembly buffer (destination DE at the current write position). After the copy, DE points past the last copied character, ready for the next word or separator.
4E67
LD A,20H 3E 20
Load Register A with 20H (ASCII space ' '). A space separator is appended after each word in the message buffer to create the natural-language error message text.
4E69
LD (DE),A 12
Store the space character into the message buffer at the current DE position.
4E6A
INC E 1C
INCrement Register E to advance the buffer write pointer past the space. Since the buffer is within page 42xxH, incrementing E alone is sufficient.
4E6B
POP HL E1
Restore Register Pair HL from the stack. This recovers the descriptor chain pointer that was saved at 4E4FH, positioning HL at the descriptor byte that was just processed.
4E6C
LD A,(HL) 7E
Re-read the current descriptor byte from the chain at (HL) into Register A. The full byte is needed to test the bit 7 last-word flag, which was stripped during the word index extraction at 4E4CH.
4E6D
INC HL 23
INCrement HL to advance the descriptor chain pointer to the next byte. If this was not the last word, the next iteration of the loop will read the next descriptor from this position.
4E6E
RLCA 07
Rotate Register A left through carry. This shifts bit 7 (the last-word flag) into the CARRY FLAG. If the carry is clear, more words remain in the chain; if set, this was the final word.
4E6F
If the NO CARRY FLAG has been set because bit 7 of the descriptor was clear (more words remain), LOOP BACK to 4E4BH to process the next word in the chain. The loop continues until a descriptor byte with bit 7 set is encountered, indicating the final word of the error message.
Loop End - Word Display Loop

4E71H - Error Display Completion and Exit Dispatch

After the word display loop has assembled the complete error message text into the buffer at 4200H, this section appends the closing marker, displays the assembled message on screen, conditionally invokes the extended error context display, restores the caller's registers, and dispatches to either a cold restart (fatal) or the DOS error-already-displayed exit (normal).

At this point the word display loop at 4E4BH-4E6FH has exited with the carry flag set (bit 7 of the last descriptor was set). Register Pair DE points to the current write position in the message assembly buffer at 4200H, past all the copied word text. The processed error code (with merged bit 6) was saved on the stack at 4E12H.

4E71
POP AF F1
Restore Register A from the stack. This recovers the processed error code that was saved at 4E12H, including the merged bit 6 (context suppression flag) and bit 7 (fatal error flag).
4E72
PUSH AF F5
Save Register A back onto the stack. The error code is needed again at 4E8AH-4E8BH for the bit 6 extended context test and at 4E91H for the bit 7 fatal error test.
4E73
PUSH HL E5
Save Register Pair HL (the descriptor chain pointer, now past the last descriptor byte) onto the stack. This pointer is needed at 4E89H to re-read the last descriptor byte for the bit 6 context flag test in the extended context routine.
4E74
BIT 6,A CB 77
Test bit 6 of Register A (the processed error code). If bit 6 is clear, the "*** " closing marker and extended context are displayed. If bit 6 is set, only the message words were shown and the closing marker is skipped.
4E76
If the NZ FLAG (Not Zero) has been set because bit 6 is set (context suppressed), JUMP to 4E80H to skip the "*** " closing marker and go directly to appending the carriage return and displaying the message.
4E78
LD HL,4F42H 21 42 4F
Point Register Pair HL to the "*** " closing marker string at 4F42H. This is actually offset +01H into the template at 4F41H, which contains the bytes 2AH 2AH 2AH (three asterisks "***") reused from the prefix template. The three bytes "***" followed by a space will be appended to close the error display line.
4E7B
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H (3 bytes). This is the length of the "***" closing marker to copy.
4E7E
LDIR ED B0
Block copy 3 bytes ("***") from 4F42H (source HL) into the message assembly buffer at the current DE position. After the copy, DE points past the closing marker.
4E80
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return). This is the string terminator that marks the end of the assembled error message in the buffer.
4E82
LD (DE),A 12
Store the carriage return (0DH) into the message buffer at the current DE position. The buffer now contains the complete error message string terminated by 0DH, ready for display.
4E83
LD HL,4200H 21 00 42
Point Register Pair HL to the start of the message assembly buffer at 4200H. The entire error message (prefix + words + closing marker + CR) has been built here.
4E86
GOSUB to the SYS0 message display routine at 447BH to display the assembled error message string on screen. The routine prints characters from the HL pointer until it encounters a 03H or 0DH terminator.
4E89
POP HL E1
Restore Register Pair HL from the stack. This recovers the descriptor chain pointer that was saved at 4E73H, now pointing past the last descriptor byte. This pointer is passed to the extended context routine at 4E9CH so it can re-read the last descriptor's bit 6 context flag.
4E8A
POP AF F1
Restore Register A from the stack. This recovers the processed error code that was saved at 4E72H.
4E8B
PUSH AF F5
Save Register A back onto the stack again. It will be needed one more time at 4E91H for the bit 7 fatal error test.
4E8C
BIT 6,A CB 77
Test bit 6 of the processed error code in Register A. If bit 6 is clear, the extended context display (device, filename, return address) is called. If set, the context display is skipped entirely.
4E8E
If the Z FLAG (Zero) has been set because bit 6 is clear (context display enabled), GOSUB to the extended error context display routine at 4E9CH. This routine displays the device/file information and the return address of the instruction that triggered the error. If bit 6 is set, this call is skipped and the error display exits with just the message text.
4E91
POP AF F1
Restore Register A from the stack. This is the final retrieval of the processed error code, needed for the bit 7 fatal error test at 4E96H.
4E92
POP BC C1
Restore Register Pair BC from the stack. This recovers the caller's original BC value that was saved at 4E08H during entry.
4E93
POP DE D1
Restore Register Pair DE from the stack. This recovers the caller's original DE value that was saved at 4E07H.
4E94
POP HL E1
Restore Register Pair HL from the stack. This recovers the caller's original HL value that was saved at 4E06H.
4E95
OR A B7
OR Register A with itself. This sets the flags based on the error code value without changing it. The critical effect is setting the SIGN FLAG (S) if bit 7 is set, which is tested by the JP M instruction that follows.
4E96
JP M,0000H FA 00 00
Self-Modifying Code
If the SIGN FLAG is set (bit 7 of the error code is set, indicating a fatal error), JUMP to the address stored in the operand field. The operand was written at 4E01H with the overlay return address from the stack. For fatal errors, this effectively performs a warm restart by jumping to 0000H (the cold restart vector). The default operand 0000H shown here is the initial value; at runtime, the address stored by 4E01H may differ, but the JP M only executes when bit 7 is set, meaning the system is performing a fatal error restart regardless. If bit 7 is clear (normal error), the sign flag is clear and execution falls through to the next instruction.
4E99
JUMP to the SYS0 error-already-displayed exit at 4030H. This is the normal exit path for non-fatal errors (bit 7 clear). The error message has already been displayed on screen, so this routine skips error display and proceeds directly to the DOS READY prompt.

4E9CH - Extended Error Context Display

Displays extended diagnostic information after the error message: the device (drive) number, the filename associated with the error, and the return address of the instruction that triggered the error. The filename source depends on the FCB status: if the FCB contains status 2AH (initialized reference, not formally opened), the device info is taken from IX+06H/IX+07H; otherwise, the FCB's own data is used to extract the filename from either the FCB buffer or a directory entry read.

This routine is called conditionally at 4E8EH only when the error code's bit 6 is clear (extended context enabled). Register Pair HL points past the last descriptor byte in the chain (from the word display loop exit). The last descriptor's bit 6 carries the filename context flag: 0 = filename from directory entry (file is open, use drive/info from IX+06H/+07H), 1 = filename from FCB filespec string.

4E9C
PUSH IX DD E5
Save Register Pair IX onto the stack. IX will be loaded with the FCB pointer from the overlay context area and is needed for filename extraction.
4E9E
LD IX,(430AH) DD 2A 0A 43
Load Register Pair IX with the saved overlay return address from 430AH. In the VTOS overlay call context, 430AH holds the FCB pointer that was active when the error occurred. IX now points to the FCB associated with the error.
4EA2
DEC HL 2B
DECrement Register Pair HL by 1 to step back to the last descriptor byte in the chain. HL was left pointing past the last byte by the INC HL at 4E6DH. The last descriptor's bit 6 carries the filename context flag.
4EA3
BIT 6,(HL) CB 76
Test bit 6 of the last descriptor byte at (HL). This is the filename context flag: bit 6 clear = filename extracted from directory entry (file is identified by drive/info byte at IX+06H/+07H, requiring a disk read); bit 6 set = filename taken from FCB filespec string (the FCB already contains readable text).
4EA5
If the NZ FLAG (Not Zero) has been set because bit 6 is set (filename from FCB), JUMP to 4EBEH to extract the filename directly from the FCB buffer rather than reading a directory sector.

The directory-entry filename path begins here. The file is identified by drive number at IX+06H and directory info byte at IX+07H. These values are saved into the device template string, then the code checks the FCB status byte to decide between the 2AH (initialized reference) shortcut or the full directory-entry read path.

4EA7
LD C,(IX+06H) DD 4E 06
Fetch the drive number from the FCB at offset IX+06H into Register C. This identifies which disk drive the file resides on (0-3).
4EAA
LD B,(IX+07H) DD 46 07
Fetch the directory info byte from the FCB at offset IX+07H into Register B. This byte encodes the directory sector and entry position within that sector, used to locate the file's directory entry on disk.
4EAD
BIT 7,(IX+00H) DD CB 00 7E
Test bit 7 of the FCB status byte at IX+00H. Bit 7 set indicates the file is formally open (status 80H or higher); bit 7 clear indicates the file is not open or is in an initialized reference state. This determines whether to use the directory entry path or the 2AH shortcut.
4EB1
If the NZ FLAG (Not Zero) has been set because bit 7 of IX+00H is set (file is formally open), JUMP to 4EE4H to extract the filename from the directory entry via a disk read using the drive number in C and the info byte in B.

The 2AH shortcut path: the FCB is in an initialized reference state (not formally opened). The drive/info values are stored into the device display template, then execution jumps to the common display path at 4F2BH.

4EB3
POP IX DD E1
Restore Register Pair IX from the stack. The FCB pointer is no longer needed for this path; the drive/info bytes have already been captured in BC.
4EB5
LD (4F57H),BC ED 43 57 4F
Self-Modifying Code
Store Register Pair BC (C = drive number, B = directory info byte) into the device display template string at 4F57H. These two bytes overwrite the "*XX" placeholder in the "DEVICE=*XX" template at 4F4DH, so the actual drive and directory info values are displayed.
4EB9
LD HL,4F4DH 21 4D 4F
Point Register Pair HL to the device display template string at 4F4DH. This string contains: C6H (semigraphics bullet), "<DEVICE=", the two bytes just stored at 4F57H, ">", 0DH (carriage return).
4EBC
JUMP unconditionally to 4F2BH to display the device template string and then the return address information. This skips the filename extraction paths since no filename is available for an uninitialized FCB.

4EBEH - FCB Direct Info Extraction Path

When the last descriptor's bit 6 is set, the filename is taken directly from the FCB buffer. This path first extracts the drive/info bytes from IX+01H/IX+02H (the FCB's config table entry pointer), checks for the special 2AH status (FCB chain indicator), then copies up to 24 bytes from the FCB into the filename display buffer at 4F62H.

4EBE
LD C,(IX+01H) DD 4E 01
Fetch the low byte of the FCB's config table entry pointer from IX+01H into Register C. For an active FCB, this contains the drive number or drive config reference.
4EC1
LD B,(IX+02H) DD 46 02
Fetch the high byte of the FCB's config table entry pointer from IX+02H into Register B. Combined with C, BC identifies the drive configuration entry associated with this file.
4EC4
LD A,(IX+00H) DD 7E 00
Fetch the FCB status byte from IX+00H into Register A. This will be checked for the special value 2AH (initialized reference / chain indicator).
4EC7
CP 2AH FE 2A
Compare Register A against 2AH (ASCII '*'). If the FCB status is 2AH, this indicates an indirect FCB reference where IX+01H/IX+02H contain the actual FCB address rather than drive config data. In this case, the code falls back to the 2AH shortcut at 4EB3H.
4EC9
If the Z FLAG (Zero) has been set because the FCB status equals 2AH, JUMP BACK to 4EB3H to use the drive/info shortcut path. The 2AH status means the FCB is an initialized reference and does not contain a readable filename, so only the device info is displayed.

The FCB has a status other than 2AH and bit 6 of the descriptor indicated the filename should come from the FCB buffer. The next block copies up to 24 bytes (18H) from the FCB starting at IX+00H into the filename display buffer at 4F62H. The copy terminates early if a 03H (ETX) or 0DH (CR) byte is encountered, as these mark the end of the filespec string.

4ECB
PUSH IX DD E5
Save Register Pair IX (the FCB pointer) onto the stack.
4ECD
POP HL E1
Restore into Register Pair HL. This is the standard IX-to-HL transfer technique: PUSH IX / POP HL copies the IX value into HL, allowing the use of HL-based instructions for the block copy loop.
4ECE
LD DE,4F62H 11 62 4F
Point Register Pair DE to the filename display buffer at 4F62H. The FCB data will be copied here for display.
4ED1
LD BC,0018H 01 18 00
Load Register Pair BC with 0018H (24 decimal). This is the maximum number of bytes to copy from the FCB into the display buffer. The actual copy may terminate earlier on a 03H or 0DH byte.

The copy loop reads each byte from the FCB, checks for terminators, and copies it to the display buffer. The loop runs up to 24 iterations (the length of a VTOS filespec string: "FILENAME/EXT.PASSWORD:D" plus terminator).

4ED4
LD A,(HL) 7E
Loop Start - FCB Copy Loop
Fetch the next byte from the FCB (pointed to by HL) into Register A.
4ED5
CP 03H FE 03
Compare Register A against 03H (ETX, the VTOS string terminator). If this byte is 03H, the filespec string has ended and the copy should terminate.
4ED7
If the Z FLAG (Zero) has been set because the byte is 03H (ETX terminator), JUMP to 4F1FH to append the ">" and carriage return to the display buffer and proceed to the display routines.
4ED9
CP 0DH FE 0D
Compare Register A against 0DH (carriage return). Some filespecs may be terminated with CR instead of ETX.
4EDB
If the Z FLAG (Zero) has been set because the byte is 0DH (carriage return), JUMP to 4F1FH to terminate the copy and proceed to display.
4EDD
INC HL 23
INCrement HL to advance the source pointer to the next byte in the FCB.
4EDE
LD (DE),A 12
Store the current byte from Register A into the filename display buffer at the DE position.
4EDF
INC DE 13
INCrement DE to advance the destination pointer to the next buffer position.
4EE0
DECrement B and loop back to 4ED4H if not zero. The loop continues copying bytes until either a terminator is found or all 24 bytes have been copied.
Loop End - FCB Copy Loop
4EE2
JUMP unconditionally to 4F1FH to append the ">" and carriage return. If the loop exhausted all 24 bytes without finding a terminator, the copy is complete and display preparation continues.

4EE4H - Directory Entry Filename Extraction

When the file is formally open (IX+00H bit 7 set) and the descriptor's bit 6 is clear, the filename is extracted from the directory entry on disk. This routine reads the directory sector using the drive number (C) and info byte (B) from the FCB, then formats the filename as "NAME/EXT:D" in the display buffer at 4F62H.

Entry: Register C = drive number from IX+06H, Register B = directory info byte from IX+07H. These were loaded at 4EA7H-4EAAH before the BIT 7 test dispatched here.

4EE4
LD C,(IX+06H) DD 4E 06
Re-fetch the drive number from FCB offset IX+06H into Register C. This ensures the correct drive number is available after the branching logic. The drive number identifies which disk to read the directory sector from.
4EE7
LD B,(IX+07H) DD 46 07
Re-fetch the directory info byte from FCB offset IX+07H into Register B. This byte encodes the directory sector location and entry position within that sector.
4EEA
GOSUB to the SYS0 directory entry validation routine at 4B10H. This reads the directory sector into a buffer and validates the entry. On return, HL points to the start of the 32-byte directory entry for this file.
4EED
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H (5 decimal). This offset skips past the first 5 bytes of the directory entry (status byte at +00H, flags at +01H, date at +02H, EOF offset at +03H, and one reserved byte at +04H) to reach the 8-byte filename field starting at offset +05H.
4EF0
ADD HL,BC 09
ADD 5 to HL to advance the pointer from the start of the directory entry to the filename field at entry+05H.
4EF1
LD DE,4F62H 11 62 4F
Point Register Pair DE to the filename display buffer at 4F62H. The formatted "NAME/EXT:D" string will be assembled here.
4EF4
LD B,08H 06 08
Load Register B with 08H (8 decimal). This is the maximum number of characters in the filename field of the directory entry. The copy loop will skip trailing spaces.

The filename copy loop reads up to 8 characters from the directory entry, skipping any space (20H) characters. Spaces in TRS-80 filenames indicate padding; only the significant characters are copied to produce a compact display.

4EF6
LD A,(HL) 7E
Loop Start - Filename Copy
Fetch the next character from the directory entry filename field at (HL) into Register A.
4EF7
CP 20H FE 20
Compare Register A against 20H (ASCII space). Space characters in the filename are padding and should be skipped rather than copied to the display buffer.
4EF9
If the Z FLAG (Zero) has been set because the character is a space, JUMP to 4F00H to skip copying this character and move to the extension field. Encountering a space means the significant portion of the filename has ended.
4EFB
INC L 2C
INCrement Register L to advance the source pointer (HL) past this character in the directory entry. Since directory entries are within a single page, incrementing L alone is sufficient.
4EFC
LD (DE),A 12
Store the filename character from Register A into the display buffer at the DE position.
4EFD
INC DE 13
INCrement DE to advance the destination pointer to the next buffer position.
4EFE
DECrement B and loop back to 4EF6H if not zero. The loop continues for up to 8 characters or until a space is encountered.
Loop End - Filename Copy

After the filename, a '/' separator is appended, then the 3-byte extension field is copied (also skipping spaces). Finally, ':D' (colon + drive digit) is appended.

4F00
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII slash '/'). This is the separator between the filename and extension in the VTOS filespec format "NAME/EXT".
4F02
LD (DE),A 12
Store the '/' separator into the display buffer at the current DE position.
4F03
INC DE 13
INCrement DE to advance past the '/' separator in the buffer.
4F04
LD C,B 48
Copy Register B (the remaining count from the filename loop) into Register C. If the filename loop was cut short by a space at position N, B holds (8 - N). The remaining characters in the 8-byte filename field must be skipped to reach the extension field.
4F05
LD B,00H 06 00
Clear Register B to form BC as a 16-bit skip count. BC now holds the number of remaining bytes to skip in the filename field to reach the extension at entry+0DH.
4F07
ADD HL,BC 09
ADD BC (remaining skip count) to HL to advance the source pointer past any unread filename padding bytes, positioning HL at the start of the 3-byte extension field in the directory entry (offset +0DH).
4F08
LD B,03H 06 03
Load Register B with 03H (3 decimal). The extension field is 3 bytes long in the directory entry.
4F0A
LD A,(HL) 7E
Loop Start - Extension Copy
Fetch the next character from the directory entry extension field at (HL) into Register A.
4F0B
INC L 2C
INCrement Register L to advance the source pointer past this extension character.
4F0C
CP 20H FE 20
Compare Register A against 20H (ASCII space). Space characters in the extension field are padding and should be skipped.
4F0E
If the Z FLAG (Zero) has been set because the extension character is a space, JUMP to 4F14H to skip copying this character and proceed to the drive number append.
4F10
LD (DE),A 12
Store the extension character from Register A into the display buffer at the DE position.
4F11
INC DE 13
INCrement DE to advance the destination pointer past the copied extension character.
4F12
DECrement B and loop back to 4F0AH if not zero. The loop continues for up to 3 extension characters or until a space is encountered.
Loop End - Extension Copy
4F14
LD A,3AH 3E 3A
Load Register A with 3AH (ASCII colon ':'). This is the separator between the extension and the drive number in the VTOS filespec format "NAME/EXT:D".
4F16
LD (DE),A 12
Store the ':' separator into the display buffer at the current DE position.
4F17
INC DE 13
INCrement DE to advance past the ':' separator.
4F18
LD A,(IX+06H) DD 7E 06
Fetch the drive number from FCB offset IX+06H into Register A. This is the numeric drive identifier (0, 1, 2, or 3).
4F1B
ADD A,30H C6 30
ADD 30H to Register A to convert the binary drive number (0-3) to its ASCII digit character ('0'-'3'). Drive 0 becomes '0' (30H), drive 1 becomes '1' (31H), etc.
4F1D
LD (DE),A 12
Store the ASCII drive digit into the display buffer.
4F1E
INC DE 13
INCrement DE to advance past the drive digit in the buffer.

4F1FH - Append Terminator and Display Context Strings

Common exit point for both filename extraction paths (FCB copy and directory entry). Appends the ">" closing bracket and carriage return to the filename buffer, restores IX, then displays the device template, filename, and return address strings in sequence.

Both the FCB copy path (4ED4H-4EE2H) and the directory entry path (4EE4H-4F1EH) converge here. Register Pair DE points to the current position in the filename display buffer at 4F62H, where the formatted filename string needs the ">" and CR terminator appended.

4F1F
LD A,3EH 3E 3E
Load Register A with 3EH (ASCII greater-than '>'). This closing bracket marks the end of the filename in the display output (e.g., "MYFILE/CMD:0>").
4F21
LD (DE),A 12
Store the '>' character into the filename display buffer at the current DE position.
4F22
INC DE 13
INCrement DE to advance past the '>' character.
4F23
LD A,0DH 3E 0D
Load Register A with 0DH (carriage return). This terminates the filename string in the buffer.
4F25
LD (DE),A 12
Store the carriage return into the buffer, completing the filename display string.
4F26
POP IX DD E1
Restore Register Pair IX from the stack. This recovers the original IX value that was saved at 4E9CH on entry to the extended context routine.
4F28
LD HL,4F5BH 21 5B 4F
Point Register Pair HL to the file display prefix string at 4F5BH. This string contains: C5H (semigraphics bullet), "<FILE=" - the visual marker preceding the filename display.
4F2B
GOSUB to the SYS0 message display routine at 447BH to display the string at HL on screen. For the filename path, this displays the "<FILE=" prefix followed by the assembled filename. For the 2AH shortcut path (entering at this address from 4EBCH), this displays the "<DEVICE=*XX>" string from 4F4DH.
4F2E
LD DE,(430CH) ED 5B 0C 43
Load Register Pair DE with the saved overlay return address from 430CH. This is the address in the calling code that invoked the overlay via RST 28H. The address needs adjustment to point back to the SVC stub instruction rather than past it.
4F32
DEC DE 1B
DECrement DE by 1. First step of the 3-byte adjustment to convert the return address to the SVC stub address.
4F33
DEC DE 1B
DECrement DE by 1. Second step of the adjustment.
4F34
DEC DE 1B
DECrement DE by 1. Third and final step. DE now points 3 bytes before the return address, which is the address of the LD A,xxH instruction in the standard SVC stub pattern (LD A,xxH = 2 bytes + RST 28H = 1 byte = 3 bytes total). This is the address displayed as "REFERENCED AT X'nnnn'" so the user knows which instruction triggered the error.
4F35
LD HL,4F83H 21 83 4F
Point Register Pair HL to the return address hex placeholder buffer at 4F83H. This buffer contains "NNNN'" + 0DH where "NNNN" will be overwritten with the 4-digit hex address by the CALL to 4DE7H.
4F38
GOSUB to the SYS0 hex display routine at 4DE7H. This routine converts the 16-bit value in DE (the adjusted return address) into 4-digit hexadecimal ASCII and writes the digits into the buffer at (HL), overwriting the "NNNN" placeholder at 4F83H with the actual hex address.
4F3B
LD HL,4F72H 21 72 4F
Point Register Pair HL to the return address display prefix string at 4F72H. This string contains: C3H (semigraphics bullet), "REFERENCED AT X'" - the prefix before the hex address digits.
4F3E
JUMP to the SYS0 message display routine at 447BH as a tail call. This displays the complete return address line: "REFERENCED AT X'nnnn'" followed by the closing apostrophe and carriage return from the 4F83H buffer. The display routine returns directly to the caller of the extended context routine (4E8EH), which then proceeds to the register restore and exit dispatch at 4E91H.

4F41H - Data: Error Code Display Template String

Template string used to build the "*** ERRCOD=XX, " error code prefix. Copied into the message assembly buffer at 4200H by LDIR at 4E26H (12 bytes). The "XX" digits at offsets 4F42H-4F43H are overwritten by the decimal conversion loop at 4E2BH-4E35H.

4F41
DEFM 0AH,"*** ERRCOD=" 0A 2A 2A 2A 20 45 52 52 43 4F 44 3D
12-byte template string: 0AH (linefeed) followed by "*** ERRCOD=" (11 ASCII characters). The linefeed ensures the error message starts on a new line. The "=" at the end precedes the decimal error code digits that are written at runtime into the next two bytes (4F4DH is the start of the next data block, but the decimal digits overwrite bytes within the buffer copy at 4200H, not this template directly).

4F4DH - Data: Device Display Template String

Template string displayed by the extended context routine to show the drive and directory info associated with the error. The two bytes at 4F57H-4F58H are overwritten at runtime by the LD (4F57H),BC instruction at 4EB5H with the actual drive number and directory info byte from the FCB.

4F4D
DEFM C6H,"<DEVICE=" C6 3C 44 45 56 49 43 45 3D
9 bytes: C6H (TRS-80 semigraphics block character, used as a visual bullet marker), followed by "<DEVICE=" (8 ASCII characters). The semigraphics character provides a distinctive visual marker in the error display output.
4F56
DEFM "*XX" 2A 58 58
Self-Modifying Code Target
3 bytes: asterisk placeholder "*" followed by two "X" placeholder characters at 4F57H-4F58H. At runtime, the LD (4F57H),BC instruction at 4EB5H overwrites the two X bytes with the actual drive number (C) and directory info byte (B) from the FCB. The asterisk at 4F56H remains as a visual separator.
4F59
DEFM ">",0DH 3E 0D
2 bytes: ">" closing bracket followed by 0DH (carriage return) string terminator. Completes the device display line as "<DEVICE=*XX>" when printed.

4F5BH - Data: File Display Prefix String

Prefix string displayed before the filename in the extended error context. Displayed by CALL 447BH at 4F2BH. The display routine prints up to the terminator, then continues into the filename buffer at 4F62H which contains the assembled filename string.

4F5B
DEFM C5H,"<FILE=" C5 3C 46 49 4C 45 3D
7 bytes: C5H (TRS-80 semigraphics block character, visual bullet), followed by "<FILE=" (6 ASCII characters). This is the prefix before the filename. Note that no terminator is present here - the display routine at 447BH continues printing into the adjacent filename buffer at 4F62H, which contains the actual filename terminated by 0DH. This concatenation trick avoids needing a separate CALL for the filename.

4F62H - Data: Filename Display Buffer

16-byte work area filled at runtime with the formatted filename string by either the FCB copy loop (4ED4H) or the directory entry extraction routine (4EE4H). The initial content shown here is the default template that is overwritten during error processing.

4F62
DEFM "NNNNNNNN/EEE:D>",0DH 4E 4E 4E 4E 4E 4E 4E 4E 2F 45 45 45 3A 44 3E 0D
16-byte filename display buffer. The default content "NNNNNNNN/EEE:D>" followed by 0DH (carriage return) serves as a template showing the VTOS filespec format: 8-character filename, "/" separator, 3-character extension, ":" drive separator, drive digit, ">" closing bracket, and CR terminator. At runtime, the FCB copy or directory extraction routines overwrite this buffer with the actual filename. The adjacent file display prefix at 4F5BH has no terminator, so 447BH prints continuously from 4F5BH through this buffer until it hits the 0DH at 4F71H.

4F72H - Data: Return Address Display Prefix String

Prefix string for the return address diagnostic line. Displayed by JP 447BH at 4F3EH as a tail call. The string includes the "REFERENCED AT X'" label followed by the hex address buffer at 4F83H.

4F72
DEFM C3H,"REFERENCED AT X'" C3 52 45 46 45 52 45 4E 43 45 44 20 41 54 20 58 27
17 bytes: C3H (TRS-80 semigraphics block character, visual bullet), followed by "REFERENCED AT X'" (16 ASCII characters). The X' prefix introduces the hexadecimal address in TRS-80 notation (X'nnnn' is the standard hex literal format). Like the file prefix at 4F5BH, this string has no terminator - the display routine continues into the adjacent hex address buffer at 4F83H.

4F83H - Data: Return Address Hex Buffer and Suffix

Work area for the hex return address digits plus the closing suffix. The "NNNN" placeholder bytes are overwritten by CALL 4DE7H at 4F38H with the 4-digit hexadecimal representation of the adjusted return address. The suffix "'" + 0DH completes the display line.

4F83
DEFM "NNNN'",0DH 4E 4E 4E 4E 27 0D
6 bytes: four "N" placeholder characters (overwritten at runtime by the hex display routine with the 4-digit address), followed by "'" (closing single quote for the X'nnnn' notation) and 0DH (carriage return terminator). The complete display output reads "REFERENCED AT X'nnnn'" where nnnn is the address of the SVC stub that triggered the error (the overlay return address at 430CH minus 3).

4F89H - Data: Error Code Offset Table

Lookup table mapping error codes (00H-29H) to descriptor chain addresses. Each byte is the low byte of an address in page 51xxH where the descriptor chain for that error code begins. The table contains 42 entries (one per supported error code). The word display loop at 4E44H-4E48H uses this table to find the starting descriptor for any given error code.

Each entry is a single byte representing the low byte of an address in the range 513EH-51DDH. For example, entry 00H contains 3EH, meaning the descriptor chain for error code 00H ("NO ERROR") starts at 513EH. Entry 29H contains DBH, meaning error code 29H ("UNKNOWN ERROR CODE") starts at 51DBH.

4F89
DEFB 3EH,40H, 45H,49H,4DH, 51H,57H,5CH 3E 40 45 49 4D 51 57 5C
Error codes 00H-07H: 00H=NO ERROR (513EH), 01H=PARITY ERROR DURING HEADER READ (5140H), 02H=SEEK ERROR DURING READ (5145H), 03H=LOST DATA DURING READ (5149H), 04H=PARITY ERROR DURING READ (514DH), 05H=DATA RECORD NOT FOUND DURING READ (5151H), 06H=ATTEMPTED TO READ SYSTEM DATA RECORD (5157H), 07H=ATTEMPTED TO READ LOCKED/DELETED DATA RECORD (515CH)
4F91
DEFB 61H,64H, 69H,6DH,71H, 75H,7BH,80H 61 64 69 6D 71 75 7B 80
Error codes 08H-0FH: 08H=DEVICE NOT AVAILABLE (5161H), 09H=PARITY ERROR DURING HEADER WRITE (5164H), 0AH=SEEK ERROR DURING WRITE (5169H), 0BH=LOST DATA DURING WRITE (516DH), 0CH=PARITY ERROR DURING WRITE (5171H), 0DH=DATA RECORD NOT FOUND DURING WRITE (5175H), 0EH=WRITE FAULT ON DISK DRIVE (517BH), 0FH=WRITE PROTECTED DISK (5180H)
4F99
DEFB 83H,87H, 8AH,8DH,90H, 93H,96H,99H 83 87 8A 8D 90 93 96 99
Error codes 10H-17H: 10H=ILLEGAL LOGICAL FILE NUMBER (5183H), 11H=DIRECTORY READ ERROR (5187H), 12H=DIRECTORY WRITE ERROR (518AH), 13H=ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE (518DH), 14H=PROTECTED FILE (5190H), 15H=READ LOCKED/DELETED DATA RECORD (5193H), 16H=RECORD (5196H), 17H=LOCKED/DELETED DATA RECORD (5199H)
4FA1
DEFB 9CH,A0H, A3H,A8H,ABH, AFH,B4H,B8H 9C A0 A3 A8 AB AF B4 B8
Error codes 18H-1FH: 18H=DEVICE NOT IN DIRECTORY (519CH), 19H=FILE ACCESS DENIED (51A0H), 1AH=FULL OR WRITE PROTECTED DISK (51A3H), 1BH=DISK SPACE FULL (51A8H), 1CH=END OF FILE ENCOUNTERED (51ABH), 1DH=RECORD NUMBER OUT OF RANGE (51AFH), 1EH=DIRECTORY FULL - CAN'T EXTEND FILE (51B4H), 1FH=PROGRAM NOT FOUND (51B8H)
4FA9
DEFB BBH,BEH, C2H,C6H,C8H, CDH,D2H,D5H, D8H,DBH BB BE C2 C6 C8 CD D2 D5 D8 DB
Error codes 20H-29H: 20H=ILLEGAL DRIVE NUMBER (51BBH), 21H=NO DEVICE SPACE AVAILABLE (51BEH), 22H=LOAD FILE FORMAT ERROR (51C2H), 23H=MEMORY FAULT (51C6H), 24H=ATTEMPTED TO LOAD READ ONLY MEMORY (51C8H), 25H=ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE (51CDH), 26H=FILE NOT OPEN (51D2H), 27H=DEVICE IN USE (51D5H), 28H=PROTECTED SYSTEM DEVICE (51D8H), 29H=UNKNOWN ERROR CODE (51DBH)

4FB1H - Data: Word Address DEFW Table

Table of 57 two-byte entries (114 bytes) providing the start address of each word in the string pool. The overlapping-entry lookup scheme at 4E57H-4E60H reads 4 consecutive bytes (the current word's DEFW and the next word's DEFW) and computes the word length by subtraction. Entry 0 (DBD8H) is a sentinel/unused value; entries 1-55 point to actual words; entry 56 (513EH) is the end sentinel that provides the length of word 55.

Each pair of bytes is a little-endian 16-bit address pointing into the word string pool at 5023H-513DH. The word index used in descriptor bytes (bits 0-5) is multiplied by 2 to index into this table. Words 3/4 and 20/21 and 36/37 share the same address, meaning they are aliases for the same word. This occurs because the DEFW table structure requires unique entries for length calculation, but multiple word indices can map to the same string when adjacent entries happen to share a boundary.

4FB1
DEFW DBD8H D8 DB
Word 0 (sentinel): points to DBD8H, which is outside the overlay address space. This entry is never referenced by any descriptor chain; it serves as a placeholder so that word indices start at 1.
4FB3
DEFW 5023H, 5025H,502AH,502AH 23 50 25 50 2A 50 2A 50
Words 1-4: 1="NO" (5023H, 2 bytes), 2="ERROR" (5025H, 5 bytes), 3=alias for word 4 (502AH, 0 bytes - not directly used), 4="PARITY" (502AH, 6 bytes)
4FBBH
DEFW 5030H, 5036H,503CH,5040H 30 50 36 50 3C 50 40 50
Words 5-8: 5="DURING" (5030H, 6 bytes), 6="HEADER" (5036H, 6 bytes), 7="DATA" (503CH, 4 bytes), 8="SEEK" (5040H, 4 bytes)
4FC3
DEFW 5044H, 5048H,504DH,5051H 44 50 48 50 4D 50 51 50
Words 9-12: 9="READ" (5044H, 4 bytes), 10="WRITE" (5048H, 5 bytes), 11="LOST" (504DH, 4 bytes), 12="NOT" (5051H, 3 bytes)
4FCBH
DEFW 5054H, 5060H,506EH,5074H 54 50 60 50 6E 50 74 50
Words 13-16: 13="ATTEMPTED TO" (5054H, 12 bytes - multi-word phrase with embedded space), 14="LOCKED/DELETED" (5060H, 14 bytes - compound word with slash), 15="SYSTEM" (506EH, 6 bytes), 16="DIRECTORY" (5074H, 9 bytes)
4FD3
DEFW 507DH, 5083H,5085H,5089H 7D 50 83 50 85 50 89 50
Words 17-20: 17="MEMORY" (507DH, 6 bytes), 18="ON" (5083H, 2 bytes), 19="DISK" (5085H, 4 bytes), 20=alias for word 21 (5089H, 0 bytes - not directly used)
4FDBH
DEFW 5089H, 508EH,5097H,509EH 89 50 8E 50 97 50 9E 50
Words 21-24: 21="FAULT" (5089H, 5 bytes), 22="PROTECTED" (508EH, 9 bytes), 23="ILLEGAL" (5097H, 7 bytes), 24="LOGICAL" (509EH, 7 bytes)
4FE3
DEFW 50A5H, 50ABH,50AFH,50B5H A5 50 AB 50 AF 50 B5 50
Words 25-28: 25="NUMBER" (50A5H, 6 bytes), 26="FILE" (50ABH, 4 bytes), 27="RECORD" (50AFH, 6 bytes), 28="END" (50B5H, 3 bytes)
4FEBH
DEFW 50B8H, 50BAH,50BDH,50C2H B8 50 BA 50 BD 50 C2 50
Words 29-32: 29="OF" (50B8H, 2 bytes), 30="OUT" (50BAH, 3 bytes), 31="RANGE" (50BDH, 5 bytes), 32="ENCOUNTERED" (50C2H, 11 bytes)
4FF3
DEFW 50CDH, 50D1H,50D4H,50D7H CD 50 D1 50 D4 50 D7 50
Words 33-36: 33="CODE" (50CDH, 4 bytes), 34="GAT" (50D1H, 3 bytes), 35="HIT" (50D4H, 3 bytes), 36=alias for word 37 (50D7H, 0 bytes - not directly used)
4FFBH
DEFW 50D7H, 50DEH,50E2H,50E7H D7 50 DE 50 E2 50 E7 50
Words 37-40: 37="UNKNOWN" (50D7H, 7 bytes), 38="LOAD" (50DEH, 4 bytes), 39="SPACE" (50E2H, 5 bytes), 40="ONLY" (50E7H, 4 bytes)
5003
DEFW 50EBH, 50EFH,50F5H,50FBH EB 50 EF 50 F5 50 FB 50
Words 41-44: 41="NAME" (50EBH, 4 bytes), 42="DEVICE" (50EFH, 6 bytes), 43="FORMAT" (50F5H, 6 bytes), 44="FOUND" (50FBH, 5 bytes)
500B
DEFW 5100H, 5102H,5108H,510CH 00 51 02 51 08 51 0C 51
Words 45-48: 45="IN" (5100H, 2 bytes), 46="ACCESS" (5102H, 6 bytes), 47="FULL" (5108H, 4 bytes), 48="DRIVE" (510CH, 5 bytes)
5013
DEFW 5111H, 5117H,511EH,5127H 11 51 17 51 1E 51 27 51
Words 49-52: 49="DENIED" (5111H, 6 bytes), 50="PROGRAM" (5117H, 7 bytes), 51="AVAILABLE" (511EH, 9 bytes), 52="- CAN'T EXTEND" (5127H, 14 bytes - multi-word phrase with embedded spaces)
501B
DEFW 5135H, 5139H,513CH,513EH 35 51 39 51 3C 51 3E 51
Words 53-56: 53="OPEN" (5135H, 4 bytes), 54="USE" (5139H, 3 bytes), 55="OR" (513CH, 2 bytes), 56=end sentinel (513EH - provides length for word 55 via overlapping subtraction)

5023H - Data: Word String Pool

Contiguous block of 55 ASCII words totaling 283 bytes (5023H-513DH). Words are stored consecutively with no separators or terminators; the DEFW table at 4FB1H defines each word's start address and the word length is computed by subtracting adjacent DEFW entries. Words range from 2 bytes ("NO", "ON", "OF", "IN", "OR") to 14 bytes ("LOCKED/DELETED" and "- CAN'T EXTEND"), with multi-word phrases stored as single dictionary entries where the embedded spaces are part of the word data.

5023
DEFM "NOERROR" 4E 4F 45 52 52 4F 52
Words 1-2: "NO" (5023H-5024H, 2 bytes) + "ERROR" (5025H-5029H, 5 bytes). Used in error 00H: "NO ERROR".
502A
DEFM "PARITYDURINGHEADER" 50 41 52 49 54 59 44 55 52 49 4E 47 48 45 41 44 45 52
Words 4-6: "PARITY" (502AH-502FH, 6 bytes) + "DURING" (5030H-5035H, 6 bytes) + "HEADER" (5036H-503BH, 6 bytes). Used in errors 01H, 09H: "PARITY ERROR DURING HEADER READ/WRITE".
503C
DEFM "DATASEEKREADWRITE" 44 41 54 41 53 45 45 4B 52 45 41 44 57 52 49 54 45
Words 7-10: "DATA" (503CH-503FH, 4 bytes) + "SEEK" (5040H-5043H, 4 bytes) + "READ" (5044H-5047H, 4 bytes) + "WRITE" (5048H-504CH, 5 bytes). Core I/O operation words used across many error messages.
504D
DEFM "LOSTNOT" 4C 4F 53 54 4E 4F 54
Words 11-12: "LOST" (504DH-5050H, 4 bytes) + "NOT" (5051H-5053H, 3 bytes). Used in "LOST DATA" and "NOT FOUND" messages.
5054
DEFM "ATTEMPTED TO" 41 54 54 45 4D 50 54 45 44 20 54 4F
Word 13: "ATTEMPTED TO" (5054H-505FH, 12 bytes). Multi-word phrase stored as a single dictionary entry with an embedded space at 505DH. Used in errors 06H, 07H, 24H, 25H.
5060
DEFM "LOCKED/DELETED" 4C 4F 43 4B 45 44 2F 44 45 4C 45 54 45 44
Word 14: "LOCKED/DELETED" (5060H-506DH, 14 bytes). Compound term with "/" separator at 5066H. Used in errors 07H, 15H, 17H.
506E
DEFM "SYSTEMDIRECTORY" 53 59 53 54 45 4D 44 49 52 45 43 54 4F 52 59
Words 15-16: "SYSTEM" (506EH-5073H, 6 bytes) + "DIRECTORY" (5074H-507CH, 9 bytes). Used in "SYSTEM DATA RECORD", "DIRECTORY READ/WRITE ERROR", etc.
507D
DEFM "MEMORYONDISK" 4D 45 4D 4F 52 59 4F 4E 44 49 53 4B
Words 17-19: "MEMORY" (507DH-5082H, 6 bytes) + "ON" (5083H-5084H, 2 bytes) + "DISK" (5085H-5088H, 4 bytes). Used in "MEMORY FAULT", "ON DISK", "DISK SPACE FULL".
5089
DEFM "FAULTPROTECTEDILLEGALLOGICAL" 46 41 55 4C 54 50 52 4F 54 45 43 54 45 44 49 4C 4C 45 47 41 4C 4C 4F 47 49 43 41 4C
Words 21-24: "FAULT" (5089H-508DH, 5 bytes) + "PROTECTED" (508EH-5096H, 9 bytes) + "ILLEGAL" (5097H-509DH, 7 bytes) + "LOGICAL" (509EH-50A4H, 7 bytes). Used in "WRITE FAULT", "PROTECTED FILE", "ILLEGAL DRIVE NUMBER", "LOGICAL FILE NUMBER".
50A5
DEFM "NUMBERFILERECORDENDOFOUT" 4E 55 4D 42 45 52 46 49 4C 45 52 45 43 4F 52 44 45 4E 44 4F 46 4F 55 54
Words 25-30: "NUMBER" (50A5H-50AAH, 6 bytes) + "FILE" (50ABH-50AEH, 4 bytes) + "RECORD" (50AFH-50B4H, 6 bytes) + "END" (50B5H-50B7H, 3 bytes) + "OF" (50B8H-50B9H, 2 bytes) + "OUT" (50BAH-50BCH, 3 bytes). Core vocabulary for file I/O errors.
50BD
DEFM "RANGEENCOUNTERED" 52 41 4E 47 45 45 4E 43 4F 55 4E 54 45 52 45 44
Words 31-32: "RANGE" (50BDH-50C1H, 5 bytes) + "ENCOUNTERED" (50C2H-50CCH, 11 bytes). Used in "OUT OF RANGE" and "END OF FILE ENCOUNTERED".
50CD
DEFM "CODEGATHITUNKNOWN" 43 4F 44 45 47 41 54 48 49 54 55 4E 4B 4E 4F 57 4E
Words 33-37: "CODE" (50CDH-50D0H, 4 bytes) + "GAT" (50D1H-50D3H, 3 bytes) + "HIT" (50D4H-50D6H, 3 bytes) + "UNKNOWN" (50D7H-50DDH, 7 bytes). Used in "ERROR CODE", "GAT READ/WRITE ERROR", "HIT READ/WRITE ERROR", "UNKNOWN ERROR CODE".
50DE
DEFM "LOADSPACEONLYNAMEDEVICE" 4C 4F 41 44 53 50 41 43 45 4F 4E 4C 59 4E 41 4D 45 44 45 56 49 43 45
Words 38-42: "LOAD" (50DEH-50E1H, 4 bytes) + "SPACE" (50E2H-50E6H, 5 bytes) + "ONLY" (50E7H-50EAH, 4 bytes) + "NAME" (50EBH-50EEH, 4 bytes) + "DEVICE" (50EFH-50F4H, 6 bytes). Used in "LOAD FILE FORMAT ERROR", "DISK SPACE FULL", "NO DEVICE SPACE AVAILABLE".
50F5
DEFM "FORMATFOUNDINACCESSFULL" 46 4F 52 4D 41 54 46 4F 55 4E 44 49 4E 41 43 43 45 53 53 46 55 4C 4C
Words 43-47: "FORMAT" (50F5H-50FAH, 6 bytes) + "FOUND" (50FBH-50FFH, 5 bytes) + "IN" (5100H-5101H, 2 bytes) + "ACCESS" (5102H-5107H, 6 bytes) + "FULL" (5108H-510BH, 4 bytes). Used in "FORMAT ERROR", "NOT FOUND", "NOT IN DIRECTORY", "FILE ACCESS DENIED", "DIRECTORY FULL".
510C
DEFM "DRIVEDENIEDPROGRAMAVAILABLE" 44 52 49 56 45 44 45 4E 49 45 44 50 52 4F 47 52 41 4D 41 56 41 49 4C 41 42 4C 45
Words 48-51: "DRIVE" (510CH-5110H, 5 bytes) + "DENIED" (5111H-5116H, 6 bytes) + "PROGRAM" (5117H-511DH, 7 bytes) + "AVAILABLE" (511EH-5126H, 9 bytes). Used in "ILLEGAL DRIVE NUMBER", "ACCESS DENIED", "PROGRAM NOT FOUND", "SPACE AVAILABLE".
5127
DEFM "- CAN'T EXTEND" 2D 20 43 41 4E 27 54 20 45 58 54 45 4E 44
Word 52: "- CAN'T EXTEND" (5127H-5134H, 14 bytes). Multi-word phrase with embedded spaces and apostrophe, stored as a single dictionary entry. Used in error 1EH: "DIRECTORY FULL - CAN'T EXTEND FILE".
5135
DEFM "OPENUSEOR" 4F 50 45 4E 55 53 45 4F 52
Words 53-55: "OPEN" (5135H-5138H, 4 bytes) + "USE" (5139H-513BH, 3 bytes) + "OR" (513CH-513DH, 2 bytes). These are VTOS-specific additions not present in TRSDOS 2.3's dictionary. Used in error 26H: "FILE NOT OPEN", error 27H: "DEVICE IN USE", error 1AH: "FULL OR WRITE PROTECTED DISK".

513EH - Data: Error Message Descriptor Chains

Variable-length descriptor chains for all 42 error codes (00H-29H), totaling 160 bytes (513EH-51DDH). Each chain is a sequence of bytes where bits 0-5 encode the word index (1-55), bit 7 is the last-word flag (set on the final byte), and bit 6 on the last byte is the filename context flag (0 = filename from directory entry, 1 = filename from FCB). The chains are packed sequentially with no separators; the offset table at 4F89H identifies the start of each chain.

In the decoded chains below, each byte is shown with its raw hex value, and the resulting word is identified. The last byte in each chain has bit 7 set (values 80H-FFH). Bit 6 on the last byte indicates the context flag: when set (C0H-FFH range after masking), filename comes from the FCB; when clear (80H-BFH range), filename comes from the directory entry.

513E
DEFB 01H,82H 01 82
Error 00H "NO ERROR": word 1 (NO) + word 2|80H (ERROR, last). Context flag clear = directory.
5140
DEFB 04H,02H, 05H,06H,89H 04 02 05 06 89
Error 01H "PARITY ERROR DURING HEADER READ": word 4 (PARITY) + word 2 (ERROR) + word 5 (DURING) + word 6 (HEADER) + word 9|80H (READ, last). Context = directory.
5145
DEFB 08H,02H, 05H,89H 08 02 05 89
Error 02H "SEEK ERROR DURING READ": word 8 (SEEK) + word 2 (ERROR) + word 5 (DURING) + word 9|80H (READ, last). Context = directory.
5149
DEFB 0BH,07H, 05H,89H 0B 07 05 89
Error 03H "LOST DATA DURING READ": word 11 (LOST) + word 7 (DATA) + word 5 (DURING) + word 9|80H (READ, last). Context = directory.
514D
DEFB 04H,02H, 05H,89H 04 02 05 89
Error 04H "PARITY ERROR DURING READ": word 4 (PARITY) + word 2 (ERROR) + word 5 (DURING) + word 9|80H (READ, last). Context = directory.
5151
DEFB 07H,1BH, 0CH,2CH,05H,89H 07 1B 0C 2C 05 89
Error 05H "DATA RECORD NOT FOUND DURING READ": word 7 (DATA) + word 27 (RECORD) + word 12 (NOT) + word 44 (FOUND) + word 5 (DURING) + word 9|80H (READ, last). Context = directory.
5157
DEFB 0DH,09H, 0FH,07H,9BH 0D 09 0F 07 9B
Error 06H "ATTEMPTED TO READ SYSTEM DATA RECORD": word 13 (ATTEMPTED TO) + word 9 (READ) + word 15 (SYSTEM) + word 7 (DATA) + word 27|80H (RECORD, last). Context = directory.
515C
DEFB 0DH,09H, 0EH,07H,9BH 0D 09 0E 07 9B
Error 07H "ATTEMPTED TO READ LOCKED/DELETED DATA RECORD": word 13 (ATTEMPTED TO) + word 9 (READ) + word 14 (LOCKED/DELETED) + word 7 (DATA) + word 27|80H (RECORD, last). Context = directory.
5161
DEFB 2AH,0CH, F3H 2A 0C F3
Error 08H "DEVICE NOT AVAILABLE": word 42 (DEVICE) + word 12 (NOT) + word 51|C0H (AVAILABLE, last + bit 6 set). Context = FCB (bit 6 set on last byte).
5164
DEFB 04H,02H, 05H,06H,8AH 04 02 05 06 8A
Error 09H "PARITY ERROR DURING HEADER WRITE": word 4 (PARITY) + word 2 (ERROR) + word 5 (DURING) + word 6 (HEADER) + word 10|80H (WRITE, last). Context = directory.
5169
DEFB 08H,02H, 05H,8AH 08 02 05 8A
Error 0AH "SEEK ERROR DURING WRITE": word 8 + word 2 + word 5 + word 10|80H. Context = directory.
516D
DEFB 0BH,07H, 05H,8AH 0B 07 05 8A
Error 0BH "LOST DATA DURING WRITE": word 11 + word 7 + word 5 + word 10|80H. Context = directory.
5171
DEFB 04H,02H, 05H,8AH 04 02 05 8A
Error 0CH "PARITY ERROR DURING WRITE": word 4 + word 2 + word 5 + word 10|80H. Context = directory.
5175
DEFB 07H,1BH, 0CH,2CH,05H,8AH 07 1B 0C 2C 05 8A
Error 0DH "DATA RECORD NOT FOUND DURING WRITE": word 7 + word 27 + word 12 + word 44 + word 5 + word 10|80H. Context = directory.
517B
DEFB 0AH,15H, 12H,13H,B0H 0A 15 12 13 B0
Error 0EH "WRITE FAULT ON DISK DRIVE": word 10 (WRITE) + word 21 (FAULT) + word 18 (ON) + word 19 (DISK) + word 48|80H (DRIVE, last). Context = directory.
5180
DEFB 0AH,16H, 93H 0A 16 93
Error 0FH "WRITE PROTECTED DISK": word 10 (WRITE) + word 22 (PROTECTED) + word 19|80H (DISK, last). Context = directory.
5183
DEFB 17H,18H, 1AH,99H 17 18 1A 99
Error 10H "ILLEGAL LOGICAL FILE NUMBER": word 23 (ILLEGAL) + word 24 (LOGICAL) + word 26 (FILE) + word 25|80H (NUMBER, last). Context = directory.
5187
DEFB 10H,09H, 82H 10 09 82
Error 11H "DIRECTORY READ ERROR": word 16 (DIRECTORY) + word 9 (READ) + word 2|80H (ERROR, last). Context = directory.
518A
DEFB 10H,0AH, 82H 10 0A 82
Error 12H "DIRECTORY WRITE ERROR": word 16 + word 10 + word 2|80H. Context = directory.
518D
DEFB 17H,2EH, 0DH 17 2E 0D
Error 13H "ILLEGAL ACCESS ATTEMPTED TO": word 23 (ILLEGAL) + word 46 (ACCESS) + word 13 (ATTEMPTED TO). Note: This chain continues - the 0DH byte is word 13 (bits 0-5 = 0DH = 13), not a terminator. However examining the offset table, error 14H starts at 5190H which is 3 bytes later, confirming this is a 3-byte chain. Re-examining: 0DH has bit 7 clear, so this is NOT the last byte. But error 14H starts at 5190H = 518DH + 3. This means the chain for error 13H is: 17H, 2EH, 0DH + continuation into 5190H... Actually, let me reconsider the boundary. The offset table gives 13H->518DH and 14H->5190H, a gap of 3 bytes. So the chain at 518DH must be exactly 3 bytes with the last byte being the one at 518FH. Byte 518FH = 0DH: bits 0-5 = 0DH = 13 (ATTEMPTED TO), bit 6 = 0, bit 7 = 0. But bit 7 = 0 means NOT last! This is inconsistent with the 3-byte boundary. The descriptor must be reinterpreted: the chains can share tail bytes. Error 13H's chain at 518DH reads bytes 17H, 2EH, then continues through bytes that also belong to the next error's chain start. The actual termination happens when the code at 4E6EH tests bit 7 after RLCA. Let me re-examine: byte 518FH = 0DH. After the display loop processes this byte, it reads the NEXT byte at 5190H which is 16H. Looking at error 14H's chain which starts at 5190H: the first byte there is expected to be the first descriptor of error 14H. But the loop for error 13H would also read from 5190H if 518FH didn't have bit 7 set. This means error 13H's chain must extend into error 14H's space - they share a common tail! Error 13H: 17H (ILLEGAL), 2EH (ACCESS), 0DH (ATTEMPTED TO), 16H (PROTECTED), 9AH (FILE|80H, last+ctx=dir). That gives "ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE". And error 14H at 5190H: 16H (PROTECTED), 9AH (FILE|80H, last) = "PROTECTED FILE". The shared tail is 16H, 9AH. This is chain overlap optimization!
5190
DEFB 16H,9AH 16 9A
Error 14H "PROTECTED FILE" (also shared tail of error 13H): word 22 (PROTECTED) + word 26|80H (FILE, last). Context = directory. Error 13H's chain at 518DH-5191H overlaps into this block, reading 17H, 2EH, 0DH, then continuing with 16H, 9AH to produce "ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE".
5192
DEFB 0DH,09H, 0EH,07H,9BH 0D 09 0E 07 9B
Error 15H "READ LOCKED/DELETED DATA RECORD": Shares the same byte pattern as error 07H. Wait - the offset says 5193H not 5192H. Let me recheck. Offset for error 15H = 93H -> 5193H. So this starts at 5193H. Bytes at 5193H: 09H, 0EH, 07H, 9BH (4 bytes to 5196H). But looking at the raw data at 5192H it is 0DH which belongs to error 14H's continuation? No - error 14H is only 2 bytes at 5190H-5191H. The byte at 5192H starts fresh. So 5192H=0DH but error 15H starts at 5193H. The byte 5192H=0DH is trailing from error 13H's extended chain. Actually, the raw byte at address 5192H has hex value 0DH from the listing. But the offset table says error 15H starts at 5193H. So 5192H is unused/dead space, OR it's the tail of the chain overlap. Regardless, error 15H at 5193H: 09H (READ), 0EH (LOCKED/DELETED), 07H (DATA), 9BH (RECORD|80H, last) = "READ LOCKED/DELETED DATA RECORD". Context = directory.
5196
DEFB 0DH,09H, 0EH,07H,9BH 0D 09 0E 07 9B
Error 16H at 5196H and Error 17H at 5199H share overlapping chains. Error 16H: starts at 5196H, reads 0DH (ATTEMPTED TO), 09H (READ), 0EH (LOCKED/DELETED), 07H (DATA), 9BH (RECORD|80H) = "ATTEMPTED TO READ LOCKED/DELETED DATA RECORD". Error 17H: starts at 5199H, reads 07H (DATA), 9BH (RECORD|80H) = "DATA RECORD" (but only if this is only 2 bytes to 519BH). Actually error 17H offset = 99H -> 5199H and error 18H offset = 9CH -> 519CH = 3 bytes. So error 17H at 5199H: 0EH (LOCKED/DELETED), 07H (DATA), 9BH (RECORD|80H) = "LOCKED/DELETED DATA RECORD". The overlap means errors 15H, 16H, and 17H share tail portions of the same descriptor sequence.
519C
DEFB 2AH,0CH, 2DH,D0H 2A 0C 2D D0
Error 18H "DEVICE NOT IN DIRECTORY": word 42 (DEVICE) + word 12 (NOT) + word 45 (IN) + word 16|C0H (DIRECTORY, last + bit 6 set). Context = FCB.
51A0
DEFB 1AH,2EH, F1H 1A 2E F1
Error 19H "FILE ACCESS DENIED": word 26 (FILE) + word 46 (ACCESS) + word 49|C0H (DENIED, last + bit 6 set). Context = FCB.
51A3
DEFB 2FH,37H, 0AH,16H,D3H 2F 37 0A 16 D3
Error 1AH "FULL OR WRITE PROTECTED DISK": word 47 (FULL) + word 55 (OR) + word 10 (WRITE) + word 22 (PROTECTED) + word 19|C0H (DISK, last + bit 6 set). Context = FCB. Note: "OR" (word 55) is a VTOS-specific addition not present in TRSDOS 2.3.
51A8
DEFB 13H,27H, AFH 13 27 AF
Error 1BH "DISK SPACE FULL": word 19 (DISK) + word 39 (SPACE) + word 47|80H (FULL, last). Context = directory.
51AB
DEFB 1CH,1DH, 1AH,A0H 1C 1D 1A A0
Error 1CH "END OF FILE ENCOUNTERED": word 28 (END) + word 29 (OF) + word 26 (FILE) + word 32|80H (ENCOUNTERED, last). Context = directory.
51AF
DEFB 1BH,19H, 1EH,1DH,9FH 1B 19 1E 1D 9F
Error 1DH "RECORD NUMBER OUT OF RANGE": word 27 (RECORD) + word 25 (NUMBER) + word 30 (OUT) + word 29 (OF) + word 31|80H (RANGE, last). Context = directory.
51B4
DEFB 10H,2FH, 34H,9AH 10 2F 34 9A
Error 1EH "DIRECTORY FULL - CAN'T EXTEND FILE": word 16 (DIRECTORY) + word 47 (FULL) + word 52 (- CAN'T EXTEND) + word 26|80H (FILE, last). Context = directory. Note that "- CAN'T EXTEND" is a single 14-byte dictionary entry (word 52) including the leading dash and spaces.
51B8
DEFB 32H,0CH, ACH 32 0C AC
Error 1FH "PROGRAM NOT FOUND": word 50 (PROGRAM) + word 12 (NOT) + word 44|80H (FOUND, last). Context = directory.
51BB
DEFB 17H,30H, D9H 17 30 D9
Error 20H "ILLEGAL DRIVE NUMBER": word 23 (ILLEGAL) + word 48 (DRIVE) + word 25|C0H (NUMBER, last + bit 6 set). Context = FCB.
51BE
DEFB 01H,2AH, 27H,F3H 01 2A 27 F3
Error 21H "NO DEVICE SPACE AVAILABLE": word 1 (NO) + word 42 (DEVICE) + word 39 (SPACE) + word 51|C0H (AVAILABLE, last + bit 6 set). Context = FCB.
51C2
DEFB 26H,1AH, 2BH,82H 26 1A 2B 82
Error 22H "LOAD FILE FORMAT ERROR": word 38 (LOAD) + word 26 (FILE) + word 43 (FORMAT) + word 2|80H (ERROR, last). Context = directory.
51C6
DEFB 11H,95H 11 95
Error 23H "MEMORY FAULT": word 17 (MEMORY) + word 21|80H (FAULT, last). Context = directory.
51C8
DEFB 0DH,26H, 09H,28H,91H 0D 26 09 28 91
Error 24H "ATTEMPTED TO LOAD READ ONLY MEMORY": word 13 (ATTEMPTED TO) + word 38 (LOAD) + word 9 (READ) + word 40 (ONLY) + word 17|80H (MEMORY, last). Context = directory.
51CD
DEFB 17H,2EH, 0DH,16H,9AH 17 2E 0D 16 9A
Error 25H "ILLEGAL ACCESS ATTEMPTED TO PROTECTED FILE": word 23 (ILLEGAL) + word 46 (ACCESS) + word 13 (ATTEMPTED TO) + word 22 (PROTECTED) + word 26|80H (FILE, last). Context = directory. Same message as error 13H but with different chain encoding (no tail sharing).
51D2
DEFB 1AH,0CH, F5H 1A 0C F5
Error 26H "FILE NOT OPEN": word 26 (FILE) + word 12 (NOT) + word 53|C0H (OPEN, last + bit 6 set). Context = FCB. Note: "OPEN" (word 53) is a VTOS-specific addition.
51D5
DEFB 2AH,2DH, B6H 2A 2D B6
Error 27H "DEVICE IN USE": word 42 (DEVICE) + word 45 (IN) + word 54|80H (USE, last). Context = directory. This error code is new in VTOS (not present in TRSDOS 2.3). "USE" (word 54) is a VTOS-specific dictionary addition.
51D8
DEFB 16H,0FH, AAH 16 0F AA
Error 28H "PROTECTED SYSTEM DEVICE": word 22 (PROTECTED) + word 15 (SYSTEM) + word 42|80H (DEVICE, last). Context = directory. This error code is new in VTOS (not present in TRSDOS 2.3).
51DB
DEFB 25H,02H, A1H 25 02 A1
Error 29H "UNKNOWN ERROR CODE": word 37 (UNKNOWN) + word 2 (ERROR) + word 33|80H (CODE, last). Context = directory. This is the default message for any error code exceeding the maximum supported value (clamped to 29H at 4E3EH-4E43H).