From eeb3c968d69b82a9f9024fa6e7bc03735da9275d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 22 Feb 2022 22:43:14 +0100 Subject: [PATCH] streamline handling of launcher type and program load address. %address is now required if not using a basic-launcher. --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 2 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 19 +++++++++----- .../src/prog8/codegen/target/C128Target.kt | 2 +- .../src/prog8/codegen/target/C64Target.kt | 2 +- .../src/prog8/codegen/target/Cx16Target.kt | 2 +- .../target/atari/AtariMachineDefinition.kt | 3 +-- .../target/c128/C128MachineDefinition.kt | 3 +-- .../target/c64/C64MachineDefinition.kt | 3 +-- .../target/cx16/CX16MachineDefinition.kt | 3 +-- compiler/src/prog8/CompilerMain.kt | 17 +++++++++---- compiler/src/prog8/compiler/Compiler.kt | 25 +++++++++++++------ compiler/test/TestOptimization.kt | 2 +- compiler/test/helpers/compileXyz.kt | 2 +- .../compilerinterface/CompilationOptions.kt | 2 +- .../compilerinterface/IMachineDefinition.kt | 1 - docs/source/portingguide.rst | 3 +-- docs/source/syntaxreference.rst | 10 +++----- docs/source/todo.rst | 1 - examples/test.p8 | 3 +++ 19 files changed, 60 insertions(+), 45 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 55796f9cb..42e992347 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -43,7 +43,7 @@ class AsmGen(internal val program: Program, override fun compileToAssembly(): IAssemblyProgram? { - if(options.compTarget.name=="atari" && options.launcher==LauncherType.BASIC) + if(options.compTarget.name=="atari" && options.launcher==LauncherType.CBMBASIC) throw AssemblyError("atari target cannot use CBM BASIC launcher type") assemblyLines.clear() diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index b19aac89d..fc2228acd 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -70,9 +70,15 @@ internal class ProgramAndVarsGen( asmgen.out(".cpu '$cpu'\n.enc 'none'\n") program.actualLoadAddress = program.definedLoadAddress - if (program.actualLoadAddress == 0u) // fix load address - program.actualLoadAddress = if (options.launcher == LauncherType.BASIC) - compTarget.machine.BASIC_LOAD_ADDRESS else compTarget.machine.RAW_LOAD_ADDRESS + if (program.actualLoadAddress == 0u) { + if (options.launcher == LauncherType.CBMBASIC) { + program.actualLoadAddress = compTarget.machine.BASIC_LOAD_ADDRESS + } + else { + errors.err("load address must be specified with %address when using launcher type ${options.launcher}", program.toplevelModule.position) + return + } + } // the global prog8 variables needed val zp = zeropage @@ -84,9 +90,10 @@ internal class ProgramAndVarsGen( asmgen.out("P8ESTACK_HI = ${compTarget.machine.ESTACK_HI.toHex()}") when { - options.launcher == LauncherType.BASIC -> { - if (program.actualLoadAddress != options.compTarget.machine.BASIC_LOAD_ADDRESS) - throw AssemblyError("BASIC output must have correct load address") + options.launcher == LauncherType.CBMBASIC -> { + if (program.actualLoadAddress != options.compTarget.machine.BASIC_LOAD_ADDRESS) { + errors.err("BASIC output must have load address ${options.compTarget.machine.BASIC_LOAD_ADDRESS.toHex()}", program.toplevelModule.position) + } asmgen.out("; ---- basic program with sys call ----") asmgen.out("* = ${program.actualLoadAddress.toHex()}") val year = LocalDate.now().year diff --git a/codeGenTargets/src/prog8/codegen/target/C128Target.kt b/codeGenTargets/src/prog8/codegen/target/C128Target.kt index 9ef07f40f..a7cb06a86 100644 --- a/codeGenTargets/src/prog8/codegen/target/C128Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/C128Target.kt @@ -15,7 +15,7 @@ class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by C override val machine = C128MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES) override val defaultEncoding = Encoding.PETSCII - override val defaultLauncherType = LauncherType.BASIC + override val defaultLauncherType = LauncherType.CBMBASIC companion object { const val NAME = "c128" diff --git a/codeGenTargets/src/prog8/codegen/target/C64Target.kt b/codeGenTargets/src/prog8/codegen/target/C64Target.kt index a160415af..429264d5b 100644 --- a/codeGenTargets/src/prog8/codegen/target/C64Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/C64Target.kt @@ -15,7 +15,7 @@ class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by Cb override val machine = C64MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES) override val defaultEncoding = Encoding.PETSCII - override val defaultLauncherType = LauncherType.BASIC + override val defaultLauncherType = LauncherType.CBMBASIC companion object { const val NAME = "c64" diff --git a/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt b/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt index e1208b093..d6bc1c98d 100644 --- a/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt @@ -15,7 +15,7 @@ class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by C override val machine = CX16MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES, Encoding.ISO) override val defaultEncoding = Encoding.PETSCII - override val defaultLauncherType = LauncherType.BASIC + override val defaultLauncherType = LauncherType.CBMBASIC companion object { const val NAME = "cx16" diff --git a/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt b/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt index 13412ec2c..974a5190b 100644 --- a/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt +++ b/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt @@ -14,7 +14,6 @@ class AtariMachineDefinition: IMachineDefinition { override val FLOAT_MAX_NEGATIVE = -9.999999999e97 override val FLOAT_MEM_SIZE = 6 override val BASIC_LOAD_ADDRESS = 0x2000u - override val RAW_LOAD_ADDRESS = 0x2000u // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override val ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive // TODO @@ -25,7 +24,7 @@ class AtariMachineDefinition: IMachineDefinition { override fun getFloat(num: Number) = TODO("float from number") override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { - return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) + return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG) listOf("syslib") else emptyList() diff --git a/codeGenTargets/src/prog8/codegen/target/c128/C128MachineDefinition.kt b/codeGenTargets/src/prog8/codegen/target/c128/C128MachineDefinition.kt index b82dd40ff..5ec482709 100644 --- a/codeGenTargets/src/prog8/codegen/target/c128/C128MachineDefinition.kt +++ b/codeGenTargets/src/prog8/codegen/target/c128/C128MachineDefinition.kt @@ -15,7 +15,6 @@ class C128MachineDefinition: IMachineDefinition { override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val BASIC_LOAD_ADDRESS = 0x1c01u - override val RAW_LOAD_ADDRESS = 0x1300u // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override val ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive @@ -26,7 +25,7 @@ class C128MachineDefinition: IMachineDefinition { override fun getFloat(num: Number) = Mflpt5.fromNumber(num) override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { - return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) + return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG) listOf("syslib") else emptyList() diff --git a/codeGenTargets/src/prog8/codegen/target/c64/C64MachineDefinition.kt b/codeGenTargets/src/prog8/codegen/target/c64/C64MachineDefinition.kt index 812b49cf0..bc9d050d3 100644 --- a/codeGenTargets/src/prog8/codegen/target/c64/C64MachineDefinition.kt +++ b/codeGenTargets/src/prog8/codegen/target/c64/C64MachineDefinition.kt @@ -14,7 +14,6 @@ class C64MachineDefinition: IMachineDefinition { override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val BASIC_LOAD_ADDRESS = 0x0801u - override val RAW_LOAD_ADDRESS = 0xc000u // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override val ESTACK_LO = 0xce00u // $ce00-$ceff inclusive @@ -25,7 +24,7 @@ class C64MachineDefinition: IMachineDefinition { override fun getFloat(num: Number) = Mflpt5.fromNumber(num) override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { - return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) + return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG) listOf("syslib") else emptyList() diff --git a/codeGenTargets/src/prog8/codegen/target/cx16/CX16MachineDefinition.kt b/codeGenTargets/src/prog8/codegen/target/cx16/CX16MachineDefinition.kt index 84e0fffe6..9d57a49f9 100644 --- a/codeGenTargets/src/prog8/codegen/target/cx16/CX16MachineDefinition.kt +++ b/codeGenTargets/src/prog8/codegen/target/cx16/CX16MachineDefinition.kt @@ -14,7 +14,6 @@ class CX16MachineDefinition: IMachineDefinition { override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE override val BASIC_LOAD_ADDRESS = 0x0801u - override val RAW_LOAD_ADDRESS = 0x8000u // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override val ESTACK_LO = 0x0400u // $0400-$04ff inclusive @@ -24,7 +23,7 @@ class CX16MachineDefinition: IMachineDefinition { override fun getFloat(num: Number) = Mflpt5.fromNumber(num) override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { - return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) + return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG) listOf("syslib") else emptyList() diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 23e812684..c827884ca 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -9,6 +9,7 @@ import prog8.codegen.target.Cx16Target import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments import prog8.compiler.compileProgram +import prog8.compilerinterface.LauncherType import java.io.File import java.nio.file.FileSystems import java.nio.file.Path @@ -18,7 +19,7 @@ import kotlin.system.exitProcess fun main(args: Array) { - val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim() + val buildVersion = object {}.javaClass.getResource("/version.txt")?.readText()?.trim() println("\nProg8 compiler v$buildVersion by Irmen de Jong (irmen@razorvine.net)") println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") @@ -167,10 +168,16 @@ private fun compileMain(args: Array): Boolean { val programNameInPath = outputPath.resolve(compilationResult.programName) - if (startEmulator1==true) - compilationResult.compTarget.machine.launchEmulator(1, programNameInPath) - else if (startEmulator2==true) - compilationResult.compTarget.machine.launchEmulator(2, programNameInPath) + if(startEmulator1==true || startEmulator2==true) { + if (compilationResult.compilationOptions.launcher != LauncherType.NONE) { + if (startEmulator1 == true) + compilationResult.compilationOptions.compTarget.machine.launchEmulator(1, programNameInPath) + else if (startEmulator2 == true) + compilationResult.compilationOptions.compTarget.machine.launchEmulator(2, programNameInPath) + } else { + println("\nCan't start emulator because program has no launcher type.") + } + } } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 6438ed9f2..424395c23 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -30,7 +30,7 @@ import kotlin.system.measureTimeMillis class CompilationResult(val success: Boolean, val program: Program, val programName: String, - val compTarget: ICompilationTarget, + val compilationOptions: CompilationOptions, val importedFiles: List) class CompilerArguments(val filepath: Path, @@ -64,10 +64,13 @@ fun compileProgram(args: CompilerArguments): CompilationResult { else -> throw IllegalArgumentException("invalid compilation target") } + var compilationOptions: CompilationOptions + try { val totalTime = measureTimeMillis { // import main module and everything it needs - val (programresult, compilationOptions, imported) = parseImports(args.filepath, args.errors, compTarget, args.sourceDirs) + val (programresult, options, imported) = parseImports(args.filepath, args.errors, compTarget, args.sourceDirs) + compilationOptions = options print("Parsed ${args.filepath}") ModuleImporter.ansiEraseRestOfLine(true) @@ -106,7 +109,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult { is WriteAssemblyResult.Ok -> programName = result.filename is WriteAssemblyResult.Fail -> { System.err.println(result.error) - return CompilationResult(false, program, programName, compTarget, importedFiles) + return CompilationResult(false, program, programName, compilationOptions, importedFiles) } } } @@ -115,7 +118,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult { System.err.flush() val seconds = totalTime/1000.0 println("\nTotal compilation+assemble time: ${round(seconds*100.0)/100.0} sec.") - return CompilationResult(true, program, programName, compTarget, importedFiles) + return CompilationResult(true, program, programName, compilationOptions, importedFiles) } catch (px: ParseError) { System.err.print("\n\u001b[91m") // bright red System.err.println("${px.position.toClickableStr()} parse error: ${px.message}".trim()) @@ -149,7 +152,13 @@ fun compileProgram(args: CompilerArguments): CompilationResult { } val failedProgram = Program("failed", BuiltinFunctionsFacade(BuiltinFunctions), compTarget, compTarget) - return CompilationResult(false, failedProgram, programName, compTarget, emptyList()) + val dummyoptions = CompilationOptions( + OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), + floats = false, + noSysInit = true, + compTarget = compTarget + ) + return CompilationResult(false, failedProgram, programName, dummyoptions, emptyList()) } private class BuiltinFunctionsFacade(functions: Map): IBuiltinFunctions { @@ -206,9 +215,9 @@ fun parseImports(filepath: Path, importer.importLibraryModule("math") importer.importLibraryModule("prog8_lib") - if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG) + if (compilerOptions.launcher == LauncherType.CBMBASIC && compilerOptions.output != OutputType.PRG) errors.err("BASIC launcher requires output type PRG", program.toplevelModule.position) - if(compilerOptions.launcher == LauncherType.BASIC && compTarget.name==AtariTarget.NAME) + if(compilerOptions.launcher == LauncherType.CBMBASIC && compTarget.name==AtariTarget.NAME) errors.err("atari target cannot use CBM BASIC launcher, use NONE", program.toplevelModule.position) errors.report() @@ -265,7 +274,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget LauncherType.valueOf(launcherTypeStr) } catch (x: IllegalArgumentException) { // set default value; actual check and error handling of invalid option is handled in the AstChecker later - LauncherType.BASIC + LauncherType.CBMBASIC } } diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 0700c1bfd..4599171bf 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -302,7 +302,7 @@ class TestOptimization: FunSpec({ expr.right.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UWORD expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE - val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir) + val options = CompilationOptions(OutputType.RAW, LauncherType.CBMBASIC, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir) result.program.processAstBeforeAsmGeneration(options, DummyVarsAndConsts, ErrorReporterForTests()) // assignment is now split into: diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index c1c79ea53..e7e7ea08b 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -86,7 +86,7 @@ internal fun generateAssembly( variables: IVariablesAndConsts, options: CompilationOptions? = null ): IAssemblyProgram? { - val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir) + val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.CBMBASIC, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir) coptions.compTarget.machine.zeropage = C64Zeropage(coptions) val asmgen = AsmGen(program, ErrorReporterForTests(), variables, coptions) return asmgen.compileToAssembly() diff --git a/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt b/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt index a7c5f259f..8bfe6a745 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/CompilationOptions.kt @@ -9,7 +9,7 @@ enum class OutputType { } enum class LauncherType { - BASIC, + CBMBASIC, NONE } diff --git a/compilerInterfaces/src/prog8/compilerinterface/IMachineDefinition.kt b/compilerInterfaces/src/prog8/compilerinterface/IMachineDefinition.kt index ab0473daf..75459eb99 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/IMachineDefinition.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/IMachineDefinition.kt @@ -20,7 +20,6 @@ interface IMachineDefinition { val ESTACK_LO: UInt val ESTACK_HI: UInt val BASIC_LOAD_ADDRESS : UInt - val RAW_LOAD_ADDRESS : UInt val opcodeNames: Set var zeropage: Zeropage diff --git a/docs/source/portingguide.rst b/docs/source/portingguide.rst index b1bf92345..2e2c23075 100644 --- a/docs/source/portingguide.rst +++ b/docs/source/portingguide.rst @@ -32,8 +32,7 @@ RAM, ROM, I/O ============= #. what part(s) of the address space is RAM? What parts of the RAM can be used by user programs? -#. what is the load address of Basic programs? -#. what is a good load address of machine code programs? +#. what is the usual starting memory address of programs? #. what is the best place to put 2 pages (512 bytes total) of scratch area data in RAM? #. what part(s) of the address space is ROM? #. what part(s) of the address space is memory mapped I/O registers? diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 83d31c24b..e5e69da96 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -90,13 +90,9 @@ Directives .. data:: %address
Level: module. - Global setting, set the program's start memory address - - - default for ``raw`` output is ``$c000`` - - default for ``prg`` output is ``$0801`` - - cannot be changed if you select ``prg`` with a ``basic`` launcher; - then it is always ``$081e`` (immediately after the BASIC program), and the BASIC program itself is always at ``$0801``. - This is because the C64 expects BASIC programs to start at this address. + Global setting, set the program's start memory address. It's usually fixed at ``$0801`` because the + default launcher type is a CBM-basic program. But you have to specify this address yourself when + you don't use a CBM-basic launcher. .. data:: %import diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 3a7b1ac67..234f821b1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- get rid of RAW_LOAD_ADDRESS and make specifying the load address for RAW launcher mode required ... diff --git a/examples/test.p8 b/examples/test.p8 index 421e1eedd..074d3c0c2 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,5 +1,8 @@ %import textio %zeropage kernalsafe +; %launcher none +;%output prg +;%address $2022 main { sub start() {