mirror of
https://github.com/irmen/prog8.git
synced 2025-02-20 03:29:01 +00:00
merge IMachineDefinition into ICompilationTarget
This commit is contained in:
parent
4f096a7511
commit
09a17743ad
@ -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))
|
||||
|
@ -34,7 +34,7 @@ class CompilationOptions(val output: OutputType,
|
||||
var symbolDefs: Map<String, String> = emptyMap()
|
||||
) {
|
||||
init {
|
||||
compTarget.machine.initializeMemoryAreas(this)
|
||||
compTarget.initializeMemoryAreas(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -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<UByte>
|
||||
fun convertBytesToFloat(bytes: List<UByte>): Double
|
||||
|
||||
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
||||
fun isIOAddress(address: UInt): Boolean
|
||||
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
|
||||
|
@ -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<UByte>
|
||||
fun convertBytesToFloat(bytes: List<UByte>): Double
|
||||
|
||||
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
||||
fun isIOAddress(address: UInt): Boolean
|
||||
}
|
@ -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<UByte> = TODO("atari float to bytes")
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
val emulatorName: String
|
||||
val cmdline: List<String>
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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?
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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<String>
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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 {
|
@ -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
|
||||
|
||||
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<UByte> = TODO("atari float to bytes")
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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.
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<UByte> {
|
||||
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<UByte>): 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 */ }
|
||||
}
|
||||
|
@ -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<UByte> = TODO("atari float to bytes")
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
val emulatorName: String
|
||||
val cmdline: List<String>
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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?
|
||||
}
|
||||
}
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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)
|
||||
}
|
||||
|
||||
}
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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<String>
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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<UByte> = TODO("atari float to bytes")
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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)
|
||||
}
|
||||
}
|
@ -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<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): 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.
|
||||
}
|
||||
|
||||
}
|
@ -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<UByte> {
|
||||
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<UByte>): 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 */ }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.atari
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.InternalCompilerException
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.c128
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.InternalCompilerException
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.c64
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.*
|
||||
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.cx16
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.*
|
||||
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.neo6502
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.*
|
||||
|
@ -1,4 +1,4 @@
|
||||
package prog8.code.target.pet
|
||||
package prog8.code.target.zp
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.InternalCompilerException
|
@ -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<String>()
|
||||
private val zeropage = options.compTarget.machine.zeropage
|
||||
private val zeropage = options.compTarget.zeropage
|
||||
private val allocator = VariableAllocator(symbolTable, options, errors)
|
||||
private val assembly = mutableListOf<String>()
|
||||
private val breakpointLabels = mutableListOf<String>()
|
||||
@ -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
|
||||
|
@ -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<String>, machine: IMachineDefinition, symbolTable: SymbolTable): Int {
|
||||
internal fun optimizeAssembly(lines: MutableList<String>, machine: ICompilationTarget, symbolTable: SymbolTable): Int {
|
||||
|
||||
var numberOfOptimizations = 0
|
||||
|
||||
@ -123,7 +123,7 @@ private fun getLinesBy(lines: MutableList<String>, windowSize: Int) =
|
||||
|
||||
private fun optimizeSameAssignments(
|
||||
linesByFourteen: Sequence<List<IndexedValue<String>>>,
|
||||
machine: IMachineDefinition,
|
||||
machine: ICompilationTarget,
|
||||
symbolTable: SymbolTable
|
||||
): List<Modification> {
|
||||
|
||||
@ -386,7 +386,7 @@ This gets generated after certain if conditions, and only the branch instruction
|
||||
|
||||
private fun optimizeStoreLoadSame(
|
||||
linesByFour: Sequence<List<IndexedValue<String>>>,
|
||||
machine: IMachineDefinition,
|
||||
machine: ICompilationTarget,
|
||||
symbolTable: SymbolTable
|
||||
): List<Modification> {
|
||||
val mods = mutableListOf<Modification>()
|
||||
|
@ -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))
|
||||
|
@ -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<Double, String>() // all float values in the entire program (value -> varname)
|
||||
internal val zeropageVars: Map<String, MemoryAllocator.VarAllocation>
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<String>): 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<String>): 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<String>): Map<String, String>? {
|
||||
|
||||
fun runVm(irFilename: String) {
|
||||
val irFile = Path(irFilename)
|
||||
val vmdef = VirtualMachineDefinition()
|
||||
val vmdef = VMTarget()
|
||||
vmdef.launchEmulator(0, irFile)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 -> {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class TestLaunchEmu: FunSpec({
|
||||
</BLOCK>
|
||||
</PROGRAM>
|
||||
""")
|
||||
target.machine.launchEmulator(0, tmpfile)
|
||||
target.launchEmulator(0, tmpfile)
|
||||
tmpfile.deleteExisting()
|
||||
}
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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<UByte> {
|
||||
throw NotImplementedError("dummy")
|
||||
}
|
||||
|
||||
override fun decodeString(bytes: Iterable<UByte>, 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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class IRFileReader {
|
||||
var zeropage = ZeropageType.FULL
|
||||
val zpReserved = mutableListOf<UIntRange>()
|
||||
val zpAllowed = mutableListOf<UIntRange>()
|
||||
var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||
var loadAddress = target.PROGRAM_LOAD_ADDRESS
|
||||
var optimize = true
|
||||
var outputDir = Path("")
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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<IRCodeChunk>
|
||||
val artificialLabelAddresses: Map<Int, IRCodeChunk>
|
||||
val registers = Registers()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user