mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
also provide a X16-style JSRFAR implementation for the C64. Enable callfar() and callfar2() on the C64 and C128.
This commit is contained in:
parent
459e9f8f3b
commit
7fd3e9bb7d
@ -208,15 +208,22 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun funcCallFar(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
if(asmgen.options.compTarget.name != "cx16")
|
||||
throw AssemblyError("callfar only works on cx16 target at this time")
|
||||
val targetName = asmgen.options.compTarget.name
|
||||
if(targetName !in arrayOf("cx16", "c64", "c128"))
|
||||
throw AssemblyError("callfar only works on cx16, c64 and c128 targets at this time")
|
||||
|
||||
val jsrfar = when(targetName) {
|
||||
"cx16" -> "cx16.JSRFAR"
|
||||
"c64" -> "c64.x16jsrfar"
|
||||
"c128" -> "c128.x16jsrfar"
|
||||
else -> TODO("jsrfar routine")
|
||||
}
|
||||
val constBank = fcall.args[0].asConstInteger()
|
||||
val constAddress = fcall.args[1].asConstInteger()
|
||||
if(constBank!=null && constAddress!=null) {
|
||||
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.AY) // uword argument
|
||||
asmgen.out("""
|
||||
jsr cx16.JSRFAR
|
||||
jsr $jsrfar
|
||||
.word ${constAddress.toHex()}
|
||||
.byte $constBank""")
|
||||
} else {
|
||||
@ -226,7 +233,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta (+)+0 | sty (+)+1")
|
||||
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.AY) // uword argument
|
||||
asmgen.out("""
|
||||
jsr cx16.JSRFAR
|
||||
jsr $jsrfar
|
||||
+ .word 0
|
||||
+ .byte 0""")
|
||||
}
|
||||
@ -238,8 +245,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun funcCallFar2(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
if(asmgen.options.compTarget.name != "cx16")
|
||||
throw AssemblyError("callfar2 only works on cx16 target at this time")
|
||||
val targetName = asmgen.options.compTarget.name
|
||||
if(targetName !in arrayOf("cx16", "c64", "c128"))
|
||||
throw AssemblyError("callfar2 only works on cx16, c64 and c128 targets at this time")
|
||||
|
||||
fun assignArgs() {
|
||||
fun assign(value: PtExpression, register: Char) {
|
||||
@ -260,12 +268,18 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
TODO("callfar2: support non-const argument values")
|
||||
}
|
||||
|
||||
val jsrfar = when(targetName) {
|
||||
"cx16" -> "cx16.JSRFAR"
|
||||
"c64" -> "c64.x16jsrfar"
|
||||
"c128" -> "c128.x16jsrfar"
|
||||
else -> TODO("jsrfar routine")
|
||||
}
|
||||
val constBank = fcall.args[0].asConstInteger()
|
||||
val constAddress = fcall.args[1].asConstInteger()
|
||||
if(constBank!=null && constAddress!=null) {
|
||||
assignArgs()
|
||||
asmgen.out("""
|
||||
jsr cx16.JSRFAR
|
||||
jsr $jsrfar
|
||||
.word ${constAddress.toHex()}
|
||||
.byte $constBank""")
|
||||
} else {
|
||||
@ -275,7 +289,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta (+)+0 | sty (+)+1")
|
||||
assignArgs()
|
||||
asmgen.out("""
|
||||
jsr cx16.JSRFAR
|
||||
jsr $jsrfar
|
||||
+ .word 0
|
||||
+ .byte 0""")
|
||||
}
|
||||
|
@ -54,27 +54,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
)
|
||||
}
|
||||
"c64" -> {
|
||||
// a bit bloated because it has to retain the status flags and A register
|
||||
asmgen.out("""
|
||||
; start doing a jsr to another bank
|
||||
php
|
||||
pha
|
||||
lda $01
|
||||
sta +
|
||||
lda #$bank
|
||||
sta $01
|
||||
pla
|
||||
plp
|
||||
jsr $subAsmName
|
||||
php
|
||||
pha
|
||||
lda +
|
||||
sta $01
|
||||
pla
|
||||
plp
|
||||
jmp ++
|
||||
+ .byte 0 ; original banks
|
||||
+""")
|
||||
jsr c64.x16jsrfar
|
||||
.word $subAsmName ; ${sub.address!!.second.toHex()}
|
||||
.byte $bank"""
|
||||
)
|
||||
}
|
||||
"c128" -> {
|
||||
asmgen.out("""
|
||||
|
@ -332,6 +332,68 @@ inline asmsub getbanks() -> ubyte @A {
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub x16jsrfar() {
|
||||
%asm {{
|
||||
; setup a JSRFAR call (using X16 call convention)
|
||||
sta P8ZP_SCRATCH_W2 ; save A
|
||||
sty P8ZP_SCRATCH_W2+1 ; save Y
|
||||
php
|
||||
pla
|
||||
sta P8ZP_SCRATCH_REG ; save Status
|
||||
|
||||
pla
|
||||
sta P8ZP_SCRATCH_W1
|
||||
pla
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
|
||||
; retrieve arguments
|
||||
ldy #$01
|
||||
lda (P8ZP_SCRATCH_W1),y ; grab low byte of target address
|
||||
sta _jmpfar+1
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y ; now the high byte
|
||||
sta _jmpfar+2
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y ; then the target bank
|
||||
sta P8ZP_SCRATCH_B1
|
||||
|
||||
; adjust return address to skip over the arguments
|
||||
clc
|
||||
lda P8ZP_SCRATCH_W1
|
||||
adc #3
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc #0
|
||||
pha
|
||||
lda P8ZP_SCRATCH_W1
|
||||
pha
|
||||
lda $01 ; save old ram banks
|
||||
pha
|
||||
; set target bank, restore A, Y and flags
|
||||
lda P8ZP_SCRATCH_REG
|
||||
pha
|
||||
lda P8ZP_SCRATCH_B1
|
||||
jsr banks
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
plp
|
||||
jsr _jmpfar ; do the actual call
|
||||
; restore bank without clobbering status flags and A register
|
||||
sta P8ZP_SCRATCH_W1
|
||||
php
|
||||
pla
|
||||
sta P8ZP_SCRATCH_B1
|
||||
pla
|
||||
jsr banks
|
||||
lda P8ZP_SCRATCH_B1
|
||||
pha
|
||||
lda P8ZP_SCRATCH_W1
|
||||
plp
|
||||
rts
|
||||
|
||||
_jmpfar jmp $0000 ; modified
|
||||
}}
|
||||
}
|
||||
|
||||
sub get_vic_memory_base() -> uword {
|
||||
; one of the 4 possible banks. $0000/$4000/$8000/$c000.
|
||||
|
@ -194,15 +194,15 @@ call (address) -> uword
|
||||
But because it doesn't handle bank switching etcetera by itself,
|
||||
it is a lot faster than ``callfar``. And it works on other systems than just the Commander X16.
|
||||
|
||||
callfar (bank, address, argumentword) -> uword ; NOTE: specific to cx16 target for now
|
||||
Calls an assembly routine in another bank on the Commander X16 (using its ``JSRFAR`` routine)
|
||||
callfar (bank, address, argumentword) -> uword
|
||||
Calls an assembly routine in another bank.
|
||||
Be aware that ram OR rom bank may be changed depending on the address it jumps to!
|
||||
The argumentword will be loaded into the A+Y registers before calling the routine.
|
||||
The uword value that the routine returns in the A+Y registers, will be returned.
|
||||
NOTE: this routine is very inefficient, so don't use it to call often. Set the bank yourself
|
||||
or even write a custom tailored trampoline routine if you need to. Or use ``call`` if you can.
|
||||
|
||||
callfar2 (bank, address, argA, argX, argY, argCarry) -> uword ; NOTE: specific to cx16 target for now
|
||||
callfar2 (bank, address, argA, argX, argY, argCarry) -> uword
|
||||
Identical to ``callfar``, except here you can give arguments not only for AY,
|
||||
but for each of the A, X and Y registers (each an ubyte) and the Carry status bit as well (a boolean).
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
in translateFunctionCall(), make the JSRFAR bloat code for the C64 into a subroutine like the kernal JSRFAR on the X16
|
||||
|
||||
fix that on C64 when program ends halfway in basic address space $a000+ the sysinit code that banks out the basic Rom
|
||||
is actually not reachable yet because it's at the end of the program in basic rom space?
|
||||
|
||||
|
@ -4,30 +4,39 @@
|
||||
|
||||
main {
|
||||
|
||||
romsub @bank 0 $4000 = routine(uword argument @AY) -> ubyte @A
|
||||
romsub @bank 15 $ffd2 = character_out(ubyte char @A)
|
||||
|
||||
romsub @bank %100 $f800 = routine_in_kernal_addr_space(uword arg @AY) -> uword @AY
|
||||
; ^-- I/O enabled, basic and kernal roms banked out
|
||||
sub start() {
|
||||
sys.memcopy(&the_routine, $4000, 255)
|
||||
; copy the routine into kernal area address space
|
||||
sys.memcopy(&the_invert_routine, $f800, 255)
|
||||
|
||||
cx16.r0L = routine($2233)
|
||||
txt.print("result=")
|
||||
txt.print_ub(cx16.r0L)
|
||||
cx16.r0 = the_invert_routine(12345)
|
||||
txt.print("inverted (normal)=")
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
cx16.r0L = routine($3344)
|
||||
txt.print("result=")
|
||||
txt.print_ub(cx16.r0L)
|
||||
cx16.r0 = routine_in_kernal_addr_space(12345)
|
||||
txt.print("inverted (kernal space)=")
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
txt.print("inverted (callfar)=")
|
||||
cx16.r0=callfar(%100, $f800, 12345)
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
txt.print("inverted (callfar2)=")
|
||||
cx16.r0=callfar2(%100, $f800, 57, 0, 48, false)
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.nl()
|
||||
|
||||
character_out('!')
|
||||
character_out('\n')
|
||||
}
|
||||
|
||||
asmsub the_routine(uword arg @AY) -> ubyte @A {
|
||||
asmsub the_invert_routine(uword arg @AY) -> uword @AY {
|
||||
%asm {{
|
||||
sty P8ZP_SCRATCH_REG
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
eor #$ff
|
||||
pha
|
||||
tya
|
||||
eor #$ff
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user