mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 04:31:20 +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() {
|
internal fun generate() {
|
||||||
header()
|
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()) {
|
if(errors.noErrors()) {
|
||||||
program.allBlocks().forEach { block2asm(it) }
|
program.allBlocks().forEach { block2asm(it) }
|
||||||
@ -114,7 +110,7 @@ internal class ProgramAndVarsGen(
|
|||||||
asmgen.out(" .word (+), $year")
|
asmgen.out(" .word (+), $year")
|
||||||
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")
|
||||||
asmgen.out(" cld")
|
asmgen.out(" cld")
|
||||||
asmgen.out(" tsx ; save stackpointer for sys.exit()")
|
asmgen.out(" tsx ; save stackpointer for sys.exit()")
|
||||||
asmgen.out(" stx prog8_lib.orig_stackpointer")
|
asmgen.out(" stx prog8_lib.orig_stackpointer")
|
||||||
|
@ -481,7 +481,7 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt
|
|||||||
callGraph.checkRecursiveCalls(errors)
|
callGraph.checkRecursiveCalls(errors)
|
||||||
program.verifyFunctionArgTypes(errors, compilerOptions)
|
program.verifyFunctionArgTypes(errors, compilerOptions)
|
||||||
errors.report()
|
errors.report()
|
||||||
program.moveMainBlockAsFirst()
|
program.moveMainBlockAsFirst(compilerOptions.compTarget)
|
||||||
program.checkValid(errors, compilerOptions) // check if final tree is still valid
|
program.checkValid(errors, compilerOptions) // check if final tree is still valid
|
||||||
errors.report()
|
errors.report()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package prog8.compiler.astprocessing
|
package prog8.compiler.astprocessing
|
||||||
|
|
||||||
|
import prog8.ast.IStatementContainer
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.expressions.CharLiteral
|
import prog8.ast.expressions.CharLiteral
|
||||||
@ -10,6 +11,7 @@ import prog8.ast.statements.*
|
|||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
|
import prog8.code.target.VMTarget
|
||||||
import java.io.CharConversionException
|
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 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 module = this.entrypoint.definingModule
|
||||||
val block = this.entrypoint.definingBlock
|
val block = this.entrypoint.definingBlock
|
||||||
@ -149,6 +152,22 @@ internal fun Program.moveMainBlockAsFirst() {
|
|||||||
module.statements.add(block)
|
module.statements.add(block)
|
||||||
else
|
else
|
||||||
module.statements.add(afterDirective, block)
|
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 {
|
internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolean {
|
||||||
|
@ -44,7 +44,7 @@ class TestCallgraph: FunSpec({
|
|||||||
graph.unused(toplevelModule) shouldBe false
|
graph.unused(toplevelModule) shouldBe false
|
||||||
graph.unused(importedModule) 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) {
|
for(stmt in mainBlock.statements) {
|
||||||
val sub = stmt as Subroutine
|
val sub = stmt as Subroutine
|
||||||
graph.calls shouldNotContainKey sub
|
graph.calls shouldNotContainKey sub
|
||||||
@ -85,7 +85,7 @@ class TestCallgraph: FunSpec({
|
|||||||
graph.unused(toplevelModule) shouldBe false
|
graph.unused(toplevelModule) shouldBe false
|
||||||
graph.unused(importedModule) 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 startSub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="start"}
|
||||||
val emptySub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="empty"}
|
val emptySub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="empty"}
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@ class TestOptimization: FunSpec({
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), true, sourcecode)!!
|
val result = compileText(C64Target(), true, sourcecode)!!
|
||||||
val toplevelModule = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = toplevelModule.statements.single() as Block
|
|
||||||
val startSub = mainBlock.statements.single() as Subroutine
|
val startSub = mainBlock.statements.single() as Subroutine
|
||||||
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub
|
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub
|
||||||
withClue("only start sub should remain") {
|
withClue("only start sub should remain") {
|
||||||
@ -85,8 +84,7 @@ main {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), true, sourcecode)!!
|
val result = compileText(C64Target(), true, sourcecode)!!
|
||||||
val toplevelModule = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = toplevelModule.statements.single() as Block
|
|
||||||
val startSub = mainBlock.statements[0] as Subroutine
|
val startSub = mainBlock.statements[0] as Subroutine
|
||||||
val emptySub = mainBlock.statements[1] as Subroutine
|
val emptySub = mainBlock.statements[1] as Subroutine
|
||||||
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub
|
result.compilerAst.entrypoint shouldBeSameInstanceAs startSub
|
||||||
|
@ -46,8 +46,7 @@ class TestScoping: FunSpec({
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||||
val module = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = module.statements.single() as Block
|
|
||||||
val start = mainBlock.statements.single() as Subroutine
|
val start = mainBlock.statements.single() as Subroutine
|
||||||
val repeatbody = start.statements.filterIsInstance<RepeatLoop>().single().body
|
val repeatbody = start.statements.filterIsInstance<RepeatLoop>().single().body
|
||||||
withClue("no vars moved to main block") {
|
withClue("no vars moved to main block") {
|
||||||
@ -120,8 +119,7 @@ class TestScoping: FunSpec({
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
|
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
|
||||||
val module = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = module.statements.single() as Block
|
|
||||||
val start = mainBlock.statements.single() as Subroutine
|
val start = mainBlock.statements.single() as Subroutine
|
||||||
val labels = start.statements.filterIsInstance<Label>()
|
val labels = start.statements.filterIsInstance<Label>()
|
||||||
withClue("only one label in subroutine scope") {
|
withClue("only one label in subroutine scope") {
|
||||||
|
@ -60,8 +60,7 @@ class TestSubroutines: FunSpec({
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
|
val result = compileText(C64Target(), false, text, writeAssembly = false)!!
|
||||||
val module = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = module.statements.single() as Block
|
|
||||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||||
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||||
asmfunc.isAsmSubroutine shouldBe true
|
asmfunc.isAsmSubroutine shouldBe true
|
||||||
@ -119,8 +118,7 @@ class TestSubroutines: FunSpec({
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||||
val module = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = module.statements.single() as Block
|
|
||||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||||
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||||
val emptysub = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="emptysub"}
|
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 result = compileText(C64Target(), false, text, writeAssembly = false)!!
|
||||||
val module = result.compilerAst.toplevelModule
|
val mainBlock = result.compilerAst.entrypoint.definingBlock
|
||||||
val mainBlock = module.statements.single() as Block
|
|
||||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||||
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||||
withClue("ubyte array param should have been replaced by UWORD pointer") {
|
withClue("ubyte array param should have been replaced by UWORD pointer") {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
TODO
|
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
|
make @bank accept a variable as well to make it dynamic
|
||||||
|
|
||||||
rename 'romsub' to 'extsub' ? keep romsub as alias?
|
rename 'romsub' to 'extsub' ? keep romsub as alias?
|
||||||
|
@ -15,9 +15,9 @@ basic_area $a000 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hiram_area $c000 {
|
;hiram_area $c000 {
|
||||||
%option force_output
|
; %option force_output
|
||||||
sub thing() {
|
; sub thing() {
|
||||||
cx16.r0++
|
; cx16.r0++
|
||||||
}
|
; }
|
||||||
}
|
;}
|
||||||
|
Loading…
Reference in New Issue
Block a user