diff --git a/codeCore/src/prog8/code/core/IMachineDefinition.kt b/codeCore/src/prog8/code/core/IMachineDefinition.kt index 1cb9c84b2..89a384e6f 100644 --- a/codeCore/src/prog8/code/core/IMachineDefinition.kt +++ b/codeCore/src/prog8/code/core/IMachineDefinition.kt @@ -16,12 +16,12 @@ interface IMachineDefinition { var ESTACK_LO: UInt var ESTACK_HI: UInt val PROGRAM_LOAD_ADDRESS : UInt - var GOLDEN: UIntRange - var zeropage: Zeropage val cpu: CpuType + var zeropage: Zeropage + var golden: GoldenRam - fun initializeZeropage(compilerOptions: CompilationOptions) + fun initializeMemoryAreas(compilerOptions: CompilationOptions) fun getFloatAsmBytes(num: Number): String fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List @@ -31,7 +31,7 @@ interface IMachineDefinition { require(evalStackBaseAddress and 255u == 0u) ESTACK_LO = evalStackBaseAddress ESTACK_HI = evalStackBaseAddress + 256u - require(ESTACK_LO !in GOLDEN && ESTACK_HI !in GOLDEN) { "user-set ESTACK can't be in GOLDEN ram" } + require(ESTACK_LO !in golden.region && ESTACK_HI !in golden.region) { "user-set ESTACK can't be in GOLDEN ram" } } } diff --git a/codeCore/src/prog8/code/core/Zeropage.kt b/codeCore/src/prog8/code/core/MemoryRegions.kt similarity index 54% rename from codeCore/src/prog8/code/core/Zeropage.kt rename to codeCore/src/prog8/code/core/MemoryRegions.kt index 24bff27a8..bce35d672 100644 --- a/codeCore/src/prog8/code/core/Zeropage.kt +++ b/codeCore/src/prog8/code/core/MemoryRegions.kt @@ -5,21 +5,31 @@ import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result -class ZeropageAllocationError(message: String) : Exception(message) +class MemAllocationError(message: String) : Exception(message) -abstract class Zeropage(protected val options: CompilationOptions) { +abstract class MemoryAllocator(protected val options: CompilationOptions) { + data class VarAllocation(val address: UInt, val dt: DataType, val size: Int) + + abstract fun allocate(name: List, + datatype: DataType, + numElements: Int?, + position: Position?, + errors: IErrorReporter): Result +} + + +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_W1 : UInt // temp storage 1 for a word $fb+$fc abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc - data class ZpAllocation(val address: UInt, val dt: DataType, val size: Int) // the variables allocated into Zeropage. // name (scoped) ==> pair of address to (Datatype + bytesize) - val allocatedVariables = mutableMapOf, ZpAllocation>() + val allocatedVariables = mutableMapOf, VarAllocation>() val free = mutableListOf() // subclasses must set this to the appropriate free locations. @@ -41,17 +51,16 @@ abstract class Zeropage(protected val options: CompilationOptions) { return free.windowed(2).any { it[0] == it[1] - 1u } } - fun allocate(name: List, - datatype: DataType, - numElements: Int?, - position: Position?, - errors: IErrorReporter - ): Result, ZeropageAllocationError> { + override fun allocate(name: List, + datatype: DataType, + numElements: Int?, + position: Position?, + errors: IErrorReporter): Result { require(name.isEmpty() || name !in allocatedVariables) {"name can't be allocated twice"} if(options.zeropage== ZeropageType.DONTUSE) - return Err(ZeropageAllocationError("zero page usage has been disabled")) + return Err(MemAllocationError("zero page usage has been disabled")) val size: Int = when (datatype) { @@ -72,9 +81,9 @@ abstract class Zeropage(protected val options: CompilationOptions) { else errors.warn("$name: allocating a large value in zeropage; float $memsize bytes", Position.DUMMY) memsize - } else return Err(ZeropageAllocationError("floating point option not enabled")) + } else return Err(MemAllocationError("floating point option not enabled")) } - else -> return Err(ZeropageAllocationError("cannot put datatype $datatype in zeropage")) + else -> throw MemAllocationError("weird dt") } synchronized(this) { @@ -82,18 +91,18 @@ abstract class Zeropage(protected val options: CompilationOptions) { if(size==1) { for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) { if(oneSeparateByteFree(candidate)) - return Ok(Pair(makeAllocation(candidate, 1, datatype, name), 1)) + return Ok(VarAllocation(makeAllocation(candidate, 1, datatype, name), datatype,1)) } - return Ok(Pair(makeAllocation(free[0], 1, datatype, name), 1)) + return Ok(VarAllocation(makeAllocation(free[0], 1, datatype, name), datatype,1)) } for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) { if (sequentialFree(candidate, size)) - return Ok(Pair(makeAllocation(candidate, size, datatype, name), size)) + return Ok(VarAllocation(makeAllocation(candidate, size, datatype, name), datatype, size)) } } } - return Err(ZeropageAllocationError("no more free space in ZP to allocate $size sequential bytes")) + return Err(MemAllocationError("no more free space in ZP to allocate $size sequential bytes")) } private fun reserve(range: UIntRange) = free.removeAll(range) @@ -103,9 +112,9 @@ abstract class Zeropage(protected val options: CompilationOptions) { free.removeAll(address until address+size.toUInt()) if(name.isNotEmpty()) { allocatedVariables[name] = when(datatype) { - in NumericDatatypes -> ZpAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments - DataType.STR -> ZpAllocation(address, datatype, size) - in ArrayDatatypes -> ZpAllocation(address, datatype, size) + in NumericDatatypes -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments + DataType.STR -> VarAllocation(address, datatype, size) + in ArrayDatatypes -> VarAllocation(address, datatype, size) else -> throw AssemblyError("invalid dt") } } @@ -120,3 +129,37 @@ abstract class Zeropage(protected val options: CompilationOptions) { abstract fun allocateCx16VirtualRegisters() } + + +class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAllocator(options) { + private var nextLocation: UInt = region.first + + override fun allocate( + name: List, + datatype: DataType, + numElements: Int?, + position: Position?, + errors: IErrorReporter): Result { + + val size: Int = + when (datatype) { + in IntegerDatatypes -> options.compTarget.memorySize(datatype) + DataType.STR, in ArrayDatatypes -> { + options.compTarget.memorySize(datatype, numElements!!) + } + DataType.FLOAT -> { + if (options.floats) { + options.compTarget.memorySize(DataType.FLOAT) + } else return Err(MemAllocationError("floating point option not enabled")) + } + else -> throw MemAllocationError("weird dt") + } + + return if(nextLocation<=region.last && (region.last + 1u - nextLocation) >= size.toUInt()) { + val result = Ok(VarAllocation(nextLocation, datatype, size)) + nextLocation += size.toUInt() + result + } else + Err(MemAllocationError("no more free space in Golden RAM to allocate $size sequential bytes")) + } +} \ No newline at end of file diff --git a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt b/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt index d4f56c783..6ce584b09 100644 --- a/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/atari/AtariMachineDefinition.kt @@ -16,9 +16,9 @@ class AtariMachineDefinition: IMachineDefinition { // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override var ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive // TODO override var ESTACK_HI = 0x1b00u // $1b00-$1bff inclusive // TODO - override var GOLDEN = UIntRange.EMPTY override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam override fun getFloatAsmBytes(num: Number) = TODO("float asm bytes from number") @@ -57,7 +57,8 @@ class AtariMachineDefinition: IMachineDefinition { override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO - override fun initializeZeropage(compilerOptions: CompilationOptions) { + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = AtariZeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) } } diff --git a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt b/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt index 39b63ec94..e0e3f9ad3 100644 --- a/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt @@ -17,9 +17,8 @@ class C128MachineDefinition: IMachineDefinition { // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override var ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive override var ESTACK_HI = 0x1b00u // $1b00-$1bff inclusive - override var GOLDEN = UIntRange.EMPTY // TODO does the c128 have some of this somewhere? - override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() @@ -47,7 +46,8 @@ class C128MachineDefinition: IMachineDefinition { override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu - override fun initializeZeropage(compilerOptions: CompilationOptions) { + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = C128Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) // TODO does the c128 have some of this somewhere? } } diff --git a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt b/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt index ad7eb314f..c9c782d4c 100644 --- a/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt @@ -18,9 +18,8 @@ class C64MachineDefinition: IMachineDefinition { // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override var ESTACK_LO = 0xce00u // $ce00-$ceff inclusive override var ESTACK_HI = 0xcf00u // $ce00-$ceff inclusive - override var GOLDEN = 0xc000u until ESTACK_LO - override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() @@ -56,8 +55,9 @@ class C64MachineDefinition: IMachineDefinition { override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu - override fun initializeZeropage(compilerOptions: CompilationOptions) { + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = C64Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, 0xc000u until ESTACK_LO) } } diff --git a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt index 8f1b99ead..42eaf7ba5 100644 --- a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt +++ b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt @@ -83,12 +83,12 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) // The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02). for(reg in 0..15) { - allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 + allocatedVariables[listOf("cx16", "r${reg}s")] = VarAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s + allocatedVariables[listOf("cx16", "r${reg}L")] = VarAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L + allocatedVariables[listOf("cx16", "r${reg}H")] = VarAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H + allocatedVariables[listOf("cx16", "r${reg}sL")] = VarAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables[listOf("cx16", "r${reg}sH")] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH free.remove((4+reg*2).toUInt()) free.remove((5+reg*2).toUInt()) } diff --git a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt b/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt index 71e380568..038fec591 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt @@ -17,9 +17,8 @@ class CX16MachineDefinition: IMachineDefinition { // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) override var ESTACK_LO = 0x0400u // $0400-$04ff inclusive override var ESTACK_HI = 0x0500u // $0500-$05ff inclusive - override var GOLDEN = 0x0600u until 0x0800u - override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm() override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { @@ -57,8 +56,9 @@ class CX16MachineDefinition: IMachineDefinition { override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu - override fun initializeZeropage(compilerOptions: CompilationOptions) { + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { zeropage = CX16Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, 0x0600u until 0x0800u) } } diff --git a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt index 10eca5cb4..50dfa10df 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt @@ -58,12 +58,12 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { // However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well. // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) for(reg in 0..15) { - allocatedVariables[listOf("cx16", "r${reg}")] = ZpAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 - allocatedVariables[listOf("cx16", "r${reg}s")] = ZpAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s - allocatedVariables[listOf("cx16", "r${reg}L")] = ZpAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L - allocatedVariables[listOf("cx16", "r${reg}H")] = ZpAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H - allocatedVariables[listOf("cx16", "r${reg}sL")] = ZpAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL - allocatedVariables[listOf("cx16", "r${reg}sH")] = ZpAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 + allocatedVariables[listOf("cx16", "r${reg}s")] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s + allocatedVariables[listOf("cx16", "r${reg}L")] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L + allocatedVariables[listOf("cx16", "r${reg}H")] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H + allocatedVariables[listOf("cx16", "r${reg}sL")] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables[listOf("cx16", "r${reg}sH")] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH } } } \ No newline at end of file diff --git a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt index 4fd516fb4..c4e0f144c 100644 --- a/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt +++ b/codeCore/src/prog8/code/target/virtual/VirtualMachineDefinition.kt @@ -1,9 +1,6 @@ package prog8.code.target.virtual -import prog8.code.core.CompilationOptions -import prog8.code.core.CpuType -import prog8.code.core.IMachineDefinition -import prog8.code.core.Zeropage +import prog8.code.core.* import java.nio.file.Path import kotlin.io.path.isReadable import kotlin.io.path.name @@ -20,9 +17,8 @@ class VirtualMachineDefinition: IMachineDefinition { override var ESTACK_LO = 0u // not actually used override var ESTACK_HI = 0u // not actually used - override var GOLDEN = UIntRange.EMPTY // not actually used - - override lateinit var zeropage: Zeropage // not actually used + override lateinit var zeropage: Zeropage // not actually used + override lateinit var golden: GoldenRam // not actually used override fun getFloatAsmBytes(num: Number) = TODO("float asm bytes from number") @@ -48,7 +44,7 @@ class VirtualMachineDefinition: IMachineDefinition { override fun isIOAddress(address: UInt): Boolean = false - override fun initializeZeropage(compilerOptions: CompilationOptions) {} + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {} } interface IVirtualMachineRunner { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 4b4b45693..fcd61da8a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -429,13 +429,13 @@ internal class ProgramAndVarsGen( private class ZpStringWithInitial( val name: List, - val alloc: Zeropage.ZpAllocation, + val alloc: MemoryAllocator.VarAllocation, val value: Pair ) private class ZpArrayWithInitial( val name: List, - val alloc: Zeropage.ZpAllocation, + val alloc: MemoryAllocator.VarAllocation, val value: StArray ) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index 488816630..fecd7aa67 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -16,7 +16,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable, private val zeropage = options.compTarget.machine.zeropage internal val globalFloatConsts = mutableMapOf() // all float values in the entire program (value -> varname) - internal val zeropageVars: Map, Zeropage.ZpAllocation> = zeropage.allocatedVariables + internal val zeropageVars: Map, MemoryAllocator.VarAllocation> = zeropage.allocatedVariables init { allocateZeropageVariables() diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 4957dfd19..243c1ea6e 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -391,7 +391,7 @@ private fun createAssemblyAndAssemble(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions ): Boolean { - compilerOptions.compTarget.machine.initializeZeropage(compilerOptions) + compilerOptions.compTarget.machine.initializeMemoryAreas(compilerOptions) program.processAstBeforeAsmGeneration(compilerOptions, errors) errors.report() val symbolTable = SymbolTableMaker().makeFrom(program, compilerOptions) diff --git a/compiler/test/TestGoldenRam.kt b/compiler/test/TestGoldenRam.kt new file mode 100644 index 000000000..9f290fb2d --- /dev/null +++ b/compiler/test/TestGoldenRam.kt @@ -0,0 +1,61 @@ +package prog8tests + +import com.github.michaelbull.result.expectError +import com.github.michaelbull.result.getOrThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import prog8.code.core.* +import prog8.code.target.VMTarget +import prog8tests.helpers.ErrorReporterForTests + + +class TestGoldenRam: FunSpec({ + + val options = CompilationOptions( + OutputType.RAW, + CbmPrgLauncherType.NONE, + ZeropageType.FULL, + listOf((0x00u..0xffu)), + floats = true, + noSysInit = false, + compTarget = VMTarget(), + loadAddress = 999u + ) + + test("empty golden ram allocations") { + val errors = ErrorReporterForTests() + val golden = GoldenRam(options, UIntRange.EMPTY) + val result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) + result.expectError { "should not be able to allocate anything" } + } + + test("regular golden ram allocations") { + val errors = ErrorReporterForTests() + val golden = GoldenRam(options, 0x400u until 0x800u) + + var result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) + var alloc = result.getOrThrow() + alloc.size shouldBe 1 + alloc.address shouldBe 0x400u + result = golden.allocate(listOf("test"), DataType.STR, 100, null, errors) + alloc = result.getOrThrow() + alloc.size shouldBe 100 + alloc.address shouldBe 0x401u + + repeat(461) { + result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) + alloc = result.getOrThrow() + alloc.size shouldBe 2 + } + + result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) + result.expectError { "just 1 more byte available" } + result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) + alloc = result.getOrThrow() + alloc.size shouldBe 1 + alloc.address shouldBe golden.region.last + result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) + result.expectError { "nothing more available" } + + } +}) diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index ea8fd3e2d..9f6ff143e 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -188,7 +188,7 @@ class TestC64Zeropage: FunSpec({ zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true var result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) - val loc = result.getOrElse { throw it } .first + val loc = result.getOrElse { throw it } .address loc shouldBeGreaterThan 3u loc shouldNotBeIn zp.free val num = zp.availableBytes() / 2 @@ -216,18 +216,18 @@ class TestC64Zeropage: FunSpec({ test("testEfficientAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) zp.availableBytes() shouldBe 18 - zp.allocate(emptyList(), DataType.WORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x04u - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x06u - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0au - zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9bu - zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0x9eu - zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xa5u - zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xb0u - zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.first shouldBe 0xbeu - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x0eu - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x92u - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0x96u - zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.first shouldBe 0xf9u + zp.allocate(emptyList(), DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xa5u + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u + zp.allocate(emptyList(), DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u + zp.allocate(emptyList(), DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u zp.availableBytes() shouldBe 0 } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2cf0d8a00..3c44eae2c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,15 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- Think this through/ ask opinions: add a mechanism to allocate variables into golden ram (see GoldenRam class) + - block "golden" treated specially: every var in here will be allocated in the Golden ram area + - that block can only contain variables. + - the variables can NOT have initialization values, they will all be set to zero on startup (simple memset) + - just initialize them yourself in start() if you need a non-zero value + - OR.... do all this automatically if 'golden' is enabled as a compiler option? So compiler allocates in ZP first, then Golden Ram, then regular ram + - (need separate step in codegen and IR to write the "golden" variables) + + - regression test the various projects before release ... @@ -20,7 +29,6 @@ Future Things and Ideas Compiler: - create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code -- add a mechanism to allocate variables into golden ram (see MachineDefinition.GOLDEN) - ir: mechanism to determine for chunks which registers are getting input values from "outside" - ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk) - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)