ERRORS prints all 28 ZX81/TS1000 BASIC error messages by invoking machine code POKEd into RAM starting at address 40000. The 25-byte machine code routine is loaded from DATA statements in line 60 and verified with a checksum (2651) before execution. The routine uses ROM calls — specifically the address 0x08A9 (RST or CALL sequences visible in the DATA) — to walk through and display each error message stored in the system ROM. A commented-out alternative DATA line at line 120 shows the same routine expressed as hex string literals, left as an incomplete development artifact.
Program Structure
The program is organized into four logical phases:
- Setup (line 20): Resets the DATA pointer to line 60, sets the load address
l=40000, and initializes a checksum accumulatorcs=0. - Machine code loading (lines 30–50): A
FORloop reads 25 bytes from the DATA statement and POKEs them into memory starting at address 40000, accumulating a byte sum incs. - Checksum verification (line 70): Compares the accumulated sum against the expected value 2651. A mismatch halts with an error message, guarding against corrupt or mistyped DATA.
- Execution (line 80):
RANDOMIZE USR ltransfers control to the machine code at address 40000.
Lines 90–120 are development remnants: REMs noting the routine was written on 4/29/86 and marked “incomplete,” followed by line 120 which holds the same machine code expressed as hex string literals in a DATA statement that is never READ. Line 130 is a STOP that prevents line 120’s DATA from being accidentally reached. Line 140 saves the program with LINE 20 to auto-run from line 20.
Machine Code Routine
The 25 bytes POKEd at address 40000 (0x9C40) are a Z80 routine. Disassembling the DATA values from line 60:
| Offset | Hex | Z80 Mnemonic | Notes |
|---|---|---|---|
| 0 | 06 1C | LD B, 28 | Loop counter: 28 error messages |
| 2 | C5 | PUSH BC | Preserve counter |
| 3 | CD A9 08 | CALL 0x08A9 | ROM routine to print error message |
| 6 | C1 | POP BC | Restore counter |
| 7 | 78 | LD A, B | Copy counter to A |
| 8 | 11 65 0F | LD DE, 0x0F65 | Load address (ROM error table or helper) |
| 11 | C5 | PUSH BC | Preserve counter again |
| 12 | CD 3F 07 | CALL 0x073F | ROM routine (likely newline/print) |
| 15 | 06 32 | LD B, 50 | Inner delay/pause count |
| 17 | 76 | HALT | Wait for interrupt (timing delay) |
| 18 | 10 FD | DJNZ -3 | Repeat HALT 50 times (~1 second pause) |
| 20 | C1 | POP BC | Restore outer counter |
| 21 | 10 EB | DJNZ -21 | Outer loop: next error message |
| 23 | CF | RST 0x08 | Return to BASIC (error/restart) |
| 24 | 1A | LD A, (DE) | (Likely part of RST 0x08 parameter) |
The outer loop runs 28 times (LD B, 28 = 0x1C), calling ROM address 0x08A9 each iteration to display an error message, then pausing for approximately 50 interrupt cycles (~1 second at 50 Hz) using a HALT/DJNZ inner loop before advancing to the next message. The RST 0x08 at the end provides a clean return to BASIC.
Checksum Verification
The sum of all 25 DATA bytes is checked against the constant 2651 at line 70. This is a simple but effective integrity check: if any byte in line 60 is mistyped during entry, the program stops rather than executing corrupt machine code that could crash or corrupt the system. The checksum is an arithmetic sum (not CRC), which is typical for this era of hobbyist machine code loading routines.
Notable Techniques
RESTORE 60at the start of line 20 ensures the DATA pointer is always reset to line 60, making the program safely re-runnable without manually resetting the pointer.- The use of
RANDOMIZE USR lrather thanRAND USR lis the standard idiom for calling machine code; the return value from USR is discarded by RANDOMIZE. - The
HALTinstruction inside the timing loop leverages the interrupt mechanism as a delay primitive — eachHALTsuspends the CPU until the next interrupt (every ~20 ms at 50 Hz), giving a reliable frame-rate-based delay without needing a busy-wait counter. - Line 120’s DATA of hex strings was an in-development alternative representation of the same machine code, preserved as a reference but intentionally unreachable due to the
STOPon line 130. VALis not used for theGO TO/GO SUBtargets here; the author uses a simple variablelfor the USR address, which is clear and idiomatic.
Bugs and Anomalies
The offset-8 operand in the DATA is 17, 101, 15 (decimal), which decodes as LD DE, 0x0F65. However, the hex comment in line 120 shows "11670f", which would be LD DE, 0x0F67. This two-byte discrepancy between the actual DATA (line 60) and the hex comment (line 120) suggests the hex string version in line 120 was not kept in sync with the final binary — consistent with its “incomplete” status noted in the REMs.
The final two bytes CF 1A (RST 0x08 followed by 1A) follow the convention where RST 8 takes an inline operand byte indicating the error code or action; 0x1A (26 decimal) would correspond to a specific system action.
Source Code
10 REM errors prints 28 error messages. From CTM 5/86 by Ed Shaughnessy
20 RESTORE 60:LET l=40000:LET cs=0
30 FOR i=l TO l+24
40 READ x:POKE i,x:LET cs=cs+x
50 NEXT i
60 DATA 6,28,197,205,169,8,193,120,17,101,15,197,205,63,7,6,50,118,16,253,193,16,235,207,26
70 IF cs <>2651 THEN PRINT "error in line 60":STOP
80 RANDOMIZE USR l
90 REM mc version of above
100 REM 4/29/86 incomplete
110 REM mc code to start at 9c40 hex
120 DATA "061c","c5","cda908","c1","78","11670f","c5","cd3f07","0632","76","10fd","c1","10eb","cf","1a"
130 STOP
140 SAVE "ERRORS" LINE 20Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
