6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 12:01 am

All times are UTC




Post new topic Reply to topic  [ 1 post ] 
Author Message
PostPosted: Tue Oct 27, 2020 7:12 pm 
Offline

Joined: Wed Jan 08, 2014 3:31 pm
Posts: 578
I decided to revisit the Mandelbrot set, but in assembler to see how much faster I could make it than my Forth version. While I'm not an assembler wizard, I'm competent enough, especially when I reuse code libraries to do the hard part of multiplication.

The net result is that assembler is about 4 times faster than Forth, and about 20 times faster than ehBasic. This makes sense when you consider that much of my code uses a Forth like approach, but with primitives like push or drop in-lined rather than called via a subroutine.

Video: https://youtu.be/W24UmuEV0Uc

Github repo: https://github.com/Martin-H1/6502/blob/master/FunStuff/mandelbrot.asm

The code depends upon a 16 bit math library and page zero stack macros, but the basic flow is understandable without them. So here's the code with the unused 4.12 fixed point removed:
Code:
; -----------------------------------------------------------------------------
; Mandelbrot in ASCI art. It uses 8.8 fixed point mathematics in a 16 bit cell
; instead of floating point. It depends upon the stack, math, and I/O functions
; defined in the other modules.
; Martin Heermance <mheermance@gmail.com>
; -----------------------------------------------------------------------------

; establish module level scope to hide module locals.
.scope

;
; Aliases
;

; Setup constants to remove magic numbers to allow
; for greater zoom with different scale factors.
.alias MAXITER   20
.alias IMAXVAL   $0170
.alias IMINVAL   $FE90
.alias ISTEP   $0010
.alias RMINVAL   $FE00
.alias RMAXVAL   $0110
.alias RSTEP   $000A
.alias ESCAPE   $0400

;
; Data segments
;
.data BSS
.space CREAL 2         ; These variables hold values during the
.space CIMAG 2         ; escape calculation.
.space ZREAL 2
.space ZIMAG 2
.space COUNT 1         ; current escape count

.text

;
; Macros
;
.macro rescale
   lda NOS_MSB,x
   sta NOS_LSB,x
   lda TOS_LSB,x
   sta NOS_MSB,x
   `drop
.macend

;
; Functions
;

; Main entry point
mandelbrot:
.scope
   `printcr
   `pushi IMAXVAL      ; Start iteration at max imaginary
_do:   jsr doRow      ; For each row in the set.
   `printcr
   `pushi ISTEP
   jsr sub16
   `dup
   `pushi IMINVAL
   jsr compare16
   bmi _do
   `drop
   rts
.scend

; For each cell in a row.
doRow:
.scope
   `pushi RMINVAL      ; Start iteration at max imaginary
_do:   jsr doCell      ; For each row in the set.
   `pushi RSTEP
   jsr add16
   `dup
   `pushi RMAXVAL
   jsr compare16
   bpl _do
   `drop
   rts
.scend

; Iterates on a single cell to compute its escape factor.
; input - row and column on stack.
; output - none
doCell:
   jsr initVars
   `pushZero      ; set the loop up for repeating
_while:
   `drop         ; drop status from last iteration.
   jsr doEscape
   `tosZero?
   beq _while
   `drop
   lda COUNT
   jsr toChar
   rts

; stores the row column values from the stack for the escape calculation.
; input - two cells on stack
; output - none
initVars:
   `over
   `over
   `pop CREAL
   `pop CIMAG
   `pushzero
   `peek ZREAL
   `pop ZIMAG
   lda #$01
   sta COUNT
   rts

; Performs a single iteration of the escape calculation.
; input - implicit from memory.
; ouput - true or false.
doEscape:
.scope
   jsr zrSq
   jsr ziSq
   `over
   `over
   jsr add16
   `pushi ESCAPE      ; Numbers >= 4 will always escape
   jsr compare16
   beq +
   bpl _else
*   `drop         ; cleanup the stack and return.
   `drop
   `pushTrue
   rts
_else:
   jsr sub16      ; Squared i yeilds negative, so subtract
   `push CREAL
   jsr add16      ; add real components and leave result on stack
   `push ZREAL      ; 2 * ZREAL * ZIMAG
   `push ZIMAG
   jsr mstar
   `rescale
   `pushi 1
   jsr lshift16
   `push CIMAG
   jsr add16
   `pop ZIMAG      ; Store stack item into ZIMAG and ZREAL
   `pop ZREAL
   jmp countAndTest
.scend

; Compute squares, but rescale to remove extra scaling factor.
; input - implicit from memory
; output - value on stack
zrSq:
   `push ZREAL
   `dup
   jsr mstar      ; rescale by shifting one byte
   `rescale
   rts

; Compute squares, but rescale to remove extra scaling factor.
; input - implicit from memory
; output - value on stack
ziSq:
   `push ZIMAG
   `dup
   jsr mstar      ; rescale by shifting one byte
   `rescale
   rts

; Translate escape count to ascii greyscale.
; input - value in accumulator
; output - character to console.
toChar:
   phy
   tay
   lda _charVals,y
   jsr putch
   ply
   rts
_charVals:
   .byte " ..,'~!^:;[/<&?oxOX#  "

; Increment count and compare to max iterations.
; input - implicit from memory
; output - true or false on stack
countAndTest:
.scope
   inc COUNT
   lda COUNT
   `pushA
   `pushi MAXITER
   `if_greater16
   `pushTrue
   rts
_else:   `pushZero
   rts
.scend

.scend


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 18 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: