From d7ceda4d822840a8cc082e18856695eef4cdd8c8 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 25 Sep 2020 22:11:06 +0200 Subject: [PATCH] removed the automatic system reset at program exit, this did't work with the new init code --- compiler/res/prog8lib/c64/syslib.p8 | 4 +- .../compiler/BeforeAsmGenerationAstChanger.kt | 11 --- compiler/src/prog8/compiler/Zeropage.kt | 8 -- .../compiler/target/CompilationTarget.kt | 9 -- .../target/c64/C64MachineDefinition.kt | 6 -- .../compiler/target/c64/codegen/AsmGen.kt | 99 +++++++------------ .../target/cx16/CX16MachineDefinition.kt | 7 -- docs/source/syntaxreference.rst | 6 +- examples/bdmusic.p8 | 2 - examples/cube3d-gfx.p8 | 2 - examples/cube3d-sprites.p8 | 2 - examples/line-circle-gfx.p8 | 2 - examples/mandelbrot-gfx.p8 | 3 - examples/plasma.p8 | 2 - examples/tehtriz.p8 | 6 +- examples/testarrays.p8 | 3 - examples/testforloops.p8 | 2 + examples/turtle-gfx.p8 | 2 - 18 files changed, 43 insertions(+), 133 deletions(-) diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index b5744606b..eb2b2ca57 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -251,8 +251,7 @@ asmsub init_system() { sta c64.COLOR lda #0 sta c64.BGCOL0 - tax - tay + jsr disable_runstop_and_charsetswitch clc clv cli @@ -272,7 +271,6 @@ asmsub reset_system() { asmsub disable_runstop_and_charsetswitch() { %asm {{ - lda #$80 lda #$80 sta 657 ; disable charset switching lda #239 diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 3c5424cde..c0e3b3b4a 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -8,7 +8,6 @@ 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,16 +106,6 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E && outerScope !is Block) { 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 } diff --git a/compiler/src/prog8/compiler/Zeropage.kt b/compiler/src/prog8/compiler/Zeropage.kt index 7ea901129..dbfb9b3c6 100644 --- a/compiler/src/prog8/compiler/Zeropage.kt +++ b/compiler/src/prog8/compiler/Zeropage.kt @@ -70,12 +70,4 @@ abstract class Zeropage(protected val options: CompilationOptions) { private fun loneByte(address: Int) = address in free && address-1 !in free && address+1 !in free private fun sequentialFree(address: Int, size: Int) = free.containsAll((address until address+size).toList()) - - enum class ExitProgramStrategy { - CLEAN_EXIT, - SYSTEM_RESET - } - - abstract val exitProgramStrategy: ExitProgramStrategy - } diff --git a/compiler/src/prog8/compiler/target/CompilationTarget.kt b/compiler/src/prog8/compiler/target/CompilationTarget.kt index b3876b7e4..5ac13f86c 100644 --- a/compiler/src/prog8/compiler/target/CompilationTarget.kt +++ b/compiler/src/prog8/compiler/target/CompilationTarget.kt @@ -17,9 +17,6 @@ internal interface CompilationTarget { fun encodeString(str: String, altEncoding: Boolean): List fun decodeString(bytes: List, altEncoding: Boolean): String 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 @@ -36,9 +33,6 @@ internal object C64Target: CompilationTarget { if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true) override fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path) = 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,7 +44,4 @@ internal object Cx16Target: CompilationTarget { if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true) override fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path) = AsmGen(program, errors, zp, options, path) - override val initProcName = "cx16.init_system" - override val resetProcName = "cx16.reset_system" - override val disableRunStopProcName = null } diff --git a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt index 0855b2e10..3180f8c4d 100644 --- a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt @@ -113,12 +113,6 @@ internal object C64MachineDefinition: IMachineDefinition { override val SCRATCH_W2 = 0xfd // temp storage 2 for a word $fb+$fc - override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) { - ZeropageType.BASICSAFE, ZeropageType.DONTUSE -> ExitProgramStrategy.CLEAN_EXIT - ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET - } - - init { if (options.floats && options.zeropage !in setOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index c29ca5eb8..e051c3120 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -29,9 +29,6 @@ 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, @@ -54,12 +51,10 @@ internal class AsmGen(private val program: Program, private val expressionsAsmGen = ExpressionsAsmGen(program, this) internal val loopEndLabels = ArrayDeque() private val blockLevelVarInits = mutableMapOf>() - private val programInitLines = mutableListOf() override fun compileToAssembly(optimize: Boolean): IAssemblyProgram { assemblyLines.clear() loopEndLabels.clear() - programInitLines.clear() println("Generating assembly code... ") @@ -126,63 +121,25 @@ 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") - if(!options.noSysInit && !CompilationTarget.instance.initProcName.isNullOrEmpty()) - out(" jsr ${CompilationTarget.instance.initProcName}") + if(!options.noSysInit) + out(" jsr ${CompilationTarget.instance.name}.init_system") } options.output == OutputType.PRG -> { out("; ---- program without basic sys call ----") out("* = ${program.actualLoadAddress.toHex()}\n") - if(!options.noSysInit && !CompilationTarget.instance.initProcName.isNullOrEmpty()) - out(" jsr ${CompilationTarget.instance.initProcName}") + if(!options.noSysInit) + out(" jsr ${CompilationTarget.instance.name}.init_system") } options.output == OutputType.RAW -> { out("; ---- raw assembler 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) { - if(!CompilationTarget.instance.disableRunStopProcName.isNullOrEmpty()) - programInitLines.add(" jsr ${CompilationTarget.instance.disableRunStopProcName}") - } - - programInitLines.add(" ; initialize the variables in each block that has globals") - programInitLines.add(" cld") - programInitLines.add(" clv") - program.allBlocks().forEach { - if(it.statements.filterIsInstance().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes}) - programInitLines.add(" jsr ${it.name}.prog8_init_vars") - } - 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") + out(" jmp main.start ; start program / force start proc to be included") } 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) { @@ -632,25 +589,18 @@ $save .byte 0 is InlineAssembly -> translate(stmt) is FunctionCallStatement -> { val functionName = stmt.target.nameInSource.last() - if(functionName == programInitializationRoutineName) { - out(""" - tsx - stx prog8_lib.orig_stackpointer - jsr $functionName""") + val builtinFunc = BuiltinFunctions[functionName] + if (builtinFunc != null) { + builtinFunctionsAsmGen.translateFunctioncallStatement(stmt, builtinFunc) } else { - 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") - } + 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") } } } @@ -811,6 +761,23 @@ $save .byte 0 out("${sub.name}\t.proc") zeropagevars2asm(sub.statements) memdefs2asm(sub.statements) + + // the main.start subroutine is the program's entrypoint and should perform some initialization logic + if(sub.name=="start" && sub.definingBlock().name=="main") { + out("; program startup initialization") + out(" cld") + program.allBlocks().forEach { + if(it.statements.filterIsInstance().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes}) + out(" jsr ${it.name}.prog8_init_vars") + } + out(""" + tsx + stx prog8_lib.orig_stackpointer ; required for func_exit + ldx #255 ; init estack ptr + clv + clc""") + } + out("; statements") sub.statements.forEach{ translate(it) } out("; variables") diff --git a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt index 5cc858fd6..094c502fb 100644 --- a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt @@ -78,13 +78,6 @@ internal object CX16MachineDefinition: IMachineDefinition { override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f - override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) { - ZeropageType.BASICSAFE, ZeropageType.DONTUSE -> ExitProgramStrategy.CLEAN_EXIT - ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET - else -> ExitProgramStrategy.SYSTEM_RESET - } - - init { if (options.floats && options.zeropage !in setOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) throw CompilerException("when floats are enabled, zero page type should be 'basicsafe' or 'dontuse'") diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index e43e87147..359f184b5 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -67,7 +67,8 @@ Directives - style ``kernalsafe`` -- use the part of the ZP that is 'free' or only used by BASIC routines, and don't change anything else. This allows full use of KERNAL ROM routines (but not BASIC routines), including default IRQs during normal system operation. - When the program exits, a system reset is performed (because BASIC will be in a corrupt state). + It's not possible to return cleanly to BASIC when the program exits. The only choice is + to perform a system reset. (A ``system_reset`` subroutine is available in the syslib to help you do this) - style ``floatsafe`` -- like the previous one but also reserves the addresses that are required to perform floating point operations (from the BASIC kernel). No clean exit is possible. - style ``basicsafe`` -- the most restricted mode; only use the handful 'free' addresses in the ZP, and don't @@ -78,9 +79,10 @@ Directives except the few addresses mentioned above that are used by the system's IRQ routine. Even though the default IRQ routine is still active, it is impossible to use most BASIC and KERNAL ROM routines. This includes many floating point operations and several utility routines that do I/O, such as ``print_string``. - As with ``kernalsafe``, it is not possible to cleanly exit the program, other than to reset the machine. This option makes programs smaller and faster because even more variables can be stored in the ZP (which allows for more efficient assembly code). + It's not possible to return cleanly to BASIC when the program exits. The only choice is + to perform a system reset. (A ``system_reset`` subroutine is available in the syslib to help you do this) - style ``dontuse`` -- don't use *any* location in the zeropage. Also read :ref:`zeropage`. diff --git a/examples/bdmusic.p8 b/examples/bdmusic.p8 index 2daf78077..29b443e38 100644 --- a/examples/bdmusic.p8 +++ b/examples/bdmusic.p8 @@ -2,8 +2,6 @@ %import textio %import syslib -; TODO fix crash it's caused by commit 2b9316c4fff5ef33340676da96a9c7ef57237bc0 reworked program init logic - main { sub start() { diff --git a/examples/cube3d-gfx.p8 b/examples/cube3d-gfx.p8 index b5c68c574..570f60dce 100644 --- a/examples/cube3d-gfx.p8 +++ b/examples/cube3d-gfx.p8 @@ -3,8 +3,6 @@ ; Note: this program is compatible with C64 and CX16. -; TODO fix crash - main { ; vertices diff --git a/examples/cube3d-sprites.p8 b/examples/cube3d-sprites.p8 index 4acb1436a..6f935f136 100644 --- a/examples/cube3d-sprites.p8 +++ b/examples/cube3d-sprites.p8 @@ -2,8 +2,6 @@ %import syslib %import textio -; TODO fix crash - spritedata $2000 { ; this memory block contains the sprite data ; it must start on an address aligned to 64 bytes. diff --git a/examples/line-circle-gfx.p8 b/examples/line-circle-gfx.p8 index 3ccaf9c16..75a2f8698 100644 --- a/examples/line-circle-gfx.p8 +++ b/examples/line-circle-gfx.p8 @@ -2,8 +2,6 @@ ; Note: this program is compatible with C64 and CX16. -; TODO fix crash - main { sub start() { diff --git a/examples/mandelbrot-gfx.p8 b/examples/mandelbrot-gfx.p8 index ea2a30dd1..b83f07f7b 100644 --- a/examples/mandelbrot-gfx.p8 +++ b/examples/mandelbrot-gfx.p8 @@ -8,9 +8,6 @@ ; Note: this program is compatible with C64 and CX16. -; TODO fix problem that it freezes or doesn't draw anything anymore - - main { const ubyte width = 255 const ubyte height = 200 diff --git a/examples/plasma.p8 b/examples/plasma.p8 index 7814007a2..ec41ebd9e 100644 --- a/examples/plasma.p8 +++ b/examples/plasma.p8 @@ -13,8 +13,6 @@ ;** ** ;\*****************************************************************************/ -; TODO fix problem - main { const uword SCREEN1 = $E000 diff --git a/examples/tehtriz.p8 b/examples/tehtriz.p8 index f63bbd9ff..6288fe632 100644 --- a/examples/tehtriz.p8 +++ b/examples/tehtriz.p8 @@ -7,8 +7,7 @@ ; staged speed increase ; some simple sound effects -; TODO fix crash - +; TODO fix auto dropping of blocks (first fix testarrays) %target c64 %import syslib @@ -34,7 +33,8 @@ main { sub start() { - @(650) = 128 ; set all keys to repeat + c64.disable_runstop_and_charsetswitch() + ;@(650) = 128 ; set all keys to repeat sound.init() newGame() drawBoard() diff --git a/examples/testarrays.p8 b/examples/testarrays.p8 index f1a06ec1d..e98f51f25 100644 --- a/examples/testarrays.p8 +++ b/examples/testarrays.p8 @@ -5,9 +5,6 @@ ; Note: this program is compatible with C64 and CX16. -; TODO fix byte var in arrayvar fail - - main { ; this is only a parser/compiler test, there's no actual working program diff --git a/examples/testforloops.p8 b/examples/testforloops.p8 index 0d907a13a..e48789946 100644 --- a/examples/testforloops.p8 +++ b/examples/testforloops.p8 @@ -3,6 +3,8 @@ ; Note: this program is compatible with C64 and CX16. +; TODO fix byte var in arrayvar fail + main { sub start() { diff --git a/examples/turtle-gfx.p8 b/examples/turtle-gfx.p8 index dd13e45e1..688eadbed 100644 --- a/examples/turtle-gfx.p8 +++ b/examples/turtle-gfx.p8 @@ -3,8 +3,6 @@ %import graphics %zeropage floatsafe -; TODO fix crash - main { sub start() {