mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
move the program startup and cleanup machinery to the front of the program to keep it in system ram
This commit is contained in:
parent
a5c7393561
commit
491e5dbcfb
@ -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")
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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") {
|
||||
|
@ -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?
|
||||
|
@ -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++
|
||||
; }
|
||||
;}
|
||||
|
Loading…
Reference in New Issue
Block a user