reworked program init logic so that it is included as the first thing inside main.start itself, to allow better stand alone asm

This commit is contained in:
Irmen de Jong 2020-09-23 22:29:21 +02:00
parent c50cbbb526
commit 2b9316c4ff
7 changed files with 84 additions and 41 deletions

View File

@ -270,6 +270,17 @@ asmsub reset_system() {
}} }}
} }
asmsub disable_runstop_and_charsetswitch() {
%asm {{
lda #$80
lda #$80
sta 657 ; disable charset switching
lda #239
sta 808 ; disable run/stop key
rts
}}
}
asmsub set_irqvec_excl() clobbers(A) { asmsub set_irqvec_excl() clobbers(A) {
%asm {{ %asm {{
sei sei

View File

@ -1 +1 @@
4.3 4.4-SNAPSHOT

View File

@ -8,6 +8,7 @@ import prog8.ast.expressions.*
import prog8.ast.processing.AstWalker import prog8.ast.processing.AstWalker
import prog8.ast.processing.IAstModification import prog8.ast.processing.IAstModification
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.target.c64.codegen.programInitializationRoutineName
internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: ErrorReporter) : AstWalker() { internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: ErrorReporter) : AstWalker() {
@ -107,6 +108,15 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope as Node) mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope as Node)
} }
// if it's the program's start subroutine, insert a call to the initalization logic (if it's not there already)
if(subroutine.name=="start" && subroutine.definingBlock().name=="main") {
val first = subroutine.statements.firstOrNull() as? FunctionCallStatement
if(first==null || first.target.nameInSource != listOf(programInitializationRoutineName)) {
val call = FunctionCallStatement(IdentifierReference(listOf(programInitializationRoutineName), subroutine.position), mutableListOf(), true, subroutine.position)
mods += IAstModification.InsertFirst(call, subroutine)
}
}
return mods return mods
} }

View File

