Mandelbrot from TTL

I got a bit stuck with the work I was planning for today, so I wrote something else to regain motivation: a fractal! Rendering takes a while (8242 seconds), being fully interpreted and lacking multiplication, and even without the “right-shift” operation you badly need for this. All those must be mimicked with slow high-level code using just addition and subtraction.

It should be easy to speed the whole thing up a lot just by adding a right-shift assembly function. Next time… GCL source code:

| |
| Mandelbrot fractal |
| |


Plot the Mandelbrot set

- 160x120 pixels and 64 colors
- Faithful translation of mandelbrot.c pre-study
- Use 16-bit vCPU math as 7-bit fixed point arithmetic (1.00 -> 128)
- Implement multiplication in interpreter
- Implement shift-right in interpreter as well
- A bit slow (8242.655 seconds)

XXX At the end change all to grey tones and redo
XXX Redo at different sections
XXX Tone for every pixel value

| RAM page 3 |

{ Pretty accurate multiply-shift ((A*B)>>7), but it can be off by one }

{Extract sign and absolute values}
0 sign= C=
{0}A- [if>0 A= 1 sign=]
0 B- [if>0 B= sign 1^ sign=]

7 shift= {Pending shift}
-$4000 C+ [if<0 C C+ C= else {Shift prematurely in an attempt to avoid overflow} B ShiftRight! B= shift 1- shift=] {Add partial product} A bit- [if>=0
C B+ C=]

bit ShiftRight! if<>0loop]

C ShiftRight! C=
shift 1- shift= if>0loop]

{Apply sign to return value}
sign [if<>0 0 C- else C]

pop ret
] MulShift7=

{ Calculate color for (X0,Y0) }
0 X= XX= Y= YY= i=
i 1+ i= 64^ if<>0 {Break after 64 iterations}

{Mandelbrot function: z' := z^2 + c}
X A= Y Y+ B= MulShift7! Y0+ Y= {Y = 2*X*Y + Y0}
XX YY- X0+ X= {X = X^2 - Y^2 + X0}

{Calculate squares}
{X}A= B= MulShift7! XX=
Y A= B= MulShift7! YY=

-$200 XX+ YY+ if<0loop] {Also break when X^2 + Y^2 >= 4}
pop ret
] CalcPixel=

|}\vLR>++ ret{ RAM page 4 |


$7ff p= {Start of video (minus 1 to compensate for 1st step)}

-323 X0= 3 DX= 161 Width= {Horizontal parameters}
-180 Y0= 0 DY= 120 Height= {Vertical parameters}

{Length of next segment, either horizontal or vertical}
DX [if<>0 Width 1- Width= else Height 1- Height=] if>0

{Step in the fractal plane}
X0 DX+ X0=
Y0 DY+ Y0=

{Matching step in video frame}
DX [if<0 p 1- p=] DX [if>0 p 1+ p=]
DY [if<0 -$100 p+ p=] DY [if>0 $100 p+ p=]

63 p. {White while busy here}

{First check if we are inside one of the main bulbs for
a quick bailout (Wikipedia)
(x+1)^ + y^2 < 1/16} Y0 A= B= MulShift7! YY= X0 128+ A= B= MulShift7! YY+ 8- [if<0 0 else {q*(q + x - 1/4) < 1/4*y^2, where q = (x - 1/4)^2 + y^2} X0 32- A= B= MulShift7! YY+ {q} A= X0+ 32- B= MulShift7! tmp= tmp+ tmp= tmp+ tmp= {*4} YY- [if<0 0 else {Otherwise run the escape algorithm} CalcPixel! ]] p. {Plot pixel} len 1- if>0loop]

DY tmp= DX DY= 0 tmp- DX= {Turn right}
pop ret
] CalcSet=

|}\vLR>++ ret{ RAM page 5 |

{ Stupid shift-right function }
{ XXX Better make a SYS extension for this }
a= 0 b=
$8000 a+ [if>=0 a= $4000 b+ b=]
$c000 a+ [if>=0 a= $2000 b+ b=]
$e000 a+ [if>=0 a= $1000 b+ b=]
$f000 a+ [if>=0 a= $0800 b+ b=]
$f800 a+ [if>=0 a= $0400 b+ b=]
$fc00 a+ [if>=0 a= $0200 b+ b=]
$fe00 a+ [if>=0 a= $0100 b+ b=]
$ff00 a+ [if>=0 a= $0080 b+ b=]
$ff80 a+ [if>=0 a= $0040 b+ b=]
$ffc0 a+ [if>=0 a= $0020 b+ b=]
$ffe0 a+ [if>=0 a= $0010 b+ b=]
$fff0 a+ [if>=0 a= $0008 b+ b=]
$fff8 a+ [if>=0 a= $0004 b+ b=]
$fffc a+ [if>=0 a= $0002 b+ b=]
a 2& [if<>0 b<++ ] b ret ] ShiftRight= {-----------------------------------------------------------------------+ |}\vLR>++ ret{ RAM page 6 |

{ Main }
60 \soundTimer. {For debugging}

| End |

– Marcel

Leave a Reply

Your email address will not be published. Required fields are marked *