about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--mandelbrot-fixed.mu224
-rw-r--r--mandelbrot.mu30
2 files changed, 239 insertions, 15 deletions
diff --git a/mandelbrot-fixed.mu b/mandelbrot-fixed.mu
new file mode 100644
index 00000000..d380c29c
--- /dev/null
+++ b/mandelbrot-fixed.mu
@@ -0,0 +1,224 @@
+# Mandelbrot set using fixed-point numbers.
+#
+# To build:
+#   $ ./translate mandelbrot-fixed.mu
+# To run:
+#   $ qemu-system-i386 code.img
+
+fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
+  mandelbrot screen
+}
+
+# Since they still look like int types, we'll append a '-f' suffix to variable
+# names to designate fixed-point numbers.
+
+fn int-to-fixed in: int -> _/eax: int {
+  var result-f/eax: int <- copy in
+  result-f <- shift-left 8/fixed-precision
+  {
+    break-if-not-overflow
+    abort "int-to-fixed: overflow"
+  }
+  return result-f
+}
+
+fn fixed-to-int in-f: int -> _/eax: int {
+  var result/eax: int <- copy in-f
+  result <- shift-right-signed 8/fixed-precision
+  return result
+}
+
+fn test-fixed-conversion {
+  # 0
+  var f/eax: int <- int-to-fixed 0
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, 0, "F - test-fixed-conversion - 0"
+  # 1
+  var f/eax: int <- int-to-fixed 1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, 1, "F - test-fixed-conversion - 1"
+  # -1
+  var f/eax: int <- int-to-fixed -1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, -1, "F - test-fixed-conversion - -1"
+  # 0.5 = 1/2
+  var f/eax: int <- int-to-fixed 1
+  f <- shift-right-signed 1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, 0, "F - test-fixed-conversion - 0.5"
+  # -0.5 = -1/2
+  var f/eax: int <- int-to-fixed -1
+  f <- shift-right-signed 1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, -1, "F - test-fixed-conversion - -0.5"
+  # 1.5 = 3/2
+  var f/eax: int <- int-to-fixed 3
+  f <- shift-right-signed 1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, 1, "F - test-fixed-conversion - 1.5"
+  # -1.5 = -3/2
+  var f/eax: int <- int-to-fixed -3
+  f <- shift-right-signed 1
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, -2, "F - test-fixed-conversion - -1.5"
+  # 1.25 = 5/4
+  var f/eax: int <- int-to-fixed 5
+  f <- shift-right-signed 2
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, 1, "F - test-fixed-conversion - 1.25"
+  # -1.25 = -5/4
+  var f/eax: int <- int-to-fixed -5
+  f <- shift-right-signed 2
+  var result/eax: int <- fixed-to-int f
+  check-ints-equal result, -2, "F - test-fixed-conversion - -1.25"
+}
+
+# special routines for multiplying and dividing fixed-point numbers
+
+fn multiply-fixed a: int, b: int -> _/eax: int {
+  var result/eax: int <- copy a
+  result <- multiply b
+  {
+    break-if-not-overflow
+    abort "multiply-fixed: overflow"
+  }
+  result <- shift-right-signed 8/fixed-precision
+  return result
+}
+
+fn divide-fixed a-f: int, b-f: int -> _/eax: int {
+  var result-f/eax: int <- copy a-f
+  result-f <- shift-left 8/fixed-precision
+  {
+    break-if-not-overflow
+    abort "divide-fixed: overflow"
+  }
+  var dummy-remainder/edx: int <- copy 0
+  result-f, dummy-remainder <- integer-divide result-f, b-f
+  return result-f
+}
+
+# multiplying or dividing by an integer can use existing instructions.
+
+# adding and subtracting two fixed-point numbers can use existing instructions.
+
+fn mandelbrot screen: (addr screen) {
+  var a/eax: int <- copy 0
+  var b/ecx: int <- copy 0
+  a, b <- screen-size screen
+  var width-f/esi: int <- copy a
+  width-f <- shift-left 0xb/log2-font-width-and-fixed-precision  # 3 + 8 = 11
+  var height-f/edi: int <- copy b
+  height-f <- shift-left 0xc/log2-font-height-and-fixed-precision  # 4 + 8 = 12
+  # it might make sense to keep x and y as regular ints
+  # treating them as fixed-point for demonstration purposes
+  var y-f/ecx: int <- copy 0
+  {
+    compare y-f, height-f
+    break-if->=
+    var imaginary-f/ebx: int <- mandelbrot-min-y y-f, width-f, height-f
+    var x-f/eax: int <- copy 0
+    {
+      compare x-f, width-f
+      break-if->=
+      var real-f/edx: int <- mandelbrot-min-x x-f, width-f
+      var iterations/esi: int <- mandelbrot-pixel real-f, imaginary-f, 0x400/max
+      {
+        var x: int
+        var y: int
+        var tmp/eax: int <- fixed-to-int x-f
+        copy-to x, tmp
+        tmp <- fixed-to-int y-f
+        copy-to y, tmp
+        compare iterations, 0x400/max
+        {
+          break-if->=
+          pixel screen, x, y, 0xf/white
+        }
+        compare iterations, 0x400/max
+        {
+          break-if-<
+          pixel screen, x, y, 0/black
+        }
+      }
+      x-f <- add 0x100/1
+      loop
+    }
+    y-f <- add 0x100/1
+    loop
+  }
+}
+
+fn mandelbrot-pixel real-f: int, imaginary-f: int, max: int -> _/esi: int {
+  var x-f/esi: int <- copy 0
+  var y-f/edi: int <- copy 0
+  var iterations/ecx: int <- copy 0
+  {
+    var done?/eax: boolean <- mandelbrot-done? x-f, y-f
+    compare done?, 0/false
+    break-if-!=
+    compare iterations, max
+    break-if->=
+    var x2-f/edx: int <- mandelbrot-x x-f, y-f, real-f
+    var y2-f/ebx: int <- mandelbrot-y x-f, y-f, imaginary-f
+    x-f <- copy x2-f
+    y-f <- copy y2-f
+    iterations <- increment
+    loop
+  }
+  return iterations
+}
+
+fn mandelbrot-done? x-f: int, y-f: int -> _/eax: boolean {
+  # x*x + y*y > 4
+  var tmp-f/eax: int <- multiply-fixed x-f, x-f
+  var result-f/ecx: int <- copy tmp-f
+  tmp-f <- multiply-fixed y-f, y-f
+  result-f <- add tmp-f
+  compare result-f, 0x400/4
+  {
+    break-if->
+    return 0/false
+  }
+  return 1/true
+}
+
+fn mandelbrot-x x-f: int, y-f: int, real-f: int -> _/edx: int {
+  # x*x - y*y + real
+  var tmp-f/eax: int <- multiply-fixed x-f, x-f
+  var result-f/ecx: int <- copy tmp-f
+  tmp-f <- multiply-fixed y-f, y-f
+  result-f <- subtract tmp-f
+  result-f <- add real-f
+  return result-f
+}
+
+fn mandelbrot-y x-f: int, y-f: int, imaginary-f: int -> _/ebx: int {
+  # 2*x*y + imaginary
+  var result-f/eax: int <- copy x-f
+  result-f <- shift-left 1/log2
+  result-f <- multiply-fixed result-f, y-f
+  result-f <- add imaginary-f
+  return result-f
+}
+
+fn mandelbrot-min-x x-f: int, width-f: int -> _/edx: int {
+  # (x - width/2)*4/width
+  var result-f/eax: int <- copy x-f
+  var half-width-f/ecx: int <- copy width-f
+  half-width-f <- shift-right-signed 1/log2
+  result-f <- subtract half-width-f
+  result-f <- shift-left 2/log4
+  result-f <- divide-fixed result-f, width-f
+  return result-f
+}
+
+fn mandelbrot-min-y y-f: int, width-f: int, height-f: int -> _/ebx: int {
+  # (y - height/2)*4/width
+  var result-f/eax: int <- copy y-f
+  shift-right-signed height-f, 1/log2
+  result-f <- subtract height-f
+  result-f <- shift-left 2/log4
+  result-f <- divide-fixed result-f, width-f
+  return result-f
+}
diff --git a/mandelbrot.mu b/mandelbrot.mu
index b1ba818e..46f91bd4 100644
--- a/mandelbrot.mu
+++ b/mandelbrot.mu
@@ -21,18 +21,18 @@ fn mandelbrot screen: (addr screen) {
   {
     compare y, height
     break-if->=
-#?     var new-x/eax: int <- render-float-decimal 0/screen, seed-y, 3, 0/x, 0/y, 7/fg, 0/bg
-    var seed-y/xmm1: float <- mandelbrot-min-y y, width, height
+#?     var new-x/eax: int <- render-float-decimal 0/screen, imaginary, 3, 0/x, 0/y, 7/fg, 0/bg
+    var imaginary/xmm1: float <- mandelbrot-min-y y, width, height
     var x/edx: int <- copy 0
     {
       compare x, width
       break-if->=
-      var seed-x/xmm0: float <- mandelbrot-min-x x, width
+      var real/xmm0: float <- mandelbrot-min-x x, width
       var new-x/eax: int <- copy 0
-      new-x <- render-float-decimal 0/screen, seed-x, 3, new-x, 0/y, 7/fg, 0/bg
+      new-x <- render-float-decimal 0/screen, real, 3, new-x, 0/y, 7/fg, 0/bg
       new-x <- increment
-      new-x <- render-float-decimal 0/screen, seed-y, 3, new-x, 0/y, 7/fg, 0/bg
-      var iterations/eax: int <- mandelbrot-pixel seed-x, seed-y, 0x400/max
+      new-x <- render-float-decimal 0/screen, imaginary, 3, new-x, 0/y, 7/fg, 0/bg
+      var iterations/eax: int <- mandelbrot-pixel real, imaginary, 0x400/max
       set-cursor-position 0/screen 0/x 1/y
       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, iterations, 7/fg, 0/bg
       compare iterations, 0x400/max
@@ -53,7 +53,7 @@ fn mandelbrot screen: (addr screen) {
   }
 }
 
-fn mandelbrot-pixel seed-x: float, seed-y: float, max: int -> _/eax: int {
+fn mandelbrot-pixel real: float, imaginary: float, max: int -> _/eax: int {
   var zero: float
   var x/xmm0: float <- copy zero
   var y/xmm1: float <- copy zero
@@ -64,8 +64,8 @@ fn mandelbrot-pixel seed-x: float, seed-y: float, max: int -> _/eax: int {
     break-if-!=
     compare iterations, max
     break-if->=
-    var newx/xmm2: float <- mandelbrot-x x, y, seed-x
-    var newy/xmm3: float <- mandelbrot-y x, y, seed-y
+    var newx/xmm2: float <- mandelbrot-x x, y, real
+    var newy/xmm3: float <- mandelbrot-y x, y, imaginary
     x <- copy newx
     y <- copy newy
     iterations <- increment
@@ -93,25 +93,25 @@ fn mandelbrot-done? x: float, y: float -> _/eax: boolean {
   return 1/true
 }
 
-fn mandelbrot-x x: float, y: float, seed-x: float -> _/xmm2: float {
-  # x*x - y*y + seed-x
+fn mandelbrot-x x: float, y: float, real: float -> _/xmm2: float {
+  # x*x - y*y + real
   var x2/xmm0: float <- copy x
   x2 <- multiply x
   var y2/xmm1: float <- copy y
   y2 <- multiply y
   var result/xmm0: float <- copy x2
   result <- subtract y2
-  result <- add seed-x
+  result <- add real
   return result
 }
 
-fn mandelbrot-y x: float, y: float, seed-y: float -> _/xmm3: float {
-  # 2*x*y + seed-y
+fn mandelbrot-y x: float, y: float, imaginary: float -> _/xmm3: float {
+  # 2*x*y + imaginary
   var two/eax: int <- copy 2
   var result/xmm0: float <- convert two
   result <- multiply x
   result <- multiply y
-  result <- add seed-y
+  result <- add imaginary
   return result
 }