jsrfar stuff

This commit is contained in:
Irmen de Jong 2024-11-05 00:15:40 +01:00
parent 5b1143bcb3
commit 459e9f8f3b
5 changed files with 146 additions and 74 deletions

View File

@ -54,7 +54,9 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
) )
} }
"c64" -> { "c64" -> {
// a bit bloated because it has to retain the status flags and A register
asmgen.out(""" asmgen.out("""
; start doing a jsr to another bank
php php
pha pha
lda $01 lda $01
@ -75,27 +77,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
+""") +""")
} }
"c128" -> { "c128" -> {
// see https://cx16.dk/c128-kernal-routines/jsrfar.html
asmgen.out(""" asmgen.out("""
sty $08 jsr c128.x16jsrfar
stx $07 .word $subAsmName ; ${sub.address!!.second.toHex()}
sta $06 .byte $bank"""
php )
pla
sta $05
lda #$bank
ldy #>$subAsmName
ldx #<$subAsmName
sta $02
sty $03
stx $04
jsr c128.JSRFAR
lda $05
pha
lda $06
ldx $07
ldy $08
plp""")
} }
else -> throw AssemblyError("callfar is not supported on the selected compilation target") else -> throw AssemblyError("callfar is not supported on the selected compilation target")
} }

View File

@ -345,6 +345,56 @@ asmsub disable_basic() clobbers(A) {
}} }}
} }
asmsub x16jsrfar() {
%asm {{
; setup a JSRFAR call (using X16 call convention)
; see https://cx16.dk/c128-kernal-routines/jsrfar.html
sty $08 ; save registers
stx $07
sta $06
php ; including PSR
pla
sta $05
pla ; get original return address
sta $fa ; and store it in a temp ZP pointer
pla
sta $fb
ldy #$01
lda ($fa),y ; grab low byte of target address
sta $04
iny
lda ($fa),y ; now the high byte
sta $03
iny
lda ($fa),y ; then the target bank
sta $02
; replace the original return address by it + 3 to skip the data bytes
clc
lda $fa
adc #3
sta $fa
lda $fb
adc #0
pha
lda $fa
pha
jsr c128.JSRFAR ; call kernal's jsrfar routine
lda $05 ; populate registers
pha
lda $06
ldx $07
ldy $08
plp
rts ; and return
}}
}
; ---- end of C128 specific system utility routines ---- ; ---- end of C128 specific system utility routines ----
} }

View File

@ -165,10 +165,10 @@ internal fun Subroutine.hasRtsInAsm(checkOnlyLastInstruction: Boolean): Boolean
.filterIsInstance<InlineAssembly>() .filterIsInstance<InlineAssembly>()
if(checkOnlyLastInstruction) { if(checkOnlyLastInstruction) {
val lastAsm = asms.lastOrNull() ?: return false val lastAsm = asms.lastOrNull() ?: return false
val lastLine = lastAsm.assembly.lineSequence().map { it.trim() }.last { val lastLine = lastAsm.assembly.lineSequence().map { it.trim() }.lastOrNull {
it.isNotBlank() && (!it.startsWith(';') || it.contains("!notreached!")) it.isNotBlank() && (!it.startsWith(';') || it.contains("!notreached!"))
} }
if(lastLine.contains("!notreached!")) if(lastLine?.contains("!notreached!")==true)
return true return true
val inlineAsm = InlineAssembly(" $lastLine", lastAsm.isIR, lastAsm.position) val inlineAsm = InlineAssembly(" $lastLine", lastAsm.isIR, lastAsm.position)
return inlineAsm.hasReturnOrRts() return inlineAsm.hasReturnOrRts()

View File

@ -1,6 +1,8 @@
TODO 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 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? is actually not reachable yet because it's at the end of the program in basic rom space?

View File

@ -1,66 +1,100 @@
%import textio %import textio
%zeropage basicsafe %zeropage basicsafe
%option no_sysinit
main { main {
romsub @bank 0 $4000 = routine(uword argument @AY) -> ubyte @A
romsub @bank 15 $ffd2 = character_out(ubyte char @A)
sub start() { sub start() {
basic_area.routine1() sys.memcopy(&the_routine, $4000, 255)
hiram_area.routine2()
; copy the kernal area routine to actual kernal address space $f800 cx16.r0L = routine($2233)
sys.memcopy(&kernal_area.routine3, $f800, 255) txt.print("result=")
txt.print_ub(cx16.r0L)
txt.nl()
cx16.r0L = routine($3344)
txt.print("result=")
txt.print_ub(cx16.r0L)
txt.nl()
; how to call the routine using manual bank switching: character_out('!')
; c64.banks(%101) ; bank out kernal rom character_out('\n')
; call($f800) ; call our routine
; c64.banks(%111) ; kernal back
; how to use prog8's automatic bank switching:
romsub @bank %101 $f800 = kernal_routine()
kernal_routine()
} }
}
kernal_area { asmsub the_routine(uword arg @AY) -> ubyte @A {
; this routine is actually copied to kernal address space first
; we cannot use CHROUT when the kernal is banked out so we write to the screen directly
asmsub routine3() {
%asm {{ %asm {{
lda #<_message sty P8ZP_SCRATCH_REG
ldy #>_message clc
sta $fe adc P8ZP_SCRATCH_REG
sty $ff rts
ldy #0
- lda ($fe),y
beq +
sta $0400+240,y
iny
bne -
+ rts
_message
.enc 'screen'
.text "hello from kernal area $f800",0
.enc 'none'
; !notreached!
}} }}
} }
} }
;main {
basic_area $a000 { ; sub start() {
sub routine1() { ; basic_area.routine1()
txt.print("hello from basic rom area ") ; hiram_area.routine2()
txt.print_uwhex(&routine1, true) ;
txt.nl() ; ; copy the kernal area routine to actual kernal address space $f800
} ; sys.memcopy(&kernal_area.routine3, $f800, 255)
} ;
; ; how to call the routine using manual bank switching:
hiram_area $ca00 { ; ; c64.banks(%101) ; bank out kernal rom
sub routine2() { ; ; call($f800) ; call our routine
txt.print("hello from hiram area ") ; ; c64.banks(%111) ; kernal back
txt.print_uwhex(&routine2, true) ;
txt.nl() ; ; how to use prog8's automatic bank switching:
} ; romsub @bank %101 $f800 = kernal_routine()
} ;
; kernal_routine()
;
; txt.print("done!\n")
; }
;}
;
;kernal_area {
; ; this routine is actually copied to kernal address space first
; ; we cannot use CHROUT when the kernal is banked out so we write to the screen directly
; asmsub routine3() {
; %asm {{
; lda #<_message
; ldy #>_message
; sta $fe
; sty $ff
; ldy #0
;- lda ($fe),y
; beq +
; sta $0400+240,y
; iny
; bne -
;+ rts
;
;_message
; .enc 'screen'
; .text "hello from kernal area $f800",0
; .enc 'none'
; ; !notreached!
; }}
; }
;}
;
;
;basic_area $a000 {
; sub routine1() {
; txt.print("hello from basic rom area ")
; txt.print_uwhex(&routine1, true)
; txt.nl()
; }
;}
;
;hiram_area $ca00 {
; sub routine2() {
; txt.print("hello from hiram area ")
; txt.print_uwhex(&routine2, true)
; txt.nl()
; }
;}
;