diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt index c6bd870a8..e46a5681d 100644 --- a/codeCore/src/prog8/code/SymbolTableMaker.kt +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -23,10 +23,10 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp if(options.compTarget.name != VMTarget.NAME) { listOf( - PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY), - PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.zeropage.SCRATCH_B1, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.zeropage.SCRATCH_REG, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.zeropage.SCRATCH_W1, null, Position.DUMMY), + PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.zeropage.SCRATCH_W2, null, Position.DUMMY), ).forEach { it.parent = program st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it)) diff --git a/codeCore/src/prog8/code/core/CompilationOptions.kt b/codeCore/src/prog8/code/core/CompilationOptions.kt index 66502ae8c..6e261819f 100644 --- a/codeCore/src/prog8/code/core/CompilationOptions.kt +++ b/codeCore/src/prog8/code/core/CompilationOptions.kt @@ -34,7 +34,7 @@ class CompilationOptions(val output: OutputType, var symbolDefs: Map = emptyMap() ) { init { - compTarget.machine.initializeMemoryAreas(this) + compTarget.initializeMemoryAreas(this) } companion object { diff --git a/codeCore/src/prog8/code/core/ICompilationTarget.kt b/codeCore/src/prog8/code/core/ICompilationTarget.kt index 37355e8bf..0f0324f53 100644 --- a/codeCore/src/prog8/code/core/ICompilationTarget.kt +++ b/codeCore/src/prog8/code/core/ICompilationTarget.kt @@ -1,8 +1,39 @@ package prog8.code.core +import java.nio.file.Path + +enum class CpuType { + CPU6502, + CPU65c02, + VIRTUAL +} + interface ICompilationTarget: IStringEncoding, IMemSizer { val name: String - val machine: IMachineDefinition + + val FLOAT_MAX_NEGATIVE: Double + val FLOAT_MAX_POSITIVE: Double + val FLOAT_MEM_SIZE: Int + val STARTUP_CODE_RESERVED_SIZE: UInt // this is here, so that certain compiler targets are able to tune this + val PROGRAM_LOAD_ADDRESS : UInt + val PROGRAM_MEMTOP_ADDRESS: UInt + val BSSHIGHRAM_START: UInt + val BSSHIGHRAM_END: UInt + val BSSGOLDENRAM_START: UInt + val BSSGOLDENRAM_END: UInt + + val cpu: CpuType + var zeropage: Zeropage + var golden: GoldenRam + + fun initializeMemoryAreas(compilerOptions: CompilationOptions) + fun getFloatAsmBytes(num: Number): String + + fun convertFloatToBytes(num: Double): List + fun convertBytesToFloat(bytes: List): Double + + fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) + fun isIOAddress(address: UInt): Boolean override fun encodeString(str: String, encoding: Encoding): List override fun decodeString(bytes: Iterable, encoding: Encoding): String diff --git a/codeCore/src/prog8/code/core/IMachineDefinition.kt b/codeCore/src/prog8/code/core/IMachineDefinition.kt deleted file mode 100644 index 6096d341a..000000000 --- a/codeCore/src/prog8/code/core/IMachineDefinition.kt +++ /dev/null @@ -1,36 +0,0 @@ -package prog8.code.core - -import java.nio.file.Path - - -enum class CpuType { - CPU6502, - CPU65c02, - VIRTUAL -} - -interface IMachineDefinition { - val FLOAT_MAX_NEGATIVE: Double - val FLOAT_MAX_POSITIVE: Double - val FLOAT_MEM_SIZE: Int - val STARTUP_CODE_RESERVED_SIZE: UInt // this is here, so that certain compiler targets are able to tune this - val PROGRAM_LOAD_ADDRESS : UInt - val PROGRAM_MEMTOP_ADDRESS: UInt - val BSSHIGHRAM_START: UInt - val BSSHIGHRAM_END: UInt - val BSSGOLDENRAM_START: UInt - val BSSGOLDENRAM_END: UInt - - val cpu: CpuType - var zeropage: Zeropage - var golden: GoldenRam - - fun initializeMemoryAreas(compilerOptions: CompilationOptions) - fun getFloatAsmBytes(num: Number): String - - fun convertFloatToBytes(num: Double): List - fun convertBytesToFloat(bytes: List): Double - - fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) - fun isIOAddress(address: UInt): Boolean -} diff --git a/codeCore/src/prog8/code/target/AtariTarget.kt b/codeCore/src/prog8/code/target/AtariTarget.kt index b56e8457c..25eb9f901 100644 --- a/codeCore/src/prog8/code/target/AtariTarget.kt +++ b/codeCore/src/prog8/code/target/AtariTarget.kt @@ -1,40 +1,72 @@ package prog8.code.target import prog8.code.core.* -import prog8.code.target.atari.AtariMachineDefinition +import prog8.code.target.encodings.Encoder +import prog8.code.target.zp.AtariZeropage +import java.nio.file.Path -class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { + +class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) { override val name = NAME - override val machine = AtariMachineDefinition() override val defaultEncoding = Encoding.ATASCII companion object { const val NAME = "atari" + const val FLOAT_MEM_SIZE = 6 } - override fun memorySize(dt: DataType, numElements: Int?): Int { - if(dt.isArray) { - if(numElements==null) return 2 // treat it as a pointer size - return when(dt.sub) { - BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 - BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE - BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") - else -> throw IllegalArgumentException("invalid sub type") + override val cpu = CpuType.CPU6502 + + override val FLOAT_MAX_POSITIVE = 9.999999999e97 + override val FLOAT_MAX_NEGATIVE = -9.999999999e97 + override val FLOAT_MEM_SIZE = AtariTarget.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x2000u + override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop? + + override val BSSHIGHRAM_START = 0u // TODO + override val BSSHIGHRAM_END = 0u // TODO + override val BSSGOLDENRAM_START = 0u // TODO + override val BSSGOLDENRAM_END = 0u // TODO + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number") + override fun convertFloatToBytes(num: Double): List = TODO("atari float to bytes") + override fun convertBytesToFloat(bytes: List): Double = TODO("atari bytes to float") + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + val emulatorName: String + val cmdline: List + when(selectedEmulator) { + 1 -> { + emulatorName = "atari800" + cmdline = listOf(emulatorName, "-xl", "-xl-rev", "2", "-nobasic", "-run", "${programNameWithPath}.xex") + } + 2 -> { + emulatorName = "altirra" + cmdline = listOf("Altirra64.exe", "${programNameWithPath.normalize()}.xex") + } + else -> { + System.err.println("Atari target only supports atari800 and altirra emulators.") + return } - } - else if (dt.isString) { - if(numElements!=null) return numElements // treat it as the size of the given string with the length - else return 2 // treat it as the size to store a string pointer } - return when { - dt.isByteOrBool -> 1 * (numElements ?: 1) - dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) - dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") - dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") - else -> 2 * (numElements ?: 1) - } + // TODO monlist? + + println("\nStarting Atari800XL emulator $emulatorName...") + val processb = ProcessBuilder(cmdline).inheritIO() + val process: Process = processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = AtariZeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) } } diff --git a/codeCore/src/prog8/code/target/C128Target.kt b/codeCore/src/prog8/code/target/C128Target.kt index 55e012af3..0fe3dc11e 100644 --- a/codeCore/src/prog8/code/target/C128Target.kt +++ b/codeCore/src/prog8/code/target/C128Target.kt @@ -1,19 +1,77 @@ package prog8.code.target +import prog8.code.core.CompilationOptions +import prog8.code.core.CpuType import prog8.code.core.Encoding +import prog8.code.core.GoldenRam import prog8.code.core.ICompilationTarget import prog8.code.core.IMemSizer import prog8.code.core.IStringEncoding -import prog8.code.target.c128.C128MachineDefinition -import prog8.code.target.cbm.CbmMemorySizer +import prog8.code.core.Zeropage +import prog8.code.target.zp.C128Zeropage +import prog8.code.target.encodings.Encoder +import java.nio.file.Path -class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { +class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) { override val name = NAME - override val machine = C128MachineDefinition() override val defaultEncoding = Encoding.PETSCII companion object { const val NAME = "c128" } + + + override val cpu = CpuType.CPU6502 + + override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE + override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE + override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x1c01u + override val PROGRAM_MEMTOP_ADDRESS = 0xc000u + + override val BSSHIGHRAM_START = 0u // TODO + override val BSSHIGHRAM_END = 0u // TODO + override val BSSGOLDENRAM_START = 0u // TODO + override val BSSGOLDENRAM_END = 0u // TODO + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() + + override fun convertFloatToBytes(num: Double): List { + val m5 = Mflpt5.fromNumber(num) + return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) + } + + override fun convertBytesToFloat(bytes: List): Double { + require(bytes.size==5) { "need 5 bytes" } + val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) + return m5.toDouble() + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The c128 target only supports the main emulator (Vice).") + return + } + + println("\nStarting C-128 emulator x128...") + val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString()) + val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist, + "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") + val processb = ProcessBuilder(cmdline).inheritIO() + val process: Process = processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = C128Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) // TODO does the c128 have some of this somewhere? + } + } diff --git a/codeCore/src/prog8/code/target/C64Target.kt b/codeCore/src/prog8/code/target/C64Target.kt index c00615a9a..9f712bbdd 100644 --- a/codeCore/src/prog8/code/target/C64Target.kt +++ b/codeCore/src/prog8/code/target/C64Target.kt @@ -1,16 +1,21 @@ package prog8.code.target +import prog8.code.core.CompilationOptions +import prog8.code.core.CpuType import prog8.code.core.Encoding +import prog8.code.core.GoldenRam import prog8.code.core.ICompilationTarget import prog8.code.core.IMemSizer import prog8.code.core.IStringEncoding -import prog8.code.target.c64.C64MachineDefinition -import prog8.code.target.cbm.CbmMemorySizer +import prog8.code.core.Zeropage +import prog8.code.target.zp.C64Zeropage +import prog8.code.target.encodings.Encoder +import java.io.IOException +import java.nio.file.Path -class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { +class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) { override val name = NAME - override val machine = C64MachineDefinition() override val defaultEncoding = Encoding.PETSCII companion object { @@ -18,6 +23,69 @@ class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by Cb fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list" } + + + override val cpu = CpuType.CPU6502 + + override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE + override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE + override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x0801u + override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used + // note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15 + + override val BSSHIGHRAM_START = 0xc000u + override val BSSHIGHRAM_END = 0xcfdfu + override val BSSGOLDENRAM_START = 0u + override val BSSGOLDENRAM_END = 0u + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() + + override fun convertFloatToBytes(num: Double): List { + val m5 = Mflpt5.fromNumber(num) + return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) + } + + override fun convertBytesToFloat(bytes: List): Double { + require(bytes.size==5) { "need 5 bytes" } + val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) + return m5.toDouble() + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The c64 target only supports the main emulator (Vice).") + return + } + + for(emulator in listOf("x64sc", "x64")) { + println("\nStarting C-64 emulator $emulator...") + val viceMonlist = viceMonListName(programNameWithPath.toString()) + val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist, + "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") + val processb = ProcessBuilder(cmdline).inheritIO() + val process: Process + try { + process=processb.start() + } catch(_: IOException) { + continue // try the next emulator executable + } + process.waitFor() + break + } + } + + override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = C64Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u) + } + } diff --git a/codeCore/src/prog8/code/target/Cx16Target.kt b/codeCore/src/prog8/code/target/Cx16Target.kt index 13c080d46..9938cf3ed 100644 --- a/codeCore/src/prog8/code/target/Cx16Target.kt +++ b/codeCore/src/prog8/code/target/Cx16Target.kt @@ -1,19 +1,90 @@ package prog8.code.target +import prog8.code.core.CompilationOptions +import prog8.code.core.CpuType import prog8.code.core.Encoding +import prog8.code.core.GoldenRam import prog8.code.core.ICompilationTarget import prog8.code.core.IMemSizer import prog8.code.core.IStringEncoding -import prog8.code.target.cbm.CbmMemorySizer -import prog8.code.target.cx16.CX16MachineDefinition +import prog8.code.core.Zeropage +import prog8.code.target.encodings.Encoder +import prog8.code.target.zp.CX16Zeropage +import java.nio.file.Path -class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { +class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) { override val name = NAME - override val machine = CX16MachineDefinition() override val defaultEncoding = Encoding.PETSCII companion object { const val NAME = "cx16" } + + + override val cpu = CpuType.CPU65c02 + + override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE + override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE + override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x0801u + override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u + + override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active + override val BSSHIGHRAM_END = 0xbfffu // Rom starts at $c000 + override val BSSGOLDENRAM_START = 0x0400u + override val BSSGOLDENRAM_END = 0x07ffu + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() + + override fun convertFloatToBytes(num: Double): List { + val m5 = Mflpt5.fromNumber(num) + return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) + } + + override fun convertBytesToFloat(bytes: List): Double { + require(bytes.size==5) { "need 5 bytes" } + val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) + return m5.toDouble() + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + val emulator: String + val extraArgs: List + + when(selectedEmulator) { + 1 -> { + emulator = "x16emu" + extraArgs = listOf("-debug") + } + 2 -> { + emulator = "box16" + extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString())) + } + else -> { + System.err.println("Cx16 target only supports x16emu and box16 emulators.") + return + } + } + + println("\nStarting Commander X16 emulator $emulator...") + val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs + val processb = ProcessBuilder(cmdline).inheritIO() + processb.environment()["PULSE_LATENCY_MSEC"] = "10" + val process: Process = processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = CX16Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u) + } + + } diff --git a/codeCore/src/prog8/code/target/cbm/Mflpt5.kt b/codeCore/src/prog8/code/target/Mflpt5.kt similarity index 99% rename from codeCore/src/prog8/code/target/cbm/Mflpt5.kt rename to codeCore/src/prog8/code/target/Mflpt5.kt index d636620ea..a97fb753e 100644 --- a/codeCore/src/prog8/code/target/cbm/Mflpt5.kt +++ b/codeCore/src/prog8/code/target/Mflpt5.kt @@ -1,10 +1,9 @@ -package prog8.code.target.cbm +package prog8.code.target import prog8.code.core.InternalCompilerException import kotlin.math.absoluteValue import kotlin.math.pow - data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) { companion object { diff --git a/codeCore/src/prog8/code/target/Neo6502Target.kt b/codeCore/src/prog8/code/target/Neo6502Target.kt index 5b5ae9539..42718f452 100644 --- a/codeCore/src/prog8/code/target/Neo6502Target.kt +++ b/codeCore/src/prog8/code/target/Neo6502Target.kt @@ -1,40 +1,60 @@ package prog8.code.target import prog8.code.core.* -import prog8.code.target.neo6502.Neo6502MachineDefinition +import prog8.code.target.encodings.Encoder +import prog8.code.target.zp.Neo6502Zeropage +import java.nio.file.Path -class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { +class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) { override val name = NAME - override val machine = Neo6502MachineDefinition() override val defaultEncoding = Encoding.ISO companion object { const val NAME = "neo" + const val FLOAT_MEM_SIZE = 6 } - override fun memorySize(dt: DataType, numElements: Int?): Int { - if(dt.isArray) { - if(numElements==null) return 2 // treat it as a pointer size - return when(dt.sub) { - BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements - BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 - BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE - BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") - else -> throw IllegalArgumentException("invalid sub type") - } - } - else if (dt.isString) { - if(numElements!=null) return numElements // treat it as the size of the given string with the length - else return 2 // treat it as the size to store a string pointer - } - return when { - dt.isByteOrBool -> 1 * (numElements ?: 1) - dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) - dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") - dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") - else -> 2 * (numElements ?: 1) + override val cpu = CpuType.CPU65c02 + + override val FLOAT_MAX_POSITIVE = 9.999999999e97 + override val FLOAT_MAX_NEGATIVE = -9.999999999e97 + override val FLOAT_MEM_SIZE = Neo6502Target.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x0800u + override val PROGRAM_MEMTOP_ADDRESS = 0xfc00u // kernal starts here + + override val BSSHIGHRAM_START = 0u // TODO + override val BSSHIGHRAM_END = 0u // TODO + override val BSSGOLDENRAM_START = 0u // TODO + override val BSSGOLDENRAM_END = 0u // TODO + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number") + override fun convertFloatToBytes(num: Double): List = TODO("atari float to bytes") + override fun convertBytesToFloat(bytes: List): Double = TODO("atari bytes to float") + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The neo target only supports the main emulator (neo).") + return } + + val cmdline = listOf("neo", "${programNameWithPath}.bin@800", "cold") + + println("\nStarting Neo6502 emulator...") + val processb = ProcessBuilder(cmdline).inheritIO() + val process: Process = processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address in 0xff00u..0xff0fu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = Neo6502Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) } } diff --git a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt b/codeCore/src/prog8/code/target/NormalMemSizer.kt similarity index 85% rename from codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt rename to codeCore/src/prog8/code/target/NormalMemSizer.kt index 4e474df3c..1917b520e 100644 --- a/codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt +++ b/codeCore/src/prog8/code/target/NormalMemSizer.kt @@ -1,18 +1,18 @@ -package prog8.code.target.cbm +package prog8.code.target import prog8.code.core.BaseDataType import prog8.code.core.DataType import prog8.code.core.IMemSizer +internal class NormalMemSizer(val floatsize: Int): IMemSizer { -internal object CbmMemorySizer: IMemSizer { override fun memorySize(dt: DataType, numElements: Int?): Int { if(dt.isArray) { if(numElements==null) return 2 // treat it as a pointer size return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 - BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE + BaseDataType.FLOAT-> numElements * floatsize BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } @@ -24,10 +24,11 @@ internal object CbmMemorySizer: IMemSizer { return when { dt.isByteOrBool -> 1 * (numElements ?: 1) - dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isFloat -> floatsize * (numElements ?: 1) dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } + } \ No newline at end of file diff --git a/codeCore/src/prog8/code/target/PETTarget.kt b/codeCore/src/prog8/code/target/PETTarget.kt index 1c5f6c0e3..781aea16b 100644 --- a/codeCore/src/prog8/code/target/PETTarget.kt +++ b/codeCore/src/prog8/code/target/PETTarget.kt @@ -1,19 +1,76 @@ package prog8.code.target +import prog8.code.core.CompilationOptions +import prog8.code.core.CpuType import prog8.code.core.Encoding +import prog8.code.core.GoldenRam import prog8.code.core.ICompilationTarget import prog8.code.core.IMemSizer import prog8.code.core.IStringEncoding -import prog8.code.target.cbm.CbmMemorySizer -import prog8.code.target.pet.PETMachineDefinition +import prog8.code.core.Zeropage +import prog8.code.target.encodings.Encoder +import prog8.code.target.zp.PETZeropage +import java.nio.file.Path -class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { +class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) { override val name = NAME - override val machine = PETMachineDefinition() override val defaultEncoding = Encoding.PETSCII companion object { const val NAME = "pet32" } + + override val cpu = CpuType.CPU6502 + + override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE + override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE + override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 20u + override val PROGRAM_LOAD_ADDRESS = 0x0401u + override val PROGRAM_MEMTOP_ADDRESS = 0x8000u + + override val BSSHIGHRAM_START = 0u + override val BSSHIGHRAM_END = 0u + override val BSSGOLDENRAM_START = 0u + override val BSSGOLDENRAM_END = 0u + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() + + override fun convertFloatToBytes(num: Double): List { + val m5 = Mflpt5.fromNumber(num) + return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) + } + + override fun convertBytesToFloat(bytes: List): Double { + require(bytes.size==5) { "need 5 bytes" } + val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) + return m5.toDouble() + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The pet target only supports the main emulator (Vice).") + return + } + + println("\nStarting PET emulator...") + val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString()) + val cmdline = listOf("xpet", "-model", "4032", "-ramsize", "32", "-videosize", "40", "-silent", "-moncommands", viceMonlist, + "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") + val processb = ProcessBuilder(cmdline).inheritIO() + val process=processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address in 0xe800u..0xe8ffu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = PETZeropage(compilerOptions) + // there's no golden ram. + } + } diff --git a/codeCore/src/prog8/code/target/VMTarget.kt b/codeCore/src/prog8/code/target/VMTarget.kt index 102b237d9..f668d7406 100644 --- a/codeCore/src/prog8/code/target/VMTarget.kt +++ b/codeCore/src/prog8/code/target/VMTarget.kt @@ -1,15 +1,85 @@ package prog8.code.target import prog8.code.core.* -import prog8.code.target.virtual.VirtualMachineDefinition +import prog8.code.target.encodings.Encoder +import java.nio.file.Path +import kotlin.io.path.isReadable +import kotlin.io.path.name +import kotlin.io.path.readText -class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { +class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) { override val name = NAME - override val machine = VirtualMachineDefinition() override val defaultEncoding = Encoding.ISO companion object { const val NAME = "virtual" + const val FLOAT_MEM_SIZE = 8 // 64-bits double + } + + override val cpu = CpuType.VIRTUAL + + override val FLOAT_MAX_POSITIVE = Double.MAX_VALUE.toDouble() + override val FLOAT_MAX_NEGATIVE = -Double.MAX_VALUE.toDouble() + override val FLOAT_MEM_SIZE = VMTarget.FLOAT_MEM_SIZE + override val STARTUP_CODE_RESERVED_SIZE = 0u // not actually used + override val PROGRAM_LOAD_ADDRESS = 0u // not actually used + override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // not actually used + + override val BSSHIGHRAM_START = 0u // not actually used + override val BSSHIGHRAM_END = 0u // not actually used + override val BSSGOLDENRAM_START = 0u // not actually used + override val BSSGOLDENRAM_END = 0u // not actually used + override lateinit var zeropage: Zeropage // not actually used + override lateinit var golden: GoldenRam // not actually used + + override fun getFloatAsmBytes(num: Number): String { + // little endian binary representation + val bits = num.toDouble().toBits().toULong() + val hexStr = bits.toString(16).padStart(16, '0') + val parts = hexStr.chunked(2).map { "\$" + it } + return parts.joinToString(", ") + } + + override fun convertFloatToBytes(num: Double): List { + val bits = num.toBits().toULong() + val hexStr = bits.toString(16).padStart(16, '0') + val parts = hexStr.chunked(2).map { it.toInt(16).toUByte() } + return parts + } + + override fun convertBytesToFloat(bytes: List): Double { + require(bytes.size==8) { "need 8 bytes" } + val b0 = bytes[0].toLong() shl (8*7) + val b1 = bytes[1].toLong() shl (8*6) + val b2 = bytes[2].toLong() shl (8*5) + val b3 = bytes[3].toLong() shl (8*4) + val b4 = bytes[4].toLong() shl (8*3) + val b5 = bytes[5].toLong() shl (8*2) + val b6 = bytes[6].toLong() shl (8*1) + val b7 = bytes[7].toLong() shl (8*0) + return Double.fromBits(b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + println("\nStarting Virtual Machine...") + // to not have external module dependencies in our own module, we launch the virtual machine via reflection + val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner + val filename = programNameWithPath.name + if(programNameWithPath.isReadable()) { + vm.runProgram(programNameWithPath.readText()) + } else { + val withExt = programNameWithPath.resolveSibling("$filename.p8ir") + if(withExt.isReadable()) + vm.runProgram(withExt.readText()) + else + throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file") + } + } + + override fun isIOAddress(address: UInt): Boolean = false + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = VirtualZeropage(compilerOptions) } override fun memorySize(dt: DataType, numElements: Int?): Int { @@ -18,7 +88,7 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { return when(dt.sub) { BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 - BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE + BaseDataType.FLOAT-> numElements * FLOAT_MEM_SIZE BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") else -> throw IllegalArgumentException("invalid sub type") } @@ -30,10 +100,29 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { return when { dt.isByteOrBool -> 1 * (numElements ?: 1) - dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) + dt.isFloat -> FLOAT_MEM_SIZE * (numElements ?: 1) dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } } -} \ No newline at end of file +} + + + +interface IVirtualMachineRunner { + fun runProgram(irSource: String) +} + +private class VirtualZeropage(options: CompilationOptions): Zeropage(options) { + override val SCRATCH_B1: UInt + get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") + override val SCRATCH_REG: UInt + get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") + override val SCRATCH_W1: UInt + get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") + override val SCRATCH_W2: UInt + get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") + + override fun allocateCx16VirtualRegisters() { /* there is no actual zero page in this target to allocate thing in */ } +} diff --git a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt b/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt deleted file mode 100644 index af0e3453b..000000000 --- a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt +++ /dev/null @@ -1,62 +0,0 @@ -package prog8.code.target.atari - -import prog8.code.core.* -import java.nio.file.Path - - -class AtariMachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU6502 - - override val FLOAT_MAX_POSITIVE = 9.999999999e97 - override val FLOAT_MAX_NEGATIVE = -9.999999999e97 - override val FLOAT_MEM_SIZE = 6 - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x2000u - override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop? - - override val BSSHIGHRAM_START = 0u // TODO - override val BSSHIGHRAM_END = 0u // TODO - override val BSSGOLDENRAM_START = 0u // TODO - override val BSSGOLDENRAM_END = 0u // TODO - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number") - override fun convertFloatToBytes(num: Double): List = TODO("atari float to bytes") - override fun convertBytesToFloat(bytes: List): Double = TODO("atari bytes to float") - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - val emulatorName: String - val cmdline: List - when(selectedEmulator) { - 1 -> { - emulatorName = "atari800" - cmdline = listOf(emulatorName, "-xl", "-xl-rev", "2", "-nobasic", "-run", "${programNameWithPath}.xex") - } - 2 -> { - emulatorName = "altirra" - cmdline = listOf("Altirra64.exe", "${programNameWithPath.normalize()}.xex") - } - else -> { - System.err.println("Atari target only supports atari800 and altirra emulators.") - return - } - } - - // TODO monlist? - - println("\nStarting Atari800XL emulator $emulatorName...") - val processb = ProcessBuilder(cmdline).inheritIO() - val process: Process = processb.start() - process.waitFor() - } - - override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = AtariZeropage(compilerOptions) - golden = GoldenRam(compilerOptions, UIntRange.EMPTY) - } -} diff --git a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt b/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt deleted file mode 100644 index cdc8c43dd..000000000 --- a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt +++ /dev/null @@ -1,62 +0,0 @@ -package prog8.code.target.c128 - -import prog8.code.core.* -import prog8.code.target.C64Target -import prog8.code.target.cbm.Mflpt5 -import java.nio.file.Path - - -class C128MachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU6502 - - override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE - override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE - override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x1c01u - override val PROGRAM_MEMTOP_ADDRESS = 0xc000u - - override val BSSHIGHRAM_START = 0u // TODO - override val BSSHIGHRAM_END = 0u // TODO - override val BSSGOLDENRAM_START = 0u // TODO - override val BSSGOLDENRAM_END = 0u // TODO - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() - - override fun convertFloatToBytes(num: Double): List { - val m5 = Mflpt5.fromNumber(num) - return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) - } - - override fun convertBytesToFloat(bytes: List): Double { - require(bytes.size==5) { "need 5 bytes" } - val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) - return m5.toDouble() - } - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - if(selectedEmulator!=1) { - System.err.println("The c128 target only supports the main emulator (Vice).") - return - } - - println("\nStarting C-128 emulator x128...") - val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString()) - val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist, - "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") - val processb = ProcessBuilder(cmdline).inheritIO() - val process: Process = processb.start() - process.waitFor() - } - - override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = C128Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, UIntRange.EMPTY) // TODO does the c128 have some of this somewhere? - } -} diff --git a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt b/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt deleted file mode 100644 index d8a161490..000000000 --- a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt +++ /dev/null @@ -1,73 +0,0 @@ -package prog8.code.target.c64 - -import prog8.code.core.* -import prog8.code.target.C64Target -import prog8.code.target.cbm.Mflpt5 -import java.io.IOException -import java.nio.file.Path - - -class C64MachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU6502 - - override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE - override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE - override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x0801u - override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used - // note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15 - - override val BSSHIGHRAM_START = 0xc000u - override val BSSHIGHRAM_END = 0xcfdfu - override val BSSGOLDENRAM_START = 0u - override val BSSGOLDENRAM_END = 0u - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() - - override fun convertFloatToBytes(num: Double): List { - val m5 = Mflpt5.fromNumber(num) - return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) - } - - override fun convertBytesToFloat(bytes: List): Double { - require(bytes.size==5) { "need 5 bytes" } - val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) - return m5.toDouble() - } - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - if(selectedEmulator!=1) { - System.err.println("The c64 target only supports the main emulator (Vice).") - return - } - - for(emulator in listOf("x64sc", "x64")) { - println("\nStarting C-64 emulator $emulator...") - val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString()) - val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist, - "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") - val processb = ProcessBuilder(cmdline).inheritIO() - val process: Process - try { - process=processb.start() - } catch(_: IOException) { - continue // try the next emulator executable - } - process.waitFor() - break - } - } - - override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = C64Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u) - } - -} diff --git a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt b/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt deleted file mode 100644 index 21838e86e..000000000 --- a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt +++ /dev/null @@ -1,75 +0,0 @@ -package prog8.code.target.cx16 - -import prog8.code.core.* -import prog8.code.target.C64Target -import prog8.code.target.cbm.Mflpt5 -import java.nio.file.Path - - -class CX16MachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU65c02 - - override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE - override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE - override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x0801u - override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u - - override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active - override val BSSHIGHRAM_END = 0xbfffu // Rom starts at $c000 - override val BSSGOLDENRAM_START = 0x0400u - override val BSSGOLDENRAM_END = 0x07ffu - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() - - override fun convertFloatToBytes(num: Double): List { - val m5 = Mflpt5.fromNumber(num) - return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) - } - - override fun convertBytesToFloat(bytes: List): Double { - require(bytes.size==5) { "need 5 bytes" } - val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) - return m5.toDouble() - } - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - val emulator: String - val extraArgs: List - - when(selectedEmulator) { - 1 -> { - emulator = "x16emu" - extraArgs = listOf("-debug") - } - 2 -> { - emulator = "box16" - extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString())) - } - else -> { - System.err.println("Cx16 target only supports x16emu and box16 emulators.") - return - } - } - - println("\nStarting Commander X16 emulator $emulator...") - val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs - val processb = ProcessBuilder(cmdline).inheritIO() - processb.environment()["PULSE_LATENCY_MSEC"] = "10" - val process: Process = processb.start() - process.waitFor() - } - - override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = CX16Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u) - } - -} diff --git a/codeCore/src/prog8/code/target/Encoder.kt b/codeCore/src/prog8/code/target/encodings/Encoder.kt similarity index 96% rename from codeCore/src/prog8/code/target/Encoder.kt rename to codeCore/src/prog8/code/target/encodings/Encoder.kt index 9b1284aa5..b47ad5988 100644 --- a/codeCore/src/prog8/code/target/Encoder.kt +++ b/codeCore/src/prog8/code/target/encodings/Encoder.kt @@ -1,11 +1,9 @@ -package prog8.code.target +package prog8.code.target.encodings import com.github.michaelbull.result.fold import prog8.code.core.Encoding import prog8.code.core.IStringEncoding import prog8.code.core.InternalCompilerException -import prog8.code.target.encodings.* - object Encoder: IStringEncoding { override val defaultEncoding: Encoding = Encoding.ISO diff --git a/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt b/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt deleted file mode 100644 index 9192f2e64..000000000 --- a/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt +++ /dev/null @@ -1,50 +0,0 @@ -package prog8.code.target.neo6502 - -import prog8.code.core.* -import java.nio.file.Path - - -class Neo6502MachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU65c02 - - override val FLOAT_MAX_POSITIVE = 9.999999999e97 - override val FLOAT_MAX_NEGATIVE = -9.999999999e97 - override val FLOAT_MEM_SIZE = 6 - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x0800u - override val PROGRAM_MEMTOP_ADDRESS = 0xfc00u // kernal starts here - - override val BSSHIGHRAM_START = 0u // TODO - override val BSSHIGHRAM_END = 0u // TODO - override val BSSGOLDENRAM_START = 0u // TODO - override val BSSGOLDENRAM_END = 0u // TODO - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number") - override fun convertFloatToBytes(num: Double): List = TODO("atari float to bytes") - override fun convertBytesToFloat(bytes: List): Double = TODO("atari bytes to float") - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - if(selectedEmulator!=1) { - System.err.println("The neo target only supports the main emulator (neo).") - return - } - - val cmdline = listOf("neo", "${programNameWithPath}.bin@800", "cold") - - println("\nStarting Neo6502 emulator...") - val processb = ProcessBuilder(cmdline).inheritIO() - val process: Process = processb.start() - process.waitFor() - } - - override fun isIOAddress(address: UInt): Boolean = address in 0xff00u..0xff0fu - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = Neo6502Zeropage(compilerOptions) - golden = GoldenRam(compilerOptions, UIntRange.EMPTY) - } -} diff --git a/codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt b/codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt deleted file mode 100644 index b9251ff34..000000000 --- a/codeCore/src/prog8/code/target/pet/PETMachineDefinition.kt +++ /dev/null @@ -1,63 +0,0 @@ -package prog8.code.target.pet - -import prog8.code.core.* -import prog8.code.target.C64Target -import prog8.code.target.cbm.Mflpt5 -import java.nio.file.Path - - -class PETMachineDefinition: IMachineDefinition { - - override val cpu = CpuType.CPU6502 - - override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE - override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE - override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE - override val STARTUP_CODE_RESERVED_SIZE = 20u - override val PROGRAM_LOAD_ADDRESS = 0x0401u - override val PROGRAM_MEMTOP_ADDRESS = 0x8000u - - override val BSSHIGHRAM_START = 0u - override val BSSHIGHRAM_END = 0u - override val BSSGOLDENRAM_START = 0u - override val BSSGOLDENRAM_END = 0u - - override lateinit var zeropage: Zeropage - override lateinit var golden: GoldenRam - - override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() - - override fun convertFloatToBytes(num: Double): List { - val m5 = Mflpt5.fromNumber(num) - return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4) - } - - override fun convertBytesToFloat(bytes: List): Double { - require(bytes.size==5) { "need 5 bytes" } - val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]) - return m5.toDouble() - } - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - if(selectedEmulator!=1) { - System.err.println("The pet target only supports the main emulator (Vice).") - return - } - - println("\nStarting PET emulator...") - val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString()) - val cmdline = listOf("xpet", "-model", "4032", "-ramsize", "32", "-videosize", "40", "-silent", "-moncommands", viceMonlist, - "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg") - val processb = ProcessBuilder(cmdline).inheritIO() - val process=processb.start() - process.waitFor() - } - - override fun isIOAddress(address: UInt): Boolean = address in 0xe800u..0xe8ffu - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = PETZeropage(compilerOptions) - // there's no golden ram. - } - -} diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt deleted file mode 100644 index 1186ee8e1..000000000 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ /dev/null @@ -1,93 +0,0 @@ -package prog8.code.target.virtual - -import prog8.code.core.* -import java.nio.file.Path -import kotlin.io.path.isReadable -import kotlin.io.path.name -import kotlin.io.path.readText - -class VirtualMachineDefinition: IMachineDefinition { - - override val cpu = CpuType.VIRTUAL - - override val FLOAT_MAX_POSITIVE = Double.MAX_VALUE.toDouble() - override val FLOAT_MAX_NEGATIVE = -Double.MAX_VALUE.toDouble() - override val FLOAT_MEM_SIZE = 8 // 64-bits double - override val STARTUP_CODE_RESERVED_SIZE = 0u // not actually used - override val PROGRAM_LOAD_ADDRESS = 0u // not actually used - override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // not actually used - - override val BSSHIGHRAM_START = 0u // not actually used - override val BSSHIGHRAM_END = 0u // not actually used - override val BSSGOLDENRAM_START = 0u // not actually used - override val BSSGOLDENRAM_END = 0u // not actually used - override lateinit var zeropage: Zeropage // not actually used - override lateinit var golden: GoldenRam // not actually used - - override fun getFloatAsmBytes(num: Number): String { - // little endian binary representation - val bits = num.toDouble().toBits().toULong() - val hexStr = bits.toString(16).padStart(16, '0') - val parts = hexStr.chunked(2).map { "\$" + it } - return parts.joinToString(", ") - } - - override fun convertFloatToBytes(num: Double): List { - val bits = num.toBits().toULong() - val hexStr = bits.toString(16).padStart(16, '0') - val parts = hexStr.chunked(2).map { it.toInt(16).toUByte() } - return parts - } - - override fun convertBytesToFloat(bytes: List): Double { - require(bytes.size==8) { "need 8 bytes" } - val b0 = bytes[0].toLong() shl (8*7) - val b1 = bytes[1].toLong() shl (8*6) - val b2 = bytes[2].toLong() shl (8*5) - val b3 = bytes[3].toLong() shl (8*4) - val b4 = bytes[4].toLong() shl (8*3) - val b5 = bytes[5].toLong() shl (8*2) - val b6 = bytes[6].toLong() shl (8*1) - val b7 = bytes[7].toLong() shl (8*0) - return Double.fromBits(b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7) - } - - override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { - println("\nStarting Virtual Machine...") - // to not have external module dependencies in our own module, we launch the virtual machine via reflection - val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner - val filename = programNameWithPath.name - if(programNameWithPath.isReadable()) { - vm.runProgram(programNameWithPath.readText()) - } else { - val withExt = programNameWithPath.resolveSibling("$filename.p8ir") - if(withExt.isReadable()) - vm.runProgram(withExt.readText()) - else - throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file") - } - } - - override fun isIOAddress(address: UInt): Boolean = false - - override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { - zeropage = VirtualZeropage(compilerOptions) - } -} - -interface IVirtualMachineRunner { - fun runProgram(irSource: String) -} - -private class VirtualZeropage(options: CompilationOptions): Zeropage(options) { - override val SCRATCH_B1: UInt - get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") - override val SCRATCH_REG: UInt - get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") - override val SCRATCH_W1: UInt - get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") - override val SCRATCH_W2: UInt - get() = throw IllegalStateException("virtual shouldn't use this zeropage variable") - - override fun allocateCx16VirtualRegisters() { /* there is no actual zero page in this target to allocate thing in */ } -} diff --git a/codeCore/src/prog8/code/target/atari/AtariZeropage.kt b/codeCore/src/prog8/code/target/zp/AtariZeropage.kt similarity index 98% rename from codeCore/src/prog8/code/target/atari/AtariZeropage.kt rename to codeCore/src/prog8/code/target/zp/AtariZeropage.kt index d7e54508e..041a41588 100644 --- a/codeCore/src/prog8/code/target/atari/AtariZeropage.kt +++ b/codeCore/src/prog8/code/target/zp/AtariZeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.atari +package prog8.code.target.zp import prog8.code.core.CompilationOptions import prog8.code.core.InternalCompilerException diff --git a/codeCore/src/prog8/code/target/c128/C128Zeropage.kt b/codeCore/src/prog8/code/target/zp/C128Zeropage.kt similarity index 99% rename from codeCore/src/prog8/code/target/c128/C128Zeropage.kt rename to codeCore/src/prog8/code/target/zp/C128Zeropage.kt index 3928eb30d..1005cd011 100644 --- a/codeCore/src/prog8/code/target/c128/C128Zeropage.kt +++ b/codeCore/src/prog8/code/target/zp/C128Zeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.c128 +package prog8.code.target.zp import prog8.code.core.CompilationOptions import prog8.code.core.InternalCompilerException diff --git a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt b/codeCore/src/prog8/code/target/zp/C64Zeropage.kt similarity index 99% rename from codeCore/src/prog8/code/target/c64/C64Zeropage.kt rename to codeCore/src/prog8/code/target/zp/C64Zeropage.kt index cbbeb094f..183c571f5 100644 --- a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt +++ b/codeCore/src/prog8/code/target/zp/C64Zeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.c64 +package prog8.code.target.zp import prog8.code.core.* diff --git a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/zp/CX16Zeropage.kt similarity index 99% rename from codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt rename to codeCore/src/prog8/code/target/zp/CX16Zeropage.kt index c4d3cf251..560239d95 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/zp/CX16Zeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.cx16 +package prog8.code.target.zp import prog8.code.core.* diff --git a/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt b/codeCore/src/prog8/code/target/zp/Neo6502Zeropage.kt similarity index 98% rename from codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt rename to codeCore/src/prog8/code/target/zp/Neo6502Zeropage.kt index a020501e4..69b9f23ea 100644 --- a/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt +++ b/codeCore/src/prog8/code/target/zp/Neo6502Zeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.neo6502 +package prog8.code.target.zp import prog8.code.core.* diff --git a/codeCore/src/prog8/code/target/pet/PETZeropage.kt b/codeCore/src/prog8/code/target/zp/PETZeropage.kt similarity index 98% rename from codeCore/src/prog8/code/target/pet/PETZeropage.kt rename to codeCore/src/prog8/code/target/zp/PETZeropage.kt index 8aa0d4f12..faef91f9d 100644 --- a/codeCore/src/prog8/code/target/pet/PETZeropage.kt +++ b/codeCore/src/prog8/code/target/zp/PETZeropage.kt @@ -1,4 +1,4 @@ -package prog8.code.target.pet +package prog8.code.target.zp import prog8.code.core.CompilationOptions import prog8.code.core.InternalCompilerException diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index d475790a7..a3676a00f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -219,7 +219,7 @@ class AsmGen6502Internal ( internal val optimizedByteMultiplications = arrayOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100) internal val optimizedWordMultiplications = arrayOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640) internal val loopEndLabels = ArrayDeque() - private val zeropage = options.compTarget.machine.zeropage + private val zeropage = options.compTarget.zeropage private val allocator = VariableAllocator(symbolTable, options, errors) private val assembly = mutableListOf() private val breakpointLabels = mutableListOf() @@ -251,7 +251,7 @@ class AsmGen6502Internal ( } } if(options.optimize) { - while(optimizeAssembly(asmLines, options.compTarget.machine, symbolTable)>0) { + while(optimizeAssembly(asmLines, options.compTarget, symbolTable)>0) { // optimize the assembly source code } output.writeLines(asmLines) @@ -328,7 +328,7 @@ class AsmGen6502Internal ( } } - internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu + internal fun isTargetCpu(cpu: CpuType) = options.compTarget.cpu == cpu private var lastSourceLineNumber: Int = -1 @@ -640,7 +640,7 @@ class AsmGen6502Internal ( } } expr.type.isFloat -> { - require(options.compTarget.machine.FLOAT_MEM_SIZE == 5) {"invalid float size ${expr.position}"} + require(options.compTarget.FLOAT_MEM_SIZE == 5) {"invalid float size ${expr.position}"} assignExpressionToRegister(expr.index, RegisterOrPair.A, false) out(""" sta P8ZP_SCRATCH_REG diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt index 291bf0831..abd79a7d6 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt @@ -4,13 +4,13 @@ import prog8.code.StConstant import prog8.code.StMemVar import prog8.code.SymbolTable import prog8.code.ast.PtLabel -import prog8.code.core.IMachineDefinition +import prog8.code.core.ICompilationTarget // note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations -internal fun optimizeAssembly(lines: MutableList, machine: IMachineDefinition, symbolTable: SymbolTable): Int { +internal fun optimizeAssembly(lines: MutableList, machine: ICompilationTarget, symbolTable: SymbolTable): Int { var numberOfOptimizations = 0 @@ -123,7 +123,7 @@ private fun getLinesBy(lines: MutableList, windowSize: Int) = private fun optimizeSameAssignments( linesByFourteen: Sequence>>, - machine: IMachineDefinition, + machine: ICompilationTarget, symbolTable: SymbolTable ): List { @@ -386,7 +386,7 @@ This gets generated after certain if conditions, and only the branch instruction private fun optimizeStoreLoadSame( linesByFour: Sequence>>, - machine: IMachineDefinition, + machine: ICompilationTarget, symbolTable: SymbolTable ): List { val mods = mutableListOf() diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 320682ccf..68ccf17d8 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -39,7 +39,7 @@ internal class ProgramAndVarsGen( // the global list of all floating point constants for the whole program asmgen.out("; global float constants") for (flt in allocator.globalFloatConsts) { - val floatFill = compTarget.machine.getFloatAsmBytes(flt.key) + val floatFill = compTarget.getFloatAsmBytes(flt.key) val floatvalue = flt.key asmgen.out("${flt.value}\t.byte $floatFill ; float $floatvalue") } @@ -52,7 +52,7 @@ internal class ProgramAndVarsGen( private fun header() { val ourName = this.javaClass.name - val cpu = when(compTarget.machine.cpu) { + val cpu = when(compTarget.cpu) { CpuType.CPU6502 -> "6502" CpuType.CPU65c02 -> "w65c02" else -> "unsupported" @@ -102,8 +102,8 @@ internal class ProgramAndVarsGen( OutputType.PRG -> { when(options.launcher) { CbmPrgLauncherType.BASIC -> { - if (options.loadAddress != options.compTarget.machine.PROGRAM_LOAD_ADDRESS) { - errors.err("BASIC output must have load address ${options.compTarget.machine.PROGRAM_LOAD_ADDRESS.toHex()}", program.position) + if (options.loadAddress != options.compTarget.PROGRAM_LOAD_ADDRESS) { + errors.err("BASIC output must have load address ${options.compTarget.PROGRAM_LOAD_ADDRESS.toHex()}", program.position) } asmgen.out("; ---- basic program with sys call ----") asmgen.out("* = ${options.loadAddress.toHex()}") @@ -203,7 +203,7 @@ internal class ProgramAndVarsGen( BaseDataType.UBYTE -> asmgen.out("$name .byte ?") BaseDataType.WORD -> asmgen.out("$name .sint ?") BaseDataType.UWORD -> asmgen.out("$name .word ?") - BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.FLOAT_MEM_SIZE}") else -> throw AssemblyError("weird dt for extravar $dt") } } @@ -219,49 +219,49 @@ internal class ProgramAndVarsGen( var relocatedBssEnd = 0u if(options.varsGolden) { - if(options.compTarget.machine.BSSGOLDENRAM_START == 0u || - options.compTarget.machine.BSSGOLDENRAM_END == 0u || - options.compTarget.machine.BSSGOLDENRAM_END <= options.compTarget.machine.BSSGOLDENRAM_START) { + if(options.compTarget.BSSGOLDENRAM_START == 0u || + options.compTarget.BSSGOLDENRAM_END == 0u || + options.compTarget.BSSGOLDENRAM_END <= options.compTarget.BSSGOLDENRAM_START) { throw AssemblyError("current compilation target hasn't got the golden ram area properly defined or it is simply not available") } relocateBssVars = true - relocatedBssStart = options.compTarget.machine.BSSGOLDENRAM_START - relocatedBssEnd = options.compTarget.machine.BSSGOLDENRAM_END + relocatedBssStart = options.compTarget.BSSGOLDENRAM_START + relocatedBssEnd = options.compTarget.BSSGOLDENRAM_END } else if(options.varsHighBank!=null) { - if(options.compTarget.machine.BSSHIGHRAM_START == 0u || - options.compTarget.machine.BSSHIGHRAM_END == 0u || - options.compTarget.machine.BSSHIGHRAM_END <= options.compTarget.machine.BSSHIGHRAM_START) { + if(options.compTarget.BSSHIGHRAM_START == 0u || + options.compTarget.BSSHIGHRAM_END == 0u || + options.compTarget.BSSHIGHRAM_END <= options.compTarget.BSSHIGHRAM_START) { throw AssemblyError("current compilation target hasn't got the high ram area properly defined or it is simply not available") } if(options.slabsHighBank!=null && options.varsHighBank!=options.slabsHighBank) throw AssemblyError("slabs and vars high bank must be the same") relocateBssVars = true - relocatedBssStart = options.compTarget.machine.BSSHIGHRAM_START - relocatedBssEnd = options.compTarget.machine.BSSHIGHRAM_END + relocatedBssStart = options.compTarget.BSSHIGHRAM_START + relocatedBssEnd = options.compTarget.BSSHIGHRAM_END } if(options.slabsGolden) { - if(options.compTarget.machine.BSSGOLDENRAM_START == 0u || - options.compTarget.machine.BSSGOLDENRAM_END == 0u || - options.compTarget.machine.BSSGOLDENRAM_END <= options.compTarget.machine.BSSGOLDENRAM_START) { + if(options.compTarget.BSSGOLDENRAM_START == 0u || + options.compTarget.BSSGOLDENRAM_END == 0u || + options.compTarget.BSSGOLDENRAM_END <= options.compTarget.BSSGOLDENRAM_START) { throw AssemblyError("current compilation target hasn't got the golden ram area properly defined or it is simply not available") } relocateBssSlabs = true - relocatedBssStart = options.compTarget.machine.BSSGOLDENRAM_START - relocatedBssEnd = options.compTarget.machine.BSSGOLDENRAM_END + relocatedBssStart = options.compTarget.BSSGOLDENRAM_START + relocatedBssEnd = options.compTarget.BSSGOLDENRAM_END } else if(options.slabsHighBank!=null) { - if(options.compTarget.machine.BSSHIGHRAM_START == 0u || - options.compTarget.machine.BSSHIGHRAM_END == 0u || - options.compTarget.machine.BSSHIGHRAM_END <= options.compTarget.machine.BSSHIGHRAM_START) { + if(options.compTarget.BSSHIGHRAM_START == 0u || + options.compTarget.BSSHIGHRAM_END == 0u || + options.compTarget.BSSHIGHRAM_END <= options.compTarget.BSSHIGHRAM_START) { throw AssemblyError("current compilation target hasn't got the high ram area properly defined or it is simply not available") } if(options.varsHighBank!=null && options.varsHighBank!=options.slabsHighBank) throw AssemblyError("slabs and vars high bank must be the same") relocateBssSlabs = true - relocatedBssStart = options.compTarget.machine.BSSHIGHRAM_START - relocatedBssEnd = options.compTarget.machine.BSSHIGHRAM_END + relocatedBssStart = options.compTarget.BSSHIGHRAM_START + relocatedBssEnd = options.compTarget.BSSHIGHRAM_END } asmgen.out("; bss sections") @@ -465,14 +465,14 @@ internal class ProgramAndVarsGen( else when(dt) { BaseDataType.UBYTE -> asmgen.out("$name .byte ?") BaseDataType.UWORD -> asmgen.out("$name .word ?") - BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.FLOAT_MEM_SIZE}") else -> throw AssemblyError("weird dt for extravar $dt") } } if(asmGenInfo.usedFloatEvalResultVar1) - asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.FLOAT_MEM_SIZE}") if(asmGenInfo.usedFloatEvalResultVar2) - asmgen.out("$subroutineFloatEvalResultVar2 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") + asmgen.out("$subroutineFloatEvalResultVar2 .fill ${options.compTarget.FLOAT_MEM_SIZE}") asmgen.out(" .send BSS") // normal statically allocated variables @@ -650,7 +650,7 @@ internal class ProgramAndVarsGen( dt.isSignedByte -> asmgen.out("${variable.name}\t.char ?") dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ?") dt.isSignedWord -> asmgen.out("${variable.name}\t.sint ?") - dt.isFloat -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}") + dt.isFloat -> asmgen.out("${variable.name}\t.fill ${compTarget.FLOAT_MEM_SIZE}") dt.isSplitWordArray -> { alignVar(variable.align) val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2 @@ -692,7 +692,7 @@ internal class ProgramAndVarsGen( if(initialValue==0) { asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float") } else { - val floatFill = compTarget.machine.getFloatAsmBytes(initialValue) + val floatFill = compTarget.getFloatAsmBytes(initialValue) asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue") } } @@ -767,7 +767,7 @@ internal class ProgramAndVarsGen( dt.isFloatArray -> { val array = value ?: zeroFilledArray(orNumberOfZeros!!) val floatFills = array.map { - compTarget.machine.getFloatAsmBytes(it.number!!) + compTarget.getFloatAsmBytes(it.number!!) } asmgen.out(varname) for (f in array.zip(floatFills)) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index 57a22f9d6..191ffaf53 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -14,7 +14,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, private val errors: IErrorReporter ) { - private val zeropage = options.compTarget.machine.zeropage + private val zeropage = options.compTarget.zeropage internal val globalFloatConsts = mutableMapOf() // all float values in the entire program (value -> varname) internal val zeropageVars: Map diff --git a/codeGenCpu6502/test/TestCodegen.kt b/codeGenCpu6502/test/TestCodegen.kt index 65ff5b89e..e946236f8 100644 --- a/codeGenCpu6502/test/TestCodegen.kt +++ b/codeGenCpu6502/test/TestCodegen.kt @@ -27,7 +27,7 @@ class TestCodegen: FunSpec({ floats = true, noSysInit = false, compTarget = target, - loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, + loadAddress = target.PROGRAM_LOAD_ADDRESS, memtopAddress = 0xffffu ) } diff --git a/codeGenIntermediate/test/TestIRPeepholeOpt.kt b/codeGenIntermediate/test/TestIRPeepholeOpt.kt index 0763b8c66..d88c899a0 100644 --- a/codeGenIntermediate/test/TestIRPeepholeOpt.kt +++ b/codeGenIntermediate/test/TestIRPeepholeOpt.kt @@ -22,7 +22,7 @@ class TestIRPeepholeOpt: FunSpec({ floats = false, noSysInit = true, compTarget = target, - loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, + loadAddress = target.PROGRAM_LOAD_ADDRESS, memtopAddress = 0xffffu ) val prog = IRProgram("test", IRSymbolTable(), options, target) diff --git a/codeGenIntermediate/test/TestVmCodeGen.kt b/codeGenIntermediate/test/TestVmCodeGen.kt index 00d55edbc..f6576d66f 100644 --- a/codeGenIntermediate/test/TestVmCodeGen.kt +++ b/codeGenIntermediate/test/TestVmCodeGen.kt @@ -24,7 +24,7 @@ class TestVmCodeGen: FunSpec({ floats = true, noSysInit = false, compTarget = target, - loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, + loadAddress = target.PROGRAM_LOAD_ADDRESS, memtopAddress = 0xffffu ) } diff --git a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt index 740dec3f6..1ba87bf58 100644 --- a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt +++ b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt @@ -298,7 +298,7 @@ class UnusedCodeRemover(private val program: Program, else -> {} } } else { - if (assign1.target.isSameAs(assign2.target, program) && !assign1.target.isIOAddress(compTarget.machine)) { + if (assign1.target.isSameAs(assign2.target, program) && !assign1.target.isIOAddress(compTarget)) { if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(assign2.target.identifier!!.nameInSource)) // only remove the second assignment if its value is a simple expression! when(assign2.value) { diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 81cd45e0f..55a8e3c34 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -6,8 +6,8 @@ import prog8.code.core.CbmPrgLauncherType import prog8.code.source.ImportFileSystem import prog8.code.target.CompilationTargets import prog8.code.target.Cx16Target +import prog8.code.target.VMTarget import prog8.code.target.getCompilationTargetByName -import prog8.code.target.virtual.VirtualMachineDefinition import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments import prog8.compiler.ErrorReporter @@ -303,9 +303,9 @@ private fun compileMain(args: Array): Boolean { if(startEmulator1==true || startEmulator2==true) { if (compilationResult.compilationOptions.launcher != CbmPrgLauncherType.NONE || compilationTarget=="atari" || compilationTarget=="neo") { if (startEmulator1 == true) - compilationResult.compilationOptions.compTarget.machine.launchEmulator(1, programNameInPath) + compilationResult.compilationOptions.compTarget.launchEmulator(1, programNameInPath) else if (startEmulator2 == true) - compilationResult.compilationOptions.compTarget.machine.launchEmulator(2, programNameInPath) + compilationResult.compilationOptions.compTarget.launchEmulator(2, programNameInPath) } else { println("\nCan't start emulator because program has no launcher type.") } @@ -319,7 +319,7 @@ private fun compileMain(args: Array): Boolean { fun convertFloatToBytes(number: String, target: String) { val tgt = getCompilationTargetByName(target) val dbl = number.toDouble() - val bytes = tgt.machine.convertFloatToBytes(dbl) + val bytes = tgt.convertFloatToBytes(dbl) print("$dbl in bytes on '$target': ") println(bytes.joinToString(",")) } @@ -327,7 +327,7 @@ fun convertFloatToBytes(number: String, target: String) { fun convertBytesToFloat(bytelist: String, target: String) { val tgt = getCompilationTargetByName(target) val bytes = bytelist.split(',').map { it.trim().toUByte() } - val number = tgt.machine.convertBytesToFloat(bytes) + val number = tgt.convertBytesToFloat(bytes) println("floating point value on '$target': $number") } @@ -348,6 +348,6 @@ private fun processSymbolDefs(symbolDefs: List): Map? { fun runVm(irFilename: String) { val irFile = Path(irFilename) - val vmdef = VirtualMachineDefinition() + val vmdef = VMTarget() vmdef.launchEmulator(0, irFile) } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index ad7a31584..28d0a9a1b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -118,7 +118,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { if (args.writeAssembly) { // re-initialize memory areas with final compilationOptions - compilationOptions.compTarget.machine.initializeMemoryAreas(compilationOptions) + compilationOptions.compTarget.initializeMemoryAreas(compilationOptions) program.processAstBeforeAsmGeneration(compilationOptions, args.errors) args.errors.report() @@ -235,24 +235,24 @@ internal fun determineProgramLoadAddress(program: Program, options: CompilationO when(options.output) { OutputType.RAW -> { if(options.compTarget.name==Neo6502Target.NAME) - loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS + loadAddress = options.compTarget.PROGRAM_LOAD_ADDRESS // for all other targets, RAW has no predefined load address. } OutputType.PRG -> { if(options.launcher==CbmPrgLauncherType.BASIC) { - loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS + loadAddress = options.compTarget.PROGRAM_LOAD_ADDRESS } } OutputType.XEX -> { if(options.launcher!=CbmPrgLauncherType.NONE) throw AssemblyError("atari xex output can't contain BASIC launcher") - loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS + loadAddress = options.compTarget.PROGRAM_LOAD_ADDRESS } } } if(options.output==OutputType.PRG && options.launcher==CbmPrgLauncherType.BASIC) { - val expected = options.compTarget.machine.PROGRAM_LOAD_ADDRESS + val expected = options.compTarget.PROGRAM_LOAD_ADDRESS if(loadAddress!=expected) { errors.err("BASIC output must have load address ${expected.toHex()}", specifiedAddress?.second ?: program.toplevelModule.position) } @@ -265,7 +265,7 @@ internal fun determineProgramLoadAddress(program: Program, options: CompilationO options.loadAddress = loadAddress - options.memtopAddress = program.toplevelModule.memtopAddress?.first ?: options.compTarget.machine.PROGRAM_MEMTOP_ADDRESS + options.memtopAddress = program.toplevelModule.memtopAddress?.first ?: options.compTarget.PROGRAM_MEMTOP_ADDRESS if(loadAddress>options.memtopAddress) { errors.warn("program load address ${loadAddress.toHex()} is beyond default memtop address ${options.memtopAddress.toHex()}. " + @@ -510,12 +510,12 @@ private fun createAssemblyAndAssemble(program: PtProgram, val asmgen = if(compilerOptions.experimentalCodegen) prog8.codegen.experimental.ExperiCodeGen() - else if (compilerOptions.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) + else if (compilerOptions.compTarget.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true, lastGeneratedLabelSequenceNr+1) else if (compilerOptions.compTarget.name == VMTarget.NAME) VmCodeGen() else - throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}") + throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.cpu}") // need to make a new symboltable here to capture possible changes made by optimization steps performed earlier! val stMaker = SymbolTableMaker(program, compilerOptions) diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 9c45fbf09..f82aeff89 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -286,7 +286,7 @@ internal class AstChecker(private val program: Program, if (addr > 65535u) errors.err("block address must be valid integer 0..\$ffff", block.position) if(compilerOptions.loadAddress!=0u) { - val gapsize = compilerOptions.compTarget.machine.STARTUP_CODE_RESERVED_SIZE + val gapsize = compilerOptions.compTarget.STARTUP_CODE_RESERVED_SIZE if (addr < compilerOptions.loadAddress + gapsize) errors.err("block address must be at least program load address + $gapsize (to allow for startup logic)", block.position) } @@ -1867,7 +1867,7 @@ internal class AstChecker(private val program: Program, // check if the floating point values are all within range val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() - if(doubles.any { it < compilerOptions.compTarget.machine.FLOAT_MAX_NEGATIVE || it > compilerOptions.compTarget.machine.FLOAT_MAX_POSITIVE }) + if(doubles.any { it < compilerOptions.compTarget.FLOAT_MAX_NEGATIVE || it > compilerOptions.compTarget.FLOAT_MAX_POSITIVE }) return err("floating point value overflow") return true } @@ -1886,7 +1886,7 @@ internal class AstChecker(private val program: Program, when { targetDt.isFloat -> { val number=value.number - if (number > compilerOptions.compTarget.machine.FLOAT_MAX_POSITIVE || number < compilerOptions.compTarget.machine.FLOAT_MAX_NEGATIVE) + if (number > compilerOptions.compTarget.FLOAT_MAX_POSITIVE || number < compilerOptions.compTarget.FLOAT_MAX_NEGATIVE) return err("value '$number' out of range") } targetDt.isUnsignedByte -> { diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index df5b87a5f..4994fa708 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -165,7 +165,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, // remove duplicated assignments, but not if it's a memory mapped IO register val isIO = try { - assignment.target.isIOAddress(options.compTarget.machine) + assignment.target.isIOAddress(options.compTarget) } catch (_: FatalAstException) { false } diff --git a/compiler/test/TestLaunchEmu.kt b/compiler/test/TestLaunchEmu.kt index 33e0dae5e..69b7fa692 100644 --- a/compiler/test/TestLaunchEmu.kt +++ b/compiler/test/TestLaunchEmu.kt @@ -39,7 +39,7 @@ class TestLaunchEmu: FunSpec({ """) - target.machine.launchEmulator(0, tmpfile) + target.launchEmulator(0, tmpfile) tmpfile.deleteExisting() } }) diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 0d1ec9b32..97f9e6487 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -39,49 +39,49 @@ class TestMemory: FunSpec({ var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false } test("assign target in mapped IO space C64") { @@ -90,25 +90,25 @@ class TestMemory: FunSpec({ var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true } fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget { @@ -123,17 +123,17 @@ class TestMemory: FunSpec({ test("identifier mapped to IO memory on C64") { var target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.VAR) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.VAR) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.CONST) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.CONST) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.MEMORY) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.MEMORY) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true } test("memory expression mapped to IO memory on C64") { @@ -141,13 +141,13 @@ class TestMemory: FunSpec({ var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) wrapWithProgram(listOf(assign)) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true } test("regular variable not in mapped IO ram on C64") { @@ -159,7 +159,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false } test("memory mapped variable not in mapped IO ram on C64") { @@ -172,7 +172,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false } test("memory mapped variable in mapped IO ram on C64") { @@ -185,7 +185,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true } test("array not in mapped IO ram") { @@ -198,7 +198,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false } test("memory mapped array not in mapped IO ram") { @@ -212,7 +212,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe false + target.isIOAddress(c64target) shouldBe false } test("memory mapped array in mapped IO ram") { @@ -226,7 +226,7 @@ class TestMemory: FunSpec({ val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) .addModule(module) - target.isIOAddress(c64target.machine) shouldBe true + target.isIOAddress(c64target) shouldBe true } @@ -263,11 +263,11 @@ class TestMemory: FunSpec({ target.memorySize(BaseDataType.BOOL) shouldBe 1 target.memorySize(BaseDataType.BYTE) shouldBe 1 target.memorySize(BaseDataType.WORD) shouldBe 2 - target.memorySize(BaseDataType.FLOAT) shouldBe target.machine.FLOAT_MEM_SIZE + target.memorySize(BaseDataType.FLOAT) shouldBe target.FLOAT_MEM_SIZE target.memorySize(DataType.forDt(BaseDataType.BOOL), null) shouldBe 1 target.memorySize(DataType.forDt(BaseDataType.WORD), null) shouldBe 2 - target.memorySize(DataType.forDt(BaseDataType.FLOAT), null) shouldBe target.machine.FLOAT_MEM_SIZE + target.memorySize(DataType.forDt(BaseDataType.FLOAT), null) shouldBe target.FLOAT_MEM_SIZE target.memorySize(DataType.forDt(BaseDataType.STR), null) shouldBe 2 target.memorySize(DataType.forDt(BaseDataType.STR), 50) shouldBe 50 @@ -279,13 +279,13 @@ class TestMemory: FunSpec({ target.memorySize(DataType.arrayFor(BaseDataType.BYTE), 10) shouldBe 10 target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20 target.memorySize(DataType.arrayFor(BaseDataType.WORD), 10) shouldBe 20 - target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE + target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.FLOAT_MEM_SIZE target.memorySize(DataType.arrayFor(BaseDataType.WORD, true), 10) shouldBe 20 target.memorySize(DataType.arrayFor(BaseDataType.UWORD, true), 10) shouldBe 20 target.memorySize(DataType.forDt(BaseDataType.BOOL), 10) shouldBe 10 target.memorySize(DataType.forDt(BaseDataType.UWORD), 10) shouldBe 20 - target.memorySize(DataType.forDt(BaseDataType.FLOAT), 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE + target.memorySize(DataType.forDt(BaseDataType.FLOAT), 10) shouldBe 10*target.FLOAT_MEM_SIZE } } }) diff --git a/compiler/test/TestNumbers.kt b/compiler/test/TestNumbers.kt index 59c6e81c6..1c3112e69 100644 --- a/compiler/test/TestNumbers.kt +++ b/compiler/test/TestNumbers.kt @@ -9,7 +9,7 @@ import io.kotest.matchers.string.shouldContain import prog8.code.core.InternalCompilerException import prog8.code.core.toHex import prog8.code.target.C64Target -import prog8.code.target.cbm.Mflpt5 +import prog8.code.target.Mflpt5 import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.compileText diff --git a/compiler/test/TestStringEncodings.kt b/compiler/test/TestStringEncodings.kt index 9540ec057..12fa9a953 100644 --- a/compiler/test/TestStringEncodings.kt +++ b/compiler/test/TestStringEncodings.kt @@ -18,7 +18,7 @@ import prog8.code.core.Position import prog8.code.core.unescape import prog8.code.target.C64Target import prog8.code.target.Cx16Target -import prog8.code.target.Encoder +import prog8.code.target.encodings.Encoder import prog8.code.target.encodings.AtasciiEncoding import prog8.code.target.encodings.IsoEncoding import prog8.code.target.encodings.PetsciiEncoding diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index 069c83f18..8efc2d68a 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -15,9 +15,8 @@ import io.kotest.matchers.shouldNotBe import prog8.code.core.* import prog8.code.target.C64Target import prog8.code.target.Cx16Target -import prog8.code.target.c64.C64Zeropage -import prog8.code.target.cx16.CX16Zeropage -import prog8tests.helpers.DummyCompilationTarget +import prog8.code.target.zp.C64Zeropage +import prog8.code.target.zp.CX16Zeropage import prog8tests.helpers.ErrorReporterForTests @@ -51,7 +50,7 @@ class TestAbstractZeropage: FunSpec({ CompilationOptions.AllZeropageAllowed, floats = false, noSysInit = false, - compTarget = DummyCompilationTarget, + compTarget = C64Target(), loadAddress = 999u, memtopAddress = 0xffffu ) diff --git a/compiler/test/helpers/Dummies.kt b/compiler/test/helpers/Dummies.kt index 8fe541968..7f2d18a84 100644 --- a/compiler/test/helpers/Dummies.kt +++ b/compiler/test/helpers/Dummies.kt @@ -5,7 +5,6 @@ import prog8.ast.expressions.Expression import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.NumericLiteral import prog8.code.core.* -import prog8.code.target.virtual.VirtualMachineDefinition internal object DummyFunctions : IBuiltinFunctions { @@ -64,25 +63,3 @@ internal object AsciiStringEncoder : IStringEncoding { return bytes.joinToString() } } - -internal object DummyCompilationTarget : ICompilationTarget { - override val name: String = "dummy" - override val machine: IMachineDefinition = VirtualMachineDefinition() // not really true but I don't want to implement a full dummy machinedef - override val defaultEncoding = Encoding.PETSCII - - override fun encodeString(str: String, encoding: Encoding): List { - throw NotImplementedError("dummy") - } - - override fun decodeString(bytes: Iterable, encoding: Encoding): String { - throw NotImplementedError("dummy") - } - - override fun memorySize(dt: DataType, numElements: Int?): Int { - throw NotImplementedError("dummy") - } - - override fun memorySize(dt: BaseDataType): Int { - throw NotImplementedError("dummy") - } -} diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index e4947c213..4382c6810 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -4,7 +4,6 @@ import prog8.ast.* import prog8.ast.expressions.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstVisitor -import prog8.code.ast.PtExpression import prog8.code.core.* import java.util.* @@ -636,7 +635,7 @@ data class AssignTarget(var identifier: IdentifierReference?, return false } - fun isIOAddress(machine: IMachineDefinition): Boolean { + fun isIOAddress(target: ICompilationTarget): Boolean { val memAddr = memoryAddress val arrayIdx = arrayindexed val ident = identifier @@ -644,12 +643,12 @@ data class AssignTarget(var identifier: IdentifierReference?, memAddr != null -> { val addr = memAddr.addressExpression.constValue(definingModule.program) if(addr!=null) - return machine.isIOAddress(addr.number.toUInt()) + return target.isIOAddress(addr.number.toUInt()) return when (memAddr.addressExpression) { is IdentifierReference -> { val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(definingModule.program) val result = if ((decl?.type == VarDeclType.MEMORY || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteral) - machine.isIOAddress((decl.value as NumericLiteral).number.toUInt()) + target.isIOAddress((decl.value as NumericLiteral).number.toUInt()) else false result @@ -662,7 +661,7 @@ data class AssignTarget(var identifier: IdentifierReference?, return if (targetStmt?.type == VarDeclType.MEMORY) { val addr = targetStmt.value as? NumericLiteral if (addr != null) - machine.isIOAddress(addr.number.toUInt()) + target.isIOAddress(addr.number.toUInt()) else false } else false @@ -670,12 +669,12 @@ data class AssignTarget(var identifier: IdentifierReference?, ident != null -> { val decl = ident.targetVarDecl(definingModule.program) ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteral) - machine.isIOAddress((decl.value as NumericLiteral).number.toUInt()) + target.isIOAddress((decl.value as NumericLiteral).number.toUInt()) else false } multi != null -> { - return multi.any { it.isIOAddress(machine) } + return multi.any { it.isIOAddress(target) } } else -> return false } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index dc09854cf..5396409e0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -10,6 +10,7 @@ TODO Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ +- Make some of the target machine config externally configurable (for 1 new target, the existing ones should stay as they are for the time being) - Kotlin: can we use inline value classes in certain spots? - allow multi-value variable initialization (var a,b,c = 1,2,3) - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions @@ -78,6 +79,7 @@ Optimizations ------------- - Multi-value returns of normal subroutines: use cpu register A or AY for the first one and only start using virtual registers for the rest. + Can FAC then be used for floats as well again? Those are now not supported for multi-value returns. - Optimize the IfExpression code generation to be more like regular if-else code. (both 6502 and IR) search for "TODO don't store condition as expression" - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? for instance, vars used inside loops first, then loopvars, then uwords used as pointers (or these first??), then the rest diff --git a/examples/cx16/audioroutines.p8 b/examples/cx16/audioroutines.p8 index 3e0bc347d..987ac8c49 100644 --- a/examples/cx16/audioroutines.p8 +++ b/examples/cx16/audioroutines.p8 @@ -2,6 +2,12 @@ %zeropage basicsafe %option no_sysinit + +; NOTE: This is a small example of the Kernal's AUDIO routines. +; There is also the "psg" library module that implements some Vera PSG routines +; of its own, but that's not used here at all. See the "cx16/bdmusic" example for that. + + main { sub start() { txt.print("\n\nsimple demonstration of the audio kernal routines.\n") diff --git a/examples/cx16/bdmusic.p8 b/examples/cx16/bdmusic.p8 index 28813322b..1dcfef4ad 100644 --- a/examples/cx16/bdmusic.p8 +++ b/examples/cx16/bdmusic.p8 @@ -4,6 +4,46 @@ main { + sub start() { + txt.print("will play the music from boulderdash,\nmade in 1984 by peter liepa.\npress enter to start: ") + void cbm.CHRIN() + txt.clear_screen() + + psg.silent() + psg.voice(0, psg.LEFT, 63, psg.TRIANGLE, 0) + psg.voice(1, psg.RIGHT, 63, psg.TRIANGLE, 0) + + cx16.enable_irq_handlers(true) + cx16.set_vsync_irq_handler(&psg.envelopes_irq) + + repeat { + uword note + for note in notes { + ubyte note0 = lsb(note) + ubyte note1 = msb(note) + psg.freq(0, vera_freqs[note0]) + psg.freq(1, vera_freqs[note1]) + psg.envelope(0, 63, 255, 0, 6) + psg.envelope(1, 63, 255, 0, 6) + print_notes(note0, note1) + sys.wait(10) + } + } + + psg.silent() + cx16.disable_irq_handlers() + } + + sub print_notes(ubyte n1, ubyte n2) { + txt.nl() + txt.plot(n1, txt.DEFAULT_HEIGHT-1) + txt.color(7) + txt.chrout('Q') + txt.plot(n2, txt.DEFAULT_HEIGHT-1) + txt.color(4) + txt.chrout('Q') + } + sub explosion() { ; this subroutine is not used but it is an example of how to make a sound effect using the psg library! psg.silent() @@ -52,46 +92,6 @@ main { } - sub start() { - txt.print("will play the music from boulderdash,\nmade in 1984 by peter liepa.\npress enter to start: ") - void cbm.CHRIN() - txt.clear_screen() - - psg.silent() - psg.voice(0, psg.LEFT, 63, psg.TRIANGLE, 0) - psg.voice(1, psg.RIGHT, 63, psg.TRIANGLE, 0) - - cx16.enable_irq_handlers(true) - cx16.set_vsync_irq_handler(&psg.envelopes_irq) - - repeat { - uword note - for note in notes { - ubyte note0 = lsb(note) - ubyte note1 = msb(note) - psg.freq(0, vera_freqs[note0]) - psg.freq(1, vera_freqs[note1]) - psg.envelope(0, 63, 255, 0, 6) - psg.envelope(1, 63, 255, 0, 6) - print_notes(note0, note1) - sys.wait(10) - } - } - - psg.silent() - cx16.disable_irq_handlers() - } - - sub print_notes(ubyte n1, ubyte n2) { - txt.nl() - txt.plot(n1, txt.DEFAULT_HEIGHT-1) - txt.color(7) - txt.chrout('Q') - txt.plot(n2, txt.DEFAULT_HEIGHT-1) - txt.color(4) - txt.chrout('Q') - } - ; details about the boulderdash music can be found here: ; https://www.elmerproductions.com/sp/peterb/sounds.html#Theme%20tune diff --git a/examples/test.p8 b/examples/test.p8 index de69daa02..c12de0ed7 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,3 +1,4 @@ +%import floats %import sprites %option no_sysinit %zeropage basicsafe @@ -18,15 +19,16 @@ main { sprites.pos(1, x, y) } + float fz cx16.r0L = single() - cx16.r0L, cx16.r1L = multi() + cx16.r0L, fz = multi() } sub single() -> ubyte { return xx } - sub multi() -> ubyte, ubyte { - return xx, yy + sub multi() -> ubyte, float { + return xx, 3.33 } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 729f78289..abe8f341d 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -89,7 +89,7 @@ class IRFileReader { var zeropage = ZeropageType.FULL val zpReserved = mutableListOf() val zpAllowed = mutableListOf() - var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS + var loadAddress = target.PROGRAM_LOAD_ADDRESS var optimize = true var outputDir = Path("") diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 8640a4f72..73ec7a82a 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -22,7 +22,7 @@ class TestIRFileInOut: FunSpec({ floats = false, noSysInit = true, compTarget = target, - loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, + loadAddress = target.PROGRAM_LOAD_ADDRESS, memtopAddress = 0xffffu, outputDir = tempdir ) diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 9f141ad9d..ddf427f96 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -365,7 +365,7 @@ object SysCalls { while(length>0u) { if(vm.memory.getFloat(array)==value) return returnValue(callspec.returns.single(), 1u, vm) - array += vm.machinedef.FLOAT_MEM_SIZE + array += vm.machine.FLOAT_MEM_SIZE length-- } returnValue(callspec.returns.single(), 0u, vm) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index cce4ad562..d5a7b128e 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -1,8 +1,8 @@ package prog8.vm import prog8.code.core.toHex -import prog8.code.target.virtual.IVirtualMachineRunner -import prog8.code.target.virtual.VirtualMachineDefinition +import prog8.code.target.IVirtualMachineRunner +import prog8.code.target.VMTarget import prog8.intermediate.* import java.awt.Color import java.awt.Toolkit @@ -43,7 +43,7 @@ class VirtualMachine(irProgram: IRProgram) { private var fileOutputStream: OutputStream? = null private var fileInputStream: InputStream? = null val memory = Memory() - val machinedef = VirtualMachineDefinition() + val machine = VMTarget() val program: List val artificialLabelAddresses: Map val registers = Registers() diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index a4f840c96..4e78e965d 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -218,7 +218,7 @@ class VmProgramLoader { } dt.isFloatArray -> { memory.setFloat(addr, 0.0) - addr += program.options.compTarget.machine.FLOAT_MEM_SIZE + addr += program.options.compTarget.FLOAT_MEM_SIZE } else -> throw IRParseException("invalid dt") } @@ -330,7 +330,7 @@ class VmProgramLoader { { memory.setFloat(address, it) }, { throw IRParseException("didn't expect bool") } ) - address += program.options.compTarget.machine.FLOAT_MEM_SIZE + address += program.options.compTarget.FLOAT_MEM_SIZE } } diff --git a/virtualmachine/test/TestVm.kt b/virtualmachine/test/TestVm.kt index 825112f8c..3eaa2666c 100644 --- a/virtualmachine/test/TestVm.kt +++ b/virtualmachine/test/TestVm.kt @@ -3,10 +3,9 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.shouldBe import prog8.code.core.* +import prog8.code.target.C64Target +import prog8.code.target.Cx16Target import prog8.code.target.VMTarget -import prog8.code.target.c64.C64MachineDefinition -import prog8.code.target.cx16.CX16MachineDefinition -import prog8.code.target.virtual.VirtualMachineDefinition import prog8.intermediate.* import prog8.vm.VirtualMachine import prog8.vm.VmRunner @@ -24,7 +23,7 @@ class TestVm: FunSpec( { floats = true, noSysInit = false, compTarget = target, - loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, + loadAddress = target.PROGRAM_LOAD_ADDRESS, memtopAddress = 0xffffu ) } @@ -125,12 +124,12 @@ class TestVm: FunSpec( { } test("vm machine float bits") { - val cx16machine = CX16MachineDefinition() + val cx16machine = Cx16Target() cx16machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2" - val c64machine = C64MachineDefinition() + val c64machine = C64Target() c64machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2" - val vm = VirtualMachineDefinition() + val vm = VMTarget() vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$09, \$21, \$fb, \$54, \$44, \$2d, \$18" } })