https://github.com/akkartik/mu/blob/main/mandelbrot.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 }