This program is a menu-driven collection of six utility routines for the TS2068, selectable from a central dispatcher at line 2500. Two “reader” routines (lines 10 and 100) walk the BASIC program area by peeking system variables at addresses 23635/23636 (PROG) and 23627/23628 (VARS), displaying each byte’s address, raw value, and printable character; Reader 2 additionally decodes line headers, line lengths, and embedded five-byte floating-point number tokens using a DATA-driven label lookup. Lines 500 and 1000 implement two custom INPUT routines—one character-at-a-time with cursor positioning and one that fills a dimensioned string array—both using the PAUSE 0/INKEY$ keypress idiom with backspace support. Line 1500 loads and executes 25 bytes of Z80 machine code (checksum-verified at 2651) into RAM at address 40000 to print all 28 BASIC error messages, and line 2000 performs a 16K ROM integrity check using a byte sum (expected 1752253), a zero-byte count (expected 609), and a floating-point arithmetic error accumulation test.
Program Analysis
Program Structure
The program is organized as six self-contained routines sharing a single file, dispatched by a menu at line 2500. Line 5 jumps directly to the menu on first run. Each routine occupies a distinct line-number band, separated by REM banners, and each returns to the menu via GO TO 2500 or RUN/PAUSE 200: RUN.
| Lines | Routine | Menu Option |
|---|---|---|
| 10–70 | Reader 1 — raw byte dump of BASIC program area | 1 |
| 100–250 | Reader 2 — structured BASIC line decoder | 2 |
| 500–630 | Input 1 — single-string character editor | 3 |
| 1000–1110 | Input 2 — array string editor | 4 |
| 1500–1630 | Error Messages — machine code loader | 5 |
| 2000–2310 | ROM Check — 16K ROM integrity tests | 6 |
| 2500–2590 | Menu dispatcher | — |
Note a minor bug in the menu: option 6 is listed in the PRINT at line 2520, but the INPUT validation at line 2530 only accepts values 1–5 (a>5 rejects 6), making ROM Check unreachable through the menu. Line 2590 (RUN 2000) is therefore dead code under normal menu navigation.
Reader 1 (Lines 10–70)
This routine uses system variables PROG (address 23635/23636) and VARS (23627/23628) to establish the boundaries of the BASIC program area. It iterates byte-by-byte from PROG to VARS, printing each address and raw byte value. Characters with codes 16–23 (Spectrum/TS2068 control codes for INK, PAPER, FLASH, etc.) are labeled (unprintable); all others are rendered with CHR$. After reaching VARS, it pauses 200 frames and restarts.
Reader 2 (Lines 100–250)
Reader 2 provides a more structured dump, decoding the BASIC line format: two-byte line number (big-endian), two-byte line length (little-endian), then token bytes. The subroutine at line 240 prints the current address and its byte value in columnar form. Special handling is provided for token 14 (the embedded five-byte floating-point literal): it triggers a RESTORE and reads five labels from the DATA statement at line 250 ("FIVE","BYTE","EQUIV.","OF","NUMBER"), printing one label per byte. End-of-program is detected when p=v (VARS boundary).
Input 1 (Lines 500–630)
This routine implements a character-by-character string input with on-screen cursor, using PAUSE 0/INKEY$ at line 560. A flashing ? serves as the cursor. Backspace (CHR$ 12) deletes the last character by slicing the string with t$(TO LEN t$-1) and overwriting the screen position with a space. The screen-wrapping logic at line 540 is notable: it tests y>31 OR y=-1 and adjusts row (x) and column (y) accordingly, supporting multi-line input.
Input 2 (Lines 1000–1110)
This routine fills a two-dimensional string array t$(n,l) (10 rows × 15 columns) one character at a time. Each row is pre-filled with hyphens (CHR$ 45) as a visual field indicator. Backspace reduces k and truncates the row string. Unlike Input 1, wrapping between rows is handled by the FOR j loop structure rather than explicit coordinate arithmetic.
Machine Code Error Message Printer (Lines 1500–1630)
Line 1510 sets the load address to l=40000. A FOR loop POKEs 25 bytes of Z80 machine code into RAM, accumulating a checksum. Line 1560 verifies the checksum equals 2651 before executing with RANDOMIZE USR l. The DATA bytes decode as:
06 1C— LD B,28 (loop counter for 28 error messages)C5— PUSH BCCD A9 08— CALL 0x08A9 (ROM routine)C1— POP BC78— LD A,B11 65 0F— LD DE,0x0F65C5— PUSH BCCD 3F 07— CALL 0x073F (print routine)06 32— LD B,5076— HALT (delay loop)10 FD— DJNZ (back to HALT)C1— POP BC10 EB— DJNZ (outer loop)CF— RST 8 (error restart)1A— error code 26
Lines 1580–1610 contain developer notes and commented-out hex strings for an alternative machine code version, and line 1620 contains a MOVE command and OUT 244 calls indicating TS2068-specific cartridge/bank switching that appears to be unfinished development code.
ROM Check (Lines 2000–2310)
Three independent checks are performed against the 16KB ROM (addresses 0–16383):
- Byte sum check: accumulates
PEEK ifor all 16384 bytes; expected value 1752253. - Zero-byte count: counts bytes equal to zero; expected value 609.
- Floating-point arithmetic error test: loops from 1000 to 1100 computing
i*0.5 - i/2,i*0.1 - i/10, andi - SQR(i*i), which should each yield zero for a correct ROM but accumulate rounding errors. The combined average is compared against a hard-coded expected error of1.3391177E-7.
The arithmetic error test is particularly clever: it exploits the fact that floating-point rounding behavior is deterministic for a correctly burned ROM, making accumulated error a fingerprint of ROM fidelity rather than just content. The comment at line 2300 notes that the additional 8K ROM for cartridge and bank-switching functionality is not tested.
Notable BASIC Idioms
PAUSE 0: LET q$=INKEY$— efficient single-keypress wait at lines 560, 1040.256*PEEK addr + PEEK (addr+1)vs.PEEK addr + 256*PEEK (addr+1)— both big-endian and little-endian 16-bit reads are used appropriately for line numbers and line lengths respectively.RESTOREwithout a line number at line 180 resets the DATA pointer to the first DATA statement, which here is line 250 — a side effect that works correctly only because no other DATA is read before this point in routine 2’s execution.- Checksum verification before
RANDOMIZE USRis a sound defensive practice for machine code loaders.
Content
Source Code
5 GO TO 2500
10 LET p=PEEK 23635+256*PEEK 23636: REM reader 1
20 LET v=PEEK 23627+256*PEEK 23628
30 LET c=PEEK p
40 PRINT p;TAB 8;c;: IF c<16 OR c>23 THEN PRINT ,CHR$ c: GO TO 60
50 PRINT ,"(unprintable)"
60 LET p=p+1: IF p<v THEN GO TO 30
70 PAUSE 200: RUN
99 REM -----------------------
100 LET p=PEEK 23635+256*PEEK 23636: REM reader 2
110 LET v=PEEK 23627+256*PEEK 23628
120 LET n=256*PEEK p+PEEK (p+1)
130 GO SUB 240: PRINT n;TAB 21;"( LINE ": LET p=p+1: GO SUB 240: PRINT TAB 21;"( NUMBER": LET p=p+1
140 LET le=PEEK p+256*PEEK (p+1)
150 GO SUB 240: PRINT le;TAB 21;"( LINE ": LET p=p+1: GO SUB 240: PRINT TAB 21;"( LENGTH": LET p=p+1
160 LET le=p+le
170 LET c=PEEK p
180 GO SUB 240: IF c=14 THEN RESTORE : PRINT TAB 21;"NUMBER:": FOR j=1 TO 5: LET p=p+1: GO SUB 240: READ n$: PRINT TAB 21;n$: NEXT j: GO TO 210
190 IF c<16 OR c>23 THEN PRINT TAB 16;CHR$ c: GO TO 210
200 PRINT ,"(unprintable)"
210 LET p=p+1: IF p=v THEN PAUSE 200: GO TO 2500
220 IF p=le THEN GO TO 120
230 GO TO 170
240 PRINT p;TAB 8;PEEK p,: RETURN
250 DATA "FIVE","BYTE","EQUIV.","OF","NUMBER"
499 REM -----------------------
500 LET x=10: LET y=0: LET t$="Name": REM INPUT 1
510 PRINT AT x,y;t$
520 LET y=y+2+LEN t$
530 LET t$=""
540 IF y>31 OR y=-1 THEN LET y=31*(y=-1): LET x=x-1+2*(y=0)
550 PRINT AT x,y; FLASH 1;"?"
560 PAUSE 0: LET q$=INKEY$
570 IF q$=CHR$ 13 AND t$<>"" THEN GO TO 630
580 IF q$=CHR$ 12 AND t$<>"" THEN PRINT AT x,y;CHR$ 32: LET y=y-1: LET t$=t$( TO LEN t$-1): GO TO 540
590 IF q$<CHR$ 32 THEN GO TO 560
600 LET t$=t$+q$
610 PRINT AT x,y;q$: LET y=y+1
620 GO TO 540
630 PRINT AT x,y;CHR$ 32: RETURN
999 REM -----------------------
1000 LET x=5: LET n=10: LET l=15: DIM t$(n,l): REM INPUT 2
1010 FOR j=1 TO n: FOR k=1 TO l
1020 PRINT AT x+j-1,k;CHR$ 45
1030 NEXT k: LET k=1
1040 PAUSE 0: LET q$=INKEY$
1050 IF q$=CHR$ 13 AND k<>1 THEN GO TO 1100
1060 IF q$=CHR$ 12 AND k<>1 THEN LET k=k-1: PRINT AT x+j-1,k;CHR$ 45: LET t$(j)=t$(j, TO k): GO TO 1040
1070 IF q$<CHR$ 32 THEN GO TO 1040
1080 LET t$(j,k)=q$: PRINT AT x+j-1,k;q$: LET k=k+1
1090 IF k<=l THEN GO TO 1040
1100 NEXT j
1110 RETURN
1499 REM -----------------------
1500 REM errors prints 28 error messages. From CTM 5/86 by Ed Shaughnessy
1510 RESTORE 1550: LET l=40000: LET cs=0
1520 FOR i=l TO l+24
1530 READ x: POKE i,x: LET cs=cs+x
1540 NEXT i
1550 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
1560 IF cs<>2651 THEN PRINT "error in line 50": STOP
1570 RANDOMIZE USR l
1580 REM mc version of above
1590 REM 4/29/86 incomplete
1600 REM mc code to start at 9c40 hex
1610 DATA "061c","c5","cda908","c1","78","11670f","c5","cd3f07","0632","76","10fd","c1","10eb","cf","1a"
1620 OUT 244,1: MOVE "errors.bas",10: OUT 244,0
1630 PAUSE 200: RUN
1999 REM -----------------------
2000 REM TS2068 16K ROM CHECK
2010 CLS : FLASH 0: BORDER 1: PAPER 6: INK 0: BRIGHT 0: INVERSE 0: CLS
2020 BEEP 1,0
2030 PRINT '" TS2068 16K ROM CHECK"
2040 PRINT '" RUN TIME IS FOUR MINUTES"
2050 PRINT '" TO BEGIN PRESS 1 AND ENTER"
2060 INPUT F
2070 IF F<>1 THEN GO TO 2050
2080 PRINT AT 10,12;"Working"
2090 LET b=0: LET a=b
2100 FOR i=a TO 16383
2110 LET a=a+PEEK i
2120 IF PEEK i=0 THEN LET b=b+1
2130 NEXT i
2140 CLS : PRINT " TS2068 16K ROM CHECK"''
2150 IF a=1752253 THEN PRINT TAB 5;"FIRST ROM CHECK IS OK"
2160 PRINT
2170 IF b=609 THEN PRINT TAB 5;"SECOND ROM CHECK IS OK"
2180 PRINT
2190 REM rom accuracy check
2200 LET c=0: LET d=c: LET e=c
2210 FOR i=1000 TO 1100
2220 LET c=c+i*.5-i/2
2230 LET d=d+i*.1-i/10
2240 LET e=e+i-SQR (i*i)
2250 NEXT i
2260 LET AEA=1.3391177E-7
2270 PRINT " ARITHMETIC ERRORS AVERAGE = ";AEA
2280 PRINT
2290 IF (C+D+E)/300<=AEA THEN PRINT " ARITHMETIC ERRORS AVERAGE IS CORRECT"
2300 PRINT ''"NOTE......THE ADDITIONAL 8K ROM DEDICATED TO COMMAND CARTRIDGE CAPABILITIES AND BANK SWITCHING IS NOT INCLUDED OR TESTED BY"'"THIS PROGRAM"
2310 BEEP 1,0: PAUSE 200
2499 REM -----------------------
2500 BORDER 6: PAPER 7: INK 9: CLEAR
2510 PRINT '" 5 Interesting Routines"
2520 PRINT '''" 1 Reader 1"''" 2 Reader 2"''" 3 Input 1"''" 4 Input 2"''" 5 Error Messages"''" 6 ROM Checks"
2530 INPUT "Select 1, 2, 3, 4, 5, 6, ";a: IF (a<1) OR (a>5) THEN GO TO 2530
2540 IF a=1 THEN RUN 10
2550 IF a=2 THEN RUN 100
2560 IF a=3 THEN RUN 500
2570 IF a=4 THEN RUN 1000
2580 IF a=5 THEN RUN 1500
2590 RUN 2000
9998 SAVE "5 routines" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
