Julia Sets

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

Julia Sets is a hi-res fractal program that computes and displays Julia set images derived from user-specified points in the Mandelbrot set, using the same floating-point processor (FFP) machine code core as its companion program “Mandelbrot FFP.” The main computation loop at lines 100–200 iterates over all 192×256 pixel positions, calling a machine code routine via USR 16514 to perform the iteration count, then uses RAND USR to plot individual pixels at address 16681. A zoom utility (line 4000) allows the user to move a flashing pixel cursor around the current image to identify corners and side lengths for a follow-up run at higher magnification. The program stores the display in a 6144-byte string array P$ so the current state can be saved to tape and resumed later. Machine code entry points for functions such as hi-res clear (HR), normal mode (NML), reverse (RVS), upload/download (ULD/DLD), and copy (CPY) are assigned to named variables at lines 9190–9310, making the BASIC readable while keeping the actual addresses in ROM/RAM.


Program Analysis

Program Structure

The program is organized into several distinct functional blocks:

  1. Lines 0–1: REM header (contains embedded machine code in line 0) and a GOTO 9E3 bootstrap that jumps to the initialization/help section.
  2. Lines 100–200: The main fractal rendering loop, iterating over rows (M) and columns (N) of the 192×256 hi-res display.
  3. Lines 4000–4450: Zoom utility — moves a cursor pixel around the screen, reads coordinates, and reports corner/side values.
  4. Lines 4990–4995: Completion message, redirects to menu.
  5. Lines 5000–5140: Main menu, offering start, save, resume, display, progress, parameters, zoom, and stop options.
  6. Lines 6000–6090: Display/copy sub-menu (reverse, copy, return).
  7. Lines 8000–8060: Save-to-tape routine with user-supplied filename.
  8. Lines 9000–9330: Parameter input and variable initialization.
  9. Lines 9480–9720: Save/splash screen, extensive help text, and re-read option.
  10. Lines 9860–9950: GOSUB wait-for-keypress subroutine used between help pages.

Machine Code Integration

The program makes heavy use of machine code routines accessed via RAND USR and USR. All machine code entry points are assigned to named BASIC variables at lines 9190–9310, keeping the code readable:

VariableAddressFunction
CLS16648Hi-res clear screen
HR16634Switch to hi-res mode
NML16639Switch to normal mode
RVS16669Reverse the display
PLT16681Plot a pixel
YP16439Y-coordinate POKE address
XP16438X-coordinate POKE address
ULD16758Upload display (P$ → screen)
DLD16765Download display (screen → P$)
CPY16790Copy (print) screen
UPL16687Update pixel location

The core Julia set iteration is performed by a machine code routine at address 16514, called inline via USR 16514 within the expression at line 150. This provides nearly 3× the speed of equivalent BASIC floating-point math, as noted in the help text referencing the original algorithm. The pixel coordinates are passed by POKEing values into addresses XP (16438) and YP (16439) before calling the plot routine.

Line 9000 also calls RAND USR 16582, which appears to be a memory initialization or relocation routine called before dimensioning P$. This same call appears at line 8055 after a save, and at line 9480 before the splash screen.

Main Rendering Loop

Lines 100–200 form the fractal computation loop. M iterates from its current value to 191 (rows), and N from its current value to 255 (columns). This design allows the run to be interrupted and resumed, since M and N retain their values between menu visits. The guard at line 110 skips directly to MNU-10 (line 4990, the “ALL DONE” message) if M has already reached 192.

Line 150 is the key computation expression:

LET C=INT((L+(CB+(CA+(M*G+B+(N*G+A+USR 16514)))))/W)

The nested additions pass the current pixel’s complex-plane coordinates (real part N*G+A, imaginary part M*G+B) along with the generator constants CA and CB to the machine code routine via the floating-point stack. The result is the iteration count, which is then banded by dividing by W and tested for odd/even at line 160 to determine whether to plot the pixel.

After each row, N is reset to 0 (line 180) so subsequent rows start from the left edge. The loop at line 200 wraps back to line 100 rather than falling through NEXT M, allowing the interrupt check at line 140 to cause a clean exit to the menu.

Interrupt and Resume Mechanism

Line 140 checks INKEY$ on every pixel. If any key is held, execution jumps to MNU (5000). Because M and N are not reset, menu option 3 (line 5080, GOTO 100) resumes exactly where the run was interrupted. Similarly, after a save/reload cycle, the saved values of M and N allow a seamless continue.

Picture Storage and Save/Restore

Line 9005 dimensions P$(6144), exactly matching the 6144-byte hi-res display memory. The machine code routines ULD and DLD transfer data between this string and the screen, allowing the current image to be preserved across menu operations and saved to tape (line 8040, SAVE N$) along with all program variables.

Zoom Utility

The zoom utility (lines 4000–4450) uses machine code to display and move a flashing cursor pixel. The user navigates to the lower-left corner of the desired area and presses 1 to record A1 and B1 (real and imaginary coordinates), then moves to the upper-right and presses 2 to compute and display the side length. The flag variable B2 is used as state: -1 means no corner selected yet, 0 means corner recorded. This gives the user the new parameters needed to start a zoomed-in run without modifying the current run’s variables.

