optimize isZpVar

This commit is contained in:
Irmen de Jong 2023-02-16 00:33:37 +01:00
parent 5c3f41f64d
commit c59df6ec20
10 changed files with 86 additions and 89 deletions

View File

@ -11,7 +11,7 @@ class MemAllocationError(message: String) : Exception(message)
abstract class MemoryAllocator(protected val options: CompilationOptions) { abstract class MemoryAllocator(protected val options: CompilationOptions) {
data class VarAllocation(val address: UInt, val dt: DataType, val size: Int) data class VarAllocation(val address: UInt, val dt: DataType, val size: Int)
abstract fun allocate(name: List<String>, abstract fun allocate(name: String,
datatype: DataType, datatype: DataType,
numElements: Int?, numElements: Int?,
position: Position?, position: Position?,
@ -29,7 +29,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
// the variables allocated into Zeropage. // the variables allocated into Zeropage.
// name (scoped) ==> pair of address to (Datatype + bytesize) // name (scoped) ==> pair of address to (Datatype + bytesize)
val allocatedVariables = mutableMapOf<List<String>, VarAllocation>() val allocatedVariables = mutableMapOf<String, VarAllocation>()
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations. val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
@ -51,7 +51,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
return free.windowed(2).any { it[0] == it[1] - 1u } return free.windowed(2).any { it[0] == it[1] - 1u }
} }
override fun allocate(name: List<String>, override fun allocate(name: String,
datatype: DataType, datatype: DataType,
numElements: Int?, numElements: Int?,
position: Position?, position: Position?,
@ -107,7 +107,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
private fun reserve(range: UIntRange) = free.removeAll(range) private fun reserve(range: UIntRange) = free.removeAll(range)
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: List<String>): UInt { private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: String): UInt {
require(size>=0) require(size>=0)
free.removeAll(address until address+size.toUInt()) free.removeAll(address until address+size.toUInt())
if(name.isNotEmpty()) { if(name.isNotEmpty()) {
@ -135,7 +135,7 @@ class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAlloc
private var nextLocation: UInt = region.first private var nextLocation: UInt = region.first
override fun allocate( override fun allocate(
name: List<String>, name: String,
datatype: DataType, datatype: DataType,
numElements: Int?, numElements: Int?,
position: Position?, position: Position?,

View File

@ -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) // 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). // The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02).
for(reg in 0..15) { for(reg in 0..15) {
allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 allocatedVariables["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["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["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["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["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 allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
free.remove((4+reg*2).toUInt()) free.remove((4+reg*2).toUInt())
free.remove((5+reg*2).toUInt()) free.remove((5+reg*2).toUInt())
} }

View File

@ -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. // 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) // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
for(reg in 0..15) { for(reg in 0..15) {
allocatedVariables[listOf("cx16", "r${reg}")] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 allocatedVariables["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["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["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["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["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 allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
} }
} }
} }

View File

@ -148,7 +148,7 @@ class AsmGen6502Internal (
is PtVariable, is PtMemMapped -> { is PtVariable, is PtMemMapped -> {
val sourceName = asmVariableName(pointervar) val sourceName = asmVariableName(pointervar)
if (isTargetCpu(CpuType.CPU65c02)) { if (isTargetCpu(CpuType.CPU65c02)) {
return if (allocator.isZpVar((target as PtNamedNode).scopedName.split('.'))) { return if (allocator.isZpVar((target as PtNamedNode).scopedName)) {
// pointervar is already in the zero page, no need to copy // pointervar is already in the zero page, no need to copy
out(" lda ($sourceName)") out(" lda ($sourceName)")
sourceName sourceName
@ -162,7 +162,7 @@ class AsmGen6502Internal (
"P8ZP_SCRATCH_W1" "P8ZP_SCRATCH_W1"
} }
} else { } else {
return if (allocator.isZpVar((target as PtNamedNode).scopedName.split('.'))) { return if (allocator.isZpVar((target as PtNamedNode).scopedName)) {
// pointervar is already in the zero page, no need to copy // pointervar is already in the zero page, no need to copy
out(" ldy #0 | lda ($sourceName),y") out(" ldy #0 | lda ($sourceName),y")
sourceName sourceName
@ -185,7 +185,7 @@ class AsmGen6502Internal (
internal fun storeAIntoPointerVar(pointervar: PtIdentifier) { internal fun storeAIntoPointerVar(pointervar: PtIdentifier) {
val sourceName = asmVariableName(pointervar) val sourceName = asmVariableName(pointervar)
if (isTargetCpu(CpuType.CPU65c02)) { if (isTargetCpu(CpuType.CPU65c02)) {
if (allocator.isZpVar(pointervar.name.split('.'))) { if (allocator.isZpVar(pointervar.name)) {
// pointervar is already in the zero page, no need to copy // pointervar is already in the zero page, no need to copy
out(" sta ($sourceName)") out(" sta ($sourceName)")
} else { } else {
@ -197,7 +197,7 @@ class AsmGen6502Internal (
sta (P8ZP_SCRATCH_W2)""") sta (P8ZP_SCRATCH_W2)""")
} }
} else { } else {
if (allocator.isZpVar(pointervar.name.split('.'))) { if (allocator.isZpVar(pointervar.name)) {
// pointervar is already in the zero page, no need to copy // pointervar is already in the zero page, no need to copy
out(" ldy #0 | sta ($sourceName),y") out(" ldy #0 | sta ($sourceName),y")
} else { } else {
@ -747,7 +747,7 @@ $repeatLabel lda $counterVar
val counterVar = makeLabel("counter") val counterVar = makeLabel("counter")
when(dt) { when(dt) {
DataType.UBYTE, DataType.UWORD -> { DataType.UBYTE, DataType.UWORD -> {
val result = zeropage.allocate(listOf(counterVar), dt, null, stmt.position, errors) val result = zeropage.allocate(counterVar, dt, null, stmt.position, errors)
result.fold( result.fold(
success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) }, success = { (address, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) },
failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally
@ -963,7 +963,7 @@ $repeatLabel lda $counterVar
} }
} }
internal fun isZpVar(variable: PtIdentifier): Boolean = allocator.isZpVar(variable.name.split('.')) internal fun isZpVar(variable: PtIdentifier): Boolean = allocator.isZpVar(variable.name)
internal fun jmp(asmLabel: String, indirect: Boolean=false) { internal fun jmp(asmLabel: String, indirect: Boolean=false) {
if(indirect) { if(indirect) {

View File

@ -289,7 +289,7 @@ $loopLabel sty $indexVar
} }
if(numElements>=16u) { if(numElements>=16u) {
// allocate index var on ZP if possible // allocate index var on ZP if possible
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
result.fold( result.fold(
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
failure = { asmgen.out("$indexVar .byte 0") } failure = { asmgen.out("$indexVar .byte 0") }
@ -330,7 +330,7 @@ $loopLabel sty $indexVar
} }
if(length>=16u) { if(length>=16u) {
// allocate index var on ZP if possible // allocate index var on ZP if possible
val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, stmt.position, asmgen.errors) val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
result.fold( result.fold(
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
failure = { asmgen.out("$indexVar .byte 0") } failure = { asmgen.out("$indexVar .byte 0") }

View File

@ -236,7 +236,7 @@ internal class ProgramAndVarsGen(
// normal statically allocated variables // normal statically allocated variables
val variables = varsInBlock val variables = varsInBlock
.filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName) }
.map { it.value as StStaticVariable } .map { it.value as StStaticVariable }
nonZpVariables2asm(variables) nonZpVariables2asm(variables)
} }
@ -354,7 +354,7 @@ internal class ProgramAndVarsGen(
// normal statically allocated variables // normal statically allocated variables
val variables = varsInSubroutine val variables = varsInSubroutine
.filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName.split('.')) } .filter { it.value.type==StNodeType.STATICVAR && !allocator.isZpVar(it.value.scopedName) }
.map { it.value as StStaticVariable } .map { it.value as StStaticVariable }
nonZpVariables2asm(variables) nonZpVariables2asm(variables)
@ -439,7 +439,7 @@ internal class ProgramAndVarsGen(
val result = mutableListOf<ZpStringWithInitial>() val result = mutableListOf<ZpStringWithInitial>()
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR } val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
for (variable in vars) { for (variable in vars) {
val scopedName = variable.key.joinToString(".") val scopedName = variable.key
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable val svar = symboltable.flat.getValue(scopedName) as StStaticVariable
if(svar.onetimeInitializationStringValue!=null) if(svar.onetimeInitializationStringValue!=null)
result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!)) result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!))
@ -451,7 +451,7 @@ internal class ProgramAndVarsGen(
val result = mutableListOf<ZpArrayWithInitial>() val result = mutableListOf<ZpArrayWithInitial>()
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes } val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
for (variable in vars) { for (variable in vars) {
val scopedName = variable.key.joinToString(".") val scopedName = variable.key
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable val svar = symboltable.flat.getValue(scopedName) as StStaticVariable
if(svar.onetimeInitializationArrayValue!=null) if(svar.onetimeInitializationArrayValue!=null)
result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!)) result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!))
@ -460,12 +460,11 @@ internal class ProgramAndVarsGen(
} }
private fun zeropagevars2asm(varNames: Set<String>) { private fun zeropagevars2asm(varNames: Set<String>) {
val namesLists = varNames.map { it.split('.') }.toSet() val zpVariables = allocator.zeropageVars.filter { it.key in varNames }.toList().sortedBy { it.second.address }
val zpVariables = allocator.zeropageVars.filter { it.key in namesLists }.toList().sortedBy { it.second.address }
for ((scopedName, zpvar) in zpVariables) { for ((scopedName, zpvar) in zpVariables) {
if (scopedName.size == 2 && scopedName[0] == "cx16" && scopedName[1][0] == 'r' && scopedName[1][1].isDigit()) if (scopedName.startsWith("cx16.r"))
continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped
asmgen.out("${scopedName.last()} \t= ${zpvar.address} \t; zp ${zpvar.dt}") asmgen.out("${scopedName.substringAfterLast('.')} \t= ${zpvar.address} \t; zp ${zpvar.dt}")
} }
} }

View File

@ -16,13 +16,14 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
private val zeropage = options.compTarget.machine.zeropage private val zeropage = options.compTarget.machine.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<List<String>, MemoryAllocator.VarAllocation> = zeropage.allocatedVariables internal val zeropageVars: Map<String, MemoryAllocator.VarAllocation>
init { init {
allocateZeropageVariables() allocateZeropageVariables()
zeropageVars = zeropage.allocatedVariables
} }
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropageVars // TODO as dotted string instead of list internal fun isZpVar(scopedName: String) = scopedName in zeropageVars
internal fun getFloatAsmConst(number: Double): String { internal fun getFloatAsmConst(number: Double): String {
val asmName = globalFloatConsts[number] val asmName = globalFloatConsts[number]
@ -56,7 +57,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
varsRequiringZp.forEach { variable -> varsRequiringZp.forEach { variable ->
val result = zeropage.allocate( val result = zeropage.allocate(
variable.scopedName.split('.'), variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode.position,
@ -75,7 +76,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
if(errors.noErrors()) { if(errors.noErrors()) {
varsPreferringZp.forEach { variable -> varsPreferringZp.forEach { variable ->
val result = zeropage.allocate( val result = zeropage.allocate(
variable.scopedName.split('.'), variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode.position,
@ -95,7 +96,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
break break
} else { } else {
val result = zeropage.allocate( val result = zeropage.allocate(
variable.scopedName.split('.'), variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode.position,

View File

@ -25,7 +25,7 @@ class TestGoldenRam: FunSpec({
test("empty golden ram allocations") { test("empty golden ram allocations") {
val errors = ErrorReporterForTests() val errors = ErrorReporterForTests()
val golden = GoldenRam(options, UIntRange.EMPTY) val golden = GoldenRam(options, UIntRange.EMPTY)
val result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) val result = golden.allocate("test", DataType.UBYTE, null, null, errors)
result.expectError { "should not be able to allocate anything" } result.expectError { "should not be able to allocate anything" }
} }
@ -33,28 +33,28 @@ class TestGoldenRam: FunSpec({
val errors = ErrorReporterForTests() val errors = ErrorReporterForTests()
val golden = GoldenRam(options, 0x400u until 0x800u) val golden = GoldenRam(options, 0x400u until 0x800u)
var result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) var result = golden.allocate("test", DataType.UBYTE, null, null, errors)
var alloc = result.getOrThrow() var alloc = result.getOrThrow()
alloc.size shouldBe 1 alloc.size shouldBe 1
alloc.address shouldBe 0x400u alloc.address shouldBe 0x400u
result = golden.allocate(listOf("test"), DataType.STR, 100, null, errors) result = golden.allocate("test", DataType.STR, 100, null, errors)
alloc = result.getOrThrow() alloc = result.getOrThrow()
alloc.size shouldBe 100 alloc.size shouldBe 100
alloc.address shouldBe 0x401u alloc.address shouldBe 0x401u
repeat(461) { repeat(461) {
result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) result = golden.allocate("test", DataType.UWORD, null, null, errors)
alloc = result.getOrThrow() alloc = result.getOrThrow()
alloc.size shouldBe 2 alloc.size shouldBe 2
} }
result = golden.allocate(listOf("test"), DataType.UWORD, null, null, errors) result = golden.allocate("test", DataType.UWORD, null, null, errors)
result.expectError { "just 1 more byte available" } result.expectError { "just 1 more byte available" }
result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) result = golden.allocate("test", DataType.UBYTE, null, null, errors)
alloc = result.getOrThrow() alloc = result.getOrThrow()
alloc.size shouldBe 1 alloc.size shouldBe 1
alloc.address shouldBe golden.region.last alloc.address shouldBe golden.region.last
result = golden.allocate(listOf("test"), DataType.UBYTE, null, null, errors) result = golden.allocate("test", DataType.UBYTE, null, null, errors)
result.expectError { "nothing more available" } result.expectError { "nothing more available" }
} }

View File

@ -71,26 +71,26 @@ class TestC64Zeropage: FunSpec({
compTarget = c64target, loadAddress = 999u compTarget = c64target, loadAddress = 999u
)) ))
var result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) var result = zp.allocate("", DataType.UBYTE, null, null, errors)
result.onFailure { fail(it.toString()) } result.onFailure { fail(it.toString()) }
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result = zp.allocate("", DataType.UBYTE, null, null, errors)
result.onFailure { fail(it.toString()) } result.onFailure { fail(it.toString()) }
result = zp.allocate(listOf("varname"), DataType.UBYTE, null, null, errors) result = zp.allocate("varname", DataType.UBYTE, null, null, errors)
result.onFailure { fail(it.toString()) } result.onFailure { fail(it.toString()) }
shouldThrow<IllegalArgumentException> { zp.allocate(listOf("varname"), DataType.UBYTE,null, null, errors) } shouldThrow<IllegalArgumentException> { zp.allocate("varname", DataType.UBYTE,null, null, errors) }
result = zp.allocate(listOf("varname2"), DataType.UBYTE, null, null, errors) result = zp.allocate("varname2", DataType.UBYTE, null, null, errors)
result.onFailure { fail(it.toString()) } result.onFailure { fail(it.toString()) }
} }
test("testZpFloatEnable") { test("testZpFloatEnable") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u))
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors) var result = zp.allocate("", DataType.FLOAT, null, null, errors)
result.expectError { "should be allocation error due to disabled floats" } result.expectError { "should be allocation error due to disabled floats" }
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, c64target, 999u)) val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, c64target, 999u))
result = zp2.allocate(emptyList(), DataType.FLOAT, null, null, errors) result = zp2.allocate("", DataType.FLOAT, null, null, errors)
result.expectError { "should be allocation error due to disabled ZP use" } result.expectError { "should be allocation error due to disabled ZP use" }
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target, 999u)) val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target, 999u))
zp3.allocate(emptyList(), DataType.FLOAT, null, null, errors) zp3.allocate("", DataType.FLOAT, null, null, errors)
} }
test("testZpModesWithFloats") { test("testZpModesWithFloats") {
@ -112,7 +112,7 @@ class TestC64Zeropage: FunSpec({
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target, 999u)) val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, c64target, 999u))
println(zp.free) println(zp.free)
zp.availableBytes() shouldBe 0 zp.availableBytes() shouldBe 0
val result = zp.allocate(emptyList(), DataType.BYTE, null, null, errors) val result = zp.allocate("", DataType.BYTE, null, null, errors)
result.expectError { "expected error due to disabled ZP use" } result.expectError { "expected error due to disabled ZP use" }
} }
@ -125,9 +125,9 @@ class TestC64Zeropage: FunSpec({
zp3.availableBytes() shouldBe 97 zp3.availableBytes() shouldBe 97
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u))
zp4.availableBytes() shouldBe 207 zp4.availableBytes() shouldBe 207
zp4.allocate(listOf("test"), DataType.UBYTE, null, null, errors) zp4.allocate("test", DataType.UBYTE, null, null, errors)
zp4.availableBytes() shouldBe 206 zp4.availableBytes() shouldBe 206
zp4.allocate(listOf("test2"), DataType.UBYTE, null, null, errors) zp4.allocate("test2", DataType.UBYTE, null, null, errors)
zp4.availableBytes() shouldBe 205 zp4.availableBytes() shouldBe 205
} }
@ -166,19 +166,19 @@ class TestC64Zeropage: FunSpec({
zp.hasByteAvailable() shouldBe true zp.hasByteAvailable() shouldBe true
zp.hasWordAvailable() shouldBe true zp.hasWordAvailable() shouldBe true
var result = zp.allocate(emptyList(), DataType.FLOAT, null, null, errors) var result = zp.allocate("", DataType.FLOAT, null, null, errors)
result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" } result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" }
for (i in 0 until zp.availableBytes()) { for (i in 0 until zp.availableBytes()) {
val alloc = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) val alloc = zp.allocate("", DataType.UBYTE, null, null, errors)
alloc.getOrElse { throw it } alloc.getOrElse { throw it }
} }
zp.availableBytes() shouldBe 0 zp.availableBytes() shouldBe 0
zp.hasByteAvailable() shouldBe false zp.hasByteAvailable() shouldBe false
zp.hasWordAvailable() shouldBe false zp.hasWordAvailable() shouldBe false
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result = zp.allocate("", DataType.UBYTE, null, null, errors)
result.expectError { "expected allocation error" } result.expectError { "expected allocation error" }
result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) result = zp.allocate("", DataType.UWORD, null, null, errors)
result.expectError { "expected allocation error" } result.expectError { "expected allocation error" }
} }
@ -187,47 +187,47 @@ class TestC64Zeropage: FunSpec({
zp.availableBytes() shouldBe 207 zp.availableBytes() shouldBe 207
zp.hasByteAvailable() shouldBe true zp.hasByteAvailable() shouldBe true
zp.hasWordAvailable() shouldBe true zp.hasWordAvailable() shouldBe true
var result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) var result = zp.allocate("", DataType.UWORD, null, null, errors)
val loc = result.getOrElse { throw it } .address val loc = result.getOrElse { throw it } .address
loc shouldBeGreaterThan 3u loc shouldBeGreaterThan 3u
loc shouldNotBeIn zp.free loc shouldNotBeIn zp.free
val num = zp.availableBytes() / 2 val num = zp.availableBytes() / 2
for(i in 0..num-3) { for(i in 0..num-3) {
zp.allocate(emptyList(), DataType.UWORD, null, null, errors) zp.allocate("", DataType.UWORD, null, null, errors)
} }
zp.availableBytes() shouldBe 5 zp.availableBytes() shouldBe 5
// can't allocate because no more sequential bytes, only fragmented // can't allocate because no more sequential bytes, only fragmented
result = zp.allocate(emptyList(), DataType.UWORD, null, null, errors) result = zp.allocate("", DataType.UWORD, null, null, errors)
result.expectError { "should give allocation error" } result.expectError { "should give allocation error" }
for(i in 0..4) { for(i in 0..4) {
zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) zp.allocate("", DataType.UBYTE, null, null, errors)
} }
zp.availableBytes() shouldBe 0 zp.availableBytes() shouldBe 0
zp.hasByteAvailable() shouldBe false zp.hasByteAvailable() shouldBe false
zp.hasWordAvailable() shouldBe false zp.hasWordAvailable() shouldBe false
result = zp.allocate(emptyList(), DataType.UBYTE, null, null, errors) result = zp.allocate("", DataType.UBYTE, null, null, errors)
result.expectError { "should give allocation error" } result.expectError { "should give allocation error" }
} }
test("testEfficientAllocation") { test("testEfficientAllocation") {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u))
zp.availableBytes() shouldBe 18 zp.availableBytes() shouldBe 18
zp.allocate(emptyList(), DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u zp.allocate("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u
zp.availableBytes() shouldBe 0 zp.availableBytes() shouldBe 0
} }
@ -258,9 +258,9 @@ class TestCx16Zeropage: FunSpec({
zp2.availableBytes() shouldBe 175 zp2.availableBytes() shouldBe 175
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u)) val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u))
zp3.availableBytes() shouldBe 216 zp3.availableBytes() shouldBe 216
zp3.allocate(listOf("test"), DataType.UBYTE, null, null, errors) zp3.allocate("test", DataType.UBYTE, null, null, errors)
zp3.availableBytes() shouldBe 215 zp3.availableBytes() shouldBe 215
zp3.allocate(listOf("test2"), DataType.UBYTE, null, null, errors) zp3.allocate("test2", DataType.UBYTE, null, null, errors)
zp3.availableBytes() shouldBe 214 zp3.availableBytes() shouldBe 214
} }
@ -276,12 +276,12 @@ class TestCx16Zeropage: FunSpec({
test("preallocated zp vars") { test("preallocated zp vars") {
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u)) val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, cx16target, 999u))
zp1.allocatedVariables[listOf("test")] shouldBe null zp1.allocatedVariables["test"] shouldBe null
zp1.allocatedVariables[listOf("cx16", "r0")] shouldNotBe null zp1.allocatedVariables["cx16.r0"] shouldNotBe null
zp1.allocatedVariables[listOf("cx16", "r15")] shouldNotBe null zp1.allocatedVariables["cx16.r15"] shouldNotBe null
zp1.allocatedVariables[listOf("cx16", "r0L")] shouldNotBe null zp1.allocatedVariables["cx16.r0L"] shouldNotBe null
zp1.allocatedVariables[listOf("cx16", "r15L")] shouldNotBe null zp1.allocatedVariables["cx16.r15L"] shouldNotBe null
zp1.allocatedVariables[listOf("cx16", "r0sH")] shouldNotBe null zp1.allocatedVariables["cx16.r0sH"] shouldNotBe null
zp1.allocatedVariables[listOf("cx16", "r15sH")] shouldNotBe null zp1.allocatedVariables["cx16.r15sH"] shouldNotBe null
} }
}) })

View File

@ -17,9 +17,6 @@ For 9.0 major changes
- OR.... make all this more generic and use some %segment option to create real segments for 64tass? - OR.... make all this more generic and use some %segment option to create real segments for 64tass?
- (need separate step in codegen and IR to write the "golden" variables) - (need separate step in codegen and IR to write the "golden" variables)
- rewrite 6502 codegen on Pt* ast and symboltable, instead of CompilerAst nodes.
- optimize "dotted string" comments again.
Need help with Need help with
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^