mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
make %asminclude work, restructure prog8lib into separate asm file
This commit is contained in:
parent
ba91ab13d5
commit
5471c5211c
704
compiler/res/prog8lib/math.asm
Normal file
704
compiler/res/prog8lib/math.asm
Normal file
@ -0,0 +1,704 @@
|
||||
; 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 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 -
|
||||
ldx c64.SCRATCH_ZPREGX
|
||||
rts
|
||||
|
||||
multiply_words_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 + W*2
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_5 .proc
|
||||
; X + X*4
|
||||
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 + W*4
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_6 .proc
|
||||
; X*2 + X*4
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_6 .proc
|
||||
; W*2 + W*4
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sta c64.SCRATCH_ZPWORD2
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
clc
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
adc c64.SCRATCH_ZPWORD2
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
adc c64.SCRATCH_ZPWORD2+1
|
||||
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_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sec
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sbc c64.ESTACK_LO+1,x
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sbc c64.ESTACK_HI+1,x
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_9 .proc
|
||||
; X + X*8
|
||||
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 + W*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_10 .proc
|
||||
; X + X + X*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc c64.ESTACK_LO+1,x
|
||||
clc
|
||||
adc c64.ESTACK_LO+1,x
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_10 .proc
|
||||
; W*2 + W*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sta c64.SCRATCH_ZPWORD2
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
clc
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
adc c64.SCRATCH_ZPWORD2
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
adc c64.SCRATCH_ZPWORD2+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_11 .proc
|
||||
; X + X + X + X*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
; mul_word_11 is skipped (too much code)
|
||||
|
||||
mul_byte_12 .proc
|
||||
; X*4 + X*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_12 .proc
|
||||
; W*4 + W*8
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sta c64.SCRATCH_ZPWORD2
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
clc
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
adc c64.SCRATCH_ZPWORD2
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
adc c64.SCRATCH_ZPWORD2+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_13 .proc
|
||||
; X*16 - X -X -X
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc c64.SCRATCH_ZPREG
|
||||
sec
|
||||
sbc c64.SCRATCH_ZPREG
|
||||
sec
|
||||
sbc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
; mul_word_13 is skipped (too much code)
|
||||
|
||||
mul_byte_14 .proc
|
||||
; X*16 - X -X
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc c64.ESTACK_LO+1,x
|
||||
sec
|
||||
sbc c64.ESTACK_LO+1,x
|
||||
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
|
||||
sta c64.SCRATCH_ZPREG
|
||||
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_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
sec
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sbc c64.ESTACK_LO+1,x
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sbc c64.ESTACK_HI+1,x
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_20 .proc
|
||||
; X*4 + X*16
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_20 .proc
|
||||
; W*4 + W*16
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sta c64.SCRATCH_ZPWORD2
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
asl c64.SCRATCH_ZPWORD2
|
||||
rol c64.SCRATCH_ZPWORD2+1
|
||||
clc
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
adc c64.SCRATCH_ZPWORD2
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
adc c64.SCRATCH_ZPWORD2+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_25 .proc
|
||||
; X + X*8 + X*16
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
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_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_40 .proc
|
||||
; X*8 + X*32
|
||||
lda c64.ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sta c64.SCRATCH_ZPREG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc c64.SCRATCH_ZPREG
|
||||
sta c64.ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_40 .proc
|
||||
; W*8 + W*32
|
||||
lda c64.ESTACK_LO+1,x
|
||||
sta c64.SCRATCH_ZPWORD1
|
||||
lda c64.ESTACK_HI+1,x
|
||||
sta c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
lda c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
asl c64.SCRATCH_ZPWORD1
|
||||
rol c64.SCRATCH_ZPWORD1+1
|
||||
clc
|
||||
lda c64.ESTACK_LO+1,x
|
||||
adc c64.SCRATCH_ZPWORD1
|
||||
sta c64.ESTACK_LO+1,x
|
||||
lda c64.ESTACK_HI+1,x
|
||||
adc c64.SCRATCH_ZPWORD1+1
|
||||
sta c64.ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
11
compiler/res/prog8lib/math.p8
Normal file
11
compiler/res/prog8lib/math.p8
Normal file
@ -0,0 +1,11 @@
|
||||
; 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
|
||||
|
||||
%import c64lib
|
||||
|
||||
~ math {
|
||||
%asminclude "library:math.asm", ""
|
||||
}
|
1025
compiler/res/prog8lib/prog8lib.asm
Normal file
1025
compiler/res/prog8lib/prog8lib.asm
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -37,11 +37,13 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
private fun compileMain(args: Array<String>) {
|
||||
var startEmu = false
|
||||
var emulatorToStart = ""
|
||||
var moduleFile = ""
|
||||
for (arg in args) {
|
||||
if(arg=="--emu")
|
||||
startEmu = true
|
||||
emulatorToStart = "x64"
|
||||
else if(arg=="--emu2")
|
||||
emulatorToStart = "x64sc"
|
||||
else if(!arg.startsWith("--"))
|
||||
moduleFile = arg
|
||||
}
|
||||
@ -139,9 +141,9 @@ private fun compileMain(args: Array<String>) {
|
||||
throw x
|
||||
}
|
||||
|
||||
if(startEmu) {
|
||||
println("\nStarting C64 emulator...")
|
||||
val cmdline = listOf("x64sc", "-silent", "-moncommands", "$programname.vice-mon-list",
|
||||
if(emulatorToStart.isNotEmpty()) {
|
||||
println("\nStarting C-64 emulator $emulatorToStart...")
|
||||
val cmdline = listOf(emulatorToStart, "-silent", "-moncommands", "$programname.vice-mon-list",
|
||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programname+".prg")
|
||||
val process = ProcessBuilder(cmdline).inheritIO().start()
|
||||
process.waitFor()
|
||||
@ -184,7 +186,8 @@ fun determineCompilationOptions(moduleAst: Module): CompilationOptions {
|
||||
|
||||
private fun usage() {
|
||||
System.err.println("Missing argument(s):")
|
||||
System.err.println(" [--emu] auto-start the C64 emulator after successful compilation")
|
||||
System.err.println(" [--emu] auto-start the 'x64' C-64 emulator after successful compilation")
|
||||
System.err.println(" [--emu2] auto-start the 'x64sc' C-64 emulator after successful compilation")
|
||||
System.err.println(" [--vm] launch the prog8 virtual machine instead of the compiler")
|
||||
System.err.println(" modulefile main module file to compile")
|
||||
exitProcess(1)
|
||||
|
@ -611,8 +611,8 @@ class AstChecker(private val namespace: INameScope,
|
||||
}
|
||||
"%asminclude" -> {
|
||||
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
|
||||
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].name==null)
|
||||
err("invalid asminclude directive, expected arguments: \"filename\", scopelabel")
|
||||
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].str==null)
|
||||
err("invalid asminclude directive, expected arguments: \"filename\", \"scopelabel\"")
|
||||
}
|
||||
"%asmbinary" -> {
|
||||
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
|
||||
|
@ -6,7 +6,12 @@ import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
import prog8.compiler.intermediate.Value
|
||||
import prog8.optimizing.same
|
||||
import prog8.parser.tryGetEmbeddedResource
|
||||
import prog8.stackvm.Syscall
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
@ -220,8 +225,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
is Return -> translate(stmt)
|
||||
is Directive -> {
|
||||
when(stmt.directive) {
|
||||
"%asminclude" -> throw CompilerException("can't use %asminclude in stackvm")
|
||||
"%asmbinary" -> throw CompilerException("can't use %asmbinary in stackvm")
|
||||
"%asminclude" -> translateAsmInclude(stmt.args)
|
||||
"%asmbinary" -> translateAsmBinary(stmt.args)
|
||||
"%breakpoint" -> {
|
||||
prog.line(stmt.position)
|
||||
prog.instr(Opcode.BREAKPOINT)
|
||||
@ -959,6 +964,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
var restoreX = Register.X in subroutine.asmClobbers
|
||||
if(restoreX)
|
||||
prog.instr(Opcode.RSAVEX)
|
||||
// We don't bother about saving A and Y. They're considered expendable.
|
||||
|
||||
if(subroutine.isAsmSubroutine) {
|
||||
if(subroutine.parameters.size!=subroutine.asmParameterRegisters.size)
|
||||
@ -2185,4 +2191,24 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateAsmInclude(args: List<DirectiveArg>) {
|
||||
val scopeprefix = if(args[1].str!!.isNotBlank()) "${args[1].str}\t.proc\n" else ""
|
||||
val scopeprefixEnd = if(args[1].str!!.isNotBlank()) "\t.pend\n" else ""
|
||||
val filename=args[0].str!!
|
||||
val sourcecode =
|
||||
if(filename.startsWith("library:")) {
|
||||
val resource = tryGetEmbeddedResource(filename.substring(8)) ?: throw IllegalArgumentException("library file '$filename' not found")
|
||||
resource.bufferedReader().use { it.readText() }
|
||||
} else {
|
||||
// TODO: look in directory of parent source file first
|
||||
File(filename).readText()
|
||||
}
|
||||
|
||||
prog.instr(Opcode.INLINE_ASSEMBLY, callLabel=scopeprefix+sourcecode+scopeprefixEnd)
|
||||
}
|
||||
|
||||
private fun translateAsmBinary(args: List<DirectiveArg>) {
|
||||
TODO("asmbinary not implemented $args")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.DISCARD_BYTE -> " inx"
|
||||
Opcode.DISCARD_WORD -> " inx"
|
||||
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
|
||||
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel ?: "") // All of the inline assembly is stored in the calllabel property.
|
||||
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel ?: "") // All of the inline assembly is stored in the calllabel property. the '@inline@' is a special marker to process it.
|
||||
Opcode.SYSCALL -> {
|
||||
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
|
||||
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
|
||||
@ -965,18 +965,22 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
}
|
||||
}
|
||||
|
||||
for(pattern in patterns.filter { it.sequence.size <= segment.size || (it.altSequence != null && it.altSequence.size <= segment.size)}) {
|
||||
val opcodesList = if(pattern.sequence.size<=opcodes.size) opcodes.subList(0, pattern.sequence.size) else null
|
||||
val opcodesListAlt = if(pattern.altSequence!=null && pattern.altSequence.size<=opcodes.size) opcodes.subList(0, pattern.altSequence.size) else null
|
||||
|
||||
// add any matching patterns from the big list
|
||||
for(pattern in patterns) {
|
||||
if(pattern.sequence.size > segment.size || (pattern.altSequence!=null && pattern.altSequence.size > segment.size))
|
||||
continue // don't process patterns that don't fit
|
||||
val opcodesList = opcodes.subList(0, pattern.sequence.size)
|
||||
if(pattern.sequence == opcodesList) {
|
||||
val asm = pattern.asm(segment)
|
||||
if(asm!=null)
|
||||
result.add(AsmFragment(asm, pattern.sequence.size))
|
||||
} else if(opcodesListAlt!=null && pattern.altSequence == opcodesListAlt) {
|
||||
val asm = pattern.asm(segment)
|
||||
if(asm!=null)
|
||||
result.add(AsmFragment(asm, pattern.sequence.size))
|
||||
} else if(pattern.altSequence!=null) {
|
||||
val opcodesListAlt = opcodes.subList(0, pattern.altSequence.size)
|
||||
if(pattern.altSequence == opcodesListAlt) {
|
||||
val asm = pattern.asm(segment)
|
||||
if (asm != null)
|
||||
result.add(AsmFragment(asm, pattern.sequence.size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@ import prog8.ast.*
|
||||
import prog8.compiler.LauncherType
|
||||
import prog8.compiler.OutputType
|
||||
import prog8.determineCompilationOptions
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
@ -52,7 +54,9 @@ fun importModule(stream: CharStream, moduleName: String, isLibrary: Boolean): Mo
|
||||
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "c64utils", null, moduleAst.position)), moduleAst.position))
|
||||
}
|
||||
}
|
||||
// always import the prog8 compiler library
|
||||
// always import the prog8lib and math compiler libraries
|
||||
if(!moduleAst.position.file.startsWith("math."))
|
||||
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "math", null, moduleAst.position)), moduleAst.position))
|
||||
if(!moduleAst.position.file.startsWith("prog8lib."))
|
||||
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "prog8lib", null, moduleAst.position)), moduleAst.position))
|
||||
|
||||
@ -118,7 +122,6 @@ private fun discoverImportedModuleFile(name: String, importedFrom: Path, positio
|
||||
throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: $locations)")
|
||||
}
|
||||
|
||||
|
||||
private fun executeImportDirective(import: Directive, importedFrom: Path): Module? {
|
||||
if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null)
|
||||
throw SyntaxError("invalid import directive", import.position)
|
||||
@ -128,11 +131,11 @@ private fun executeImportDirective(import: Directive, importedFrom: Path): Modul
|
||||
if(importedModules.containsKey(moduleName))
|
||||
return null
|
||||
|
||||
val resource = import::class.java.getResource("/prog8lib/$moduleName.p8")
|
||||
val resource = tryGetEmbeddedResource(moduleName+".p8")
|
||||
val importedModule =
|
||||
if(resource!=null) {
|
||||
// load the module from the embedded resource
|
||||
resource.openStream().use {
|
||||
resource.use {
|
||||
println("importing '$moduleName' (embedded library)")
|
||||
importModule(CharStreams.fromStream(it), moduleName, true)
|
||||
}
|
||||
@ -144,3 +147,7 @@ private fun executeImportDirective(import: Directive, importedFrom: Path): Modul
|
||||
importedModule.checkImportedValid()
|
||||
return importedModule
|
||||
}
|
||||
|
||||
fun tryGetEmbeddedResource(name: String): InputStream? {
|
||||
return object{}.javaClass.getResourceAsStream("/prog8lib/$name")
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ Directives
|
||||
The assembler will include the file as binary bytes at this point, prog8 will not process this at all.
|
||||
The optional offset and length can be used to select a particular piece of the file.
|
||||
|
||||
.. data:: %asminclude "<filename>", scopelabel
|
||||
.. data:: %asminclude "<filename>", "scopelabel"
|
||||
|
||||
Level: block.
|
||||
This directive can only be used inside a block.
|
||||
@ -128,6 +128,7 @@ Directives
|
||||
prog8 will not process this at all, with one exception: the labels.
|
||||
The scopelabel argument will be used as a prefix to access the labels from the included source code,
|
||||
otherwise you would risk symbol redefinitions or duplications.
|
||||
If you know what you are doing you can leave it as an empty string to not have a scope prefix.
|
||||
|
||||
.. data:: %breakpoint
|
||||
|
||||
|
@ -44,10 +44,10 @@ sub start() {
|
||||
|
||||
sub print_notes(ubyte n1, ubyte n2) {
|
||||
c64.CHROUT('\n')
|
||||
c64.PLOT(0, n1/2, 24)
|
||||
c64scr.PLOT(n1/2, 24)
|
||||
c64.COLOR=7
|
||||
c64.CHROUT('Q')
|
||||
c64.PLOT(0, n2/2, 24)
|
||||
c64scr.PLOT(n2/2, 24)
|
||||
c64.COLOR=4
|
||||
c64.CHROUT('Q')
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
c64scr.clear_screenchars(32)
|
||||
draw_edges()
|
||||
time+=0.2
|
||||
c64.PLOT(0,0,0)
|
||||
c64scr.PLOT(0,0)
|
||||
c64scr.print("3d cube! (float) ")
|
||||
c64scr.print_ub(c64.TIME_LO)
|
||||
c64scr.print(" jiffies/frame")
|
||||
|
@ -89,7 +89,7 @@
|
||||
anglex-=500
|
||||
angley+=217
|
||||
anglez+=452
|
||||
c64.PLOT(0,0,0)
|
||||
c64scr.PLOT(0,0)
|
||||
c64scr.print("3d cube! (sprites) ")
|
||||
c64scr.print_ub(c64.TIME_LO)
|
||||
c64scr.print(" jiffies/frame ")
|
||||
|
@ -29,7 +29,7 @@
|
||||
anglex+=1000
|
||||
angley+=433
|
||||
anglez+=907
|
||||
c64.PLOT(0,0,0)
|
||||
c64scr.PLOT(0,0)
|
||||
c64scr.print("3d cube! (integer) ")
|
||||
c64scr.print_ub(c64.TIME_LO)
|
||||
c64scr.print(" jiffies/frame")
|
||||
|
@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
float duration = floor(((c64.TIME_LO as float) + 256.0*(c64.TIME_MID as float) + 65536.0*(c64.TIME_HI as float))/60.0)
|
||||
c64.PLOT(0, 0, 21)
|
||||
c64scr.PLOT(0, 21)
|
||||
c64scr.print("finished in ")
|
||||
c64flt.print_f(duration)
|
||||
c64scr.print(" seconds!\n")
|
||||
|
@ -29,58 +29,9 @@
|
||||
uword[3] uwa2
|
||||
word[3] wa2
|
||||
|
||||
; ub1 = ub2 & 44
|
||||
; b1 = b2 & 44
|
||||
; uw1 = uw2 & 4444
|
||||
; w1 = w2 & 4444
|
||||
; ub1 = ub2 | 44
|
||||
; b1 = b2 | 44
|
||||
; uw1 = uw2 | 4444
|
||||
; w1 = w2 | 4444
|
||||
; ub1 = ub2 ^ 44
|
||||
; b1 = b2 ^ 44
|
||||
; uw1 = uw2 ^ 4444
|
||||
; w1 = w2 ^ 4444
|
||||
;
|
||||
; ub1 = ub2 & ub1
|
||||
; b1 = b2 & b1
|
||||
; uw1 = uw2 & uw1
|
||||
; w1 = w2 & w1
|
||||
; ub1 = ub2 | ub1
|
||||
; b1 = b2 | b1
|
||||
; uw1 = uw2 | uw1
|
||||
; w1 = w2 | w1
|
||||
; ub1 = ub2 ^ ub1
|
||||
; b1 = b2 ^ b1
|
||||
; uw1 = uw2 ^ uw1
|
||||
; w1 = w2 ^ w1
|
||||
|
||||
swap(ub1, ub2)
|
||||
swap(b1, b2)
|
||||
swap(uw1, uw2)
|
||||
swap(w1, w2)
|
||||
swap(@($d020), @($d021))
|
||||
swap(mub1, mub2)
|
||||
swap(muw1, muw2)
|
||||
swap(mub1, ub2)
|
||||
swap(muw1, uw2)
|
||||
ub1=ub2*ub1
|
||||
|
||||
swap(uba1[1], uba2[2])
|
||||
swap(ba1[1], ba2[2])
|
||||
swap(uwa1[1], uwa2[2])
|
||||
swap(wa1[1], wa2[2])
|
||||
|
||||
ubyte i1
|
||||
ubyte i2
|
||||
swap(uba1[i1], uba2[i2])
|
||||
swap(ba1[i1], ba2[i2])
|
||||
swap(uwa1[i1], uwa2[i2])
|
||||
swap(wa1[i1], wa2[i2])
|
||||
|
||||
swap(uba1[1], ub1)
|
||||
swap(uba1[i1], ub1)
|
||||
swap(uwa1[1], uw1)
|
||||
swap(uwa1[i1], uw1)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user