--- title: "ERRORS" id: 71029 type: "computer_media" slug: "errors" url: "http://localhost/computer_media/errors/" markdown_url: "http://localhost/computer_media/errors.md" published_at: "2026-08-26T01:45:33+00:00" modified_at: "2026-08-26T01:47:05+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/errors.png" alt: "ERRORS screen" excerpt: "A compact 25-byte machine code routine, checksum-verified before launch, coaxes all 28 built-in error messages out of the system ROM in one go." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Ed Shaughnessy" slug: "ed-shaughnessy" taxonomy: "indiv" url: "http://localhost/indiv/ed-shaughnessy/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_type: "Program" programmers: - name: "Ed Shaughnessy" slug: "ed-shaughnessy" taxonomy: "indiv" url: "http://localhost/indiv/ed-shaughnessy/" download_url: "https://archive.org/download/timex-sinclair-software-archive/ERRORS%20%281986%29%28Shaughnessy%2C%20Ed%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "ERRORS (1986)(Shaughnessy, Ed)(TS2068)(US)(Program).tap" mediadate: "1986" images: - url: "http://localhost/wp-content/uploads/2026/08/errors.png" alt: "ERRORS screen" media_type_tags: "Demo" --- # ERRORS 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: 1. **Setup** (line 20): Resets the DATA pointer to line 60, sets the load address `l=40000`, and initializes a checksum accumulator `cs=0`. 2. **Machine code loading** (lines 30–50): A `FOR` loop reads 25 bytes from the DATA statement and POKEs them into memory starting at address 40000, accumulating a byte sum in `cs`. 3. **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. 4. **Execution** (line 80): `RANDOMIZE USR l` transfers 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 60` at 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 l` rather than `RAND USR l` is the standard idiom for calling machine code; the return value from USR is discarded by RANDOMIZE. - The `HALT` instruction inside the timing loop leverages the interrupt mechanism as a delay primitive — each `HALT` suspends 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 `STOP` on line 130. - `VAL` is not used for the `GO TO`/`GO SUB` targets here; the author uses a simple variable `l` for 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 20 ```