move the program startup and cleanup machinery to the front of the program to keep it in system ram

This commit is contained in:
Irmen de Jong 2024-11-05 22:12:25 +01:00
parent a5c7393561
commit 491e5dbcfb
9 changed files with 38 additions and 33 deletions

View File

@ -32,10 +32,6 @@ internal class ProgramAndVarsGen(
internal fun generate() {
header()
val allBlocks = program.allBlocks()
if(allBlocks.first().name != "p8b_main" && allBlocks.first().name != "main")
throw AssemblyError("first block should be 'main' or 'p8b_main'")
if(errors.noErrors()) {
program.allBlocks().forEach { block2asm(it) }
@ -114,7 +110,7 @@ internal class ProgramAndVarsGen(
asmgen.out(" .word (+), $year")
asmgen.out(" .null $9e, format(' %d ', prog8_entrypoint), $3a, $8f, ' prog8'")
asmgen.out("+\t.word 0")
asmgen.out("prog8_entrypoint\t; assembly code starts here")
asmgen.out("prog8_entrypoint")
asmgen.out(" cld")
asmgen.out(" tsx ; save stackpointer for sys.exit()")
asmgen.out(" stx prog8_lib.orig_stackpointer")

View File

@ -481,7 +481,7 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt
callGraph.checkRecursiveCalls(errors)
program.verifyFunctionArgTypes(errors, compilerOptions)
errors.report()
program.moveMainBlockAsFirst()
program.moveMainBlockAsFirst(compilerOptions.compTarget)
program.checkValid(errors, compilerOptions) // check if final tree is still valid
errors.report()
}

View File

@ -1,5 +1,6 @@
package prog8.compiler.astprocessing
import prog8.ast.IStatementContainer
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.expressions.CharLiteral
@ -10,6 +11,7 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
import prog8.code.target.VMTarget
import java.io.CharConversionException
@ -136,9 +138,10 @@ internal fun Program.variousCleanups(errors: IErrorReporter, options: Compilatio
}
}
internal fun Program.moveMainBlockAsFirst() {
internal fun Program.moveMainBlockAsFirst(target: ICompilationTarget) {
// The module containing the program entrypoint is moved to the first in the sequence.
// the "main" block containing the entrypoint is moved to the top in there.
// The "main" block containing the entrypoint is moved to the top in there.
// The startup and cleanup machinery is moved to the front as well.
val module = this.entrypoint.definingModule
val block = this.entrypoint.definingBlock
@ -149,6 +152,22 @@ internal fun Program.moveMainBlockAsFirst() {
module.statements.add(block)
else
module.statements.add(afterDirective, block)
if(target.name != VMTarget.NAME) {
// the program startup and cleanup machinery needs to be located in system ram
// so in an attempt to not be pushed into ROM space at the end of the program,
// this moves that block to the beginning of the program as much as possible.
val startupBlock = this.allBlocks.single { it.name == "p8_sys_startup" }
val mainBlockIdx = module.statements.indexOf(block)
(startupBlock.parent as IStatementContainer).remove(startupBlock)
if (block.address == null) {
module.statements.add(mainBlockIdx, startupBlock)
} else {
module.statements.add(mainBlockIdx + 1, startupBlock)
}
startupBlock.parent = module
}
}
internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolean {

View File

@ -44,7 +44,7 @@ class TestCallgraph: FunSpec({
graph.unused(toplevelModule) shouldBe false
graph.unused(importedModule) shouldBe false
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single()
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single{it.name=="main"}
for(stmt in mainBlock.statements) {
val sub = stmt as Subroutine
graph.calls shouldNotContainKey sub
@ -85,7 +85,7 @@ class TestCallgraph: FunSpec({
graph.unused(toplevelModule) shouldBe false
graph.unused(importedModule) shouldBe false
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single()
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single{it.name=="main"}
val startSub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="start"}
val emptySub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="empty"}

View File

@ -35,8 +35,7 @@ class TestOptimization: FunSpec({
}
"""
val result = compileText(C64Target(), true, sourcecode)!!
val toplevelModule = result.compilerAst.toplevelModule
val mainBlock = toplevelModule.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val startSub = mainBlock.statements.single() as Subroutine
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub
withClue("only start sub should remain") {
@ -85,8 +84,7 @@ main {
}
"""
val result = compileText(C64Target(), true, sourcecode)!!
val toplevelModule = result.compilerAst.toplevelModule
val mainBlock = toplevelModule.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val startSub = mainBlock.statements[0] as Subroutine
val emptySub = mainBlock.statements[1] as Subroutine
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub

View File

@ -46,8 +46,7 @@ class TestScoping: FunSpec({
"""
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
val module = result.compilerAst.toplevelModule
val mainBlock = module.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val start = mainBlock.statements.single() as Subroutine
val repeatbody = start.statements.filterIsInstance<RepeatLoop>().single().body
withClue("no vars moved to main block") {
@ -120,8 +119,7 @@ class TestScoping: FunSpec({
"""
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
val module = result.compilerAst.toplevelModule
val mainBlock = module.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val start = mainBlock.statements.single() as Subroutine
val labels = start.statements.filterIsInstance<Label>()
withClue("only one label in subroutine scope") {

View File

@ -60,8 +60,7 @@ class TestSubroutines: FunSpec({
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val module = result.compilerAst.toplevelModule
val mainBlock = module.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
asmfunc.isAsmSubroutine shouldBe true
@ -119,8 +118,7 @@ class TestSubroutines: FunSpec({
}
"""
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
val module = result.compilerAst.toplevelModule
val mainBlock = module.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
val emptysub = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="emptysub"}
@ -181,8 +179,7 @@ class TestSubroutines: FunSpec({
"""
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
val module = result.compilerAst.toplevelModule
val mainBlock = module.statements.single() as Block
val mainBlock = result.compilerAst.entrypoint.definingBlock
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
withClue("ubyte array param should have been replaced by UWORD pointer") {

View File

@ -1,9 +1,6 @@
TODO
====
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?
make @bank accept a variable as well to make it dynamic
rename 'romsub' to 'extsub' ? keep romsub as alias?

View File

@ -15,9 +15,9 @@ basic_area $a000 {
}
}
hiram_area $c000 {
%option force_output
sub thing() {
cx16.r0++
}
}
;hiram_area $c000 {
; %option force_output
; sub thing() {
; cx16.r0++
; }
;}