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:
- Line 1:
REM— stores a machine code payload. - Lines 2–8:
PRINT ATandPRINT— draw a multi-row inverse-video banner. - Line 9:
PRINT AT 18,9— prints an author credit line. - Line 20:
RAND USR VAL "16514"— calls the machine code. - 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 theRAND USRcall andVAL "20"inGOTOare 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 USRis 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"Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.