@ -19,6 +19,7 @@ internal interface CompilationTarget {
fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path): IAssemblyGenerator fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path): IAssemblyGenerator
val initProcName: String? val initProcName: String?
val resetProcName: String? val resetProcName: String?
val disableRunStopProcName: String?
companion object { companion object {
lateinit var instance: CompilationTarget lateinit var instance: CompilationTarget
@ -37,6 +38,7 @@ internal object C64Target: CompilationTarget {
AsmGen(program, errors, zp, options, path) AsmGen(program, errors, zp, options, path)
override val initProcName = "c64.init_system" override val initProcName = "c64.init_system"
override val resetProcName = "c64.reset_system" override val resetProcName = "c64.reset_system"
override val disableRunStopProcName = "c64.disable_runstop_and_charsetswitch"
} }
internal object Cx16Target: CompilationTarget { internal object Cx16Target: CompilationTarget {
@ -50,4 +52,5 @@ internal object Cx16Target: CompilationTarget {
AsmGen(program, errors, zp, options, path) AsmGen(program, errors, zp, options, path)
override val initProcName = "cx16.init_system" override val initProcName = "cx16.init_system"
override val resetProcName = "cx16.reset_system" override val resetProcName = "cx16.reset_system"
override val disableRunStopProcName = null
} }

View File

@ -29,6 +29,9 @@ import java.util.*
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal const val programInitializationRoutineName = "prog8_initialize_program"
internal class AsmGen(private val program: Program, internal class AsmGen(private val program: Program,
val errors: ErrorReporter, val errors: ErrorReporter,
val zeropage: Zeropage, val zeropage: Zeropage,
@ -50,11 +53,13 @@ internal class AsmGen(private val program: Program,
private val assignmentAsmGen = AssignmentAsmGen(program, this) private val assignmentAsmGen = AssignmentAsmGen(program, this)
private val expressionsAsmGen = ExpressionsAsmGen(program, this) private val expressionsAsmGen = ExpressionsAsmGen(program, this)
internal val loopEndLabels = ArrayDeque<String>() internal val loopEndLabels = ArrayDeque<String>()
internal val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>() private val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
private val programInitLines = mutableListOf<String>()
override fun compileToAssembly(optimize: Boolean): IAssemblyProgram { override fun compileToAssembly(optimize: Boolean): IAssemblyProgram {
assemblyLines.clear() assemblyLines.clear()
loopEndLabels.clear() loopEndLabels.clear()
programInitLines.clear()
println("Generating assembly code... ") println("Generating assembly code... ")
@ -81,6 +86,7 @@ internal class AsmGen(private val program: Program,
return AssemblyProgram(program.name, outputDir) return AssemblyProgram(program.name, outputDir)
} }
private fun header() { private fun header() {
val ourName = this.javaClass.name val ourName = this.javaClass.name
val cpu = when(CompilationTarget.instance.machine.cpu) { val cpu = when(CompilationTarget.instance.machine.cpu) {
@ -120,16 +126,12 @@ internal class AsmGen(private val program: Program,
out(" .null $9e, format(' %d ', _prog8_entrypoint), $3a, $8f, ' prog8 by idj'") out(" .null $9e, format(' %d ', _prog8_entrypoint), $3a, $8f, ' prog8 by idj'")
out("+\t.word 0") out("+\t.word 0")
out("_prog8_entrypoint\t; assembly code starts here\n") out("_prog8_entrypoint\t; assembly code starts here\n")
out(" tsx")
out(" stx prog8_lib.orig_stackpointer")
if(!CompilationTarget.instance.initProcName.isNullOrEmpty()) if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
out(" jsr ${CompilationTarget.instance.initProcName}") out(" jsr ${CompilationTarget.instance.initProcName}")
} }
options.output == OutputType.PRG -> { options.output == OutputType.PRG -> {
out("; ---- program without basic sys call ----") out("; ---- program without basic sys call ----")
out("* = ${program.actualLoadAddress.toHex()}\n") out("* = ${program.actualLoadAddress.toHex()}\n")
out(" tsx")
out(" stx prog8_lib.orig_stackpointer")
if(!CompilationTarget.instance.initProcName.isNullOrEmpty()) if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
out(" jsr ${CompilationTarget.instance.initProcName}") out(" jsr ${CompilationTarget.instance.initProcName}")
} }
@ -138,37 +140,49 @@ internal class AsmGen(private val program: Program,
out("* = ${program.actualLoadAddress.toHex()}\n") out("* = ${program.actualLoadAddress.toHex()}\n")
} }
} }
out(" jmp main.start ; start program / force start proc to be included")
if (zeropage.exitProgramStrategy != Zeropage.ExitProgramStrategy.CLEAN_EXIT) { if (zeropage.exitProgramStrategy != Zeropage.ExitProgramStrategy.CLEAN_EXIT) {
// disable shift-commodore charset switching and run/stop key if(!CompilationTarget.instance.disableRunStopProcName.isNullOrEmpty())
out(" lda #$80") programInitLines.add(" jsr ${CompilationTarget.instance.disableRunStopProcName}")
out(" lda #$80")
out(" sta 657\t; disable charset switching")
out(" lda #239")
out(" sta 808\t; disable run/stop key")
} }
out(" ldx #\$ff\t; init estack pointer") programInitLines.add(" ; initialize the variables in each block that has globals")
programInitLines.add(" cld")
out(" ; initialize the variables in each block that has globals") programInitLines.add(" clv")
program.allBlocks().forEach { program.allBlocks().forEach {
if(it.statements.filterIsInstance<VarDecl>().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes}) if(it.statements.filterIsInstance<VarDecl>().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes})
out(" jsr ${it.name}.prog8_init_vars") programInitLines.add(" jsr ${it.name}.prog8_init_vars")
}
out(" clc")
when (zeropage.exitProgramStrategy) {
Zeropage.ExitProgramStrategy.CLEAN_EXIT -> {
out(" jmp main.start\t; jump to program entrypoint")
}
Zeropage.ExitProgramStrategy.SYSTEM_RESET -> {
out(" jsr main.start\t; call program entrypoint")
out(" jmp ${CompilationTarget.instance.resetProcName}")
} }
if (zeropage.exitProgramStrategy == Zeropage.ExitProgramStrategy.SYSTEM_RESET) {
// push the reset routine onto the cpu stack so that it is executed when the program does an rts
programInitLines.addAll(listOf(
" tsx",
" lda $0102,x",
" pha",
" lda $0103,x",
" pha",
" lda #>(${CompilationTarget.instance.resetProcName}-1)",
" sta $0102,x",
" lda #<(${CompilationTarget.instance.resetProcName}-1)",
" sta $0103,x",
))
} }
programInitLines.add(" ldx #\$ff\t; init estack pointer")
programInitLines.add(" rts")
} }
private fun footer() { private fun footer() {
// the program preamble or initialization code
out("")
out("; program initialization")
out(programInitializationRoutineName)
for(line in programInitLines) {
out(line)
}
out("")
// the global list of all floating point constants for the whole program // the global list of all floating point constants for the whole program
out("; global float constants") out("; global float constants")
for (flt in globalFloatConsts) { for (flt in globalFloatConsts) {
@ -618,6 +632,12 @@ $save .byte 0
is InlineAssembly -> translate(stmt) is InlineAssembly -> translate(stmt)
is FunctionCallStatement -> { is FunctionCallStatement -> {
val functionName = stmt.target.nameInSource.last() val functionName = stmt.target.nameInSource.last()
if(functionName == programInitializationRoutineName) {
out("""
tsx
stx prog8_lib.orig_stackpointer
jsr $functionName""")
} else {
val builtinFunc = BuiltinFunctions[functionName] val builtinFunc = BuiltinFunctions[functionName]
if (builtinFunc != null) { if (builtinFunc != null) {
builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc) builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc)
@ -634,6 +654,7 @@ $save .byte 0
} }
} }
} }
}
is Assignment -> assignmentAsmGen.translate(stmt) is Assignment -> assignmentAsmGen.translate(stmt)
is Jump -> translate(stmt) is Jump -> translate(stmt)
is PostIncrDecr -> postincrdecrAsmGen.translate(stmt) is PostIncrDecr -> postincrdecrAsmGen.translate(stmt)

View File

@ -3,9 +3,8 @@ TODO
==== ====
- get rid of all other TODO's in the code ;-) - get rid of all other TODO's in the code ;-)
- move the ldx #$ff | clc | cld from the startup logic into the start() function as first instructions
- add an %option that omits the 'system-init' code at the start. Useful to create separate standalone routines that shouldn't re-init the whole machine every time they're called - add an %option that omits the 'system-init' code at the start. Useful to create separate standalone routines that shouldn't re-init the whole machine every time they're called
- line-circle-gfx examples are now a few hundred bytes larger than before. Why is that, can it be fixed? - line-circle-gfx examples are now a few hundred bytes larger than before (~4.0/4.1 version i think?). Why is that, can it be fixed?
- until condition should be able to refer to variables defined IN the do-until block itself. - until condition should be able to refer to variables defined IN the do-until block itself.
- add support? example? for processing arguments to a sys call : sys 999, 1, 2, "aaa" - add support? example? for processing arguments to a sys call : sys 999, 1, 2, "aaa"
- make it possible for array literals to not only contain compile time constants - make it possible for array literals to not only contain compile time constants

View File

@ -4,10 +4,9 @@
%zeropage basicsafe %zeropage basicsafe
main { main $0900{
sub start() { sub start() {
ubyte v = 1 ubyte v = 1
@($c000+v) = 10 @($c000+v) = 10