--- title: "TSUG Demo" id: 57125 type: "computer_media" slug: "tsug-demo" url: "http://localhost/computer_media/tsug-demo/" markdown_url: "http://localhost/computer_media/tsug-demo.md" published_at: "2024-10-03T23:55:02+00:00" modified_at: "2026-03-30T21:19:45+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/74_TSUG.png" excerpt: "A users' group banner demo cycles through eight Z80 machine-code screen effects, each triggered 32 times before clearing and moving to the next routine." 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 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/74_TSUG.png" media_type_tags: "Demo" --- # TSUG Demo This program is a display demo for a Timex/Sinclair users’ group, cycling through eight machine-code routines stored as entry-point addresses in the array S(). The REM statement at line 0 contains a Z80 machine-code payload—approximately 100 bytes—that implements the various screen-effect routines called via RAND USR. The BASIC loop fills the screen with the text “==TIMEX/SINCLAIR USER’S GROUP==” (22 lines), then calls each machine-code routine 32 times before clearing the screen and advancing to the next effect. The eight S() values (16514–16633) are addresses within or near the REM statement’s data area, pointing to different sub-routines within that single block of Z80 code. *** ## Program Analysis ### Program Structure The program is organized into three distinct phases: initialization (lines 1–9), the main display loop (lines 10–19), and housekeeping lines (20–21) that are not reached during normal execution. The core loop nests three levels: an outer loop over eight routines (`X`, lines 10–18), a screen-fill loop (`I`, lines 11–13), and a machine-code invocation loop (`I`, lines 14–16). ### Machine Code in REM (Line 0) Line 0 is a `REM` statement whose body is raw Z80 binary. This is the standard ZX81/TS1000 technique for embedding executable machine code: the first byte of a `REM` body lies at a well-known offset from the system variable `RAMTOP`, and `RAND USR` jumps directly into it. The payload is roughly 100 bytes and contains multiple entry points, all branching within the same block. A partial disassembly of notable sub-routines (addresses are absolute, assuming the REM lands at the expected location near 0x4000): - The opening bytes `2A 0C 40` = `LD HL,(400C)` — loads the display-file pointer. - `ED B0` = `LDIR` and `ED B8` = `LDDR` — block copy instructions used for screen scrolling effects. - `10 FB` / `10 F2` = `DJNZ` — tight inner loops for counting iterations. - `CD CC 40`, `CD 91 40`, `CD B0 40`, `CD 82 40` = `CALL` instructions — the tail of the REM chains calls to the sub-routines, combining them into composite effects for the later S() entries. - Each sub-routine ends with `C9` = `RET`. ### Entry-Point Array The array `S(8)` holds the absolute Z80 addresses of eight entry points within the REM machine-code block. By iterating over this array and calling `RAND USR S(X)`, the program selects a different screen effect for each pass. | S() index | Address (decimal) | Address (hex) | | --- | --- | --- | | 1 | 16626 | 0x40F2 | | 2 | 16514 | 0x4082 | | 3 | 16633 | 0x40F9 | | 4 | 16560 | 0x40B0 | | 5 | 16588 | 0x40CC | | 6 | 16619 | 0x40EB | | 7 | 16529 | 0x4091 | | 8 | 16612 | 0x40E4 | The higher-numbered entries (S(3), S(6), S(8)) appear to be composite routines—their Z80 entry points contain `CALL` sequences that chain two simpler sub-routines together before returning, giving more complex visual effects without duplicating code. ### Key BASIC Idioms - **RAND USR address**: The idiomatic ZX81/TS1000 way to call machine code; `RAND` discards the return value, avoiding a syntax error from the integer result. - **Infinite loop via GOTO**: Line 19 jumps back to line 10, so the demo runs forever, cycling through all eight effects repeatedly. - **Variable reuse**: The loop variable `I` is reused for both the screen-fill loop (lines 11–13) and the USR invocation loop (lines 14–16), saving a small amount of memory. ### Screen Fill Technique Before each machine-code effect, the program fills the screen by printing the banner string “==TIMEX/SINCLAIR USER’S GROUP==” 22 times (line 12, looped by lines 11–13). The string is 32 characters wide, exactly filling one display line, so 22 repetitions covers the full 24-line display minus the two system lines. This provides the raw pixel data that the machine-code scrolling and block-copy routines then manipulate. ### Notable Techniques - The machine-code entry points are not sequential; they are scattered through the REM block and selected in an order (1,2,3,…,8) chosen for visual variety rather than memory order. - Each effect is applied 32 times (line 14: `FOR I=1 TO 32`) before `CLS` and the next effect, giving a consistent duration per effect. - The `SAVE` at line 20 and `RUN` at line 21 are unreachable from the infinite loop and serve only as a persistent storage / auto-start mechanism for the tape image. ## Source Code ``` 0 REM \2A\0C\40\E5\11\21\00\19\D1\01\D6\02\ED\B0\C9\2A\10\40\11\43\00\ED\52\E5\11\21\00\ED\52\D1\01\B5\02\ED\B8\2A\0C\40\06\20\23\36\00\10\FB\C9\2A\0C\40\11\D6\02\19\06\16\2B\4E\36\00\2B\7E\FE\76\28\02\18\03\10\F2\C9\71\4F\18\F1\2A\0C\40\06\16\23\4E\36\00\23\7E\FE\76\28\02\18\03\10\F2\C9\71\4F\18\F1\CD\CC\40\CD\91\40\C9\CD\B0\40\CD\91\40\C9\CD\B0\40\CD\82\40\C9\CD\CC\40\CD\82\40\C9 1 DIM S(8) 2 LET S(1)=16626 3 LET S(2)=16514 4 LET S(3)=16633 5 LET S(4)=16560 6 LET S(5)=16588 7 LET S(6)=16619 8 LET S(7)=16529 9 LET S(8)=16612 10 FOR X=1 TO 8 11 FOR I=1 TO 22 12 PRINT "==TIMEX/SINCLAIR USER""S GROUP==" 13 NEXT I 14 FOR I=1 TO 32 15 RAND USR S(X) 16 NEXT I 17 CLS 18 NEXT X 19 GOTO 10 20 SAVE "1007%4" 21 RUN ```