prog8/prog8lib/prog8lib.p8

1185 lines
22 KiB
Lua

; Prog8 internal 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
~ prog8_lib {
%asm {{
; 16-bit rotate right (as opposed to the 6502's usual 17-bit rotate with carry)
; the word is placed in c64.SCRATCH_ZPWORD1
ror2_word .proc
lsr c64.SCRATCH_ZPWORD1+1
ror c64.SCRATCH_ZPWORD1
bcc +
lda c64.SCRATCH_ZPWORD1+1
ora #$80
sta c64.SCRATCH_ZPWORD1+1
+ rts
.pend
add_a_to_zpword .proc
; -- add ubyte in A to the uword in c64.SCRATCH_ZPWORD1
clc
adc c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD1
bcc +
inc c64.SCRATCH_ZPWORD1+1
+ rts
.pend
pop_index_times_5 .proc
inx
lda c64.ESTACK_LO,x
sta c64.SCRATCH_ZPB1
asl a
asl a
clc
adc c64.SCRATCH_ZPB1 ; A*=5
rts
.pend
neg_b .proc
lda c64.ESTACK_LO+1,x
eor #255
clc
adc #1
sta c64.ESTACK_LO+1,x
rts
.pend
neg_w .proc
sec
lda #0
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda #0
sbc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
inv_word .proc
lda c64.ESTACK_LO+1,x
eor #255
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
eor #255
sta c64.ESTACK_HI+1,x
rts
.pend
not_byte .proc
lda c64.ESTACK_LO+1,x
beq +
lda #0
beq ++
+ lda #1
+ sta c64.ESTACK_LO+1,x
rts
.pend
not_word .proc
lda c64.ESTACK_LO + 1,x
ora c64.ESTACK_HI + 1,x
beq +
lda #0
beq ++
+ lda #1
+ sta c64.ESTACK_LO + 1,x
sta c64.ESTACK_HI + 1,x
rts
.pend
abs_b .proc
; -- push abs(byte) on stack (as byte)
lda c64.ESTACK_LO+1,x
bmi neg_b
rts
.pend
abs_w .proc
; -- push abs(word) on stack (as word)
lda c64.ESTACK_HI+1,x
bmi neg_w
rts
.pend
add_w .proc
; -- push word+word / uword+uword
inx
clc
lda c64.ESTACK_LO,x
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI,x
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
sub_w .proc
; -- push word-word
inx
sec
lda c64.ESTACK_LO+1,x
sbc c64.ESTACK_LO,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
sbc c64.ESTACK_HI,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte .proc
; -- b*b->b (signed and unsigned)
inx
lda c64.ESTACK_LO,x
ldy c64.ESTACK_LO+1,x
jsr math.multiply_bytes
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word .proc
inx
lda c64.ESTACK_LO,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI,x
sta c64.SCRATCH_ZPWORD1+1
lda c64.ESTACK_LO+1,x
ldy c64.ESTACK_HI+1,x
stx c64.SCRATCH_ZPREGX
jsr math.multiply_words
ldx c64.SCRATCH_ZPREGX
lda math.multiply_words.multiply_words_result
sta c64.ESTACK_LO+1,x
lda math.multiply_words.multiply_words_result+1
sta c64.ESTACK_HI+1,x
rts
.pend
idiv_b .proc
; signed division: use unsigned division and fix sign of result afterwards
lda c64.ESTACK_LO+1,x
eor c64.ESTACK_LO+2,x
php ; save sign of result
inx
lda c64.ESTACK_LO,x
bpl +
eor #$ff
sec
adc #0 ; make num1 positive
+ tay
inx
lda c64.ESTACK_LO,x
bpl +
eor #$ff
sec
adc #0 ; make num2 positive
+ jsr math.divmod_ubytes
tya
plp ; get sign of result
bpl +
eor #$ff
sec
adc #0 ; negate result
+ sta c64.ESTACK_LO,x
dex
rts
.pend
idiv_ub .proc
inx
ldy c64.ESTACK_LO,x
inx
lda c64.ESTACK_LO,x
jsr math.divmod_ubytes
tya
sta c64.ESTACK_LO,x
dex
rts
.pend
idiv_w .proc
.error "idiv_w not yet implemented"
.pend
idiv_uw .proc
.error "idiv_uw not implemented"
.pend
remainder_b .proc
.error "remainder_b not yet implemented, via div_b?"
.pend
remainder_ub .proc
inx
lda c64.ESTACK_LO,x ; right operand
sta c64.SCRATCH_ZPB1
lda c64.ESTACK_LO+1,x ; left operand
- cmp c64.SCRATCH_ZPB1
bcc +
sbc c64.SCRATCH_ZPB1
jmp -
+ sta c64.ESTACK_LO+1,x
rts
.pend
remainder_w .proc
.error "remainder_w not implemented - via div_w"
.pend
remainder_uw .proc
.error "remainder_uw not implemented - via div_uw"
.pend
equal_w .proc
; -- are the two words on the stack identical?
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
bne equal_b._equal_b_false
lda c64.ESTACK_HI+1,x
cmp c64.ESTACK_HI+2,x
bne equal_b._equal_b_false
beq equal_b._equal_b_true
.pend
notequal_b .proc
; -- are the two bytes on the stack different?
inx
lda c64.ESTACK_LO,x
eor c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
notequal_w .proc
; -- are the two words on the stack different?
inx
lda c64.ESTACK_LO,x
eor c64.ESTACK_LO+1,x
beq +
sta c64.ESTACK_LO+1,x
rts
+ lda c64.ESTACK_HI,x
eor c64.ESTACK_HI+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
less_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcc equal_b._equal_b_true
bcs equal_b._equal_b_false
.pend
less_b .proc
; see http://www.6502.org/tutorials/compare_beyond.html
lda c64.ESTACK_LO+2,x
sec
sbc c64.ESTACK_LO+1,x
bvc +
eor #$80
+ bmi equal_b._equal_b_true
bpl equal_b._equal_b_false
.pend
less_uw .proc
lda c64.ESTACK_HI+2,x
cmp c64.ESTACK_HI+1,x
bcc equal_b._equal_b_true
bne equal_b._equal_b_false
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcc equal_b._equal_b_true
bcs equal_b._equal_b_false
.pend
less_w .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+2,x
sbc c64.ESTACK_HI+1,x
bvc +
eor #$80
+ bmi equal_b._equal_b_true
bpl equal_b._equal_b_false
.pend
equal_b .proc
; -- are the two bytes on the stack identical?
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bne _equal_b_false
_equal_b_true lda #1
_equal_b_store inx
sta c64.ESTACK_LO+1,x
rts
_equal_b_false lda #0
beq _equal_b_store
.pend
lesseq_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcc equal_b._equal_b_true
beq equal_b._equal_b_true ; @todo optimize by flipping comparison
bcs equal_b._equal_b_false
.pend
lesseq_b .proc
; see http://www.6502.org/tutorials/compare_beyond.html
lda c64.ESTACK_LO+2,x
clc
sbc c64.ESTACK_LO+1,x
bvc +
eor #$80
+ bmi equal_b._equal_b_true
bpl equal_b._equal_b_false
.pend
lesseq_uw .proc
lda c64.ESTACK_HI+1,x
cmp c64.ESTACK_HI+2,x
bcc equal_b._equal_b_false
bne equal_b._equal_b_true
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
bcs equal_b._equal_b_true
bcc equal_b._equal_b_false
.pend
lesseq_w .proc
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
lda c64.ESTACK_HI+1,x
sbc c64.ESTACK_HI+2,x
bvc +
eor #$80
+ bpl equal_b._equal_b_true
bmi equal_b._equal_b_false
.pend
greater_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
beq equal_b._equal_b_false
bcs equal_b._equal_b_true ; @todo optimize by flipping comparison?
bcc equal_b._equal_b_false
.pend
greater_b .proc
; see http://www.6502.org/tutorials/compare_beyond.html
lda c64.ESTACK_LO+2,x
clc
sbc c64.ESTACK_LO+1,x
bvc +
eor #$80
+ bpl equal_b._equal_b_true
bmi equal_b._equal_b_false
.pend
greater_uw .proc
lda c64.ESTACK_HI+1,x
cmp c64.ESTACK_HI+2,x
bcc equal_b._equal_b_true
bne equal_b._equal_b_false
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
bcc equal_b._equal_b_true
bcs equal_b._equal_b_false
.pend
greater_w .proc
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
lda c64.ESTACK_HI+1,x
sbc c64.ESTACK_HI+2,x
bvc +
eor #$80
+ bmi equal_b._equal_b_true
bpl equal_b._equal_b_false
.pend
greatereq_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcs equal_b._equal_b_true
bcc equal_b._equal_b_false
.pend
greatereq_b .proc
; see http://www.6502.org/tutorials/compare_beyond.html
lda c64.ESTACK_LO+2,x
sec
sbc c64.ESTACK_LO+1,x
bvc +
eor #$80
+ bpl equal_b._equal_b_true
bmi equal_b._equal_b_false
.pend
greatereq_uw .proc
lda c64.ESTACK_HI+2,x
cmp c64.ESTACK_HI+1,x
bcc equal_b._equal_b_false
bne equal_b._equal_b_true
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcs equal_b._equal_b_true
bcc equal_b._equal_b_false
.pend
greatereq_w .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+2,x
sbc c64.ESTACK_HI+1,x
bvc +
eor #$80
+ bpl equal_b._equal_b_true
bmi equal_b._equal_b_false
.pend
func_sin8 .proc
ldy c64.ESTACK_LO+1,x
lda func_sin16.sinecos8hi,y
sta c64.ESTACK_LO+1,x
rts
.pend
func_sin16 .proc
ldy c64.ESTACK_LO+1,x
lda func_sin16.sinecos8lo,y
sta c64.ESTACK_LO+1,x
lda func_sin16.sinecos8hi,y
sta c64.ESTACK_HI+1,x
rts
_ := 32767 * sin(range(256+64) * rad(360.0/256.0))
sinecos8lo .byte <_
sinecos8hi .byte >_
.pend
func_cos8 .proc
ldy c64.ESTACK_LO+1,x
lda func_sin16.sinecos8hi+64,y
sta c64.ESTACK_LO+1,x
rts
.pend
func_cos16 .proc
ldy c64.ESTACK_LO+1,x
lda func_sin16.sinecos8lo+64,y
sta c64.ESTACK_LO+1,x
lda func_sin16.sinecos8hi+64,y
sta c64.ESTACK_HI+1,x
rts
.pend
peek_address .proc
; -- peek address on stack into c64.SCRATCH_ZPWORD1
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
rts
.pend
func_any_b .proc
inx
lda c64.ESTACK_LO,x ; array size
_entry sta _cmp_mod+1 ; self-modifying code
jsr peek_address
ldy #0
- lda (c64.SCRATCH_ZPWORD1),y
bne _got_any
iny
_cmp_mod cpy #255 ; modified
bne -
lda #0
sta c64.ESTACK_LO+1,x
rts
_got_any lda #1
sta c64.ESTACK_LO+1,x
rts
.pend
func_any_w .proc
inx
lda c64.ESTACK_LO,x ; array size
asl a ; times 2 because of word
jmp func_any_b._entry
.pend
func_all_b .proc
inx
lda c64.ESTACK_LO,x ; array size
sta _cmp_mod+1 ; self-modifying code
jsr peek_address
ldy #0
- lda (c64.SCRATCH_ZPWORD1),y
beq _got_not_all
iny
_cmp_mod cpy #255 ; modified
bne -
lda #1
sta c64.ESTACK_LO+1,x
rts
_got_not_all lda #0
sta c64.ESTACK_LO+1,x
rts
.pend
func_all_w .proc
inx
lda c64.ESTACK_LO,x ; array size
asl a ; times 2 because of word
sta _cmp_mod+1 ; self-modifying code
jsr peek_address
ldy #0
- lda (c64.SCRATCH_ZPWORD1),y
bne +
iny
lda (c64.SCRATCH_ZPWORD1),y
bne +
lda #0
sta c64.ESTACK_LO+1,x
rts
+ iny
_cmp_mod cpy #255 ; modified
bne -
lda #1
sta c64.ESTACK_LO+1,x
rts
.pend
func_max_ub .proc
jsr pop_array_and_lengthmin1Y
lda #0
sta c64.SCRATCH_ZPB1
- lda (c64.SCRATCH_ZPWORD1),y
cmp c64.SCRATCH_ZPB1
bcc +
sta c64.SCRATCH_ZPB1
+ dey
cpy #255
bne -
lda c64.SCRATCH_ZPB1
sta c64.ESTACK_LO,x
dex
rts
.pend
func_max_b .proc
jsr pop_array_and_lengthmin1Y
lda #-128
sta c64.SCRATCH_ZPB1
- lda (c64.SCRATCH_ZPWORD1),y
sec
sbc c64.SCRATCH_ZPB1
bvc +
eor #$80
+ bmi +
lda (c64.SCRATCH_ZPWORD1),y
sta c64.SCRATCH_ZPB1
+ dey
cpy #255
bne -
lda c64.SCRATCH_ZPB1
sta c64.ESTACK_LO,x
dex
rts
.pend
func_max_uw .proc
lda #0
sta _result_maxuw
sta _result_maxuw+1
jsr pop_array_and_lengthmin1Y
tya
asl a
tay ; times 2 because of word array
_loop
iny
lda (c64.SCRATCH_ZPWORD1),y
dey
cmp _result_maxuw+1
bcc _lesseq
bne _greater
lda (c64.SCRATCH_ZPWORD1),y
cmp _result_maxuw
bcc _lesseq
_greater lda (c64.SCRATCH_ZPWORD1),y
sta _result_maxuw
iny
lda (c64.SCRATCH_ZPWORD1),y
sta _result_maxuw+1
dey
_lesseq dey
dey
bpl _loop ; @todo doesn't work for arrays where y will be >127. FIX OTHER LOOPS TOO!
lda _result_maxuw
sta c64.ESTACK_LO,x
lda _result_maxuw+1
sta c64.ESTACK_HI,x
dex
rts
_result_maxuw .word 0
.pend
func_max_w .proc
lda #$00
sta _result_maxw
lda #$80
sta _result_maxw+1
jsr pop_array_and_lengthmin1Y
tya
asl a
tay ; times 2 because of word array
_loop
lda (c64.SCRATCH_ZPWORD1),y
cmp _result_maxw
iny
lda (c64.SCRATCH_ZPWORD1),y
dey
sbc _result_maxw+1
bvc +
eor #$80
+ bmi _lesseq
lda (c64.SCRATCH_ZPWORD1),y
sta _result_maxw
iny
lda (c64.SCRATCH_ZPWORD1),y
sta _result_maxw+1
dey
_lesseq dey
dey
bpl _loop
lda _result_maxw
sta c64.ESTACK_LO,x
lda _result_maxw+1
sta c64.ESTACK_HI,x
dex
rts
_result_maxw .word 0
.pend
func_sum_b .proc
jsr pop_array_and_lengthmin1Y
lda #0
sta c64.ESTACK_LO,x
sta c64.ESTACK_HI,x
_loop lda (c64.SCRATCH_ZPWORD1),y
pha
clc
adc c64.ESTACK_LO,x
sta c64.ESTACK_LO,x
; sign extend the high byte
pla
and #$80
beq +
lda #$ff
+ adc c64.ESTACK_HI,x
sta c64.ESTACK_HI,x
dey
cpy #255
bne _loop
dex
rts
.pend
func_sum_ub .proc
jsr pop_array_and_lengthmin1Y
lda #0
sta c64.ESTACK_LO,x
sta c64.ESTACK_HI,x
- lda (c64.SCRATCH_ZPWORD1),y
clc
adc c64.ESTACK_LO,x
sta c64.ESTACK_LO,x
bcc +
inc c64.ESTACK_HI,x
+ dey
cpy #255
bne -
dex
rts
.pend
func_sum_uw .proc
jsr pop_array_and_lengthmin1Y
tya
asl a
tay
lda #0
sta c64.ESTACK_LO,x
sta c64.ESTACK_HI,x
- lda (c64.SCRATCH_ZPWORD1),y
iny
clc
adc c64.ESTACK_LO,x
sta c64.ESTACK_LO,x
lda (c64.SCRATCH_ZPWORD1),y
adc c64.ESTACK_HI,x
sta c64.ESTACK_HI,x
dey
dey
dey
cpy #254
bne -
dex
rts
.pend
func_sum_w .proc
jmp func_sum_uw
.pend
pop_array_and_lengthmin1Y .proc
inx
ldy c64.ESTACK_LO,x
dey ; length minus 1, for iteration
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
inx
rts
.pend
func_min_ub .proc
jsr pop_array_and_lengthmin1Y
lda #255
sta c64.SCRATCH_ZPB1
- lda (c64.SCRATCH_ZPWORD1),y
cmp c64.SCRATCH_ZPB1
bcs +
sta c64.SCRATCH_ZPB1
+ dey
cpy #255
bne -
lda c64.SCRATCH_ZPB1
sta c64.ESTACK_LO,x
dex
rts
.pend
func_min_b .proc
jsr pop_array_and_lengthmin1Y
lda #127
sta c64.SCRATCH_ZPB1
- lda (c64.SCRATCH_ZPWORD1),y
clc
sbc c64.SCRATCH_ZPB1
bvc +
eor #$80
+ bpl +
lda (c64.SCRATCH_ZPWORD1),y
sta c64.SCRATCH_ZPB1
+ dey
cpy #255
bne -
lda c64.SCRATCH_ZPB1
sta c64.ESTACK_LO,x
dex
rts
.pend
func_min_uw .proc
lda #$ff
sta _result_minuw
sta _result_minuw+1
jsr pop_array_and_lengthmin1Y
tya
asl a
tay ; times 2 because of word array
_loop
iny
lda (c64.SCRATCH_ZPWORD1),y
dey
cmp _result_minuw+1
bcc _less
bne _gtequ
lda (c64.SCRATCH_ZPWORD1),y
cmp _result_minuw
bcs _gtequ
_less lda (c64.SCRATCH_ZPWORD1),y
sta _result_minuw
iny
lda (c64.SCRATCH_ZPWORD1),y
sta _result_minuw+1
dey
_gtequ dey
dey
bpl _loop
lda _result_minuw
sta c64.ESTACK_LO,x
lda _result_minuw+1
sta c64.ESTACK_HI,x
dex
rts
_result_minuw .word 0
.pend
func_min_w .proc
lda #$ff
sta _result_minw
lda #$7f
sta _result_minw+1
jsr pop_array_and_lengthmin1Y
tya
asl a
tay ; times 2 because of word array
_loop
lda (c64.SCRATCH_ZPWORD1),y
cmp _result_minw
iny
lda (c64.SCRATCH_ZPWORD1),y
dey
sbc _result_minw+1
bvc +
eor #$80
+ bpl _gtequ
lda (c64.SCRATCH_ZPWORD1),y
sta _result_minw
iny
lda (c64.SCRATCH_ZPWORD1),y
sta _result_minw+1
dey
_gtequ dey
dey
bpl _loop
lda _result_minw
sta c64.ESTACK_LO,x
lda _result_minw+1
sta c64.ESTACK_HI,x
dex
rts
_result_minw .word 0
.pend
func_len_str .proc
; -- push length of 0-terminated string on stack
jsr peek_address
ldy #0
- lda (c64.SCRATCH_ZPWORD1),y
beq +
iny
bne -
+ tya
sta c64.ESTACK_LO+1,x
rts
.pend
func_len_strp .proc
; -- push length of pascal-string on stack
jsr peek_address
ldy #0
lda (c64.SCRATCH_ZPWORD1),y ; first byte is length
sta c64.ESTACK_LO+1,x
rts
.pend
func_rnd .proc
; -- put a random ubyte on the estack
jsr math.randbyte
sta c64.ESTACK_LO,x
dex
rts
.pend
func_rndw .proc
; -- put a random uword on the estack
jsr math.randword
sta c64.ESTACK_LO,x
tya
sta c64.ESTACK_HI,x
dex
rts
.pend
func_memcopy .proc ; clobbers A,Y
inx
stx c64.SCRATCH_ZPREGX
lda c64.ESTACK_LO+2,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+2,x
sta c64.SCRATCH_ZPWORD1+1
lda c64.ESTACK_LO+1,x
ldy c64.ESTACK_HI+1,x
pha
lda c64.ESTACK_LO,x
tax
pla
jsr c64utils.memcopy
ldx c64.SCRATCH_ZPREGX
inx
inx
rts
.pend
}}
}
~ math {
; some more interesting routines can be found here:
; http://6502org.wikidot.com/software-math
; http://codebase64.org/doku.php?id=base:6502_6510_maths
;
asmsub multiply_bytes (ubyte byte1 @ A, ubyte byte2 @ Y) -> clobbers() -> (ubyte @ A) {
; ---- multiply 2 bytes, result as byte in A (signed or unsigned)
%asm {{
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
}}
}
asmsub multiply_bytes_16 (ubyte byte1 @ A, ubyte byte2 @ Y) -> clobbers(X) -> (uword @ AY) {
; ---- multiply 2 bytes, result as word in A/Y (unsigned)
%asm {{
sta c64.SCRATCH_ZPB1
sty c64.SCRATCH_ZPREG
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
rts
}}
}
asmsub multiply_words (uword number @ AY) -> clobbers(A,X) -> () {
; ---- 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)
%asm {{
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
mult16 lda #$00
sta multiply_words_result+2 ; clear upper bits of product
sta multiply_words_result+3
ldx #16 ; for all 16 bits...
- lsr c64.SCRATCH_ZPWORD1+1 ; divide multiplier by 2
ror c64.SCRATCH_ZPWORD1
bcc +
lda multiply_words_result+2 ; get upper half of product and add multiplicand
clc
adc c64.SCRATCH_ZPWORD2
sta multiply_words_result+2
lda multiply_words_result+3
adc c64.SCRATCH_ZPWORD2+1
+ ror a ; rotate partial product
sta multiply_words_result+3
ror multiply_words_result+2
ror multiply_words_result+1
ror multiply_words_result
dex
bne -
rts
multiply_words_result .byte 0,0,0,0
}}
}
asmsub divmod_ubytes (ubyte number @ A, ubyte divisor @ Y) -> clobbers() -> (ubyte @ Y, ubyte @ A) {
; ---- divide A by Y, result quotient in Y, remainder in A (unsigned)
; division by zero will result in quotient = 255 and remainder = original number
%asm {{
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
}}
}
asmsub divmod_words (uword divisor @ AY) -> clobbers(X) -> (uword @ AY) {
; ---- divide two 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_ZPWORD1 in ZP: 16 bit result, A/Y: 16 bit remainder
; division by zero will result in quotient = 65535 and remainder = divident
%asm {{
remainder = c64.SCRATCH_ZPB1
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
lda #0 ;preset remainder to 0
sta remainder
sta remainder+1
ldx #16 ;repeat for each bit: ...
- asl c64.SCRATCH_ZPWORD1 ;number lb & hb*2, msb -> Carry
rol c64.SCRATCH_ZPWORD1+1
rol remainder ;remainder lb & hb * 2 + msb from carry
rol remainder+1
lda remainder
sec
sbc c64.SCRATCH_ZPWORD2 ;substract divisor to see if it fits in
tay ;lb result -> Y, for we may need it later
lda remainder+1
sbc c64.SCRATCH_ZPWORD2+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 c64.SCRATCH_ZPWORD1 ;and INCrement result cause divisor fit in 1 times
+ dex
bne -
lda remainder ; copy remainder to ZPWORD2 result register
sta c64.SCRATCH_ZPWORD2
lda remainder+1
sta c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPWORD1 ; load division result in A/Y
ldy c64.SCRATCH_ZPWORD1+1
rts
}}
}
asmsub randseed (uword seed @ AY) -> clobbers(A, Y) -> () {
; ---- reset the random seeds for the byte and word random generators
; default starting values are: A=$2c Y=$9e
%asm {{
sta randword._seed
sty randword._seed+1
stx c64.SCRATCH_ZPREG
clc
adc #14
sta randbyte._seed
ora #$80 ; make negative
; jsr c64flt.FREADSA
; jsr c64flt.RND ; reseed the float rng using the (negative) number in A
ldx c64.SCRATCH_ZPREG
rts
}}
}
asmsub randbyte () -> clobbers() -> (ubyte @ A) {
; ---- 8-bit pseudo random number generator into A
%asm {{
lda _seed
beq +
asl a
beq ++ ;if the input was $80, skip the EOR
bcc ++
+ eor _magic ; #$1d ; could be self-modifying code to set new magic
+ sta _seed
rts
_seed .byte $3a
_magic .byte $1d
_magiceors .byte $1d, $2b, $2d, $4d, $5f, $63, $65, $69
.byte $71, $87, $8d, $a9, $c3, $cf, $e7, $f5
}}
}
asmsub randword () -> clobbers() -> (uword @ AY) {
; ---- 16 bit pseudo random number generator into AY
%asm {{
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+1 ; #>magic ; could be self-modifying code to set new magic
sta _seed+1
lda _seed
eor _magic ; #<magic ; could be self-modifying code to set new magic
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
_magic .word $3f1d
_magiceors .word $3f1d, $3f81, $3fa5, $3fc5, $4075, $409d, $40cd, $4109
.word $413f, $414b, $4153, $4159, $4193, $4199, $41af, $41bb
}}
}
}