tweak program start initialization and fix cleanup at exit for atari and pet compiler targets

This commit is contained in:
Irmen de Jong 2024-09-27 02:14:54 +02:00
parent 4c843571ea
commit 04cb684fd4
5 changed files with 76 additions and 36 deletions

View File

@ -103,6 +103,9 @@ internal class ProgramAndVarsGen(
asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'") asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'")
asmgen.out("+\t.word 0") asmgen.out("+\t.word 0")
asmgen.out("prog8_entrypoint\t; assembly code starts here") asmgen.out("prog8_entrypoint\t; assembly code starts here")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr sys.init_system") asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2") asmgen.out(" jsr sys.init_system_phase2")
@ -110,6 +113,9 @@ internal class ProgramAndVarsGen(
CbmPrgLauncherType.NONE -> { CbmPrgLauncherType.NONE -> {
asmgen.out("; ---- program without basic sys call ----") asmgen.out("; ---- program without basic sys call ----")
asmgen.out("* = ${options.loadAddress.toHex()}") asmgen.out("* = ${options.loadAddress.toHex()}")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr sys.init_system") asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2") asmgen.out(" jsr sys.init_system_phase2")
@ -119,6 +125,9 @@ internal class ProgramAndVarsGen(
OutputType.XEX -> { OutputType.XEX -> {
asmgen.out("; ---- atari xex program ----") asmgen.out("; ---- atari xex program ----")
asmgen.out("* = ${options.loadAddress.toHex()}") asmgen.out("* = ${options.loadAddress.toHex()}")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")
if(!options.noSysInit) if(!options.noSysInit)
asmgen.out(" jsr sys.init_system") asmgen.out(" jsr sys.init_system")
asmgen.out(" jsr sys.init_system_phase2") asmgen.out(" jsr sys.init_system_phase2")
@ -149,7 +158,10 @@ internal class ProgramAndVarsGen(
asmgen.out(" jsr p8b_main.p8s_start | lda #0 | sta ${"$"}ff00") asmgen.out(" jsr p8b_main.p8s_start | lda #0 | sta ${"$"}ff00")
asmgen.out(" jmp sys.cleanup_at_exit") asmgen.out(" jmp sys.cleanup_at_exit")
} }
else -> asmgen.jmp("p8b_main.p8s_start") else -> {
asmgen.out(" jsr p8b_main.p8s_start")
asmgen.out(" jmp sys.cleanup_at_exit")
}
} }
} }
@ -451,22 +463,7 @@ internal class ProgramAndVarsGen(
} }
private fun entrypointInitialization() { private fun entrypointInitialization() {
asmgen.out("; program startup initialization") // initialize block-level (global) variables at program start
asmgen.out(" cld | tsx | stx prog8_lib.orig_stackpointer ; required for sys.exit()")
// set full BSS area to zero
asmgen.out("""
.if prog8_bss_section_size>0
; reset all variables in BSS section to zero
lda #<prog8_bss_section_start
ldy #>prog8_bss_section_start
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldx #<prog8_bss_section_size
ldy #>prog8_bss_section_size
lda #0
jsr prog8_lib.memset
.endif""")
blockVariableInitializers.forEach { blockVariableInitializers.forEach {
if (it.value.isNotEmpty()) if (it.value.isNotEmpty())
asmgen.out(" jsr ${it.key.name}.prog8_init_vars") asmgen.out(" jsr ${it.key.name}.prog8_init_vars")
@ -517,9 +514,8 @@ internal class ProgramAndVarsGen(
arrayVariable2asm(varname, it.alloc.dt, it.value, null) arrayVariable2asm(varname, it.alloc.dt, it.value, null)
} }
asmgen.out("""+ // zero out the BSS area
clv asmgen.out("+ jsr prog8_lib.program_startup_clear_bss")
clc""")
} }
private class ZpStringWithInitial( private class ZpStringWithInitial(

View File

@ -44,6 +44,22 @@ sys {
}} }}
} }
asmsub cleanup_at_exit() {
; executed when the main subroutine does rts
%asm {{
_exitcodeCarry = *+1
lda #0
lsr a
_exitcode = *+1
lda #0 ; exit code possibly modified in exit()
_exitcodeX = *+1
ldx #0
_exitcodeY = *+1
ldy #0
rts
}}
}
asmsub reset_system() { asmsub reset_system() {
; Soft-reset the system back to initial power-on Basic prompt. ; Soft-reset the system back to initial power-on Basic prompt.
; TODO ; TODO
@ -248,27 +264,38 @@ save_SCRATCH_ZPWORD2 .word 0
asmsub exit(ubyte returnvalue @A) { asmsub exit(ubyte returnvalue @A) {
; -- immediately exit the program with a return code in the A register ; -- immediately exit the program with a return code in the A register
; TODO where to store A as exit code?
%asm {{ %asm {{
sta cleanup_at_exit._exitcode
ldx prog8_lib.orig_stackpointer ldx prog8_lib.orig_stackpointer
txs txs
rts ; return to original caller jmp cleanup_at_exit
}} }}
} }
asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) { asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) {
; -- immediately exit the program with result values in the A, X and Y registers. ; -- immediately exit the program with result values in the A, X and Y registers.
; TODO where to store A,X,Y as exit code?
%asm {{ %asm {{
jmp exit sta cleanup_at_exit._exitcode
stx cleanup_at_exit._exitcodeX
sty cleanup_at_exit._exitcodeY
ldx prog8_lib.orig_stackpointer
txs
jmp cleanup_at_exit
}} }}
} }
asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) { asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) {
; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register. ; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register.
; TODO where to store A,X,Y,Carry as exit code?
%asm {{ %asm {{
jmp exit sta cleanup_at_exit._exitcode
lda #0
rol a
sta cleanup_at_exit._exitcodeCarry
stx cleanup_at_exit._exitcodeX
sty cleanup_at_exit._exitcodeY
ldx prog8_lib.orig_stackpointer
txs
jmp cleanup_at_exit
}} }}
} }

View File

@ -5,6 +5,26 @@
orig_stackpointer .byte 0 ; stores the Stack pointer register at program start orig_stackpointer .byte 0 ; stores the Stack pointer register at program start
program_startup_clear_bss .proc
; this is always ran first thing from the start routine to clear out the BSS area
.if prog8_bss_section_size>0
; reset all variables in BSS section to zero
lda #<prog8_bss_section_start
ldy #>prog8_bss_section_start
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldx #<prog8_bss_section_size
ldy #>prog8_bss_section_size
lda #0
jsr prog8_lib.memset
.endif
clv
clc
rts
.pend
read_byte_from_address_in_AY_into_A .proc read_byte_from_address_in_AY_into_A .proc
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1

View File

@ -1,7 +1,7 @@
TODO TODO
==== ====
Can we move the asm init code that is injected into the start() subroutine, to init_system_phase2 instead? Shouldn't RAW output target have some initialization logic too? Does it even clear the variables/bss etc?
Doc improvements: some short overview for people coming from other programming languages like C: Doc improvements: some short overview for people coming from other programming languages like C:
tell something about prog8 not having function overloading, max 16 bit (u)word integer as native type (and floats sometimes), tell something about prog8 not having function overloading, max 16 bit (u)word integer as native type (and floats sometimes),

View File

@ -1,16 +1,13 @@
%import textio %import textio
%import floats %zeropage dontuse
%zeropage basicsafe %option no_sysinit
main { main {
uword @shared variable
sub start() { sub start() {
float fl = 5.23 txt.print("hello!\n")
fl = floats.ceil(fl) txt.print_uw(variable)
floats.print(fl)
txt.nl()
fl = 5.23
fl = floats.floor(fl)
floats.print(fl)
txt.nl() txt.nl()
sys.exit3(1,2,3,false)
} }
} }