Skip to content

Commit

Permalink
adding a configurable compilation target
Browse files Browse the repository at this point in the history
  • Loading branch information
irmen committed Jan 16, 2025
1 parent f9c7c7d commit e8f3af6
Show file tree
Hide file tree
Showing 35 changed files with 617 additions and 139 deletions.
11 changes: 10 additions & 1 deletion codeCore/src/prog8/code/core/ICompilationTarget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import java.nio.file.Path

enum class CpuType {
CPU6502,
CPU65c02,
CPU65C02,
VIRTUAL
}

enum class ProgramType {
CBMPRG,
ATARIXEX,
NEORAW,
VIRTUALIR
}

interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String

Expand All @@ -23,8 +30,10 @@ interface ICompilationTarget: IStringEncoding, IMemSizer {
val BSSGOLDENRAM_END: UInt

val cpu: CpuType
val programType: ProgramType
var zeropage: Zeropage
var golden: GoldenRam
val libraryPath: Path?

fun initializeMemoryAreas(compilerOptions: CompilationOptions)
fun getFloatAsmBytes(num: Number): String
Expand Down
4 changes: 1 addition & 3 deletions codeCore/src/prog8/code/core/MemoryRegions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract class MemoryAllocator(protected val options: CompilationOptions) {
abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {

abstract val SCRATCH_B1 : UInt // temp storage for a single byte
abstract val SCRATCH_REG : UInt // temp storage for a register, must be B1+1
abstract val SCRATCH_REG : UInt // temp storage for a register byte, must be B1+1
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc

Expand Down Expand Up @@ -133,8 +133,6 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
require(size>0)
return free.containsAll((address until address+size.toUInt()).toList())
}

abstract fun allocateCx16VirtualRegisters()
}


Expand Down
2 changes: 2 additions & 0 deletions codeCore/src/prog8/code/target/AtariTarget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import java.nio.file.Path
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.ATASCII
override val libraryPath = null

companion object {
const val NAME = "atari"
const val FLOAT_MEM_SIZE = 6
}

override val cpu = CpuType.CPU6502
override val programType = ProgramType.ATARIXEX

override val FLOAT_MAX_POSITIVE = 9.999999999e97
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
Expand Down
3 changes: 3 additions & 0 deletions codeCore/src/prog8/code/target/C128Target.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.ProgramType
import prog8.code.core.Zeropage
import prog8.code.target.zp.C128Zeropage
import prog8.code.target.encodings.Encoder
Expand All @@ -16,13 +17,15 @@ import java.nio.file.Path
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null

companion object {
const val NAME = "c128"
}


override val cpu = CpuType.CPU6502
override val programType = ProgramType.CBMPRG

override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
Expand Down
13 changes: 4 additions & 9 deletions codeCore/src/prog8/code/target/C64Target.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
package prog8.code.target

import prog8.code.core.CompilationOptions
import prog8.code.core.CpuType
import prog8.code.core.Encoding
import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.Zeropage
import prog8.code.target.zp.C64Zeropage
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.C64Zeropage
import java.io.IOException
import java.nio.file.Path


class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null

companion object {
const val NAME = "c64"
Expand All @@ -26,6 +20,7 @@ class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by No


override val cpu = CpuType.CPU6502
override val programType = ProgramType.CBMPRG

override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
Expand Down
156 changes: 156 additions & 0 deletions codeCore/src/prog8/code/target/ConfigFileTarget.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package prog8.code.target

import prog8.code.core.*
import prog8.code.source.ImportFileSystem.expandTilde
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.ConfigurableZeropage
import java.io.IOException
import java.nio.file.Path
import java.util.*
import kotlin.io.path.Path
import kotlin.io.path.inputStream
import kotlin.io.path.isDirectory
import kotlin.io.path.nameWithoutExtension


class ConfigFileTarget(
override val name: String,
override val defaultEncoding: Encoding,
override val cpu: CpuType,
override val programType: ProgramType,
override val PROGRAM_LOAD_ADDRESS: UInt,
override val PROGRAM_MEMTOP_ADDRESS: UInt,
override val STARTUP_CODE_RESERVED_SIZE: UInt,
override val BSSHIGHRAM_START: UInt,
override val BSSHIGHRAM_END: UInt,
override val BSSGOLDENRAM_START: UInt,
override val BSSGOLDENRAM_END: UInt,
override val libraryPath: Path,
val ioAddresses: List<UIntRange>,
val zpScratchB1: UInt,
val zpScratchReg: UInt,
val zpScratchW1: UInt,
val zpScratchW2: UInt,
val virtualregistersStart: UInt,
val zpFullsafe: List<UIntRange>,
val zpKernalsafe: List<UIntRange>,
val zpBasicsafe: List<UIntRange>
): ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(8) {

companion object {

private fun Properties.getString(property: String): String {
val value = this.getProperty(property, null)
if(value!=null)
return value
throw NoSuchElementException("string property '$property' not found in config file")
}

private fun Properties.getInteger(property: String): UInt {
val value = this.getProperty(property, null)
if(value!=null) return parseInt(value)
throw NoSuchElementException("integer property '$property' not found in config file")
}

private fun parseInt(value: String): UInt {
if(value.startsWith("0x"))
return value.drop(2).toUInt(16)
if(value.startsWith("$"))
return value.drop(1).toUInt(16)
if(value.startsWith("%"))
return value.drop(1).toUInt(2)
return value.toUInt()
}

private fun parseAddressRanges(key: String, props: Properties): List<UIntRange> {
val rangesStr = props.getString(key)
if(rangesStr.isBlank())
return emptyList()
val result = mutableListOf<UIntRange>()
val ranges = rangesStr.split(",").map { it.trim() }
for(rangeStr in ranges) {
if ('-' in rangeStr) {
val (fromStr, toStr) = rangeStr.split("-")
val from = parseInt(fromStr.trim())
val to = parseInt(toStr.trim())
result.add(from..to)
} else {
val address = parseInt(rangesStr)
result.add(address..address)
}
}
return result
}

fun fromConfigFile(configfile: Path): ConfigFileTarget {
val props = Properties()
props.load(configfile.inputStream())

val cpuString = props.getString("cpu").uppercase()
val cpuType = try {
CpuType.valueOf(cpuString)
} catch (_: IllegalArgumentException) {
CpuType.valueOf("CPU$cpuString")
}
val ioAddresses = parseAddressRanges("io_regions", props)
val zpFullsafe = parseAddressRanges("zp_fullsafe", props)
val zpKernalsafe = parseAddressRanges("zp_kernalsafe", props)
val zpBasicsafe = parseAddressRanges("zp_basicsafe", props)

val libraryPath = expandTilde(Path(props.getString("library")))
if(!libraryPath.isDirectory())
throw IOException("invalid library path: $libraryPath")

return ConfigFileTarget(
configfile.nameWithoutExtension,
Encoding.entries.first { it.prefix==props.getString("encoding") },
cpuType,
ProgramType.valueOf(props.getString("program")),
props.getInteger("load_address"),
props.getInteger("memtop"),
props.getInteger("startup_reserved"),
props.getInteger("bss_highram_start"),
props.getInteger("bss_highram_end"),
props.getInteger("bss_goldenram_start"),
props.getInteger("bss_goldenram_end"),
libraryPath,
ioAddresses,
props.getInteger("zp_scratch_b1"),
props.getInteger("zp_scratch_reg"),
props.getInteger("zp_scratch_w1"),
props.getInteger("zp_scratch_w2"),
props.getInteger("virtual_registers"),
zpFullsafe,
zpKernalsafe,
zpBasicsafe,
)
}
}

// TODO floats are not yet supported here, just enter some values
override val FLOAT_MAX_POSITIVE = 9.999999999e97
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
override val FLOAT_MEM_SIZE = 8

override lateinit var zeropage: Zeropage
override lateinit var golden: GoldenRam // TODO this is not yet used

override fun getFloatAsmBytes(num: Number) = TODO("floats")
override fun convertFloatToBytes(num: Double): List<UByte> = TODO("floats")
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("floats")
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) = TODO("emulator")

override fun isIOAddress(address: UInt): Boolean = ioAddresses.any { address in it }

override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
zeropage = ConfigurableZeropage(
zpScratchB1, zpScratchReg, zpScratchW1, zpScratchW2,
virtualregistersStart,
zpBasicsafe,
zpKernalsafe,
zpFullsafe,
compilerOptions
)
// note: there's no golden ram yet
}
}
5 changes: 4 additions & 1 deletion codeCore/src/prog8/code/target/Cx16Target.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.ProgramType
import prog8.code.core.Zeropage
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.CX16Zeropage
Expand All @@ -16,13 +17,15 @@ import java.nio.file.Path
class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null

