mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 08:29:25 +00:00
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:
parent
c50cbbb526
commit
2b9316c4ff
@ -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) {
|
||||
%asm {{
|
||||
sei
|
||||
|
@ -1 +1 @@
|
||||
4.3
|
||||
4.4-SNAPSHOT
|
||||
|
@ -8,6 +8,7 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.target.c64.codegen.programInitializationRoutineName
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ internal interface CompilationTarget {
|
||||
fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path): IAssemblyGenerator
|
||||
val initProcName: String?
|
||||
val resetProcName: String?
|
||||
val disableRunStopProcName: String?
|
||||
|
||||
companion object {
|
||||
lateinit var instance: CompilationTarget
|
||||
@ -37,6 +38,7 @@ internal object C64Target: CompilationTarget {
|
||||
AsmGen(program, errors, zp, options, path)
|
||||
override val initProcName = "c64.init_system"
|
||||
override val resetProcName = "c64.reset_system"
|
||||
override val disableRunStopProcName = "c64.disable_runstop_and_charsetswitch"
|
||||
}
|
||||
|
||||
internal object Cx16Target: CompilationTarget {
|
||||
@ -50,4 +52,5 @@ internal object Cx16Target: CompilationTarget {
|
||||
AsmGen(program, errors, zp, options, path)
|
||||
override val initProcName = "cx16.init_system"
|
||||
override val resetProcName = "cx16.reset_system"
|
||||
override val disableRunStopProcName = null
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
internal const val programInitializationRoutineName = "prog8_initialize_program"
|
||||
|
||||
|
||||
internal class AsmGen(private val program: Program,
|
||||
val errors: ErrorReporter,
|
||||
val zeropage: Zeropage,
|
||||
@ -50,11 +53,13 @@ internal class AsmGen(private val program: Program,
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, this)
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this)
|
||||
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 {
|
||||
assemblyLines.clear()
|
||||
loopEndLabels.clear()
|
||||
programInitLines.clear()
|
||||
|
||||
println("Generating assembly code... ")
|
||||
|
||||
@ -81,6 +86,7 @@ internal class AsmGen(private val program: Program,
|
||||
return AssemblyProgram(program.name, outputDir)
|
||||
}
|
||||
|
||||
|
||||
private fun header() {
|
||||
val ourName = this.javaClass.name
|
||||
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("+\t.word 0")
|
||||
out("_prog8_entrypoint\t; assembly code starts here\n")
|
||||
out(" tsx")
|
||||
out(" stx prog8_lib.orig_stackpointer")
|
||||
if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
|
||||
out(" jsr ${CompilationTarget.instance.initProcName}")
|
||||
}
|
||||
options.output == OutputType.PRG -> {
|
||||
out("; ---- program without basic sys call ----")
|
||||
out("* = ${program.actualLoadAddress.toHex()}\n")
|
||||
out(" tsx")
|
||||
out(" stx prog8_lib.orig_stackpointer")
|
||||
if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
|
||||
out(" jsr ${CompilationTarget.instance.initProcName}")
|
||||
}
|
||||
@ -138,37 +140,49 @@ internal class AsmGen(private val program: Program,
|
||||
out("* = ${program.actualLoadAddress.toHex()}\n")
|
||||
}
|
||||
}
|
||||
out(" jmp main.start ; start program / force start proc to be included")
|
||||
|
||||
if (zeropage.exitProgramStrategy != Zeropage.ExitProgramStrategy.CLEAN_EXIT) {
|
||||
// disable shift-commodore charset switching and run/stop key
|
||||
out(" lda #$80")
|
||||
out(" lda #$80")
|
||||
out(" sta 657\t; disable charset switching")
|
||||
out(" lda #239")
|
||||
out(" sta 808\t; disable run/stop key")
|
||||
if(!CompilationTarget.instance.disableRunStopProcName.isNullOrEmpty())
|
||||
programInitLines.add(" jsr ${CompilationTarget.instance.disableRunStopProcName}")
|
||||
}
|
||||
|
||||
out(" ldx #\$ff\t; init estack pointer")
|
||||
|
||||
out(" ; initialize the variables in each block that has globals")
|
||||
programInitLines.add(" ; initialize the variables in each block that has globals")
|
||||
programInitLines.add(" cld")
|
||||
programInitLines.add(" clv")
|
||||
program.allBlocks().forEach {
|
||||
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() {
|
||||
// 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
|
||||
out("; global float constants")
|
||||
for (flt in globalFloatConsts) {
|
||||
@ -618,18 +632,25 @@ $save .byte 0
|
||||
is InlineAssembly -> translate(stmt)
|
||||
is FunctionCallStatement -> {
|
||||
val functionName = stmt.target.nameInSource.last()
|
||||
val builtinFunc = BuiltinFunctions[functionName]
|
||||
if(builtinFunc!=null) {
|
||||
builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc)
|
||||
if(functionName == programInitializationRoutineName) {
|
||||
out("""
|
||||
tsx
|
||||
stx prog8_lib.orig_stackpointer
|
||||
jsr $functionName""")
|
||||
} else {
|
||||
functioncallAsmGen.translateFunctionCall(stmt)
|
||||
// discard any results from the stack:
|
||||
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||
for((t, reg) in returns) {
|
||||
if(reg.stack) {
|
||||
if (t in IntegerDatatypes || t in PassByReferenceDatatypes) out(" inx")
|
||||
else if (t == DataType.FLOAT) out(" inx | inx | inx")
|
||||
val builtinFunc = BuiltinFunctions[functionName]
|
||||
if (builtinFunc != null) {
|
||||
builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc)
|
||||
} else {
|
||||
functioncallAsmGen.translateFunctionCall(stmt)
|
||||
// discard any results from the stack:
|
||||
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||
for ((t, reg) in returns) {
|
||||
if (reg.stack) {
|
||||
if (t in IntegerDatatypes || t in PassByReferenceDatatypes) out(" inx")
|
||||
else if (t == DataType.FLOAT) out(" inx | inx | inx")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,8 @@ TODO
|
||||
====
|
||||
|
||||
- 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
|
||||
- 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.
|
||||
- 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
|
||||
|
@ -4,10 +4,9 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
main $0900{
|
||||
|
||||
sub start() {
|
||||
|
||||
ubyte v = 1
|
||||
@($c000+v) = 10
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user