This commit is contained in:
Irmen de Jong 2017-12-30 20:03:19 +01:00
parent a7465f480a
commit be40cdd8aa
6 changed files with 116 additions and 25 deletions

View File

@ -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")

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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.