--- title: "5 Interesting Routines" id: 55714 type: "computer_media" slug: "5-interesting-routines" url: "http://localhost/computer_media/5-interesting-routines/" markdown_url: "http://localhost/computer_media/5-interesting-routines.md" published_at: "2024-07-05T00:18:47+00:00" modified_at: "2026-03-30T21:40:53+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "Six utilities in one program — BASIC memory readers, custom input handlers, a machine-code error message printer, and a ROM integrity checker — all selectable from a menu." 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/" genre: - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_contents: - id: 55711 title: "ISTUG Public Domain Library 8" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-8/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/5%20Routines%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1986" images: - url: "http://localhost/wp-content/uploads/2024/07/5-routines.png" media_type_tags: "Programming, Utility" --- 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: 1. `06 1C` — LD B,28 (loop counter for 28 error messages) 2. `C5` — PUSH BC 3. `CD A9 08` — CALL 0x08A9 (ROM routine) 4. `C1` — POP BC 5. `78` — LD A,B 6. `11 65 0F` — LD DE,0x0F65 7. `C5` — PUSH BC 8. `CD 3F 07` — CALL 0x073F (print routine) 9. `06 32` — LD B,50 10. `76` — HALT (delay loop) 11. `10 FD` — DJNZ (back to HALT) 12. `C1` — POP BC 13. `10 EB` — DJNZ (outer loop) 14. `CF` — RST 8 (error restart) 15. `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 i` for 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`, and `i - 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 of `1.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. - `RESTORE` without 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 USR` is a sound defensive practice for machine code loaders. ## 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 p23 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$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$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 ```