mirror of
https://github.com/irmen/prog8.git
synced 2024-09-10 09:54:32 +00:00
math
This commit is contained in:
parent
a7465f480a
commit
be40cdd8aa
@ -1723,9 +1723,9 @@ class CodeGenerator:
|
|||||||
if rvalue.datatype == DataType.FLOAT:
|
if rvalue.datatype == DataType.FLOAT:
|
||||||
with self.preserving_registers({'A', 'X', 'Y'}, loads_a_within=True):
|
with self.preserving_registers({'A', 'X', 'Y'}, loads_a_within=True):
|
||||||
self.p("\t\tlda #<" + r_str)
|
self.p("\t\tlda #<" + r_str)
|
||||||
self.p("\t\tsta c64.SCRATCH_ZPWORD")
|
self.p("\t\tsta c64.SCRATCH_ZPWORD1")
|
||||||
self.p("\t\tlda #>" + r_str)
|
self.p("\t\tlda #>" + r_str)
|
||||||
self.p("\t\tsta c64.SCRATCH_ZPWORD+1")
|
self.p("\t\tsta c64.SCRATCH_ZPWORD1+1")
|
||||||
self.p("\t\tldx #<" + l_str)
|
self.p("\t\tldx #<" + l_str)
|
||||||
self.p("\t\tldy #>" + l_str)
|
self.p("\t\tldy #>" + l_str)
|
||||||
self.p("\t\tjsr c64_lib.copy_mflt")
|
self.p("\t\tjsr c64_lib.copy_mflt")
|
||||||
|
@ -208,7 +208,8 @@ class SubroutineDef(SymbolDefinition):
|
|||||||
class Zeropage:
|
class Zeropage:
|
||||||
SCRATCH_B1 = 0x02
|
SCRATCH_B1 = 0x02
|
||||||
SCRATCH_B2 = 0x03
|
SCRATCH_B2 = 0x03
|
||||||
SCRATCH_W1 = 0xfd # $fd/$fe
|
SCRATCH_W1 = 0xfb # $fb/$fc
|
||||||
|
SCRATCH_W2 = 0xfd # $fd/$fe
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.unused_bytes = [] # type: List[int]
|
self.unused_bytes = [] # type: List[int]
|
||||||
@ -219,13 +220,14 @@ class Zeropage:
|
|||||||
if self._configured:
|
if self._configured:
|
||||||
raise SymbolError("cannot configure the ZP multiple times")
|
raise SymbolError("cannot configure the ZP multiple times")
|
||||||
if clobber_zp:
|
if clobber_zp:
|
||||||
self.unused_bytes = list(range(0x04, 0x80)) + [0xfc, 0xff]
|
self.unused_bytes = list(range(0x04, 0x80)) + [0xff]
|
||||||
self.unused_words = list(range(0x80, 0xfc, 2))
|
self.unused_words = list(range(0x80, 0xfb, 2))
|
||||||
else:
|
else:
|
||||||
# these are valid for the C-64 (when no RS232 I/O is performed):
|
# these are valid for the C-64 (when no RS232 I/O is performed):
|
||||||
# ($02, $03, $fd-$fe are reserved as scratch addresses for various routines)
|
# ($02, $03, $fb-$fc, $fd-$fe are reserved as scratch addresses for various routines)
|
||||||
self.unused_bytes = [0x04, 0x05, 0x06, 0x2a, 0x52] # 5 zp variables (1 byte each)
|
self.unused_bytes = [0x04, 0x05, 0x06, 0x2a, 0x52] # 5 zp variables (1 byte each)
|
||||||
self.unused_words = [0xf7, 0xf9, 0xfb] # 3 zp word variables (2 bytes each)
|
self.unused_words = [0xf7, 0xf9] # 2 zp word variables (2 bytes each)
|
||||||
|
# @todo more clever allocating, don't have fixed bytes and words
|
||||||
assert self.SCRATCH_B1 not in self.unused_bytes and self.SCRATCH_B1 not in self.unused_words
|
assert self.SCRATCH_B1 not in self.unused_bytes and self.SCRATCH_B1 not in self.unused_words
|
||||||
assert self.SCRATCH_B2 not in self.unused_bytes and self.SCRATCH_B2 not in self.unused_words
|
assert self.SCRATCH_B2 not in self.unused_bytes and self.SCRATCH_B2 not in self.unused_words
|
||||||
self._configured = True
|
self._configured = True
|
||||||
|
@ -12,7 +12,8 @@ output raw
|
|||||||
~ c64 {
|
~ c64 {
|
||||||
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
memory .byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
memory .byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
memory .word SCRATCH_ZPWORD = $fd ; scratch word in ZP ($fd/$fe)
|
memory .word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||||
|
memory .word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||||
|
|
||||||
memory .byte COLOR = $0286 ; cursor color
|
memory .byte COLOR = $0286 ; cursor color
|
||||||
memory .word CINV = $0314 ; IRQ vector
|
memory .word CINV = $0314 ; IRQ vector
|
||||||
@ -717,25 +718,25 @@ sub input_chars (buffer: AX) -> (A?, Y) {
|
|||||||
asm {
|
asm {
|
||||||
|
|
||||||
; ---- copy a 5 byte MFLT floating point variable to another place
|
; ---- copy a 5 byte MFLT floating point variable to another place
|
||||||
; input: X/Y = source address, SCRATCH_ZPWORD = destination address
|
; input: X/Y = source address, SCRATCH_ZPWORD1 = destination address
|
||||||
copy_mflt stx c64.SCRATCH_ZP1
|
copy_mflt stx c64.SCRATCH_ZP1
|
||||||
sty c64.SCRATCH_ZPWORD+1
|
sty c64.SCRATCH_ZPWORD1+1
|
||||||
ldy #0
|
ldy #0
|
||||||
lda (c64.SCRATCH_ZP1),y
|
lda (c64.SCRATCH_ZP1),y
|
||||||
sta (c64.SCRATCH_ZPWORD),y
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
iny
|
iny
|
||||||
lda (c64.SCRATCH_ZP1),y
|
lda (c64.SCRATCH_ZP1),y
|
||||||
sta (c64.SCRATCH_ZPWORD),y
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
iny
|
iny
|
||||||
lda (c64.SCRATCH_ZP1),y
|
lda (c64.SCRATCH_ZP1),y
|
||||||
sta (c64.SCRATCH_ZPWORD),y
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
iny
|
iny
|
||||||
lda (c64.SCRATCH_ZP1),y
|
lda (c64.SCRATCH_ZP1),y
|
||||||
sta (c64.SCRATCH_ZPWORD),y
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
iny
|
iny
|
||||||
lda (c64.SCRATCH_ZP1),y
|
lda (c64.SCRATCH_ZP1),y
|
||||||
sta (c64.SCRATCH_ZPWORD),y
|
sta (c64.SCRATCH_ZPWORD1),y
|
||||||
ldy c64.SCRATCH_ZPWORD+1
|
ldy c64.SCRATCH_ZPWORD1+1
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,11 @@ zp_backup .fill 254, 0
|
|||||||
|
|
||||||
|
|
||||||
~ il65_lib {
|
~ il65_lib {
|
||||||
; note: the following two ZP scratch registers must be the same as in c64lib
|
; note: the following ZP scratch registers must be the same as in c64lib
|
||||||
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
memory .byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
|
memory .word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||||
|
memory .word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||||
|
|
||||||
|
|
||||||
asm {
|
asm {
|
||||||
|
@ -12,9 +12,11 @@
|
|||||||
output raw
|
output raw
|
||||||
|
|
||||||
~ math {
|
~ math {
|
||||||
; note: the following two ZP scratch registers must be the same as in c64lib
|
; note: the following ZP scratch registers must be the same as in c64lib
|
||||||
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
memory .byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
|
memory .word SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
|
||||||
|
memory .word SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -65,13 +67,48 @@ sub multiply_bytes_addA_16 (byte1: X, byte2: Y, add: A) -> (A?, XY) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var .wordarray(2) multiply_words_product
|
||||||
|
sub multiply_words (number: XY) -> (A?, X?, Y?) { ; @todo '?' to mean all 3 registers
|
||||||
|
; ---- multiply two 16-bit words into a 32-bit result
|
||||||
|
; input: X/Y = first 16-bit number, SCRATCH_ZPWORD1 in ZP = second 16-bit number
|
||||||
|
; output: multiply_words_product 32-bits product, LSB order (low-to-high)
|
||||||
|
|
||||||
sub divide_bytes (numerator: X, denominator: Y) -> (X, A) {
|
asm {
|
||||||
|
stx SCRATCH_ZPWORD2
|
||||||
|
sty SCRATCH_ZPWORD2+1
|
||||||
|
|
||||||
|
mult16 lda #$00
|
||||||
|
sta multiply_words_product+2 ; clear upper bits of product
|
||||||
|
sta multiply_words_product+3
|
||||||
|
ldx #16 ; for all 16 bits...
|
||||||
|
- lsr SCRATCH_ZPWORD1+1 ; divide multiplier by 2
|
||||||
|
ror SCRATCH_ZPWORD1
|
||||||
|
bcc +
|
||||||
|
lda multiply_words_product+2 ; get upper half of product and add multiplicand
|
||||||
|
clc
|
||||||
|
adc SCRATCH_ZPWORD2
|
||||||
|
sta multiply_words_product+2
|
||||||
|
lda multiply_words_product+3
|
||||||
|
adc SCRATCH_ZPWORD2+1
|
||||||
|
+ ror a ; rotate partial product
|
||||||
|
sta multiply_words_product+3
|
||||||
|
ror multiply_words_product+2
|
||||||
|
ror multiply_words_product+1
|
||||||
|
ror multiply_words_product
|
||||||
|
dex
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub divmod_bytes (number: X, divisor: Y) -> (X, A) {
|
||||||
; ---- divide X by Y, result quotient in X, remainder in A (unsigned)
|
; ---- divide X by Y, result quotient in X, remainder in A (unsigned)
|
||||||
; division by zero will result in quotient = 255 and remainder = original number
|
; division by zero will result in quotient = 255 and remainder = original number
|
||||||
asm {
|
asm {
|
||||||
stx SCRATCH_ZP1
|
stx SCRATCH_ZP1
|
||||||
sty SCRATCH_ZP2
|
sty SCRATCH_ZP2
|
||||||
|
|
||||||
lda #0
|
lda #0
|
||||||
ldx #8
|
ldx #8
|
||||||
asl SCRATCH_ZP1
|
asl SCRATCH_ZP1
|
||||||
@ -82,9 +119,58 @@ sub divide_bytes (numerator: X, denominator: Y) -> (X, A) {
|
|||||||
+ rol SCRATCH_ZP1
|
+ rol SCRATCH_ZP1
|
||||||
dex
|
dex
|
||||||
bne -
|
bne -
|
||||||
|
|
||||||
ldx SCRATCH_ZP1
|
ldx SCRATCH_ZP1
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub divmod_words (divisor: XY) -> (A?, XY) {
|
||||||
|
; ---- divide two words (16 bit each) into 16 bit results
|
||||||
|
; input: SCRATCH_ZPWORD1 in ZP: 16 bit number, X/Y: 16 bit divisor
|
||||||
|
; output: SCRATCH_ZPWORD1 in ZP: 16 bit result, X/Y: 16 bit remainder
|
||||||
|
; division by zero will result in quotient = 65535 and remainder = divident
|
||||||
|
|
||||||
|
asm {
|
||||||
|
remainder = SCRATCH_ZP1
|
||||||
|
|
||||||
|
stx SCRATCH_ZPWORD2
|
||||||
|
sty SCRATCH_ZPWORD2+1
|
||||||
|
lda #0 ;preset remainder to 0
|
||||||
|
sta remainder
|
||||||
|
sta remainder+1
|
||||||
|
ldx #16 ;repeat for each bit: ...
|
||||||
|
|
||||||
|
- asl SCRATCH_ZPWORD1 ;number lb & hb*2, msb -> Carry
|
||||||
|
rol SCRATCH_ZPWORD1+1
|
||||||
|
rol remainder ;remainder lb & hb * 2 + msb from carry
|
||||||
|
rol remainder+1
|
||||||
|
lda remainder
|
||||||
|
sec
|
||||||
|
sbc SCRATCH_ZPWORD2 ;substract divisor to see if it fits in
|
||||||
|
tay ;lb result -> Y, for we may need it later
|
||||||
|
lda remainder+1
|
||||||
|
sbc 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 SCRATCH_ZPWORD1 ;and INCrement result cause divisor fit in 1 times
|
||||||
|
|
||||||
|
+ dex
|
||||||
|
bne -
|
||||||
|
|
||||||
|
lda remainder ; copy remainder to ZPWORD2 result register
|
||||||
|
sta SCRATCH_ZPWORD2
|
||||||
|
lda remainder+1
|
||||||
|
sta SCRATCH_ZPWORD2+1
|
||||||
|
|
||||||
|
ldx SCRATCH_ZPWORD1 ; load division result in X/Y
|
||||||
|
ldy SCRATCH_ZPWORD1+1
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ The following 6502 hardware registers are directly accessible in your code (and
|
|||||||
The zero page locations ``$02`` - ``$ff`` can be regarded as 254 other registers because
|
The zero page locations ``$02`` - ``$ff`` can be regarded as 254 other registers because
|
||||||
they take less clock cycles to access and need fewer instruction bytes than access to other memory locations.
|
they take less clock cycles to access and need fewer instruction bytes than access to other memory locations.
|
||||||
Theoretically you can use all of them in your program but there are a few limitations:
|
Theoretically you can use all of them in your program but there are a few limitations:
|
||||||
- the four locations ``$02``, ``$03``, ``$fd - $fe`` are reserved for internal use as scratch registers by IL65
|
- several locations (``$02``, ``$03``, ``$fb - $fc``, ``$fd - $fe``) are reserved for internal use as scratch registers by IL65
|
||||||
- most other addresses often are in use by the machine's operating system or kernal,
|
- most other addresses often are in use by the machine's operating system or kernal,
|
||||||
and overwriting them can crash the machine. Your program must take over the entire
|
and overwriting them can crash the machine. Your program must take over the entire
|
||||||
system to be able to safely use all zero page locations.
|
system to be able to safely use all zero page locations.
|
||||||
@ -99,7 +99,7 @@ For the Commodore-64 here is a list of free-to-use zero page locations even when
|
|||||||
``$f7`` - ``$f8``; ``$f9`` - ``$fa``; ``$fb`` - ``$fc``; ``$fd`` - ``$fe``
|
``$f7`` - ``$f8``; ``$f9`` - ``$fa``; ``$fb`` - ``$fc``; ``$fd`` - ``$fe``
|
||||||
|
|
||||||
The four reserved locations mentioned above are subtracted from this set, leaving you with
|
The four reserved locations mentioned above are subtracted from this set, leaving you with
|
||||||
five 1-byte and three 2-byte usable zero page registers.
|
five 1-byte and two 2-byte usable zero page registers.
|
||||||
IL65 knows about all this: it will use the above zero page locations to place its ZP variables in,
|
IL65 knows about all this: it will use the above zero page locations to place its ZP variables in,
|
||||||
until they're all used up. You can instruct it to treat your program as taking over the entire
|
until they're all used up. You can instruct it to treat your program as taking over the entire
|
||||||
machine, in which case all of the zero page locations are suddenly available for variables.
|
machine, in which case all of the zero page locations are suddenly available for variables.
|
||||||
|
Loading…
Reference in New Issue
Block a user