The zoom loop at line 4120 uses GOTO USR 16963 — a computed GOTO to a machine code routine that reads the cursor keys and updates the pixel position, returning a line number to branch to for each action (move, corner, side, escape).

Key BASIC Idioms

  • VAL "number" in GOTO and GOSUB statements (e.g., lines 9515, 9550) — a memory optimization that stores the target as a short string rather than a floating-point number.
  • Named numeric variables (MNU, PLT, HR, etc.) used as symbolic constants for machine code addresses and line numbers, improving readability.
  • AND used as a conditional string mask at line 5030: ("3: RESUME CURRENT RUN " AND M<192) prints the option only if a run is in progress.
  • POKE VAL "16418",NOT PI at line 9490 — NOT PI evaluates to 0, switching the display to FAST mode by poking 0 into the system variable at 16418.
  • Line 9695 uses POKE VAL "16418",VAL "2" to re-enable SLOW mode.

Parameter Input and Validation

Lines 9000–9180 collect six parameters: A (real corner), B (imaginary corner), S (vertical side length), CA and CB (the generator point from the Mandelbrot set), L (iteration limit), and W (band width). After input, the user is prompted with “OK?” and if the answer is not “Y”, the program restarts with RUN (line 9180), clearing all variables and starting fresh. The grid step G=S/192 is computed at line 9090.

The two dummy FOR loops at lines 9100–9110 (FOR M=0 TO 0, FOR N=0 TO 0) initialize M and N to 0 without a visible loop body, ensuring the rendering loop starts from the top-left pixel.

Help System

Lines 9480–9720 implement a multi-page help and splash screen system. Each page ends with a call to the subroutine at line 9860, which displays a “press a key twice to continue” prompt and waits for a keypress, clears the screen, then waits for the key to be released and a second press before returning. This two-keypress debounce prevents accidental page advances. The user can opt to re-read all help screens or proceed directly to the main menu.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

   0 REM  LOAD [4]VAL ▝""▝AT ▝TAB ▝#▝CODE ▝ STOP LLIST  STEP H▖ LPRINT H▖▀?▘ STEP  LPRINT ▖H??AT ▘""H▖▘H▖?KN ▀N " FAST[5]?VAL  SLOW: ▀JCHR$ [4][4][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 PEEK 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 9E3                                   AND       CODE "[H][R][-][J][U][L][I][A]█[S][E][T][S]     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+(CB+(CA+(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 16582
 8060 GOTO MNU
 9000 RAND USR 16582
 9005 DIM P$(6144)
 9010 CLS
 9020 SLOW
 9030 PRINT " INPUT CO-ORDS OF SW CORNER OF   THE PROPOSED JULIA-SET 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
 9092 PRINT S;AT 9,0;"CO-ORDINATES OF MANDELBROT SET  ""GENERATOR"" (REAL)=";
 9093 INPUT CA
 9094 PRINT CA,TAB 7;"(IMAGINARY)=";
 9095 INPUT CB
 9100 FOR M=0 TO 0
 9110 FOR N=0 TO 0
 9120 PRINT CB;AT 13,0;"ITERATION LIMIT=";
 9130 INPUT L
 9140 PRINT L;AT 15,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=16634
 9210 LET NML=16639
 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 "JUL-FF[P]"
 9482 RAND USR 16582
 9485 CLS
 9487 SLOW
 9490 POKE VAL "16418",NOT PI
 9492 PRINT "[J][U][L][I][A]█[S][E][T][S]█[W][I][T][H][I][N]█[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 ">>>>>>>>>>>[J][U][L][I][A]█[S][E][T][S]<<<<<<<<<<<",,"ARE FRACTALS RELATED TO THE WELLKNOWN MANDELBROT SET. EACH POINTIN THE MANDELBROT SET GIVES RISETO A UNIQUE NEW FRACTAL BASED ONTHE SAME ESSENTIAL ALGORITHM."
 9530 PRINT ,," THIS PROGRAM LETS YOU EXAMINE   ENTIRE OR PARTIAL JULIA SETS;   ITS A ""SEQUEL"" TO MANDEL-FFP."
 9540 PRINT ,," THE COVER SCREEN DISPLAYS ONE   ENTIRE SET, GENERATED BY  THE   POINT -.74543 + .11301(I)","""A""-CORNER=-5/3, ""B""-CORNER=-5/4LENGTH OF SIDE=2.5",,,"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",,,"""CA""=REAL COMP. OF GENERATOR","""CB""=IMAGINARY COMPONENT",,,"""L""=ITERATION LIMIT BEFORE PGM. ASSUMES THAT POINT IS WITHIN SET"
 9570 PRINT ,,"""W""= BAND WIDTH; NO. OF COUNTS  FOR EACH BAND. NORMALLY 1, BUT  IF PICTURE 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