Skip to content

Commit

Permalink
Mandelbrot Example for Minimal 64 Computer (#29)
Browse files Browse the repository at this point in the history
* added error check

* added mandelbrot example for min64

* update documentation and comments
  • Loading branch information
michaelkamprath committed Jul 28, 2023
1 parent b6b71bf commit 7e02749
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 71 deletions.
1 change: 1 addition & 0 deletions examples/slu4-minimal-64/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The following instruction macros have been added in the ISA configuration file f
| `cpy4ai` | absolute address | immediate | Copy 4 bytes of immediate value to memory starting at indicated absolute address. Preserves endian ordering. |
| `cpy4si` | stack offset | immediate | Copy 4 bytes of immediate value to stack at indicated offset. Convert from RAM little endian to stack big endian ordering ordering. |
| `cpy4ss` | stack offset | stack offset | Copy 4 bytes of data from stack starting at indicated offset (2nd operand) to another location in stack starting at indicated offset (1rst operand). Byte ordering is preserved. |
| `cpy4aa` | absolute address | absolute address | Copy 4 bytes starting at source address (secord operand) to destination address (first operand) |

The operand descriptions use the definitions provided by documentation for Minimal 64. You should assume the accumulator (register `A`) is not preserved across any of these macros.

Expand Down
17 changes: 17 additions & 0 deletions examples/slu4-minimal-64/slu4-minimal-64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,23 @@ macros:
- "sts @ARG(0)+2"
- "lds @ARG(1)+3"
- "sts @ARG(0)+3"
cpy4aa:
- operands:
count: 2
operand_sets:
list:
- absolute_address
- absolute_address
instructions:
# Copies from source (arg 1) to destination (arg 0)
- "lda @ARG(1)+0"
- "sta @ARG(0)+0"
- "lda @ARG(1)+1"
- "sta @ARG(0)+1"
- "lda @ARG(1)+2"
- "sta @ARG(0)+2"
- "lda @ARG(1)+3"
- "sta @ARG(0)+3"
inc16a:
- operands:
count: 1
Expand Down
182 changes: 182 additions & 0 deletions examples/slu4-minimal-64/software/mandelbrot.min64
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
; Mandelbrot for the Minimal 64 Home Computer
;
; Approach is to used fixed point math to only use integer operations. A detailed
; explanation of this approach can be found here:
;
; https://github.com/rahra/intfract
;
#require "slu4-min64-asm >= 1.2.0"

IMAGE_X_PIXELS = 400
IMAGE_Y_PIXELS = 240

SCALE_BITS = 10
SCALE_FACTOR = (1 << SCALE_BITS)

MANDELBROT_START_X = -2*SCALE_FACTOR
MANDELBROT_END_X = 1*SCALE_FACTOR
MANDELBROT_STEP_X = (MANDELBROT_END_X - MANDELBROT_START_X)/IMAGE_X_PIXELS

MANDELBROT_START_Y = -1*SCALE_FACTOR
MANDELBROT_END_Y = 1*SCALE_FACTOR
MANDELBROT_STEP_Y = (MANDELBROT_END_Y - MANDELBROT_START_Y)/IMAGE_Y_PIXELS

MAX_ITERATIONS = $FF


.org $8000
init:
spinit ; init stack
jps _Clear
cpy4ai cur_pixel_x,0
cpy4ai cur_pixel_y,0

.pixel_loop_y:
; calculate scaled y0
phs4a cur_pixel_y
phs4i MANDELBROT_STEP_Y
jps multiply_int32 ; results are 64 bit
pls4
phs4i MANDELBROT_START_Y
jps add32
cpy4as scaled_y0,1 ; fetch results
pls4 pls4 ; discard upper 32 bits of multiplications

.pixel_loop_x:
; calcualted scaled x0
phs4a cur_pixel_x
phs4i MANDELBROT_STEP_X
jps multiply_int32 ; results are 64 bit
pls4
phs4i MANDELBROT_START_X
jps add32
cpy4as scaled_x0,1 ; fetch results
pls4 pls4 ;

; check if in mandelbrot set
.init_mandelbrot:
; start interations
ldi 0 sta iteration_count
; initialize zx and zy
cpy4aa zx,scaled_x0
cpy4aa zy,scaled_y0

; push pixel coordinates on stack
phsa cur_pixel_x+0
phsa cur_pixel_x+1
phsa cur_pixel_y+0
jps _SetPixel
pls pls pls

.mandelbrot_loop:
; find zx*zx + zy*zy
phs4a zx
phs4a zx
jps multiply_int32
pls4
phsi SCALE_BITS jps asr32n pls ; rescale
cpy4as zx_squared,1
pls4

phs4a zy
phs4a zy
jps multiply_int32
pls4
phsi SCALE_BITS jps asr32n pls ; rescale
cpy4as zy_squared,1
phs4a zx_squared
jps add32
cpy4as temp_int32,1
pls4 pls4

; check if value is greater than NOT_MANDELBROT_THRESHOLD
phs4a temp_int32 ; left value
phs4i 4*SCALE_FACTOR ; right value
jps compare_int32
pls4 pls4
bgt .not_in_mandelbrot

; increment counter and check count
inb iteration_count
lda iteration_count cpi MAX_ITERATIONS
beq .in_mandelbrot ; if we are at max iterations, point is in set

; set up for next mandelbrot iteration

; zy = 2*zx*zy + scaled_y0
phs4a zx
phs4a zy
jps multiply_int32
pls4 ; remove top 4 bytes
phsi (SCALE_BITS-1) jps asr32n pls ; rescale
; stack now contains 2*zx*zy
phs4a scaled_y0
jps add32
cpy4as zy,1
pls4 pls4

; zx = zx*zx - zy*zy + scaled_x0, but steo in temp for now
phs4a zy_squared ; Y value
phs4a zx_squared ; X value
jps subtract32 ; X-Y
phs4a scaled_x0
jps add32
cpy4as zx,1 ; the new zx value
pls4 pls4 pls4

; next loop
jpa .mandelbrot_loop

.in_mandelbrot:
; push pixel coordinates on stack
phsa cur_pixel_x+0
phsa cur_pixel_x+1
phsa cur_pixel_y+0
jps _ClrPixel
pls pls pls ; remove pixel coordinates from stack
.not_in_mandelbrot:
.mandelbot_pixel_done:

.pixel_loop_x_end:
; next x pixel
inc32a cur_pixel_x
; check to see if we are done with current x row
phs4i IMAGE_X_PIXELS
phs4a cur_pixel_x
jps compare_uint32
pls4 pls4
bne .pixel_loop_x
cpy4ai cur_pixel_x,0

.pixel_loop_y_end:
; next y pixel
inc32a cur_pixel_y
; check to see if we are done overall
phs4i IMAGE_Y_PIXELS
phs4a cur_pixel_y
jps compare_uint32
pls4 pls4
bne .pixel_loop_y

.looping_done:
ldi 0 sta _XPos ldi 29 sta _YPos
jps _ScrollUp
jpa _Prompt

;
; Variables
;

cur_pixel_x: .4byte 0
cur_pixel_y: .4byte 0
scaled_x0: .4byte 0
scaled_y0: .4byte 0
zx: .4byte 0
zy: .4byte 0
zx_squared: .4byte 0
zy_squared: .4byte 0
temp_int32: .4byte 0
iteration_count: .byte 0

#include "math32lib.min64"
#include "stringlib.min64"
Loading

0 comments on commit 7e02749

Please sign in to comment.