mandelbrot set in fixed-point
This commit is contained in:
parent
14b7162bd6
commit
b94e1fec30
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue