merge IMachineDefinition into ICompilationTarget

This commit is contained in:
Irmen de Jong
2025-01-13 21:12:18 +01:00
parent 4f096a7511
commit 09a17743ad
56 changed files with 685 additions and 791 deletions

View File

@@ -23,10 +23,10 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
if(options.compTarget.name != VMTarget.NAME) { if(options.compTarget.name != VMTarget.NAME) {
listOf( listOf(
PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, 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.machine.zeropage.SCRATCH_REG, 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.machine.zeropage.SCRATCH_W1, 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.machine.zeropage.SCRATCH_W2, null, Position.DUMMY), PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.zeropage.SCRATCH_W2, null, Position.DUMMY),
).forEach { ).forEach {
it.parent = program it.parent = program
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it)) st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))

View File

@@ -34,7 +34,7 @@ class CompilationOptions(val output: OutputType,
var symbolDefs: Map<String, String> = emptyMap() var symbolDefs: Map<String, String> = emptyMap()
) { ) {
init { init {
compTarget.machine.initializeMemoryAreas(this) compTarget.initializeMemoryAreas(this)
} }
companion object { companion object {

View File

@@ -1,8 +1,39 @@
package prog8.code.core package prog8.code.core
import java.nio.file.Path
enum class CpuType {
CPU6502,
CPU65c02,
VIRTUAL
}
interface ICompilationTarget: IStringEncoding, IMemSizer { interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String 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 encodeString(str: String, encoding: Encoding): List<UByte>
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String

View File

@@ -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
}

View File

@@ -1,40 +1,72 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.* 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 name = NAME
override val machine = AtariMachineDefinition()
override val defaultEncoding = Encoding.ATASCII override val defaultEncoding = Encoding.ATASCII
companion object { companion object {
const val NAME = "atari" const val NAME = "atari"
const val FLOAT_MEM_SIZE = 6
} }
override fun memorySize(dt: DataType, numElements: Int?): Int { override val cpu = CpuType.CPU6502
if(dt.isArray) {
if(numElements==null) return 2 // treat it as a pointer size override val FLOAT_MAX_POSITIVE = 9.999999999e97
return when(dt.sub) { override val FLOAT_MAX_NEGATIVE = -9.999999999e97
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements override val FLOAT_MEM_SIZE = AtariTarget.FLOAT_MEM_SIZE
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 override val STARTUP_CODE_RESERVED_SIZE = 20u
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE override val PROGRAM_LOAD_ADDRESS = 0x2000u
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop?
else -> throw IllegalArgumentException("invalid sub type")
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 { // TODO monlist?
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) println("\nStarting Atari800XL emulator $emulatorName...")
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") val processb = ProcessBuilder(cmdline).inheritIO()
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") val process: Process = processb.start()
else -> 2 * (numElements ?: 1) 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)
} }
} }

View File

@@ -1,19 +1,77 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.CompilationOptions
import prog8.code.core.CpuType
import prog8.code.core.Encoding import prog8.code.core.Encoding
import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.target.c128.C128MachineDefinition import prog8.code.core.Zeropage
import prog8.code.target.cbm.CbmMemorySizer 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 name = NAME
override val machine = C128MachineDefinition()
override val defaultEncoding = Encoding.PETSCII override val defaultEncoding = Encoding.PETSCII
companion object { companion object {
const val NAME = "c128" 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?
}
} }

View File

@@ -1,16 +1,21 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.CompilationOptions
import prog8.code.core.CpuType
import prog8.code.core.Encoding import prog8.code.core.Encoding
import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.target.c64.C64MachineDefinition import prog8.code.core.Zeropage
import prog8.code.target.cbm.CbmMemorySizer 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 name = NAME
override val machine = C64MachineDefinition()
override val defaultEncoding = Encoding.PETSCII override val defaultEncoding = Encoding.PETSCII
companion object { companion object {
@@ -18,6 +23,69 @@ class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by Cb
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list" 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)
}
} }

View File

@@ -1,19 +1,90 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.CompilationOptions
import prog8.code.core.CpuType
import prog8.code.core.Encoding import prog8.code.core.Encoding
import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.target.cbm.CbmMemorySizer import prog8.code.core.Zeropage
import prog8.code.target.cx16.CX16MachineDefinition 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 name = NAME
override val machine = CX16MachineDefinition()
override val defaultEncoding = Encoding.PETSCII override val defaultEncoding = Encoding.PETSCII
companion object { companion object {
const val NAME = "cx16" 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)
}
} }

View File

@@ -1,10 +1,9 @@
package prog8.code.target.cbm package prog8.code.target
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.pow import kotlin.math.pow
data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) { data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) {
companion object { companion object {

View File

@@ -1,40 +1,60 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.* 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 name = NAME
override val machine = Neo6502MachineDefinition()
override val defaultEncoding = Encoding.ISO override val defaultEncoding = Encoding.ISO
companion object { companion object {
const val NAME = "neo" const val NAME = "neo"
const val FLOAT_MEM_SIZE = 6
} }
override fun memorySize(dt: DataType, numElements: Int?): Int {
if(dt.isArray) { override val cpu = CpuType.CPU65c02
if(numElements==null) return 2 // treat it as a pointer size
return when(dt.sub) { override val FLOAT_MAX_POSITIVE = 9.999999999e97
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements override val FLOAT_MAX_NEGATIVE = -9.999999999e97
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 override val FLOAT_MEM_SIZE = Neo6502Target.FLOAT_MEM_SIZE
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE override val STARTUP_CODE_RESERVED_SIZE = 20u
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size") override val PROGRAM_LOAD_ADDRESS = 0x0800u
else -> throw IllegalArgumentException("invalid sub type") override val PROGRAM_MEMTOP_ADDRESS = 0xfc00u // kernal starts here
}
} override val BSSHIGHRAM_START = 0u // TODO
else if (dt.isString) { override val BSSHIGHRAM_END = 0u // TODO
if(numElements!=null) return numElements // treat it as the size of the given string with the length override val BSSGOLDENRAM_START = 0u // TODO
else return 2 // treat it as the size to store a string pointer 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 { val cmdline = listOf("neo", "${programNameWithPath}.bin@800", "cold")
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1) println("\nStarting Neo6502 emulator...")
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory") val processb = ProcessBuilder(cmdline).inheritIO()
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") val process: Process = processb.start()
else -> 2 * (numElements ?: 1) 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)
} }
} }

View File

@@ -1,18 +1,18 @@
package prog8.code.target.cbm package prog8.code.target
import prog8.code.core.BaseDataType import prog8.code.core.BaseDataType
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.code.core.IMemSizer import prog8.code.core.IMemSizer
internal class NormalMemSizer(val floatsize: Int): IMemSizer {
internal object CbmMemorySizer: IMemSizer {
override fun memorySize(dt: DataType, numElements: Int?): Int { override fun memorySize(dt: DataType, numElements: Int?): Int {
if(dt.isArray) { if(dt.isArray) {
if(numElements==null) return 2 // treat it as a pointer size if(numElements==null) return 2 // treat it as a pointer size
return when(dt.sub) { return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 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") BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
else -> throw IllegalArgumentException("invalid sub type") else -> throw IllegalArgumentException("invalid sub type")
} }
@@ -24,10 +24,11 @@ internal object CbmMemorySizer: IMemSizer {
return when { return when {
dt.isByteOrBool -> 1 * (numElements ?: 1) 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.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
else -> 2 * (numElements ?: 1) else -> 2 * (numElements ?: 1)
} }
} }
} }

View File

@@ -1,19 +1,76 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.CompilationOptions
import prog8.code.core.CpuType
import prog8.code.core.Encoding import prog8.code.core.Encoding
import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.target.cbm.CbmMemorySizer import prog8.code.core.Zeropage
import prog8.code.target.pet.PETMachineDefinition 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 name = NAME
override val machine = PETMachineDefinition()
override val defaultEncoding = Encoding.PETSCII override val defaultEncoding = Encoding.PETSCII
companion object { companion object {
const val NAME = "pet32" 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.
}
} }

View File

@@ -1,15 +1,85 @@
package prog8.code.target package prog8.code.target
import prog8.code.core.* 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 name = NAME
override val machine = VirtualMachineDefinition()
override val defaultEncoding = Encoding.ISO override val defaultEncoding = Encoding.ISO
companion object { companion object {
const val NAME = "virtual" 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 { override fun memorySize(dt: DataType, numElements: Int?): Int {
@@ -18,7 +88,7 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
return when(dt.sub) { return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2 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") BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
else -> throw IllegalArgumentException("invalid sub type") else -> throw IllegalArgumentException("invalid sub type")
} }
@@ -30,10 +100,29 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
return when { return when {
dt.isByteOrBool -> 1 * (numElements ?: 1) 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.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
else -> 2 * (numElements ?: 1) 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 */ }
}

View File

@@ -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)
}
}

View File

@@ -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?
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -1,11 +1,9 @@
package prog8.code.target package prog8.code.target.encodings
import com.github.michaelbull.result.fold import com.github.michaelbull.result.fold
import prog8.code.core.Encoding import prog8.code.core.Encoding
import prog8.code.core.IStringEncoding import prog8.code.core.IStringEncoding
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException
import prog8.code.target.encodings.*
object Encoder: IStringEncoding { object Encoder: IStringEncoding {
override val defaultEncoding: Encoding = Encoding.ISO override val defaultEncoding: Encoding = Encoding.ISO

View File

@@ -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)
}
}

View File

@@ -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.
}
}

View File

@@ -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 */ }
}

View File

@@ -1,4 +1,4 @@
package prog8.code.target.atari package prog8.code.target.zp
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException

View File

@@ -1,4 +1,4 @@
package prog8.code.target.c128 package prog8.code.target.zp
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException

View File

@@ -1,4 +1,4 @@
package prog8.code.target.c64 package prog8.code.target.zp
import prog8.code.core.* import prog8.code.core.*

View File

@@ -1,4 +1,4 @@
package prog8.code.target.cx16 package prog8.code.target.zp
import prog8.code.core.* import prog8.code.core.*

View File

@@ -1,4 +1,4 @@
package prog8.code.target.neo6502 package prog8.code.target.zp
import prog8.code.core.* import prog8.code.core.*

View File

@@ -1,4 +1,4 @@
package prog8.code.target.pet package prog8.code.target.zp
import prog8.code.core.CompilationOptions import prog8.code.core.CompilationOptions
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException

View File

@@ -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 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 optimizedWordMultiplications = arrayOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
internal val loopEndLabels = ArrayDeque<String>() 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 allocator = VariableAllocator(symbolTable, options, errors)
private val assembly = mutableListOf<String>() private val assembly = mutableListOf<String>()
private val breakpointLabels = mutableListOf<String>() private val breakpointLabels = mutableListOf<String>()
@@ -251,7 +251,7 @@ class AsmGen6502Internal (
} }
} }
if(options.optimize) { if(options.optimize) {
while(optimizeAssembly(asmLines, options.compTarget.machine, symbolTable)>0) { while(optimizeAssembly(asmLines, options.compTarget, symbolTable)>0) {
// optimize the assembly source code // optimize the assembly source code
} }
output.writeLines(asmLines) 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 private var lastSourceLineNumber: Int = -1
@@ -640,7 +640,7 @@ class AsmGen6502Internal (
} }
} }
expr.type.isFloat -> { 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) assignExpressionToRegister(expr.index, RegisterOrPair.A, false)
out(""" out("""
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG

View File

@@ -4,13 +4,13 @@ import prog8.code.StConstant
import prog8.code.StMemVar import prog8.code.StMemVar
import prog8.code.SymbolTable import prog8.code.SymbolTable
import prog8.code.ast.PtLabel 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 // 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 var numberOfOptimizations = 0
@@ -123,7 +123,7 @@ private fun getLinesBy(lines: MutableList<String>, windowSize: Int) =
private fun optimizeSameAssignments( private fun optimizeSameAssignments(
linesByFourteen: Sequence<List<IndexedValue<String>>>, linesByFourteen: Sequence<List<IndexedValue<String>>>,
machine: IMachineDefinition, machine: ICompilationTarget,
symbolTable: SymbolTable symbolTable: SymbolTable
): List<Modification> { ): List<Modification> {
@@ -386,7 +386,7 @@ This gets generated after certain if conditions, and only the branch instruction
private fun optimizeStoreLoadSame( private fun optimizeStoreLoadSame(
linesByFour: Sequence<List<IndexedValue<String>>>, linesByFour: Sequence<List<IndexedValue<String>>>,
machine: IMachineDefinition, machine: ICompilationTarget,
symbolTable: SymbolTable symbolTable: SymbolTable
): List<Modification> { ): List<Modification> {
val mods = mutableListOf<Modification>() val mods = mutableListOf<Modification>()

View File

@@ -39,7 +39,7 @@ internal class ProgramAndVarsGen(
// the global list of all floating point constants for the whole program // the global list of all floating point constants for the whole program
asmgen.out("; global float constants") asmgen.out("; global float constants")
for (flt in allocator.globalFloatConsts) { for (flt in allocator.globalFloatConsts) {
val floatFill = compTarget.machine.getFloatAsmBytes(flt.key) val floatFill = compTarget.getFloatAsmBytes(flt.key)
val floatvalue = flt.key val floatvalue = flt.key
asmgen.out("${flt.value}\t.byte $floatFill ; float $floatvalue") asmgen.out("${flt.value}\t.byte $floatFill ; float $floatvalue")
} }
@@ -52,7 +52,7 @@ internal class ProgramAndVarsGen(
private fun header() { private fun header() {
val ourName = this.javaClass.name val ourName = this.javaClass.name
val cpu = when(compTarget.machine.cpu) { val cpu = when(compTarget.cpu) {
CpuType.CPU6502 -> "6502" CpuType.CPU6502 -> "6502"
CpuType.CPU65c02 -> "w65c02" CpuType.CPU65c02 -> "w65c02"
else -> "unsupported" else -> "unsupported"
@@ -102,8 +102,8 @@ internal class ProgramAndVarsGen(
OutputType.PRG -> { OutputType.PRG -> {
when(options.launcher) { when(options.launcher) {
CbmPrgLauncherType.BASIC -> { CbmPrgLauncherType.BASIC -> {
if (options.loadAddress != options.compTarget.machine.PROGRAM_LOAD_ADDRESS) { if (options.loadAddress != options.compTarget.PROGRAM_LOAD_ADDRESS) {
errors.err("BASIC output must have load address ${options.compTarget.machine.PROGRAM_LOAD_ADDRESS.toHex()}", program.position) 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("; ---- basic program with sys call ----")
asmgen.out("* = ${options.loadAddress.toHex()}") asmgen.out("* = ${options.loadAddress.toHex()}")
@@ -203,7 +203,7 @@ internal class ProgramAndVarsGen(
BaseDataType.UBYTE -> asmgen.out("$name .byte ?") BaseDataType.UBYTE -> asmgen.out("$name .byte ?")
BaseDataType.WORD -> asmgen.out("$name .sint ?") BaseDataType.WORD -> asmgen.out("$name .sint ?")
BaseDataType.UWORD -> asmgen.out("$name .word ?") 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") else -> throw AssemblyError("weird dt for extravar $dt")
} }
} }
@@ -219,49 +219,49 @@ internal class ProgramAndVarsGen(
var relocatedBssEnd = 0u var relocatedBssEnd = 0u
if(options.varsGolden) { if(options.varsGolden) {
if(options.compTarget.machine.BSSGOLDENRAM_START == 0u || if(options.compTarget.BSSGOLDENRAM_START == 0u ||
options.compTarget.machine.BSSGOLDENRAM_END == 0u || options.compTarget.BSSGOLDENRAM_END == 0u ||
options.compTarget.machine.BSSGOLDENRAM_END <= options.compTarget.machine.BSSGOLDENRAM_START) { 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") throw AssemblyError("current compilation target hasn't got the golden ram area properly defined or it is simply not available")
} }
relocateBssVars = true relocateBssVars = true
relocatedBssStart = options.compTarget.machine.BSSGOLDENRAM_START relocatedBssStart = options.compTarget.BSSGOLDENRAM_START
relocatedBssEnd = options.compTarget.machine.BSSGOLDENRAM_END relocatedBssEnd = options.compTarget.BSSGOLDENRAM_END
} }
else if(options.varsHighBank!=null) { else if(options.varsHighBank!=null) {
if(options.compTarget.machine.BSSHIGHRAM_START == 0u || if(options.compTarget.BSSHIGHRAM_START == 0u ||
options.compTarget.machine.BSSHIGHRAM_END == 0u || options.compTarget.BSSHIGHRAM_END == 0u ||
options.compTarget.machine.BSSHIGHRAM_END <= options.compTarget.machine.BSSHIGHRAM_START) { 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") 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) if(options.slabsHighBank!=null && options.varsHighBank!=options.slabsHighBank)
throw AssemblyError("slabs and vars high bank must be the same") throw AssemblyError("slabs and vars high bank must be the same")
relocateBssVars = true relocateBssVars = true
relocatedBssStart = options.compTarget.machine.BSSHIGHRAM_START relocatedBssStart = options.compTarget.BSSHIGHRAM_START
relocatedBssEnd = options.compTarget.machine.BSSHIGHRAM_END relocatedBssEnd = options.compTarget.BSSHIGHRAM_END
} }
if(options.slabsGolden) { if(options.slabsGolden) {
if(options.compTarget.machine.BSSGOLDENRAM_START == 0u || if(options.compTarget.BSSGOLDENRAM_START == 0u ||
options.compTarget.machine.BSSGOLDENRAM_END == 0u || options.compTarget.BSSGOLDENRAM_END == 0u ||
options.compTarget.machine.BSSGOLDENRAM_END <= options.compTarget.machine.BSSGOLDENRAM_START) { 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") throw AssemblyError("current compilation target hasn't got the golden ram area properly defined or it is simply not available")
} }
relocateBssSlabs = true relocateBssSlabs = true
relocatedBssStart = options.compTarget.machine.BSSGOLDENRAM_START relocatedBssStart = options.compTarget.BSSGOLDENRAM_START
relocatedBssEnd = options.compTarget.machine.BSSGOLDENRAM_END relocatedBssEnd = options.compTarget.BSSGOLDENRAM_END
} }
else if(options.slabsHighBank!=null) { else if(options.slabsHighBank!=null) {
if(options.compTarget.machine.BSSHIGHRAM_START == 0u || if(options.compTarget.BSSHIGHRAM_START == 0u ||
options.compTarget.machine.BSSHIGHRAM_END == 0u || options.compTarget.BSSHIGHRAM_END == 0u ||
options.compTarget.machine.BSSHIGHRAM_END <= options.compTarget.machine.BSSHIGHRAM_START) { 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") 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) if(options.varsHighBank!=null && options.varsHighBank!=options.slabsHighBank)
throw AssemblyError("slabs and vars high bank must be the same") throw AssemblyError("slabs and vars high bank must be the same")
relocateBssSlabs = true relocateBssSlabs = true
relocatedBssStart = options.compTarget.machine.BSSHIGHRAM_START relocatedBssStart = options.compTarget.BSSHIGHRAM_START
relocatedBssEnd = options.compTarget.machine.BSSHIGHRAM_END relocatedBssEnd = options.compTarget.BSSHIGHRAM_END
} }
asmgen.out("; bss sections") asmgen.out("; bss sections")
@@ -465,14 +465,14 @@ internal class ProgramAndVarsGen(
else when(dt) { else when(dt) {
BaseDataType.UBYTE -> asmgen.out("$name .byte ?") BaseDataType.UBYTE -> asmgen.out("$name .byte ?")
BaseDataType.UWORD -> asmgen.out("$name .word ?") 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") else -> throw AssemblyError("weird dt for extravar $dt")
} }
} }
if(asmGenInfo.usedFloatEvalResultVar1) 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) 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") asmgen.out(" .send BSS")
// normal statically allocated variables // normal statically allocated variables
@@ -650,7 +650,7 @@ internal class ProgramAndVarsGen(
dt.isSignedByte -> asmgen.out("${variable.name}\t.char ?") dt.isSignedByte -> asmgen.out("${variable.name}\t.char ?")
dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ?") dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ?")
dt.isSignedWord -> asmgen.out("${variable.name}\t.sint ?") 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 -> { dt.isSplitWordArray -> {
alignVar(variable.align) alignVar(variable.align)
val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2 val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2
@@ -692,7 +692,7 @@ internal class ProgramAndVarsGen(
if(initialValue==0) { if(initialValue==0) {
asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float") asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float")
} else { } else {
val floatFill = compTarget.machine.getFloatAsmBytes(initialValue) val floatFill = compTarget.getFloatAsmBytes(initialValue)
asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue") asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue")
} }
} }
@@ -767,7 +767,7 @@ internal class ProgramAndVarsGen(
dt.isFloatArray -> { dt.isFloatArray -> {
val array = value ?: zeroFilledArray(orNumberOfZeros!!) val array = value ?: zeroFilledArray(orNumberOfZeros!!)
val floatFills = array.map { val floatFills = array.map {
compTarget.machine.getFloatAsmBytes(it.number!!) compTarget.getFloatAsmBytes(it.number!!)
} }
asmgen.out(varname) asmgen.out(varname)
for (f in array.zip(floatFills)) for (f in array.zip(floatFills))

View File

@@ -14,7 +14,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
private val errors: IErrorReporter 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 globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
internal val zeropageVars: Map<String, MemoryAllocator.VarAllocation> internal val zeropageVars: Map<String, MemoryAllocator.VarAllocation>

View File

@@ -27,7 +27,7 @@ class TestCodegen: FunSpec({
floats = true, floats = true,
noSysInit = false, noSysInit = false,
compTarget = target, compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu memtopAddress = 0xffffu
) )
} }

View File

@@ -22,7 +22,7 @@ class TestIRPeepholeOpt: FunSpec({
floats = false, floats = false,
noSysInit = true, noSysInit = true,
compTarget = target, compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu memtopAddress = 0xffffu
) )
val prog = IRProgram("test", IRSymbolTable(), options, target) val prog = IRProgram("test", IRSymbolTable(), options, target)

View File

@@ -24,7 +24,7 @@ class TestVmCodeGen: FunSpec({
floats = true, floats = true,
noSysInit = false, noSysInit = false,
compTarget = target, compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu memtopAddress = 0xffffu
) )
} }

View File

@@ -298,7 +298,7 @@ class UnusedCodeRemover(private val program: Program,
else -> {} else -> {}
} }
} 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)) if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(assign2.target.identifier!!.nameInSource))
// only remove the second assignment if its value is a simple expression! // only remove the second assignment if its value is a simple expression!
when(assign2.value) { when(assign2.value) {

View File

@@ -6,8 +6,8 @@ import prog8.code.core.CbmPrgLauncherType
import prog8.code.source.ImportFileSystem import prog8.code.source.ImportFileSystem
import prog8.code.target.CompilationTargets import prog8.code.target.CompilationTargets
import prog8.code.target.Cx16Target import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8.code.target.getCompilationTargetByName import prog8.code.target.getCompilationTargetByName
import prog8.code.target.virtual.VirtualMachineDefinition
import prog8.compiler.CompilationResult import prog8.compiler.CompilationResult
import prog8.compiler.CompilerArguments import prog8.compiler.CompilerArguments
import prog8.compiler.ErrorReporter import prog8.compiler.ErrorReporter
@@ -303,9 +303,9 @@ private fun compileMain(args: Array<String>): Boolean {
if(startEmulator1==true || startEmulator2==true) { if(startEmulator1==true || startEmulator2==true) {
if (compilationResult.compilationOptions.launcher != CbmPrgLauncherType.NONE || compilationTarget=="atari" || compilationTarget=="neo") { if (compilationResult.compilationOptions.launcher != CbmPrgLauncherType.NONE || compilationTarget=="atari" || compilationTarget=="neo") {
if (startEmulator1 == true) if (startEmulator1 == true)
compilationResult.compilationOptions.compTarget.machine.launchEmulator(1, programNameInPath) compilationResult.compilationOptions.compTarget.launchEmulator(1, programNameInPath)
else if (startEmulator2 == true) else if (startEmulator2 == true)
compilationResult.compilationOptions.compTarget.machine.launchEmulator(2, programNameInPath) compilationResult.compilationOptions.compTarget.launchEmulator(2, programNameInPath)
} else { } else {
println("\nCan't start emulator because program has no launcher type.") 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) { fun convertFloatToBytes(number: String, target: String) {
val tgt = getCompilationTargetByName(target) val tgt = getCompilationTargetByName(target)
val dbl = number.toDouble() val dbl = number.toDouble()
val bytes = tgt.machine.convertFloatToBytes(dbl) val bytes = tgt.convertFloatToBytes(dbl)
print("$dbl in bytes on '$target': ") print("$dbl in bytes on '$target': ")
println(bytes.joinToString(",")) println(bytes.joinToString(","))
} }
@@ -327,7 +327,7 @@ fun convertFloatToBytes(number: String, target: String) {
fun convertBytesToFloat(bytelist: String, target: String) { fun convertBytesToFloat(bytelist: String, target: String) {
val tgt = getCompilationTargetByName(target) val tgt = getCompilationTargetByName(target)
val bytes = bytelist.split(',').map { it.trim().toUByte() } 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") println("floating point value on '$target': $number")
} }
@@ -348,6 +348,6 @@ private fun processSymbolDefs(symbolDefs: List<String>): Map<String, String>? {
fun runVm(irFilename: String) { fun runVm(irFilename: String) {
val irFile = Path(irFilename) val irFile = Path(irFilename)
val vmdef = VirtualMachineDefinition() val vmdef = VMTarget()
vmdef.launchEmulator(0, irFile) vmdef.launchEmulator(0, irFile)
} }

View File

@@ -118,7 +118,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
if (args.writeAssembly) { if (args.writeAssembly) {
// re-initialize memory areas with final compilationOptions // re-initialize memory areas with final compilationOptions
compilationOptions.compTarget.machine.initializeMemoryAreas(compilationOptions) compilationOptions.compTarget.initializeMemoryAreas(compilationOptions)
program.processAstBeforeAsmGeneration(compilationOptions, args.errors) program.processAstBeforeAsmGeneration(compilationOptions, args.errors)
args.errors.report() args.errors.report()
@@ -235,24 +235,24 @@ internal fun determineProgramLoadAddress(program: Program, options: CompilationO
when(options.output) { when(options.output) {
OutputType.RAW -> { OutputType.RAW -> {
if(options.compTarget.name==Neo6502Target.NAME) 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. // for all other targets, RAW has no predefined load address.
} }
OutputType.PRG -> { OutputType.PRG -> {
if(options.launcher==CbmPrgLauncherType.BASIC) { if(options.launcher==CbmPrgLauncherType.BASIC) {
loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS loadAddress = options.compTarget.PROGRAM_LOAD_ADDRESS
} }
} }
OutputType.XEX -> { OutputType.XEX -> {
if(options.launcher!=CbmPrgLauncherType.NONE) if(options.launcher!=CbmPrgLauncherType.NONE)
throw AssemblyError("atari xex output can't contain BASIC launcher") 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) { 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) { if(loadAddress!=expected) {
errors.err("BASIC output must have load address ${expected.toHex()}", specifiedAddress?.second ?: program.toplevelModule.position) 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.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) { if(loadAddress>options.memtopAddress) {
errors.warn("program load address ${loadAddress.toHex()} is beyond default memtop address ${options.memtopAddress.toHex()}. " + 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) val asmgen = if(compilerOptions.experimentalCodegen)
prog8.codegen.experimental.ExperiCodeGen() 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) prog8.codegen.cpu6502.AsmGen6502(prefixSymbols = true, lastGeneratedLabelSequenceNr+1)
else if (compilerOptions.compTarget.name == VMTarget.NAME) else if (compilerOptions.compTarget.name == VMTarget.NAME)
VmCodeGen() VmCodeGen()
else 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! // need to make a new symboltable here to capture possible changes made by optimization steps performed earlier!
val stMaker = SymbolTableMaker(program, compilerOptions) val stMaker = SymbolTableMaker(program, compilerOptions)

View File

@@ -286,7 +286,7 @@ internal class AstChecker(private val program: Program,
if (addr > 65535u) if (addr > 65535u)
errors.err("block address must be valid integer 0..\$ffff", block.position) errors.err("block address must be valid integer 0..\$ffff", block.position)
if(compilerOptions.loadAddress!=0u) { 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) if (addr < compilerOptions.loadAddress + gapsize)
errors.err("block address must be at least program load address + $gapsize (to allow for startup logic)", block.position) 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 // check if the floating point values are all within range
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() 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 err("floating point value overflow")
return true return true
} }
@@ -1886,7 +1886,7 @@ internal class AstChecker(private val program: Program,
when { when {
targetDt.isFloat -> { targetDt.isFloat -> {
val number=value.number 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") return err("value '$number' out of range")
} }
targetDt.isUnsignedByte -> { targetDt.isUnsignedByte -> {

View File

@@ -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 // remove duplicated assignments, but not if it's a memory mapped IO register
val isIO = try { val isIO = try {
assignment.target.isIOAddress(options.compTarget.machine) assignment.target.isIOAddress(options.compTarget)
} catch (_: FatalAstException) { } catch (_: FatalAstException) {
false false
} }

View File

@@ -39,7 +39,7 @@ class TestLaunchEmu: FunSpec({
</BLOCK> </BLOCK>
</PROGRAM> </PROGRAM>
""") """)
target.machine.launchEmulator(0, tmpfile) target.launchEmulator(0, tmpfile)
tmpfile.deleteExisting() tmpfile.deleteExisting()
} }
}) })

View File

@@ -39,49 +39,49 @@ class TestMemory: FunSpec({
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY) 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) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
} }
test("assign target in mapped IO space C64") { 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 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) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY) memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
} }
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget { fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
@@ -123,17 +123,17 @@ class TestMemory: FunSpec({
test("identifier mapped to IO memory on C64") { test("identifier mapped to IO memory on C64") {
var target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.VAR) var target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.VAR)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.VAR) target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.VAR)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.CONST) target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.CONST)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.CONST) target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.CONST)
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.MEMORY) target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.MEMORY)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.MEMORY) 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") { 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 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) var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY) memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, 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) assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
} }
test("regular variable not in mapped IO ram on C64") { 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")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .addModule(module)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
} }
test("memory mapped variable not in mapped IO ram on C64") { 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")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .addModule(module)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
} }
test("memory mapped variable in mapped IO ram on C64") { 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")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .addModule(module)
target.isIOAddress(c64target.machine) shouldBe true target.isIOAddress(c64target) shouldBe true
} }
test("array not in mapped IO ram") { test("array not in mapped IO ram") {
@@ -198,7 +198,7 @@ class TestMemory: FunSpec({
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .addModule(module)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
} }
test("memory mapped array not in mapped IO ram") { 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")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .addModule(module)
target.isIOAddress(c64target.machine) shouldBe false target.isIOAddress(c64target) shouldBe false
} }
test("memory mapped array in mapped IO ram") { 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")) val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module) .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.BOOL) shouldBe 1
target.memorySize(BaseDataType.BYTE) shouldBe 1 target.memorySize(BaseDataType.BYTE) shouldBe 1
target.memorySize(BaseDataType.WORD) shouldBe 2 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.BOOL), null) shouldBe 1
target.memorySize(DataType.forDt(BaseDataType.WORD), null) shouldBe 2 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), null) shouldBe 2
target.memorySize(DataType.forDt(BaseDataType.STR), 50) shouldBe 50 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.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.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.WORD, true), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.UWORD, 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.BOOL), 10) shouldBe 10
target.memorySize(DataType.forDt(BaseDataType.UWORD), 10) shouldBe 20 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
} }
} }
}) })

View File

@@ -9,7 +9,7 @@ import io.kotest.matchers.string.shouldContain
import prog8.code.core.InternalCompilerException import prog8.code.core.InternalCompilerException
import prog8.code.core.toHex import prog8.code.core.toHex
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.cbm.Mflpt5 import prog8.code.target.Mflpt5
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText import prog8tests.helpers.compileText

View File

@@ -18,7 +18,7 @@ import prog8.code.core.Position
import prog8.code.core.unescape import prog8.code.core.unescape
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.Cx16Target 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.AtasciiEncoding
import prog8.code.target.encodings.IsoEncoding import prog8.code.target.encodings.IsoEncoding
import prog8.code.target.encodings.PetsciiEncoding import prog8.code.target.encodings.PetsciiEncoding

View File

@@ -15,9 +15,8 @@ import io.kotest.matchers.shouldNotBe
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.Cx16Target import prog8.code.target.Cx16Target
import prog8.code.target.c64.C64Zeropage import prog8.code.target.zp.C64Zeropage
import prog8.code.target.cx16.CX16Zeropage import prog8.code.target.zp.CX16Zeropage
import prog8tests.helpers.DummyCompilationTarget
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
@@ -51,7 +50,7 @@ class TestAbstractZeropage: FunSpec({
CompilationOptions.AllZeropageAllowed, CompilationOptions.AllZeropageAllowed,
floats = false, floats = false,
noSysInit = false, noSysInit = false,
compTarget = DummyCompilationTarget, compTarget = C64Target(),
loadAddress = 999u, loadAddress = 999u,
memtopAddress = 0xffffu memtopAddress = 0xffffu
) )

View File

@@ -5,7 +5,6 @@ import prog8.ast.expressions.Expression
import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.NumericLiteral
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.virtual.VirtualMachineDefinition
internal object DummyFunctions : IBuiltinFunctions { internal object DummyFunctions : IBuiltinFunctions {
@@ -64,25 +63,3 @@ internal object AsciiStringEncoder : IStringEncoding {
return bytes.joinToString() 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")
}
}

View File

@@ -4,7 +4,6 @@ import prog8.ast.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor import prog8.ast.walk.IAstVisitor
import prog8.code.ast.PtExpression
import prog8.code.core.* import prog8.code.core.*
import java.util.* import java.util.*
@@ -636,7 +635,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
return false return false
} }
fun isIOAddress(machine: IMachineDefinition): Boolean { fun isIOAddress(target: ICompilationTarget): Boolean {
val memAddr = memoryAddress val memAddr = memoryAddress
val arrayIdx = arrayindexed val arrayIdx = arrayindexed
val ident = identifier val ident = identifier
@@ -644,12 +643,12 @@ data class AssignTarget(var identifier: IdentifierReference?,
memAddr != null -> { memAddr != null -> {
val addr = memAddr.addressExpression.constValue(definingModule.program) val addr = memAddr.addressExpression.constValue(definingModule.program)
if(addr!=null) if(addr!=null)
return machine.isIOAddress(addr.number.toUInt()) return target.isIOAddress(addr.number.toUInt())
return when (memAddr.addressExpression) { return when (memAddr.addressExpression) {
is IdentifierReference -> { is IdentifierReference -> {
val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(definingModule.program) val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(definingModule.program)
val result = if ((decl?.type == VarDeclType.MEMORY || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteral) 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 else
false false
result result
@@ -662,7 +661,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
return if (targetStmt?.type == VarDeclType.MEMORY) { return if (targetStmt?.type == VarDeclType.MEMORY) {
val addr = targetStmt.value as? NumericLiteral val addr = targetStmt.value as? NumericLiteral
if (addr != null) if (addr != null)
machine.isIOAddress(addr.number.toUInt()) target.isIOAddress(addr.number.toUInt())
else else
false false
} else false } else false
@@ -670,12 +669,12 @@ data class AssignTarget(var identifier: IdentifierReference?,
ident != null -> { ident != null -> {
val decl = ident.targetVarDecl(definingModule.program) ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") val decl = ident.targetVarDecl(definingModule.program) ?: throw FatalAstException("invalid identifier ${ident.nameInSource}")
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteral) 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 else
false false
} }
multi != null -> { multi != null -> {
return multi.any { it.isIOAddress(machine) } return multi.any { it.isIOAddress(target) }
} }
else -> return false else -> return false
} }

View File

@@ -10,6 +10,7 @@ TODO
Future Things and Ideas 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? - Kotlin: can we use inline value classes in certain spots?
- allow multi-value variable initialization (var a,b,c = 1,2,3) - 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 - 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. - 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" - 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? - 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 for instance, vars used inside loops first, then loopvars, then uwords used as pointers (or these first??), then the rest

View File

@@ -2,6 +2,12 @@
%zeropage basicsafe %zeropage basicsafe
%option no_sysinit %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 { main {
sub start() { sub start() {
txt.print("\n\nsimple demonstration of the audio kernal routines.\n") txt.print("\n\nsimple demonstration of the audio kernal routines.\n")

View File

@@ -4,6 +4,46 @@
main { 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() { sub explosion() {
; this subroutine is not used but it is an example of how to make a sound effect using the psg library! ; this subroutine is not used but it is an example of how to make a sound effect using the psg library!
psg.silent() 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: ; details about the boulderdash music can be found here:
; https://www.elmerproductions.com/sp/peterb/sounds.html#Theme%20tune ; https://www.elmerproductions.com/sp/peterb/sounds.html#Theme%20tune

View File

@@ -1,3 +1,4 @@
%import floats
%import sprites %import sprites
%option no_sysinit %option no_sysinit
%zeropage basicsafe %zeropage basicsafe
@@ -18,15 +19,16 @@ main {
sprites.pos(1, x, y) sprites.pos(1, x, y)
} }
float fz
cx16.r0L = single() cx16.r0L = single()
cx16.r0L, cx16.r1L = multi() cx16.r0L, fz = multi()
} }
sub single() -> ubyte { sub single() -> ubyte {
return xx return xx
} }
sub multi() -> ubyte, ubyte { sub multi() -> ubyte, float {
return xx, yy return xx, 3.33
} }
} }

View File

@@ -89,7 +89,7 @@ class IRFileReader {
var zeropage = ZeropageType.FULL var zeropage = ZeropageType.FULL
val zpReserved = mutableListOf<UIntRange>() val zpReserved = mutableListOf<UIntRange>()
val zpAllowed = mutableListOf<UIntRange>() val zpAllowed = mutableListOf<UIntRange>()
var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS var loadAddress = target.PROGRAM_LOAD_ADDRESS
var optimize = true var optimize = true
var outputDir = Path("") var outputDir = Path("")

View File

@@ -22,7 +22,7 @@ class TestIRFileInOut: FunSpec({
floats = false, floats = false,
noSysInit = true, noSysInit = true,
compTarget = target, compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu, memtopAddress = 0xffffu,
outputDir = tempdir outputDir = tempdir
) )

View File

@@ -365,7 +365,7 @@ object SysCalls {
while(length>0u) { while(length>0u) {
if(vm.memory.getFloat(array)==value) if(vm.memory.getFloat(array)==value)
return returnValue(callspec.returns.single(), 1u, vm) return returnValue(callspec.returns.single(), 1u, vm)
array += vm.machinedef.FLOAT_MEM_SIZE array += vm.machine.FLOAT_MEM_SIZE
length-- length--
} }
returnValue(callspec.returns.single(), 0u, vm) returnValue(callspec.returns.single(), 0u, vm)

View File

@@ -1,8 +1,8 @@
package prog8.vm package prog8.vm
import prog8.code.core.toHex import prog8.code.core.toHex
import prog8.code.target.virtual.IVirtualMachineRunner import prog8.code.target.IVirtualMachineRunner
import prog8.code.target.virtual.VirtualMachineDefinition import prog8.code.target.VMTarget
import prog8.intermediate.* import prog8.intermediate.*
import java.awt.Color import java.awt.Color
import java.awt.Toolkit import java.awt.Toolkit
@@ -43,7 +43,7 @@ class VirtualMachine(irProgram: IRProgram) {
private var fileOutputStream: OutputStream? = null private var fileOutputStream: OutputStream? = null
private var fileInputStream: InputStream? = null private var fileInputStream: InputStream? = null
val memory = Memory() val memory = Memory()
val machinedef = VirtualMachineDefinition() val machine = VMTarget()
val program: List<IRCodeChunk> val program: List<IRCodeChunk>
val artificialLabelAddresses: Map<Int, IRCodeChunk> val artificialLabelAddresses: Map<Int, IRCodeChunk>
val registers = Registers() val registers = Registers()

View File

@@ -218,7 +218,7 @@ class VmProgramLoader {
} }
dt.isFloatArray -> { dt.isFloatArray -> {
memory.setFloat(addr, 0.0) 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") else -> throw IRParseException("invalid dt")
} }
@@ -330,7 +330,7 @@ class VmProgramLoader {
{ memory.setFloat(address, it) }, { memory.setFloat(address, it) },
{ throw IRParseException("didn't expect bool") } { throw IRParseException("didn't expect bool") }
) )
address += program.options.compTarget.machine.FLOAT_MEM_SIZE address += program.options.compTarget.FLOAT_MEM_SIZE
} }
} }

View File

@@ -3,10 +3,9 @@ import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget 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.intermediate.*
import prog8.vm.VirtualMachine import prog8.vm.VirtualMachine
import prog8.vm.VmRunner import prog8.vm.VmRunner
@@ -24,7 +23,7 @@ class TestVm: FunSpec( {
floats = true, floats = true,
noSysInit = false, noSysInit = false,
compTarget = target, compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS, loadAddress = target.PROGRAM_LOAD_ADDRESS,
memtopAddress = 0xffffu memtopAddress = 0xffffu
) )
} }
@@ -125,12 +124,12 @@ class TestVm: FunSpec( {
} }
test("vm machine float bits") { test("vm machine float bits") {
val cx16machine = CX16MachineDefinition() val cx16machine = Cx16Target()
cx16machine.getFloatAsmBytes(Math.PI) shouldBe "\$82, \$49, \$0f, \$da, \$a2" 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" 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" vm.getFloatAsmBytes(Math.PI) shouldBe "\$40, \$09, \$21, \$fb, \$54, \$44, \$2d, \$18"
} }
}) })