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, 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 | | | +-----------------------------------------------------------------------} gcl0x { 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 | +-----------------------------------------------------------------------} $0300: { Pretty accurate multiply-shift ((A*B)>>7), but it can be off by one } [def push {Extract sign and absolute values} 0 sign= C= {0}A- [if>0 A= 1 sign=] 0 B- [if>0 B= sign 1^ sign=] {Multiply} 7 shift= {Pending shift} $200 [do bit= -$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 A= C B+ C=] bit ShiftRight! if<>0loop] {Shift} [do 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) } [def push 0 X= XX= Y= YY= i= [do 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} i pop ret ] CalcPixel= {-----------------------------------------------------------------------+ |}\vLR>++ ret{ RAM page 4 | +-----------------------------------------------------------------------} $0400: [def push $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} [do {Length of next segment, either horizontal or vertical} DX [if<>0 Width 1- Width= else Height 1- Height=] if>0 [do len= {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} loop] pop ret ] CalcSet= {-----------------------------------------------------------------------+ |}\vLR>++ ret{ RAM page 5 | +-----------------------------------------------------------------------} $0500: { Stupid shift-right function } { XXX Better make a SYS extension for this } [def 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 | +-----------------------------------------------------------------------} $0600: { Main } [do CalcSet! 60 \soundTimer. {For debugging} loop] {-----------------------------------------------------------------------+ | End | +-----------------------------------------------------------------------}
– Marcel