mirror of
https://github.com/irmen/prog8.git
synced 2025-02-09 07:31:34 +00:00
jsrfar stuff
This commit is contained in:
parent
5b1143bcb3
commit
459e9f8f3b
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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 ----
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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?
|
||||||
|
|
||||||
|
138
examples/test.p8
138
examples/test.p8
@ -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()
|
||||||
|
; }
|
||||||
|
;}
|
||||||
|
;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user