--- title: "Flash" id: 54960 type: "computer_media" slug: "flash" url: "http://localhost/computer_media/flash/" markdown_url: "http://localhost/computer_media/flash.md" published_at: "2024-06-10T01:18:09+00:00" modified_at: "2026-04-02T15:24:15+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A contest entry that uses an inline machine code routine to flash a bold inverse-video banner in a continuous display loop." 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/" indiv: - name: "Kenneth Majors" slug: "kenneth-majors" taxonomy: "indiv" url: "http://localhost/indiv/kenneth-majors/" genre: - name: "Banner" slug: "banner" taxonomy: "genre" url: "http://localhost/type/banner/" media_type: "Program" programmers: - name: "Kenneth Majors" slug: "kenneth-majors" taxonomy: "indiv" url: "http://localhost/indiv/kenneth-majors/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Flash%20%281985%29%28Majors%2C%20Kenneth%29%28TS1000%29%28US%29%28Program%29.zip" mediadate: "1985" article_media: - id: 39170 title: "The Fame & The Glory" type: "article" url: "http://localhost/article/the-fame-the-glory/" media_type_tags: "Banner" --- # Flash Flash is a display program that renders a large ASCII-art banner across the screen using inverse-video block characters to form stylized text. A machine code routine is embedded in the REM statement at line 1 and is called via RAND USR 16514, which points into that REM data. The machine code routine appears to perform a memory operation — iterating over a block, XORing each byte with 0x80 (toggling the high bit, i.e., inverting video attributes or character data), then looping until a counter expires, creating a flashing effect. After the machine code returns, line 60 loops back to line 20 to repeat the flash cycle indefinitely. Entry for the SyncWare News display program contest. *** ## Program Analysis ### Program Structure The program is compact at six executable lines plus a REM and a banner built from eight PRINT statements. Control flow is straightforward: 1. Line 1: `REM` — stores a machine code payload. 2. Lines 2–8: `PRINT AT` and `PRINT` — draw a multi-row inverse-video banner. 3. Line 9: `PRINT AT 18,9` — prints an author credit line. 4. Line 20: `RAND USR VAL "16514"` — calls the machine code. 5. Line 60: `GOTO VAL "20"` — loops back to re-invoke the machine code, creating continuous animation. Note that lines 2–9 are only executed on the first pass; the `GOTO` at line 60 jumps back to line 20, so the PRINT statements are not re-executed on subsequent iterations. This means the banner is drawn once and then the machine code is called in a tight loop. ### Machine Code Routine The REM statement at line 1 contains 29 bytes of Z80 machine code beginning at address 16514 (0x4082), immediately after the REM token and length bytes. The hex sequence is: | Offset | Hex | Z80 Mnemonic | Comment | | --- | --- | --- | --- | | 0 | `2A 0C 40` | `LD HL,(400C)` | Load HL from address 0x400C | | 3 | `01 19 03` | `LD BC,0x0319` | Load BC with byte count (793 bytes) | | 6 | `7E` | `LD A,(HL)` | Load byte at HL into A | | 7 | `FE 76` | `CP 0x76` | Compare with HALT / newline token | | 9 | `CA 91 40` | `JP Z,0x4091` | Skip (jump past XOR) if byte is 0x76 | | 12 | `EE 80` | `XOR 0x80` | Toggle bit 7 — invert video flag | | 14 | `77` | `LD (HL),A` | Write back modified byte | | 15 | `23` | `INC HL` | Advance pointer | | 16 | `0B` | `DEC BC` | Decrement counter | | 17 | `3E 00` | `LD A,0x00` | Load 0 to test BC | | 19 | `B8` | `CP B` | Test B | | 20 | `C2 88 40` | `JP NZ,0x4088` | Loop if B ≠ 0 | | 23 | `B9` | `CP C` | Test C | | 24 | `C2 88 40` | `JP NZ,0x4088` | Loop if C ≠ 0 | | 27 | `C9` | `RET` | Return to BASIC | The routine loads a base address from memory location `0x400C` (which on the ZX81 holds the start of the display file, i.e., `DFILE`), then iterates over 793 bytes. For each byte, it skips the `0x76` newline token (preserving line structure) and XORs all other bytes with `0x80`, toggling the inverse-video bit. Each call to line 20 therefore flips the entire display between normal and inverse, producing a flashing effect. The loop at line 60 keeps this going indefinitely. ### Banner Construction Lines 2–8 use inverse-video characters (shown as `%` and space in the listing) to draw a large multi-character banner. The `PRINT AT 8,0` at line 2 positions the banner in the vertical center of the display. Each row of the banner is a separate `PRINT` statement, giving seven rows of stylized lettering. Line 9 adds an attribution line at row 18, column 9. ### Key BASIC Idioms - `VAL "16514"` in the `RAND USR` call and `VAL "20"` in `GOTO` are memory-saving idioms: storing a number as a string avoids the five-byte floating-point constant the ZX81 would otherwise append to the token. - `RAND USR` is the standard method for calling machine code from BASIC; the return value is discarded. - The tight `GOTO VAL "20"` loop means the screen is never cleared between flash cycles, so the banner persists while only its video polarity alternates. ### Notable Techniques By reading `DFILE` start from `0x400C` rather than using a hardcoded address, the routine is robust against display file relocation (e.g., when the ZX81 is used with a RAM pack). Skipping `0x76` bytes prevents corruption of the display file’s line-end markers, keeping the display structure intact across repeated inversions. The use of separate `JP NZ` tests for B and C rather than a single `DJNZ`/`DEC BC; JP NZ` pair correctly handles the full 16-bit counter. ### Potential Anomalies The `JP Z,0x4091` at offset 9 jumps to address `0x4091`, which is the `INC HL` instruction at offset 15 — correctly skipping only the XOR and write-back while still advancing the pointer and decrementing the counter. This is precise and intentional. No bugs are apparent in the logic. ## Source Code ``` 1 REM \2A\0C\40\01\19\03\7E\FE\76\CA\91\40\EE\80\77\23\0B\3E\00\B8\C2\88\40\B9\C2\88\40\C9\25\1C\1D\1E\1F\20\21\22\23\24\25\1C\1D\1E\1F\20\21\22\23\24\25\1C 2 PRINT AT VAL "8",VAL "0";"% % % % % % % % % % % % % % " 3 PRINT "% % % % % % % % % " 4 PRINT "% % % % % % % % " 5 PRINT "% % % % % % % % % % % % % % % % " 6 PRINT "% % % % % % % % % % % " 7 PRINT "% % % % % % % % " 8 PRINT "% % % % % % % % % % % % % % % " 9 PRINT AT VAL "18",VAL "9";"BY K.E. MAJORS" 20 RAND USR VAL "16514" 60 GOTO VAL "20" ```