https://github.com/akkartik/mu/blob/main/mandelbrot-silhouette.mu
  1 # Mandelbrot set
  2 #
  3 # Install:
  4 #   $ git clone https://github.com/akkartik/mu
  5 #   $ cd mu
  6 # Build on Linux:
  7 #   $ ./translate mandelbrot.mu
  8 # Build on other platforms (slow):
  9 #   $ ./translate_emulated mandelbrot.mu
 10 # Run:
 11 #   $ qemu-system-i386 code.img
 12 
 13 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
 14   mandelbrot screen
 15 }
 16 
 17 fn mandelbrot screen: (addr screen) {
 18   var a/eax: int <- copy 0
 19   var b/ecx: int <- copy 0
 20   a, b <- screen-size screen
 21   var width/esi: int <- copy a
 22   width <- shift-left 3/log2-font-width
 23   var height/edi: int <- copy b
 24   height <- shift-left 4/log2-font-height
 25   var y/ecx: int <- copy 0
 26   {
 27     compare y, height
 28     break-if->=
 29     var imaginary/xmm1: float <- viewport-to-imaginary y, width, height
 30     var x/edx: int <- copy 0
 31     {
 32       compare x, width
 33       break-if->=
 34       var real/xmm0: float <- viewport-to-real x, width
 35       var iterations/eax: int <- mandelbrot-iterations-for-point real, imaginary, 0x400/max
 36       compare iterations, 0x400/max
 37       {
 38         break-if->=
 39         pixel screen, x, y, 0xf/white
 40       }
 41       compare iterations, 0x400/max
 42       {
 43         break-if-<
 44         pixel screen, x, y, 0/black
 45       }
 46       x <- increment
 47       loop
 48     }
 49     y <- increment
 50     loop
 51   }
 52 }
 53 
 54 fn mandelbrot-iterations-for-point real: float, imaginary: float, max: int -> _/eax: int {
 55   var zero: float
 56   var x/xmm0: float <- copy zero
 57   var y/xmm1: float <- copy zero
 58   var iterations/ecx: int <- copy 0
 59   {
 60     var done?/eax: boolean <- mandelbrot-done? x, y
 61     compare done?, 0/false
 62     break-if-!=
 63     compare iterations, max
 64     break-if->=
 65     var newx/xmm2: float <- mandelbrot-x x, y, real
 66     var newy/xmm3: float <- mandelbrot-y x, y, imaginary
 67     x <- copy newx
 68     y <- copy newy
 69     iterations <- increment
 70     loop
 71   }
 72   return iterations
 73 }
 74 
 75 fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
 76   # x*x + y*y > 4
 77   var x2/xmm0: float <- copy x
 78   x2 <- multiply x
 79   var y2/xmm1: float <- copy y
 80   y2 <- multiply y
 81   var sum/xmm0: float <- copy x2
 82   sum <- add y2
 83   var four/eax: int <- copy 4
 84   var four-f/xmm1: float <- convert four
 85   compare sum, four-f
 86   {
 87     break-if-float>
 88     return 0/false
 89   }
 90   return 1/true
 91 }
 92 
 93 fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
 94   # x*x - y*y + real
 95   var x2/xmm0: float <- copy x
 96   x2 <- multiply x
 97   var y2/xmm1: float <- copy y
 98   y2 <- multiply y
 99   var result/xmm0: float <- copy x2
100   result <- subtract y2
101   result <- add real
102   return result
103 }
104 
105 fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
106   # 2*x*y + imaginary
107   var two/eax: int <- copy 2
108   var result/xmm0: float <- convert two
109   result <- multiply x
110   result <- multiply y
111   result <- add imaginary
112   return result
113 }
114 
115 # Scale (x, y) pixel coordinates to a complex plane where the viewport width
116 # ranges from -2 to +2. Viewport height just follows the viewport's aspect
117 # ratio.
118 
119 fn viewport-to-real x: int, width: int -> _/xmm0: float {
120   # (x - width/2)*4/width
121   var result/xmm0: float <- convert x
122   var width-f/xmm1: float <- convert width
123   var two/eax: int <- copy 2
124   var two-f/xmm2: float <- convert two
125   var half-width-f/xmm2: float <- reciprocal two-f
126   half-width-f <- multiply width-f
127   result <- subtract half-width-f
128   var four/eax: int <- copy 4
129   var four-f/xmm2: float <- convert four
130   result <- multiply four-f
131   result <- divide width-f
132   return result
133 }
134 
135 fn viewport-to-imaginary y: int, width: int, height: int -> _/xmm1: float {
136   # (y - height/2)*4/width
137   var result/xmm0: float <- convert y
138   var height-f/xmm1: float <- convert height
139   var half-height-f/xmm1: float <- copy height-f
140   var two/eax: int <- copy 2
141   var two-f/xmm2: float <- convert two
142   half-height-f <- divide two-f
143   result <- subtract half-height-f
144   var four/eax: int <- copy 4
145   var four-f/xmm1: float <- convert four
146   result <- multiply four-f
147   var width-f/xmm1: float <- convert width
148   result <- divide width-f
149   return result
150 }