companion object {
const val NAME = "cx16"
}


override val cpu = CpuType.CPU65c02
override val cpu = CpuType.CPU65C02
override val programType = ProgramType.CBMPRG

override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
Expand Down
4 changes: 3 additions & 1 deletion codeCore/src/prog8/code/target/Neo6502Target.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import java.nio.file.Path
class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.ISO
override val libraryPath = null

companion object {
const val NAME = "neo"
const val FLOAT_MEM_SIZE = 6
}


override val cpu = CpuType.CPU65c02
override val cpu = CpuType.CPU65C02
override val programType = ProgramType.NEORAW

override val FLOAT_MAX_POSITIVE = 9.999999999e97
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
Expand Down
3 changes: 3 additions & 0 deletions codeCore/src/prog8/code/target/PETTarget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import prog8.code.core.GoldenRam
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.ProgramType
import prog8.code.core.Zeropage
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.PETZeropage
Expand All @@ -16,12 +17,14 @@ import java.nio.file.Path
class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(Mflpt5.Companion.FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null

companion object {
const val NAME = "pet32"
}

override val cpu = CpuType.CPU6502
override val programType = ProgramType.CBMPRG

override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
Expand Down
4 changes: 2 additions & 2 deletions codeCore/src/prog8/code/target/VMTarget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import kotlin.io.path.readText
class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) {
override val name = NAME
override val defaultEncoding = Encoding.ISO
override val libraryPath = null

companion object {
const val NAME = "virtual"
const val FLOAT_MEM_SIZE = 8 // 64-bits double
}

override val cpu = CpuType.VIRTUAL
override val programType = ProgramType.VIRTUALIR

override val FLOAT_MAX_POSITIVE = Double.MAX_VALUE.toDouble()
override val FLOAT_MAX_NEGATIVE = -Double.MAX_VALUE.toDouble()
Expand Down Expand Up @@ -123,6 +125,4 @@ private class VirtualZeropage(options: CompilationOptions): Zeropage(options) {
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 */ }
}
6 changes: 1 addition & 5 deletions codeCore/src/prog8/code/target/zp/AtariZeropage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import prog8.code.core.ZeropageType
class AtariZeropage(options: CompilationOptions) : Zeropage(options) {

override val SCRATCH_B1 = 0xcbu // temp storage for a single byte
override val SCRATCH_REG = 0xccu // temp storage for a register, must be B1+1
override val SCRATCH_REG = 0xccu // temp storage for a register byte, must be B1+1
override val SCRATCH_W1 = 0xcdu // temp storage 1 for a word $cd+$ce
override val SCRATCH_W2 = 0xcfu // temp storage 2 for a word $cf+$d0 TODO is $d0 okay to use?

Expand Down Expand Up @@ -50,8 +50,4 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
removeReservedFromFreePool()
retainAllowed()
}

override fun allocateCx16VirtualRegisters() {
TODO("Not known if atari can put the virtual regs in ZP")
}
}
Loading

0 comments on commit e8f3af6

Please sign in to comment.