That was the month and year I discovered the Mandelbrot Set. My dad was a subscriber to Scientific American Magazine and in August, 1985 issue, the Mandelbrot Set was featured on the cover. I couldn’t get enough of the amazing pictures I saw inside the article.
At the time, I had a Commodore 64, but my dad had an IBM XT with an EGA graphics adapter. That meant I could display a 640×350 with 16 colors, and it was fast, 4.77MHz! It was also much easier to program graphics using IBM’s BASICA verses the C64 Basic V2. So I dug in and wrote a program to make my own Mandelbrot pictures. I could sit there for hours watching the computer slowly drawing each pixel.
After finishing up writing Lunar Lander recently, I wanted a change of pace. I had learned a bunch about setting up the graphics for the game. I also learned a bunch about using bitmaps. I wan’t successful making Lunar Lander with a bitmap screen, but I really wanted to do something to make the C64 use its graphics screen. I also wanted to do it in machine language.
At the time, I was also looking for something on the C64 to generate the Mandelbrot Set. No real reason, I just wanted to see the machine make pretty pictures. After some searching, I didn’t really find anything I was looking for. So it seemed like the perfect little project for me to tackle.
I started by writing a program using Simons’ Basic to draw my first few fractals. I did some research online and found some BASIC example code for making the Mandelbrot Set. As you can imagine, it was really slow. I also don’t like writing programs that need something extra to make them work. In this case Simons’ Basic. I hated that as a kid because there were a bunch of programs I wanted to run, but was unable to because I was missing some enhanced version of something. I always want my programs to run on a vanilla Commodore 64!
Writing the entire program in BASIC, graphics and all, would have been even slower than it was already running. I needed to do some of this in machine language! There was 1 major issue though.
Floating Point Math in Assembly
I had no idea how to do floating point numbers and math in machine language. Everything up to this point for me has been integer numbers. The most complex concept I had mastered was simple in comparison. So I went to the internet looking for answers. I eventually found exactly what I was looking for from www.codebase64.org. It is a machine language program for the 64 that calculates the Mandelbrot Set and outputs it to the character screen. How it does the math was ingenious to me!
Not BASIC, but BASIC!
I don’t know who the programmer is for the article is, but what the person did was call out BASIC routines from within the assembly code. Macros were set up at the beginning of the code for the different operations needed and called later in the program as needed.
The only other issue I had is storing floating point numbers in assembly. The answer for that is, since BASIC routines are being used, the number would need to be stored the way BASIC stores them.
BASIC uses 7 bytes to store a number. The first two bytes are for the variable name, the other 5 are used to store the floating point number. In machine language, you can get rid of the first two byte and just use 5 because the ML program needs to keep track of where these variable are, not BASIC. My problem now is that I need to change some of the floating point variables set in the program. I wanted to make a 320×200 multicolor picture, not a 40×24 character screen image. I needed to change 320×200 into 5 bytes each. I had no idea how to do this (and still don’t). I researched the internet again (including codebase64.org) and simply couldn’t wrap my head around it. My problem was, I still needed to change those numbers!
I had my solution when looking through my worn copy of Jim Butterfield’s Machine Language for the Commodore 64, 128, and Other Commodore Computers. In chapter 6, he talks about linking BASIC and machine language together and discusses the BASIC pointers (memory locations 45 and 46) that point to where variables start in memory and how to read those variables. From that, I wrote a little program that lets me input a number with the result being the 5 bytes, in hex, that BASIC sees internally to process them. You can load FLOAT NUMBERS from the d64 image and try it out.
10 INPUT WI 12 IF WI=0THENEND 15 HX$="0123456789ABCDEF" 20 A=PEEK(45):B=PEEK(46) 30 C=B*256+A 40 PRINT:PRINTWI:PRINT 50 FORN=CTOC+6 60 IF N<C+2THENPRINTCHR$(PEEK(N)); 62 IF N>C+1 THEN GOSUB 100 70 NEXTN 75 PRINT:PRINT 80 RUN 100 G=PEEK(N) 110 H=INT(G/16)+1 120 L=((G/16)-(INT(G/16)))*16+1 130 PRINT" $"MID$(HX$,H,1);MID$(HX$,L,1); 140 RETURN
Line 20 looks up the Start of Variables (SOV) pointer and line 30 calculates the full address. I used variable WI for the floating point number and put it first so that it would be the first variable in line after the BASIC program. Because floating point variables are placed directly after the BASIC program, the SOV pointer will continue to change as you add or subtract to the program. That is why it needs to be a dynamic variable calculated within the program.
Learning this came in handy because after I wrote the machine language program to calculate and draw the Mandelbrot Set, I decided to write the front end interface in BASIC. The BASIC program and the ML program need to communicate back and forth seamlessly for it to work well.
There’s lots more to talk about, but right now, download the software and try it out. Here are a few good coordinates to investigate. (The higher the iterations, the better detail, the longer the render)
xmin = -.375 xmax = .125 ymin = .682 ymax = 1.122 iterations = 28
xmin = .33125 xmax = .43125 ymin = -.131999999 ymax = -.0439999995 iterations = 32
xmin = .3875 xmax = .4875 ymin = -.4048 ymax = -.3168 iterations = 25
Until next time,