mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
streamline handling of launcher type and program load address. %address is now required if not using a basic-launcher.
This commit is contained in:
parent
406658a10f
commit
eeb3c968d6
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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<String> {
|
||||
return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
||||
return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG)
|
||||
listOf("syslib")
|
||||
else
|
||||
emptyList()
|
||||
|
@ -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<String> {
|
||||
return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
||||
return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG)
|
||||
listOf("syslib")
|
||||
else
|
||||
emptyList()
|
||||
|
@ -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<String> {
|
||||
return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
||||
return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG)
|
||||
listOf("syslib")
|
||||
else
|
||||
emptyList()
|
||||
|
@ -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<String> {
|
||||
return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
|
||||
return if (compilerOptions.launcher == LauncherType.CBMBASIC || compilerOptions.output == OutputType.PRG)
|
||||
listOf("syslib")
|
||||
else
|
||||
emptyList()
|
||||
|
@ -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<String>) {
|
||||
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<String>): 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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Path>)
|
||||
|
||||
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<String, FSignature>): 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -9,7 +9,7 @@ enum class OutputType {
|
||||
}
|
||||
|
||||
enum class LauncherType {
|
||||
BASIC,
|
||||
CBMBASIC,
|
||||
NONE
|
||||
}
|
||||
|
||||
|
@ -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<String>
|
||||
var zeropage: Zeropage
|
||||
|
@ -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?
|
||||
|
@ -90,13 +90,9 @@ Directives
|
||||
.. data:: %address <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 <name>
|
||||
|
@ -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
|
||||
...
|
||||
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
%import textio
|
||||
%zeropage kernalsafe
|
||||
; %launcher none
|
||||
;%output prg
|
||||
;%address $2022
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user