mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 20:33:39 +00:00
309 lines
14 KiB
Kotlin
309 lines
14 KiB
Kotlin
package prog8tests
|
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
|
import io.kotest.assertions.withClue
|
|
import io.kotest.core.spec.style.FunSpec
|
|
import io.kotest.matchers.collections.shouldBeIn
|
|
import io.kotest.matchers.collections.shouldNotBeIn
|
|
import io.kotest.matchers.ints.shouldBeGreaterThan
|
|
import io.kotest.matchers.shouldBe
|
|
import prog8.ast.base.DataType
|
|
import prog8.compiler.target.C64Target
|
|
import prog8.compiler.target.Cx16Target
|
|
import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
|
|
import prog8.compiler.target.cx16.CX16MachineDefinition.CX16Zeropage
|
|
import prog8.compilerinterface.*
|
|
import prog8tests.helpers.ErrorReporterForTests
|
|
|
|
|
|
class TestAbstractZeropage: FunSpec({
|
|
|
|
class DummyCompilationTarget: ICompilationTarget {
|
|
override val name: String = "dummy"
|
|
override val machine: IMachineDefinition
|
|
get() = throw NotImplementedError("dummy")
|
|
|
|
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {
|
|
throw NotImplementedError("dummy")
|
|
}
|
|
|
|
override fun decodeString(bytes: List<Short>, altEncoding: Boolean): String {
|
|
throw NotImplementedError("dummy")
|
|
}
|
|
|
|
override fun memorySize(dt: DataType): Int {
|
|
throw NotImplementedError("dummy")
|
|
}
|
|
|
|
}
|
|
|
|
class DummyZeropage(options: CompilationOptions) : Zeropage(options) {
|
|
override val SCRATCH_B1: Int = 0x10
|
|
override val SCRATCH_REG: Int = 0x11
|
|
override val SCRATCH_W1: Int= 0x20
|
|
override val SCRATCH_W2: Int = 0x30
|
|
|
|
init {
|
|
free.addAll(0..255)
|
|
|
|
removeReservedFromFreePool()
|
|
}
|
|
}
|
|
|
|
|
|
test("testAbstractZeropage") {
|
|
val compTarget = DummyCompilationTarget()
|
|
val zp = DummyZeropage(
|
|
CompilationOptions(
|
|
OutputType.RAW,
|
|
LauncherType.NONE,
|
|
ZeropageType.FULL,
|
|
listOf((0x50..0x5f)),
|
|
false,
|
|
false,
|
|
compTarget
|
|
)
|
|
)
|
|
zp.free.size shouldBe 256-6-16
|
|
}
|
|
|
|
})
|
|
|
|
|
|
class TestC64Zeropage: FunSpec({
|
|
|
|
val errors = ErrorReporterForTests()
|
|
|
|
test("testNames") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target))
|
|
|
|
zp.allocate("", DataType.UBYTE, null, errors)
|
|
zp.allocate("", DataType.UBYTE, null, errors)
|
|
zp.allocate("varname", DataType.UBYTE, null, errors)
|
|
shouldThrow<IllegalArgumentException> {
|
|
zp.allocate("varname", DataType.UBYTE, null, errors)
|
|
}
|
|
zp.allocate("varname2", DataType.UBYTE, null, errors)
|
|
}
|
|
|
|
test("testZpFloatEnable") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
shouldThrow<InternalCompilerException> {
|
|
zp.allocate("", DataType.FLOAT, null, errors)
|
|
}
|
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, false, C64Target))
|
|
shouldThrow<InternalCompilerException> {
|
|
zp2.allocate("", DataType.FLOAT, null, errors)
|
|
}
|
|
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, C64Target))
|
|
zp3.allocate("", DataType.FLOAT, null, errors)
|
|
}
|
|
|
|
test("testZpModesWithFloats") {
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target))
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target))
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target))
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, C64Target))
|
|
shouldThrow<InternalCompilerException> {
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true, false, C64Target))
|
|
}
|
|
shouldThrow<InternalCompilerException> {
|
|
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, false, C64Target))
|
|
}
|
|
}
|
|
|
|
test("testZpDontuse") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, C64Target))
|
|
println(zp.free)
|
|
zp.availableBytes() shouldBe 0
|
|
shouldThrow<InternalCompilerException> {
|
|
zp.allocate("", DataType.BYTE, null, errors)
|
|
}
|
|
}
|
|
|
|
test("testFreeSpacesBytes") {
|
|
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
|
zp1.availableBytes() shouldBe 18
|
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target))
|
|
zp2.availableBytes() shouldBe 85
|
|
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target))
|
|
zp3.availableBytes() shouldBe 125
|
|
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
zp4.availableBytes() shouldBe 238
|
|
zp4.allocate("test", DataType.UBYTE, null, errors)
|
|
zp4.availableBytes() shouldBe 237
|
|
zp4.allocate("test2", DataType.UBYTE, null, errors)
|
|
zp4.availableBytes() shouldBe 236
|
|
}
|
|
|
|
test("testFreeSpacesWords") {
|
|
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
|
zp1.availableWords() shouldBe 6
|
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target))
|
|
zp2.availableWords() shouldBe 38
|
|
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target))
|
|
zp3.availableWords() shouldBe 57
|
|
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
zp4.availableWords() shouldBe 116
|
|
zp4.allocate("test", DataType.UWORD, null, errors)
|
|
zp4.availableWords() shouldBe 115
|
|
zp4.allocate("test2", DataType.UWORD, null, errors)
|
|
zp4.availableWords() shouldBe 114
|
|
}
|
|
|
|
test("testReservedSpace") {
|
|
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
zp1.availableBytes() shouldBe 238
|
|
50 shouldBeIn zp1.free
|
|
100 shouldBeIn zp1.free
|
|
49 shouldBeIn zp1.free
|
|
101 shouldBeIn zp1.free
|
|
200 shouldBeIn zp1.free
|
|
255 shouldBeIn zp1.free
|
|
199 shouldBeIn zp1.free
|
|
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false, false, C64Target))
|
|
zp2.availableBytes() shouldBe 139
|
|
50 shouldNotBeIn zp2.free
|
|
100 shouldNotBeIn zp2.free
|
|
49 shouldBeIn zp2.free
|
|
101 shouldBeIn zp2.free
|
|
200 shouldNotBeIn zp2.free
|
|
255 shouldNotBeIn zp2.free
|
|
199 shouldBeIn zp2.free
|
|
}
|
|
|
|
test("testBasicsafeAllocation") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
|
zp.availableBytes() shouldBe 18
|
|
zp.hasByteAvailable() shouldBe true
|
|
zp.hasWordAvailable() shouldBe true
|
|
|
|
shouldThrow<ZeropageDepletedError> {
|
|
// in regular zp there aren't 5 sequential bytes free
|
|
zp.allocate("", DataType.FLOAT, null, errors)
|
|
}
|
|
|
|
for (i in 0 until zp.availableBytes()) {
|
|
val loc = zp.allocate("", DataType.UBYTE, null, errors)
|
|
loc shouldBeGreaterThan 0
|
|
}
|
|
zp.availableBytes() shouldBe 0
|
|
zp.hasByteAvailable() shouldBe false
|
|
zp.hasWordAvailable() shouldBe false
|
|
shouldThrow<ZeropageDepletedError> {
|
|
zp.allocate("", DataType.UBYTE, null, errors)
|
|
}
|
|
shouldThrow<ZeropageDepletedError> {
|
|
zp.allocate("", DataType.UWORD, null, errors)
|
|
}
|
|
}
|
|
|
|
test("testFullAllocation") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
|
zp.availableBytes() shouldBe 238
|
|
zp.hasByteAvailable() shouldBe true
|
|
zp.hasWordAvailable() shouldBe true
|
|
val loc = zp.allocate("", DataType.UWORD, null, errors)
|
|
loc shouldBeGreaterThan 3
|
|
loc shouldNotBeIn zp.free
|
|
val num = zp.availableBytes() / 2
|
|
|
|
for(i in 0..num-4) {
|
|
zp.allocate("", DataType.UWORD, null, errors)
|
|
}
|
|
zp.availableBytes() shouldBe 6
|
|
|
|
shouldThrow<ZeropageDepletedError> {
|
|
// can't allocate because no more sequential bytes, only fragmented
|
|
zp.allocate("", DataType.UWORD, null, errors)
|
|
}
|
|
|
|
for(i in 0..5) {
|
|
zp.allocate("", DataType.UBYTE, null, errors)
|
|
}
|
|
|
|
zp.availableBytes() shouldBe 0
|
|
zp.hasByteAvailable() shouldBe false
|
|
zp.hasWordAvailable() shouldBe false
|
|
shouldThrow<ZeropageDepletedError> {
|
|
// no more space
|
|
zp.allocate("", DataType.UBYTE, null, errors)
|
|
}
|
|
}
|
|
|
|
test("testEfficientAllocation") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
|
zp.availableBytes() shouldBe 18
|
|
zp.allocate("", DataType.WORD, null, errors) shouldBe 0x04
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x06
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x0a
|
|
zp.allocate("", DataType.UWORD, null, errors) shouldBe 0x9b
|
|
zp.allocate("", DataType.UWORD, null, errors) shouldBe 0x9e
|
|
zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xa5
|
|
zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xb0
|
|
zp.allocate("", DataType.UWORD, null, errors) shouldBe 0xbe
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x0e
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x92
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0x96
|
|
zp.allocate("", DataType.UBYTE, null, errors) shouldBe 0xf9
|
|
zp.availableBytes() shouldBe 0
|
|
}
|
|
|
|
test("testReservedLocations") {
|
|
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, C64Target))
|
|
withClue("zp _B1 and _REG must be next to each other to create a word") {
|
|
zp.SCRATCH_B1 + 1 shouldBe zp.SCRATCH_REG
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
class TestCx16Zeropage: FunSpec({
|
|
val errors = ErrorReporterForTests()
|
|
|
|
test("testReservedLocations") {
|
|
val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, Cx16Target))
|
|
withClue("zp _B1 and _REG must be next to each other to create a word") {
|
|
zp.SCRATCH_B1 + 1 shouldBe zp.SCRATCH_REG
|
|
}
|
|
}
|
|
|
|
test("testFreeSpacesBytes") {
|
|
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target))
|
|
zp1.availableBytes() shouldBe 88
|
|
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target))
|
|
zp2.availableBytes() shouldBe 175
|
|
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
|
zp3.availableBytes() shouldBe 216
|
|
zp3.allocate("test", DataType.UBYTE, null, errors)
|
|
zp3.availableBytes() shouldBe 215
|
|
zp3.allocate("test2", DataType.UBYTE, null, errors)
|
|
zp3.availableBytes() shouldBe 214
|
|
}
|
|
|
|
test("testFreeSpacesWords") {
|
|
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
|
zp1.availableWords() shouldBe 108
|
|
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target))
|
|
zp2.availableWords() shouldBe 87
|
|
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target))
|
|
zp3.availableWords() shouldBe 44
|
|
zp3.allocate("test", DataType.UWORD, null, errors)
|
|
zp3.availableWords() shouldBe 43
|
|
zp3.allocate("test2", DataType.UWORD, null, errors)
|
|
zp3.availableWords() shouldBe 42
|
|
}
|
|
|
|
test("testReservedSpace") {
|
|
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
|
zp1.availableBytes() shouldBe 216
|
|
0x22 shouldBeIn zp1.free
|
|
0x80 shouldBeIn zp1.free
|
|
0xff shouldBeIn zp1.free
|
|
0x02 shouldNotBeIn zp1.free
|
|
0x21 shouldNotBeIn zp1.free
|
|
}
|
|
})
|