This program renders the Mandelbrot set fractal in hi-res graphics on a ZX81/TS1000 equipped with static RAM in the 8–16K region. Its central performance technique is invoking the ROM’s floating-point calculator stack directly via RAND USR calls rather than relying on interpreted BASIC arithmetic, achieving roughly a 3× speed improvement at the cost of considerable complexity in line 0’s embedded machine code. The program supports a full interactive menu system with options to start, save, resume, display, reverse, copy, zoom, and report progress on a run. A zoom utility (option 7) lets the user move a flashing pixel cursor to identify new corner coordinates and side lengths for successive magnifications. Parameters include real and imaginary corner values (A, B), vertical side length (S), iteration limit (L), and band width (W), which controls the number of iterations per black/white band.
Program Analysis
Program Structure
The program is organized into several functional blocks accessed via a central menu at line 5000 (stored in the variable MNU). Execution begins at line 1, which jumps to 9000 for initialization and the extensive help/documentation screens. Line 0 is a REM block containing embedded machine code routines that are called throughout the program via RAND USR.
| Line Range | Function |
|---|---|
| 0 | Machine code block (REM statement) |
| 1 | Entry point — GOTO 9000 |
| 100–200 | Main rendering loop (FAST mode) |
| 4000–4450 | Zoom utility |
| 4990–4995 | “All Done” completion handler |
| 5000–5140 | Main menu |
| 6000–6090 | Display/reverse/copy picture |
| 8000–8060 | Save current state to tape |
| 9000–9330 | Initialization, parameter input |
| 9480–9720 | Help/documentation screens |
| 9860–9950 | Subroutine: wait for keypress |
Machine Code Routines
All machine code is stored inside the REM statement at line 0. The routines are referenced by address constants initialized in lines 9190–9310. The variable names and their corresponding addresses are:
| Variable | Address | Purpose |
|---|---|---|
CLS | 16648 | Clear screen |
HR | 16628 | Switch to hi-res mode |
NML | 16633 | Switch to normal mode |
RVS | 16669 | Reverse picture |
PLT | 16681 | Plot pixel at current coordinates |
YP | 16439 | Y-coordinate register (POKEd directly) |
XP | 16438 | X-coordinate register (POKEd directly) |
ULD | 16758 | Upload display data |
DLD | 16765 | Download display data |
CPY | 16790 | Copy/print picture |
UPL | 16687 | Update plot location |
The core Mandelbrot iteration at line 150 calls USR 16514 directly, bypassing the BASIC variable lookup and invoking the ROM floating-point calculator stack. This is the principal performance optimization, credited in the help text as delivering nearly a 3× speed increase over equivalent BASIC arithmetic.
Main Rendering Loop
Lines 100–200 implement the scan loop in FAST mode. The outer loop iterates M from its current value to 191 (rows), the inner loop iterates N from its current value to 255 (columns). Current coordinates are POKEd into the machine code’s X and Y registers (XP and YP) rather than passed as parameters, which is an efficient interface to the machine code layer.
- Line
140: checksINKEY$to allow escape to menu mid-run without halting - Line
150: computes the iteration countCusing the USR call into the FP calculator - Line
160: plots a pixel ifCis odd (i.e.,C/2 <> INT(C/2)), implementing band-based black/white rendering controlled byW - Lines
180and200: resetNto 0 and loop back, allowing resumption (MandNpreserve state)
State Preservation and Resume
The program preserves run state by retaining the values of M and N in BASIC variables across menu visits. Line 110 checks if M >= 192 to redirect to a completion handler. The main menu option 3 simply GOTO 100, resuming mid-scan without resetting the loop counters. Line 9100–9110 initialize M and N to zero at the start of a new run only.
The string array P$(6144) (line 9000) is allocated to store the 192×32-byte hi-res display buffer so that the program state (including the picture) can be saved to tape with a single SAVE command at line 8040.
Zoom Utility
Lines 4000–4450 implement an interactive zoom coordinate picker. A flashing pixel cursor is moved around the hi-res display using cursor keys (handled by machine code at USR 16963). Pressing key 1 records the lower-left corner coordinates; pressing key 2 records the upper-right corner and computes the side length. These values are printed on screen for the user to note and re-enter in a subsequent run. The zoom utility explicitly does not disturb the current rendering state.
Display and Copy Options
Line 6000–6090 provide three operations on the completed picture: reverse (invert pixels via RAND USR RVS), copy (send to printer via RAND USR CPY), and return to menu. POKE to address 16418 with values 0 or 2 toggles between hi-res and normal display modes at the hardware level.
Key BASIC Idioms
VAL "number"used inGOSUBandPOKEstatements (lines9490,9515,9695, etc.) as a memory-saving technique- Symbolic address variables (
MNU,PLT,HR, etc.) used inGOTOandRAND USRfor readability and maintainability GOTO MNU+10andGOTO MNU-10for near-menu entry points without additional labels- Conditional string expression
("3: RESUME ..." AND M<192)in the menu PRINT to suppress option 3 when rendering is complete - The wait-for-keypress subroutine at
9860uses a double-edge detection pattern: wait for key down, then wait for key up, then wait for key down again, preventing accidental continuation
Notable Anomalies
Line 9700 checks IF INKEY$ ="Y" THEN GOTO VAL "9485" and line 9710 checks for "N", but both share the fall-through GOTO 9700 at line 9720. Since both conditions branch away, any other key simply loops — this is intentional behavior rather than a bug.
The variable B2 is used as a state flag within the zoom utility: -1 means “cursor active, no corner set”, 0 means “first corner set”, and non-zero (the computed side) means “measurement complete”. This multi-role usage of a single variable is compact but requires careful reading of the zoom logic flow.
Content
Image Gallery
Source Code
0 REM LOAD [4]""AT VAL ▝TAB ▝#▝CODE ▝ STOP LLIST STEP H▖ LPRINT H▖▀?▘ STEP LPRINT ▖H??AT ▘""H▖▘H▖?KN ▀N " FAST[5]?VAL SLOW: ▀JCHR$ [4][4] FASTO▘ TAN 5 LIST INKEY$ ) LIST AT ▘9 GOSUB [K]TAN E£RNDE£RNDE£RND ) RUN ▙;Y2 GOSUB #Y PRINT ▘▛▝LN [P]▝LN [>]▝LN 4▝<>5+PI#[8]▝<>5+PITAN Y2 GOSUB #<>5▟▝TAN 5 4U6PI333#: Q "##< GOSUB [K]TAN 5 PAUSE INKEY$ ▘4 #LEN █#/ GOSUB CLEARACS VCHR$ /▖ CLEARACS V[-] GOSUB #QRNDU6PIX[(] AND [H]:##ACS UACS .ACS UACS .ACS UACS .5 4;## NEW▛W▘ ▒ACS ▝ACS )X4£ CLEARACS V#C▖ACS AT /▝ACS ▟( FOR #TAN LN ▙INKEY$ FOR GOSUB [K]TAN LN ▙INKEY$ /:E(RND)▞ ;) 4▘ /TAN GOSUB [K]#AT RND LN 7?U6PI#5 4[J]PEEK CLSLN #?ABS ▐▒<= CLS*K CLS-4▞▒# FASTSTR$ Y4[>]#- 5 PAUSE INKEY$ ;ACS #SGN LPRINT #C▘J#<= CLS3K CLS# NEW█PEEK CLSACS )( PAUSE 7+4CHR$ <= CLS3K CLS14[Y]Y▖PEEK CLS0#F? GOSUB # #GPI NEXT Y▛# ( CLEARLEN INPUT W4 CLEAR▞"")4 5 4#NPI ▌ASN LN RND;# GOSUB ### LIST AT LN [V]▝G4▖▘6(TAN H##LN [X]▛K POKE # GOSUB #QRND RETURN64=#X RETURN COPY4▝Y[Z] RETURN""4▘[J]MRRND▘#(TAN RETURN74▖#W/ GOTO RETURN54▛#XMQRND/ DIM RETURN84▖#W/ NEXT RETURN14▖▘ATN (TAN RETURN24▖▘K)TAN RETURN#4[C]▘#(TAN
1 GOTO 9000 AND CODE "[H][R][-][M][A][N][D][E][L][B][R][O][T] FASTF.P. V1.4 [G][O][T][O]█[M][N][U]█[T][O]█[S][T][A][R][T][/][S][A][V][E] "
100 FAST
110 IF M>=192 THEN GOTO MNU-10
120 FOR M=M TO 191
125 POKE YP,M
130 FOR N=N TO 255
135 POKE XP,N
140 IF INKEY$ <>"" THEN GOTO MNU
150 LET C=INT ((L+(M*G+B+(N*G+A+USR 16514)))/W)
160 IF C/2<>INT (C/2) THEN RAND USR PLT
170 NEXT N
180 LET N=0
190 NEXT M
200 GOTO 100
4000 POKE 16418,0
4020 RAND USR HR
4030 RAND USR ULD
4040 LET M1=0
4050 LET N1=0
4070 CLS
4072 PRINT AT 23,0;"[5][-][8]:MOVE [1]:CORNER [2]:SIDE [N][/][L]:ESC"
4075 LET B2=-1
4090 POKE XP,N1
4095 POKE YP,M1
4110 RAND USR PLT
4120 GOTO USR 16963
4130 RAND USR UPL
4170 GOTO 4110
4180 RAND USR DLD
4190 POKE 16418,2
4195 GOTO MNU
4200 LET M1=PEEK YP
4210 LET N1=PEEK XP
4220 RAND USR UPL
4250 GOTO 4110
4300 CLS
4310 LET A1=A+N1*G
4315 LET B1=B+M1*G
4330 PRINT AT 23,0;"A=";A1,"B=";B1
4340 LET B2=0
4350 GOTO 4110
4400 IF B2<>0 THEN GOTO 4070
4410 CLS
4420 LET B2=B+M1*G
4430 PRINT AT 23,0;"SIDE=";B2-B1
4440 IF INKEY$ ="" THEN GOTO 4440
4450 GOTO 4070
4990 CLS
4992 PRINT AT 10,0;"ALL DONE.",,,,
4995 GOTO MNU+10
5000 CLS
5010 RAND USR NML
5020 SLOW
5030 PRINT AT 0,0;" [M][A][I][N]█[M][E][N][U][:]",,,,"1: START A NEW RUN ","2: SAVE CURRENT PROGRAM STATE";TAB 0;("3: RESUME CURRENT RUN " AND M<192);TAB 0;"4: DISPLAY/COPY PICTURE","5: PROGRESS REPORT","6: PRINT PARAMETERS","7: ZOOM LOCATION","8: STOP"
5040 LET Z$=INKEY$
5050 IF Z$="" THEN GOTO 5040
5060 IF Z$="1" THEN RUN
5070 IF Z$="2" THEN GOTO 8000
5080 IF Z$="3" THEN GOTO 100
5090 IF Z$="4" THEN GOTO 6000
5100 IF Z$="5" THEN PRINT ,,"ROW: ";M,"COL: ";N,49151-256*M-N;" TO GO"
5110 IF Z$="6" THEN PRINT ,,"R-CORNER=";A;TAB 0;"I-CORNER=";B;TAB 0;"R-SIDE =";S*4/3;TAB 0;"I-SIDE =";S;TAB 0;"IT.LIMIT=";L;TAB 0;"BANDWIDTH=";W
5120 IF Z$="7" THEN GOTO 4000
5130 IF Z$="8" THEN STOP
5140 GOTO 5040
6000 CLS
6010 POKE 16418,0
6020 PRINT AT 23,0;"[R]= REVERSE, [Z]= COPY, [Y]= RETURN"
6030 POKE 16418,2
6040 RAND USR HR
6050 LET Z$=INKEY$
6060 IF Z$="R" THEN RAND USR RVS
6070 IF Z$="Z" THEN RAND USR CPY
6080 IF Z$="Y" THEN GOTO MNU
6090 GOTO 6050
8000 RAND USR ULD
8010 CLS
8020 PRINT " INPUT SAVE NAME:"
8030 INPUT N$
8040 SAVE N$
8050 RAND USR DLD
8055 RAND USR 16577
8060 GOTO MNU
9000 DIM P$(6144)
9010 CLS
9020 SLOW
9030 PRINT " INPUT CO-ORDS OF SW CORNER OF PROPOSED MANDELBROT PLANE:",,,"A-CORNER (REAL PART)=";
9040 INPUT A
9050 PRINT A;AT 5,0;"B-CORNER (IMAG PART)=";
9060 INPUT B
9070 PRINT B;AT 7,0;"LENGTH OF VERT SIDE =";
9080 INPUT S
9090 LET G=S/192
9100 FOR M=0 TO 0
9110 FOR N=0 TO 0
9120 PRINT S;AT 10,0;"ITERATION LIMIT=";
9130 INPUT L
9140 PRINT L;AT 12,0;"BAND WIDTH=";
9150 INPUT W
9160 PRINT W,,,,"OK?"
9170 INPUT Y$
9180 IF Y$<>"Y" THEN RUN
9190 LET CLS=16648
9200 LET HR=16628
9210 LET NML=16633
9220 LET RVS=16669
9230 LET PLT=16681
9240 LET YP=16439
9250 LET XP=16438
9260 LET ULD=16758
9270 LET DLD=16765
9280 LET CPY=16790
9290 LET MNU= 5000
9300 LET UPL=16687
9310 RAND USR CLS
9320 CLS
9330 GOTO 100
9480 SAVE "MAND-FF[P]"
9482 RAND USR 16577
9485 CLS
9487 SLOW
9490 POKE VAL "16418",NOT PI
9492 PRINT ">>>>>>>>[T][H][E]█[M][A][N][D][E][L][B][R][O][T]█[S][E][T]<<<<<<",,"A HI-RES FRACTAL PROGRAM FOR THEZX81/TS1000 AND 1500 WITH STATICRAM IN THE 8-16K REGION.",,,"BY FRED NACHBAUR, HI-RES CORE BYWILF RIGTER. CONCEPT BY BENOIT BMANDELBROT, I.B.M. RESEARCH.",,,"▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜▌[F][E][E][L]█[F][R][E][E]█[T][O]█[D][I][S][T][R][I][B][U][T][E][:]█[T][H][I][S]█▐▌[P][R][O][G][R][A][M]█[I][S]█[I][N]██[P][U][B][L][I][C]█[D][O][M][A][I][N][,]█▐▌[B][U][T]█[I][S]█[N][O][T]█[T][O]█[B][E]█[S][O][L][D]█[F][O][R]█[G][A][I][N]▐▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟",,"PRESS BREAK, THEN GOTO 9480 TO MAKE COPIES OF ORIGINAL PG."
9495 PRINT ,,"WRITE: [S][I][L][I][C][O][N]█[M][O][U][N][T][A][I][N]█[C][O][M][P][U][T][E][R] [C][-][1][2][,]█[M][T][N][.]█[S][T][N][.]█[G][R][O][U][P]█[B][O][X] [N][E][L][S][O][N][,]█[B][C]█[V][1][L]█[5][P][1]█[C][A][N][A][D][A]FOR INFO ON MORE HI-RES PROGRAMS"
9502 RAND USR DLD
9505 SLOW
9510 POKE VAL "16418",NOT PI
9515 GOSUB VAL "9860"
9520 PRINT ">>>>>>>>[T][H][E]█[M][A][N][D][E][L][B][R][O][T]█[S][E][T]<<<<<<",,"IS A REGION IN THE COMPLEX PLANETHAT NEVER DIVERGES WHEN SUBJECTTO AN ITERATIVE CALCULATION. SEE[S][C][I][E][N][T][I][F][I][C]█[A][M][E][R][I][C][A][N]█[A][U][G][.][1][9][8][5] FORDETAILS."
9530 PRINT ,," THIS PROGRAM LETS YOU EXAMINE AREAS NEAR THE SET; STRIKING IMAGES ARE THEREBY PRODUCED."
9540 PRINT ,," THE COVER SCREEN DISPLAYS THE ENTIRE SET (THE BIG BLACK AREA IN THE CENTRE OF THE PICTURE).","""A""-CORNER=-2.5, ""B""-CORNER=-1.4LENGTH OF SIDE=2.8",,,"YOU CAN ZOOM IN ON ANY AREA NEARTHE SET (EG THE STIPPLED REGION)TO REVEAL EVER MORE DETAILS ASYOU ZOOM IN FURTHER AND FURTHER."
9550 GOSUB VAL "9860"
9560 PRINT ,,"VAR [T][H][E]█[P][A][R][A][M][E][T][E][R][S]",,,"""A"" (REAL)=COORD. OF X-AXIS","""B"" (IMAG)=COORD. OF Y-AXIS"," (LOWER LEFT CORNER)",,,"""S""=LENGTH OF VERTICAL SIDE",,,"""L""=ITERATION LIMIT BEFORE PGM. GIVES UP (ASSUMES THAT POINT NEVER CONVERGES AND LIES WITHIN THE MANDELBROT SET)"
9570 PRINT ,,"""W""= BAND WIDTH; NO. OF COUNTS FOR EACH BLACK/WHITE BAND. NOR- MALLY THIS WILL BE 1,BUT IF YOURPICTURE IS TOO ""BUSY"", TRY 2-3."
9575 PRINT ,,"P$ - USED FOR STORAGE OF YOUR PICTURE SO IT WILL SAVE TO TAPE"
9580 GOSUB VAL "9860"
9590 PRINT TAB VAL "10";"[M][E][N][U]█[O][P][T][I][O][N][S]",,,"1: START ANEW. CLEARS PICTURE.",,,"2: SAVE PRESENT STATUS TO TAPE. USEFUL IF YOU NEED TO USE YOUR MACHINE FOR OTHER THINGS, AS THESE RUNS CAN TAKE AWHILE",,,"3: CONTINUE RUN AFTER SAVE , RE- LOAD , OR OTHER MENU OPTION",,,"4: DISPLAY/REVERSE/COPY PICTURE",,,"5: REPORT ON PROGRESS SO FAR",,,"6: PRINT PARAMETERS"
9600 PRINT ,,"7: ZOOM UTILITY; SEE NEXT PAGE",,,"8: STOPPGM. GOTO MNU TO CONT "
9610 GOSUB VAL "9860"
9620 PRINT TAB VAL "12";"[Z][O][O][M][I][N][G]","AFTER PRESSING 7 FROM MENU, MOVEFLASHING PIXEL TO DESIRED AREA (LOWER LEFT CORNER OF AREA TO BEZOOMED), USING CURSOR KEYS. NOW HIT 1 TO PRINT A/B-CORNER; NOTE THESE DOWN. MOVE PIXEL VERTICAL-LY TO UPPER RIGHT CORNER THEN PRESS 2 TO PRINT LENGTH OF SIDE.ANY KEY TO CONT OR ENTER TO GO BACK TO MENU.",,,,"NOTE: USING THIS OPTION DOES NOTMESS UP YOUR CURRENT RUN. TRY ITWITH THE SAMPLE SCREEN SUPPLIED."
9630 PRINT ,,"YOU CAN THENSTART A NEW RUN ANDSPECIFY THE NEW PARAMETERS TO BLOW-UP ANY REGION. YOU CAN KEEPENLARGING (WITHIN LIMITS OF ZX CALCULATOR) AND ALWAYS FIND MOREDETAIL."
9640 GOSUB VAL "9860"
9650 PRINT "ONCE YOU HAVE THE HANG OF IT YOUCAN DELETE THESE HELP SCREENS (LINES 9480-9950) TO REDUCE TIMETO LOAD / SAVE YOUR RUNS."
9670 PRINT ,,"NOTE: THE EVALUATION LOOP USES THE ROM▘S FLOATING-POINT CALCU- LATOR DIRECTLY, FOR AN ALMOST 3XSPEED INCREASE OVER BASIC. SEE SYNCWARE NEWS VOL. 3 NO. 5 FOR THE ORIGINAL ALGORITHM"
9680 PRINT ,,"TS2040 USE IS SUPPORTED, OTHER PRINTOUTS POSSIBLE USING PETER MCMULLIN▘S ""BIG-PRINTER"" SINC- ARTIST UPGRADE. JUST MOVE DATA FROM 8192-14335 INTO A$.",,,"DURING A RUN, HOLD ANY KEY TOGET TO MENU (CHECK PROGRESS,ETC)"
9690 PRINT ,," DO YOU WANT TO RE-READ THESE HELP SCREENS? (Y/N)"
9692 SLOW
9695 POKE VAL "16418",VAL "2"
9700 IF INKEY$ ="Y" THEN GOTO VAL "9485"
9710 IF INKEY$ ="N" THEN GOTO MNU
9720 GOTO 9700
9860 REM [W][A][I][T]
9870 PRINT AT VAL "23",VAL "0";"*[P][R][E][S][S]█[A]█[K][E][Y]█[T][W][I][C][E]█[T][O]█[C][O][N][T][I][N][U][E]**"
9880 SLOW
9890 IF INKEY$ ="" THEN GOTO 9890
9900 RAND USR HR
9910 CLS
9920 IF INKEY$ <>"" THEN GOTO 9920
9930 IF INKEY$ ="" THEN GOTO 9930
9940 FAST
9950 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.