This program is a promotional demo for the Chicago Sinclair Special Interest Group, displaying an animated introduction screen with scrolling ticker text. It makes extensive use of machine code routines called via RAND USR at addresses in the 30000–31000+ range to handle graphics drawing, screen effects, and hardware control, with parameters passed by POKEing values into fixed RAM locations just before each call. The program builds a long inverse-video text string in C$ that scrolls smoothly across row 22 in three phases: an entry scroll from the right, a middle pan, and an exit scroll to the left. A subroutine at line 2000 displays a sequence of inverse-video advertising messages (“LOOKING FOR INEXPENSIVE COMPUTING?”) and then draws what appears to be a logo using ZX81 block graphics characters. The program loops indefinitely via GOTO 10 at line 1220.
Program Analysis
Program Structure
The program is organized into a main sequence and two subroutines, executing in a continuous loop:
- Lines 10–200: Machine code initialization and startup animation sequence, including screen setup, palette cycling, and display effects via repeated RAND USR calls inside FOR loops.
- Lines 210–490: Further animation phases, culminating in a CLS and transition to the main content.
- Lines 498–499: GOSUB to the advertisement subroutine (2000) and then to a screen-fill subroutine (4000).
- Lines 500–510: Draws a decorative border on rows 21–23 using block graphic characters.
- Lines 520–570: Builds the scrolling ticker string
C$(andB$) from concatenated inverse-video text fragments. - Lines 1060–1200: Three-phase horizontal scroll of
B$across row 22. - Line 1210–1220: CLS and GOTO 10 for an infinite loop.
- Lines 2000–2660: Advertisement subroutine — displays inverse-video promotional messages with delay loops, then draws a block-graphic logo using PLOT and machine code line-draw routines.
- Lines 4000–4130: Screen animation subroutine using machine code loops for rows and columns.
Machine Code Usage
The program relies heavily on external machine code routines loaded elsewhere in RAM. Parameters are passed by POKEing values into fixed addresses immediately before each RAND USR call. The following addresses are used:
| Address | Usage |
|---|---|
30646 / 30656 | Row/column animation routine (scroll down?) |
30696 / 30699 | Row/column animation routine (scroll up?) |
30946 | Called once after POKE 31738,50 — likely sets display mode or speed |
30962 | Called after delay loop — display effect |
30968 | Called at startup |
31017 | Called in subroutines; may clear or initialize screen region |
31028 | Called at program start and in subroutine 2000 — likely hardware init |
31152 | Called after POKEing 31737,0 and 31736,21 |
31179 | Called once after startup |
31329 | Called after POKEing coordinates into 31733/31732 — likely a line-draw routine |
31351 | Called with parameter in 31741 — likely a colour/attribute cycle routine |
31465 | Called at start of subroutine 4000 |
31666 | Column animation routine |
The parameter-passing convention is consistent: POKE the target address with a value, then immediately call RAND USR. For example, lines 2300–2320 POKE X and Y into addresses 31733 and 31732 before calling the line-draw routine at 31329. The PLOT call preceding each line-draw likely sets the start point.
The REM Line as Data
Line 50 is a REM statement containing a long sequence of block graphic characters (%, >, <, V, etc. rendered as block graphics in the ZX81 character set). This is a classic technique for embedding machine code or sprite data within a BASIC program — the REM body is never executed by BASIC but sits at a known address in memory where machine code can read or use it as a data table. The characters in the REM are almost certainly the machine code payload itself, encoded as BASIC token bytes.
Scrolling Ticker Implementation
The scrolling marquee is implemented in three FOR loops across lines 1060–1200, all printing to row 22:
- Entry phase (lines 1060–1100):
Fruns 0 to 30; printsB$(1 TO F+1)at column31-F, sliding text in from the right. - Middle phase (lines 1110–1150):
Eruns 1 toLEN B$-33; prints a 32-character windowB$(E+1 TO E+32)at column 0, panning through the string. - Exit phase (lines 1160–1200):
Cruns 0 to 31; prints a shrinking tail of the string at column 0, sliding text off to the left.
Each phase includes a short delay loop (FOR D=1 TO 3: NEXT D) and a POKE 16418,0 before each print. Address 16418 is the ZX81 system variable MARGIN, and zeroing it suppresses the automatic scroll so the display stays stable during animation.
Inverse Video Text
All displayed text uses the %X inverse video escape throughout, giving the entire presentation a reverse-video aesthetic. The ticker string C$ is built in three concatenation steps (lines 520, 560, 565) to stay within BASIC line-length limits. The content credits club officers by name and role, including the chair and contacts for beginners, BASIC programming, machine/assembly language, and hardware.
Block Graphics Logo
Subroutine 2000 draws a multi-row logo at lines 2490–2650 using ZX81 block graphic characters (▌, ▘, ▝, ▄, ▟, etc.) arranged carefully across rows 1–18. The logo appears to spell out “SINCLAIR” or a related acronym in chunky pixel art. Three PLOT+POKE+RAND USR 31329 sequences before the logo draw lines connecting elements of the graphic.
Notable Techniques
POKE 16418,0before each PRINT in the scroll loop suppresses auto-scroll (zeroes the MARGIN system variable).- Parameters for machine code routines are passed via fixed POKE addresses rather than registers, allowing clean BASIC-to-ML interfacing.
- String concatenation across multiple LET statements works around the ZX81’s line-length restriction for long ticker messages.
- Delay loops (
FOR I=1 TO N: NEXT I) are used for timing throughout, since no PAUSE command with fine granularity is available. - The program restarts via
GOTO 10(line 1220) rather thanGOTO 1orRUN, skipping re-execution of the very first machine code init calls if any state persists — though in practice the ML routines at line 10 and 20 are called again each loop.
Potential Anomalies
Line 40 sets up FOR B=1 TO 1, which executes its body exactly once. The corresponding NEXT B at line 200 closes this single-iteration loop. This appears to be a structural leftover — perhaps the loop count was once larger for repeated animation passes during the intro sequence.
The exit-scroll phase (lines 1160–1200) prints a string slice B$(C+LEN B$-31 TO LEN B$) which shrinks from 32 characters down to 1 as C increases, but the AT column stays at 0. This means the text does not actually slide off to the left — it truncates from the left edge while the right end stays fixed. Whether this is intentional or a minor bug depends on the desired visual effect.
Content
Source Code
10 RAND USR 31028
20 RAND USR 30968
40 FOR B=1 TO 1
50 REM :% >% >% >% >% > >% >% >% > >% >% >% >% >% V < < < <% < < <% < < < < < < <% V% > > > > > > >% > > >% > > > > V < < < <% < < <% < < < < < < <% V% >% >% >% >% > > >% > > >% > >% >% >% V% < <% < <% < < <% < < <% < < < < V > > > >% > > >% > > >% > > > >% V% < < < <% < < <% < < <% < < < < V% >% >% >% >% > >% >% >% > >% >% >% >% >% :
60 POKE 31738,50
70 RAND USR 30946
72 RAND USR 31179
80 FOR I=1 TO 16
90 RAND USR 30699
100 NEXT I
110 FOR I=1 TO 13
120 RAND USR 31666
130 NEXT I
140 FOR I=1 TO 16
150 RAND USR 30696
160 NEXT I
170 FOR I=1 TO 12
180 RAND USR 30656
190 NEXT I
200 NEXT B
210 FOR I=1 TO 8
220 RAND USR 30699
230 NEXT I
240 FOR I=1 TO 5
250 RAND USR 31666
260 NEXT I
270 PRINT AT 2,5;"SPECIAL INTEREST GROUP"
280 PRINT AT 18,6;"SINCLAIR ZX/TS 1000"
281 FOR I=128 TO 138
282 FOR P=1 TO 6
284 POKE 31742,I
285 RAND USR 31017
286 NEXT P
287 NEXT I
288 POKE 31742,151
289 RAND USR 31017
300 FOR P=1 TO 75
310 NEXT P
330 POKE 31737,0
340 POKE 31736,21
350 RAND USR 31152
360 FOR I=1 TO 90
370 NEXT I
380 RAND USR 30962
390 POKE 31361,21
400 POKE 31740,0
410 FOR I=1 TO 37
420 POKE 31741,I
430 RAND USR 31351
440 NEXT I
445 FOR I=1 TO 12
450 POKE 31741,151
460 RAND USR 31351
470 POKE 31741,0
480 RAND USR 31351
490 NEXT I
492 CLS
498 GOSUB 2000
499 GOSUB 4000
500 POKE 16418,0
505 PRINT AT 21,0;"\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!\!!"
508 PRINT AT 22,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
510 PRINT AT 23,0;"\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;\;;"
520 LET C$="%P%R%E%S%E%N%T%I%N%G% %C%H%I%C%A%G%O%S% %O%L%D%E%S%T% %R%U%N%N%I%N%G% %S%P%E%C%I%A%L% %I%N%T%E%R%E%S%T% %G%R%O%U%P% % % % % % % % "
560 LET C$=C$+"%C%H%A%I%R%-%P%E%R%S%O%N% % %L%A%R%R%Y% %P%.% %W%E%I%G%E%L% % % % %F%O%R% %B%E%G%I%N%N%E%R%S% % %S%E%E% % %B%I%L%L% %K%E%N%T% % % % %F%O%R% %B%A%S%I%C% %P%R%O%G%R%A%M%M%I%N%G% % %S%E%E% % %K%E%N% %D%U%D%A% % % % %F%O%R% %M%A%C%H%I%N%E% %L%A%N%G%U%A%G%E% % %O%R% % %A%S%S%E%M%B%L%Y% %L%A%N%G%U%A%G%E% % %S%E%E% % %R%I%C%K% %S%H%A%N%D%R%O%S%S% % %O%R% % %R%I%C%H%A%R%D% %M%E%H%A%N% % % % "
565 LET C$=C$+"%F%O%R% %H%A%R%D%W%A%R%E% % %S%E%E% % %F%R%A%N%K% %K%E%Y%S%E%R% % %O%R% % %J%O%H%N% %M%E%N%A%R%E%K% % % "
570 LET B$=C$
\n1060 FOR F=0 TO 30
\n1065 POKE 16418,0
\n1070 PRINT AT 22,31-F;B$(1 TO F+1)
\n1080 FOR D=1 TO 3
\n1090 NEXT D
\n1100 NEXT F
\n1110 FOR E=1 TO LEN B$-33
\n1115 POKE 16418,0
\n1120 PRINT AT 22,0;B$(E+1 TO E+32)
\n1130 FOR D=1 TO 3
\n1140 NEXT D
\n1150 NEXT E
\n1160 FOR C=0 TO 31
\n1165 POKE 16418,0
\n1170 PRINT AT 22,0;B$(C+LEN B$-31 TO LEN B$)
\n1180 FOR D=1 TO 3
\n1190 NEXT D
\n1200 NEXT C
\n1210 CLS
\n1220 GOTO 10
\n2000 RAND USR 31017
\n2010 POKE 31741,128
\n2020 RAND USR 31351
\n2060 PRINT AT 4,10;"%L%O%O%K%I%N%G% %F%O%R"
\n2070 PRINT AT 10,5;"%I%N%E%X%P%E%N%S%I%V%E% %C%O%M%P%U%T%I%N%G% %?"
\n2080 FOR I=1 TO 60
\n2090 NEXT I
\n2100 PRINT AT 16,10;"%L%O%O%K% %N%O% %M%O%R%E"
\n2110 FOR I=1 TO 60
\n2120 NEXT I
\n2130 FOR I=1 TO 40
\n2140 PRINT AT 4,10;"% % %S%I%N%C%L%A%I%R% % "
\n2150 PRINT AT 10,5;"%S%P%E%C%I%A%L% %I%N%T%E%R%E%S%T% %G%R%O%U%P% % % "
\n2160 PRINT AT 16,5;"%H%A%S% %T%H%E% %A%N%S%W%E%R%S% %F%O%R% %Y%O%U"
\n2170 NEXT I
\n2180 FOR P=1 TO 40
\n2190 PRINT AT 4,10;"% %T%A%L%K% %T%O% %U%S"
\n2200 PRINT AT 10,5;"% % % %I%T% %W%O%N%T% %C%O%S%T% %Y%O%U% % % % % "
\n2210 PRINT AT 16,5;"% % % % % % % %A%N%Y%T%H%I%N%G% % % % % % % % % % "
\n2220 NEXT P
\n2230 CLS
\n2240 RAND USR 31028
\n2250 LET A=0
\n2260 LET B=42
\n2270 LET X=10
\n2280 LET Y=6
\n2290 PLOT A,B
\n2300 POKE 31733,X
\n2310 POKE 31732,Y
\n2320 RAND USR 31329
\n2330 LET A=12
\n2340 LET B=42
\n2350 LET X=35
\n2360 LET Y=29
\n2370 PLOT A,B
\n2380 POKE 31733,X
\n2390 POKE 31732,Y
\n2400 RAND USR 31329
\n2410 LET A=12
\n2420 LET B=23
\n2430 LET X=60
\n2440 LET Y=6
\n2450 PLOT A,B
\n2460 POKE 31733,X
\n2470 POKE 31732,Y
\n2480 RAND USR 31329
\n2490 PRINT AT 1,0;"% % % % % \: % % % % % % % % % % % % "
\n2500 PRINT AT 2,0;"\: \: \: \ : \: "
\n2510 PRINT AT 3,0;"\: \ :% % \: % \:' \.:\ '\''\' \: % % % \ :"
\n2520 PRINT AT 4,0;"\: \: \:' \.:% \ .\..\. \: % % % \ :"
\n2530 PRINT AT 5,0;"% % % \: \: \ : \: \ :"
\n2540 PRINT AT 6,0;"\: \: % % % % % % % % % % % % "
\n2550 PRINT AT 7,0;"% % % % % "
\n2560 PRINT AT 8,0;"\: \ :"
\n2570 PRINT AT 9,0;"% \: \ :% "
\n2580 PRINT AT 10,0;"% \: \ :% \: % % % % % % % % % % % % % % % % % % % % % % % % "
\n2590 PRINT AT 11,0;"\: \ :\: \: % % % % % % % "
\n2600 PRINT AT 12,0;"% % % % % \: \: % % % % % % % % % % % % % "
\n2610 PRINT AT 13,0;"\: \ :\: \: % % % % % % % % % % % % % "
\n2620 PRINT AT 14,0;"\: \ :% % % \: \: % % % % % % % % % % % "
\n2630 PRINT AT 15,0;"\: \ :% \:.\ :\: % \: % % % % % % % % % % % % "
\n2640 PRINT AT 16,0;"\: \ :\: % \: % % % % % % % % % % % % "
\n2650 PRINT AT 17,0;"\:.\..\..\..\.:\: \: % % % % % \ : % % % % % ";AT 18,0;"% % % % % \: % % % % % % % % % % % % % % % % % % % % % % % % "
\n2660 RETURN
\n4000 RAND USR 31465
\n4010 FOR I=1 TO 32
\n4020 RAND USR 30699
\n4030 NEXT I
\n4040 FOR I=1 TO 23
\n4050 RAND USR 30656
\n4060 NEXT I
\n4070 FOR I=1 TO 32
\n4080 RAND USR 30696
\n4090 NEXT I
\n4100 FOR I=1 TO 23
\n4110 RAND USR 31666
\n4120 NEXT I
\n4130 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
