Mandelbrot-FPP

Developer(s): Fred Nachbaur
Date: 1987
Type: Cassette
Platform(s): TS 1000

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 RangeFunction
0Machine code block (REM statement)
1Entry point — GOTO 9000
100–200Main rendering loop (FAST mode)
4000–4450Zoom utility
4990–4995“All Done” completion handler
5000–5140Main menu
6000–6090Display/reverse/copy picture
8000–8060Save current state to tape
9000–9330Initialization, parameter input
9480–9720Help/documentation screens
9860–9950Subroutine: 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 91909310. The variable names and their corresponding addresses are:

VariableAddressPurpose
CLS16648Clear screen
HR16628Switch to hi-res mode
NML16633Switch to normal mode
RVS16669Reverse picture
PLT16681Plot pixel at current coordinates
YP16439Y-coordinate register (POKEd directly)
XP16438X-coordinate register (POKEd directly)
ULD16758Upload display data
DLD16765Download display data
CPY16790Copy/print picture
UPL16687Update 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 100200 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: checks INKEY$ to allow escape to menu mid-run without halting
  • Line 150: computes the iteration count C using the USR call into the FP calculator
  • Line 160: plots a pixel if C is odd (i.e., C/2 <> INT(C/2)), implementing band-based black/white rendering controlled by W
  • Lines 180 and 200: reset N to 0 and loop back, allowing resumption (M and N preserve 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 91009110 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 40004450 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 60006090 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 in GOSUB and POKE statements (lines 9490, 9515, 9695, etc.) as a memory-saving technique
  • Symbolic address variables (MNU, PLT, HR, etc.) used in GOTO and RAND USR for readability and maintainability
  • GOTO MNU+10 and GOTO MNU-10 for 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 9860 uses 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

Appears On

Related Products

Program to implement the Mandelbrot Set using SRAM HI-RES Extended BASIC. 16K.

Related Articles

The purpose for writing this article is to show you how easily you can get beautiful math-art creations using a...

Related 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.

Scroll to Top