mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
math
This commit is contained in:
parent
a7465f480a
commit
be40cdd8aa
@ -1723,9 +1723,9 @@ class CodeGenerator:
|
||||
if rvalue.datatype == DataType.FLOAT:
|
||||
with self.preserving_registers({'A', 'X', 'Y'}, loads_a_within=True):
|
||||
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\tsta c64.SCRATCH_ZPWORD+1")
|
||||
self.p("\t\tsta c64.SCRATCH_ZPWORD1+1")
|
||||
self.p("\t\tldx #<" + l_str)
|
||||
self.p("\t\tldy #>" + l_str)
|
||||
self.p("\t\tjsr c64_lib.copy_mflt")
|
||||
|
@ -208,7 +208,8 @@ class SubroutineDef(SymbolDefinition):
|
||||
class Zeropage:
|
||||
SCRATCH_B1 = 0x02
|
||||
SCRATCH_B2 = 0x03
|
||||
SCRATCH_W1 = 0xfd # $fd/$fe
|
||||
SCRATCH_W1 = 0xfb # $fb/$fc
|
||||
SCRATCH_W2 = 0xfd # $fd/$fe
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.unused_bytes = [] # type: List[int]
|
||||
@ -219,13 +220,14 @@ class Zeropage:
|
||||
if self._configured:
|
||||
raise SymbolError("cannot configure the ZP multiple times")
|
||||
if clobber_zp:
|
||||
self.unused_bytes = list(range(0x04, 0x80)) + [0xfc, 0xff]
|
||||
self.unused_words = list(range(0x80, 0xfc, 2))
|
||||
self.unused_bytes = list(range(0x04, 0x80)) + [0xff]
|
||||
self.unused_words = list(range(0x80, 0xfb, 2))
|
||||
else:
|
||||
# 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_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_B2 not in self.unused_bytes and self.SCRATCH_B2 not in self.unused_words
|
||||
self._configured = True
|
||||
|
@ -12,7 +12,8 @@ output raw
|
||||
~ c64 {
|
||||
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 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 .word CINV = $0314 ; IRQ vector
|
||||
@ -717,25 +718,25 @@ sub input_chars (buffer: AX) -> (A?, Y) {
|
||||
asm {
|
||||
|
||||
; ---- 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
|
||||
sty c64.SCRATCH_ZPWORD+1
|
||||
sty c64.SCRATCH_ZPWORD1+1
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZP1),y
|
||||
sta (c64.SCRATCH_ZPWORD),y
|
||||
sta (c64.SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
lda (c64.SCRATCH_ZP1),y
|
||||
sta (c64.SCRATCH_ZPWORD),y
|
||||
sta (c64.SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
lda (c64.SCRATCH_ZP1),y
|
||||
sta (c64.SCRATCH_ZPWORD),y
|
||||
sta (c64.SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
lda (c64.SCRATCH_ZP1),y
|
||||
sta (c64.SCRATCH_ZPWORD),y
|
||||
sta (c64.SCRATCH_ZPWORD1),y
|
||||
iny
|
||||
lda (c64.SCRATCH_ZP1),y
|
||||
sta (c64.SCRATCH_ZPWORD),y
|
||||
ldy c64.SCRATCH_ZPWORD+1
|
||||
sta (c64.SCRATCH_ZPWORD1),y
|
||||
ldy c64.SCRATCH_ZPWORD1+1
|
||||
rts
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,11 @@ zp_backup .fill 254, 0
|
||||
|
||||
|
||||
~ il65_lib {
|
||||
; note: the following two ZP scratch registers must be the same as in c64lib
|
||||
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
; note: the following ZP scratch registers must be the same as in c64lib
|
||||
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 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 {
|
||||
|
@ -12,9 +12,11 @@
|
||||
output raw
|
||||
|
||||
~ math {
|
||||
; note: the following two ZP scratch registers must be the same as in c64lib
|
||||
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||
; note: the following ZP scratch registers must be the same as in c64lib
|
||||
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 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)
|
||||
; division by zero will result in quotient = 255 and remainder = original number
|
||||
asm {
|
||||
stx SCRATCH_ZP1
|
||||
sty SCRATCH_ZP2
|
||||
|
||||
lda #0
|
||||
ldx #8
|
||||
asl SCRATCH_ZP1
|
||||
@ -82,9 +119,58 @@ sub divide_bytes (numerator: X, denominator: Y) -> (X, A) {
|
||||
+ rol SCRATCH_ZP1
|
||||
dex
|
||||
bne -
|
||||
|
||||
ldx SCRATCH_ZP1
|
||||
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
|
||||
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:
|
||||
- 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,
|
||||
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.
|
||||
@ -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``
|
||||
|
||||
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,
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user