mirror of
https://github.com/irmen/prog8.git
synced 2024-12-30 11:30:15 +00:00
646 lines
12 KiB
NASM
646 lines
12 KiB
NASM
; Prog8 internal Math library routines - always included by the compiler
|
|
;
|
|
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|
;
|
|
; indent format: TABS, size=8
|
|
|
|
|
|
; some more interesting routines can be found here:
|
|
; http://6502org.wikidot.com/software-math
|
|
; http://codebase64.org/doku.php?id=base:6502_6510_maths
|
|
;
|
|
|
|
multiply_bytes .proc
|
|
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
|
|
sta c64.SCRATCH_ZPB1 ; num1
|
|
sty c64.SCRATCH_ZPREG ; num2
|
|
lda #0
|
|
beq _enterloop
|
|
_doAdd clc
|
|
adc c64.SCRATCH_ZPB1
|
|
_loop asl c64.SCRATCH_ZPB1
|
|
_enterloop lsr c64.SCRATCH_ZPREG
|
|
bcs _doAdd
|
|
bne _loop
|
|
rts
|
|
.pend
|
|
|
|
|
|
multiply_bytes_16 .proc
|
|
; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
|
|
sta c64.SCRATCH_ZPB1
|
|
sty c64.SCRATCH_ZPREG
|
|
stx c64.SCRATCH_ZPREGX
|
|
lda #0
|
|
ldx #8
|
|
lsr c64.SCRATCH_ZPB1
|
|
- bcc +
|
|
clc
|
|
adc c64.SCRATCH_ZPREG
|
|
+ ror a
|
|
ror c64.SCRATCH_ZPB1
|
|
dex
|
|
bne -
|
|
tay
|
|
lda c64.SCRATCH_ZPB1
|
|
ldx c64.SCRATCH_ZPREGX
|
|
rts
|
|
.pend
|
|
|
|
|
|
multiply_words .proc
|
|
; -- multiply two 16-bit words into a 32-bit result (signed and unsigned)
|
|
; input: A/Y = first 16-bit number, c64.SCRATCH_ZPWORD1 in ZP = second 16-bit number
|
|
; output: multiply_words.result 4-bytes/32-bits product, LSB order (low-to-high)
|
|
|
|
sta c64.SCRATCH_ZPWORD2
|
|
sty c64.SCRATCH_ZPWORD2+1
|
|
stx c64.SCRATCH_ZPREGX
|
|
|
|
mult16 lda #$00
|
|
sta result+2 ; clear upper bits of product
|
|
sta result+3
|
|
ldx #16 ; for all 16 bits...
|
|
- lsr c64.SCRATCH_ZPWORD1+1 ; divide multiplier by 2
|
|
ror c64.SCRATCH_ZPWORD1
|
|
bcc +
|
|
lda result+2 ; get upper half of product and add multiplicand
|
|
clc
|
|
adc c64.SCRATCH_ZPWORD2
|
|
sta result+2
|
|
lda result+3
|
|
adc c64.SCRATCH_ZPWORD2+1
|
|
+ ror a ; rotate partial product
|
|
sta result+3
|
|
ror result+2
|
|
ror result+1
|
|
ror result
|
|
dex
|
|
bne -
|
|
ldx c64.SCRATCH_ZPREGX
|
|
rts
|
|
|
|
result .byte 0,0,0,0
|
|
.pend
|
|
|
|
|
|
divmod_ub .proc
|
|
; -- divide A by Y, result quotient in Y, remainder in A (unsigned)
|
|
; division by zero will result in quotient = 255 and remainder = original number
|
|
sty c64.SCRATCH_ZPREG
|
|
sta c64.SCRATCH_ZPB1
|
|
stx c64.SCRATCH_ZPREGX
|
|
|
|
lda #0
|
|
ldx #8
|
|
asl c64.SCRATCH_ZPB1
|
|
- rol a
|
|
cmp c64.SCRATCH_ZPREG
|
|
bcc +
|
|
sbc c64.SCRATCH_ZPREG
|
|
+ rol c64.SCRATCH_ZPB1
|
|
dex
|
|
bne -
|
|
ldy c64.SCRATCH_ZPB1
|
|
ldx c64.SCRATCH_ZPREGX
|
|
rts
|
|
.pend
|
|
|
|
divmod_uw_asm .proc
|
|
; -- divide two unsigned words (16 bit each) into 16 bit results
|
|
; input: c64.SCRATCH_ZPWORD1 in ZP: 16 bit number, A/Y: 16 bit divisor
|
|
; output: c64.SCRATCH_ZPWORD2 in ZP: 16 bit remainder, A/Y: 16 bit division result
|
|
; division by zero will result in quotient = 65535 and remainder = divident
|
|
|
|
|
|
dividend = c64.SCRATCH_ZPWORD1
|
|
remainder = c64.SCRATCH_ZPWORD2
|
|
result = dividend ;save memory by reusing divident to store the result
|
|
|
|
sta _divisor
|
|
sty _divisor+1
|
|
stx c64.SCRATCH_ZPREGX
|
|
lda #0 ;preset remainder to 0
|
|
sta remainder
|
|
sta remainder+1
|
|
ldx #16 ;repeat for each bit: ...
|
|
|
|
- asl dividend ;dividend lb & hb*2, msb -> Carry
|
|
rol dividend+1
|
|
rol remainder ;remainder lb & hb * 2 + msb from carry
|
|
rol remainder+1
|
|
lda remainder
|
|
sec
|
|
sbc _divisor ;substract divisor to see if it fits in
|
|
tay ;lb result -> Y, for we may need it later
|
|
lda remainder+1
|
|
sbc _divisor+1
|
|
bcc + ;if carry=0 then divisor didn't fit in yet
|
|
|
|
sta remainder+1 ;else save substraction result as new remainder,
|
|
sty remainder
|
|
inc result ;and INCrement result cause divisor fit in 1 times
|
|
|
|
+ dex
|
|
bne -
|
|
|
|
lda result
|
|
ldy result+1
|
|
ldx c64.SCRATCH_ZPREGX
|
|
rts
|
|
_divisor .word 0
|
|
.pend
|
|
|
|
|
|
randseed .proc
|
|
; -- reset the random seeds for the byte and word random generators
|
|
; arguments: uword seed in A/Y clobbers A
|
|
; (default starting values are: A=$2c Y=$9e)
|
|
sta randword._seed
|
|
sty randword._seed+1
|
|
clc
|
|
adc #14
|
|
sta randbyte._seed
|
|
rts
|
|
.pend
|
|
|
|
|
|
randbyte .proc
|
|
; -- 8-bit pseudo random number generator into A
|
|
lda _seed
|
|
beq _eor
|
|
asl a
|
|
beq _done ; if the input was $80, skip the EOR
|
|
bcc _done
|
|
_eor eor #$1d ; xor with magic value see below for possible values
|
|
_done sta _seed
|
|
rts
|
|
|
|
_seed .byte $3a
|
|
|
|
; possible 'magic' eor bytes are:
|
|
; $1d, $2b, $2d, $4d, $5f, $63, $65, $69
|
|
; $71, $87, $8d, $a9, $c3, $cf, $e7, $f5
|
|
|
|
.pend
|
|
|
|
|
|
randword .proc
|
|
; -- 16 bit pseudo random number generator into AY
|
|
|
|
magic_eor = $3f1d
|
|
; possible magic eor words are:
|
|
; $3f1d, $3f81, $3fa5, $3fc5, $4075, $409d, $40cd, $4109
|
|
; $413f, $414b, $4153, $4159, $4193, $4199, $41af, $41bb
|
|
|
|
lda _seed
|
|
beq _lowZero ; $0000 and $8000 are special values to test for
|
|
|
|
; Do a normal shift
|
|
asl _seed
|
|
lda _seed+1
|
|
rol a
|
|
bcc _noEor
|
|
|
|
_doEor ; high byte is in A
|
|
eor #>magic_eor
|
|
sta _seed+1
|
|
lda _seed
|
|
eor #<magic_eor
|
|
sta _seed
|
|
ldy _seed+1
|
|
rts
|
|
|
|
_lowZero lda _seed+1
|
|
beq _doEor ; High byte is also zero, so apply the EOR
|
|
; For speed, you could store 'magic' into 'seed' directly
|
|
; instead of running the EORs
|
|
|
|
; wasn't zero, check for $8000
|
|
asl a
|
|
beq _noEor ; if $00 is left after the shift, then it was $80
|
|
bcs _doEor ; else, do the EOR based on the carry bit as usual
|
|
|
|
_noEor sta _seed+1
|
|
tay
|
|
lda _seed
|
|
rts
|
|
|
|
_seed .word $2c9e
|
|
.pend
|
|
|
|
|
|
mul_byte_3 .proc
|
|
; X + X*2
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_3 .proc
|
|
; W*2 + W
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
|
|
mul_byte_5 .proc
|
|
; X*4 + X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_5 .proc
|
|
; W*4 + W
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
|
|
mul_byte_6 .proc
|
|
; (X*2 + X)*2
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_6 .proc
|
|
; (W*2 + W)*2
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_7 .proc
|
|
; X*8 - X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_7 .proc
|
|
; W*8 - W
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
sbc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_9 .proc
|
|
; X*8 + X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_9 .proc
|
|
; W*8 + W
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_10 .proc
|
|
; (X*4 + X)*2
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_10 .proc
|
|
; (W*4 + W)*2
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_11 .proc
|
|
; (X*2 + X)*4 - X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
; mul_word_11 is skipped (too much code)
|
|
|
|
mul_byte_12 .proc
|
|
; (X*2 + X)*4
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_12 .proc
|
|
; (W*2 + W)*4
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_13 .proc
|
|
; (X*2 + X)*4 + X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
; mul_word_13 is skipped (too much code)
|
|
|
|
mul_byte_14 .proc
|
|
; (X*8 - X)*2
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
; mul_word_14 is skipped (too much code)
|
|
|
|
mul_byte_15 .proc
|
|
; X*16 - X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
asl a
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_15 .proc
|
|
; W*16 - W
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
sec
|
|
sbc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
sbc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_20 .proc
|
|
; (X*4 + X)*4
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_20 .proc
|
|
; (W*4 + W)*4
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_25 .proc
|
|
; (X*2 + X)*8 + X
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_25 .proc
|
|
; W + W*8 + W*16
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPWORD1+1
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPWORD1+1
|
|
asl a
|
|
rol c64.SCRATCH_ZPWORD1+1
|
|
asl a
|
|
rol c64.SCRATCH_ZPWORD1+1
|
|
sta c64.SCRATCH_ZPWORD1
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPWORD1+1
|
|
adc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
lda c64.SCRATCH_ZPWORD1
|
|
asl a
|
|
rol c64.SCRATCH_ZPWORD1+1
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPWORD1+1
|
|
adc c64.ESTACK_HI+1,x
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_byte_40 .proc
|
|
; (X*4 + X)*8
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
asl a
|
|
asl a
|
|
asl a
|
|
sta c64.ESTACK_LO+1,x
|
|
rts
|
|
.pend
|
|
|
|
mul_word_40 .proc
|
|
; (W*4 + W)*8
|
|
lda c64.ESTACK_HI+1,x
|
|
sta c64.SCRATCH_ZPREG
|
|
lda c64.ESTACK_LO+1,x
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
asl a
|
|
rol c64.SCRATCH_ZPREG
|
|
clc
|
|
adc c64.ESTACK_LO+1,x
|
|
sta c64.ESTACK_LO+1,x
|
|
lda c64.SCRATCH_ZPREG
|
|
adc c64.ESTACK_HI+1,x
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
asl c64.ESTACK_LO+1,x
|
|
rol a
|
|
sta c64.ESTACK_HI+1,x
|
|
rts
|
|
.pend
|