mirror of
https://github.com/irmen/prog8.git
synced 2024-11-30 08:52:30 +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) {
|
asmsub set_irqvec_excl() clobbers(A) {
|
||||||
%asm {{
|
%asm {{
|
||||||
sei
|
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.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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user