mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-03 19:16:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			297 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Kotlin
		
	
	
	
	
	
package prog8tests.compiler
 | 
						|
 | 
						|
import com.github.michaelbull.result.expectError
 | 
						|
import com.github.michaelbull.result.getOrElse
 | 
						|
import com.github.michaelbull.result.onFailure
 | 
						|
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.comparables.shouldBeGreaterThan
 | 
						|
import io.kotest.matchers.shouldBe
 | 
						|
import io.kotest.matchers.shouldNotBe
 | 
						|
import prog8.code.core.*
 | 
						|
import prog8.code.target.C64Target
 | 
						|
import prog8.code.target.Cx16Target
 | 
						|
import prog8.code.target.zp.C64Zeropage
 | 
						|
import prog8.code.target.zp.CX16Zeropage
 | 
						|
import prog8tests.helpers.ErrorReporterForTests
 | 
						|
 | 
						|
 | 
						|
class TestAbstractZeropage: FunSpec({
 | 
						|
 | 
						|
    class DummyZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
						|
        override val SCRATCH_B1 = 0x10u
 | 
						|
        override val SCRATCH_REG = 0x11u
 | 
						|
        override val SCRATCH_W1 = 0x20u
 | 
						|
        override val SCRATCH_W2 = 0x30u
 | 
						|
        override val SCRATCH_PTR = 0x40u
 | 
						|
 | 
						|
        init {
 | 
						|
            free.addAll(0u..255u)
 | 
						|
 | 
						|
            removeReservedFromFreePool()
 | 
						|
            retainAllowed()
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    test("testAbstractZeropage") {
 | 
						|
        val zp = DummyZeropage(
 | 
						|
            CompilationOptions(
 | 
						|
                OutputType.RAW,
 | 
						|
                CbmPrgLauncherType.NONE,
 | 
						|
                ZeropageType.FULL,
 | 
						|
                listOf((0x50u..0x5fu)),
 | 
						|
                CompilationOptions.AllZeropageAllowed,
 | 
						|
                floats = false,
 | 
						|
                noSysInit = false,
 | 
						|
                romable = false,
 | 
						|
                compTarget = C64Target(),
 | 
						|
                loadAddress = 999u,
 | 
						|
                memtopAddress = 0xffffu
 | 
						|
            )
 | 
						|
        )
 | 
						|
        zp.free.size shouldBe 256-8-16
 | 
						|
    }
 | 
						|
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
class TestC64Zeropage: FunSpec({
 | 
						|
 | 
						|
    val errors = ErrorReporterForTests()
 | 
						|
    val c64target = C64Target()
 | 
						|
 | 
						|
    test("testNames") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed,
 | 
						|
            floats = false,
 | 
						|
            noSysInit = false,
 | 
						|
            romable = false,
 | 
						|
            compTarget = c64target, loadAddress = 999u, memtopAddress = 0xffffu
 | 
						|
        ))
 | 
						|
 | 
						|
        var result = zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
        result.onFailure { error(it.toString()) }
 | 
						|
        result = zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
        result.onFailure { error(it.toString()) }
 | 
						|
        result = zp.allocate("varname", DataType.UBYTE, null, null, errors)
 | 
						|
        result.onFailure { error(it.toString()) }
 | 
						|
        shouldThrow<IllegalArgumentException> {  zp.allocate("varname", DataType.UBYTE,null, null, errors) }
 | 
						|
        result = zp.allocate("varname2", DataType.UBYTE, null, null, errors)
 | 
						|
        result.onFailure { error(it.toString()) }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testZpFloatEnable") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        var result = zp.allocate("", DataType.FLOAT, null, null, errors)
 | 
						|
        result.expectError { "should be allocation error due to disabled floats" }
 | 
						|
        val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        result = zp2.allocate("", DataType.FLOAT, null, null, errors)
 | 
						|
        result.expectError { "should be allocation error due to disabled ZP use" }
 | 
						|
        val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp3.allocate("", DataType.FLOAT, null, null, errors)
 | 
						|
    }
 | 
						|
 | 
						|
    test("testZpModesWithFloats") {
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        shouldThrow<InternalCompilerException> {
 | 
						|
            C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        }
 | 
						|
        shouldThrow<InternalCompilerException> {
 | 
						|
            C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testZpDontuse") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        println(zp.free)
 | 
						|
        zp.availableBytes() shouldBe 0
 | 
						|
        val result = zp.allocate("", DataType.BYTE, null, null, errors)
 | 
						|
        result.expectError { "expected error due to disabled ZP use" }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testFreeSpacesBytes") {
 | 
						|
        val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp1.availableBytes() shouldBe 15
 | 
						|
        val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp2.availableBytes() shouldBe 85
 | 
						|
        val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp3.availableBytes() shouldBe 94
 | 
						|
        val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp4.availableBytes() shouldBe 205
 | 
						|
        zp4.allocate("test", DataType.UBYTE, null, null, errors)
 | 
						|
        zp4.availableBytes() shouldBe 204
 | 
						|
        zp4.allocate("test2", DataType.UBYTE, null, null, errors)
 | 
						|
        zp4.availableBytes() shouldBe 203
 | 
						|
    }
 | 
						|
 | 
						|
    test("testReservedSpace") {
 | 
						|
        val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp1.availableBytes() shouldBe 205
 | 
						|
        4u shouldNotBeIn zp1.free
 | 
						|
        5u shouldNotBeIn zp1.free
 | 
						|
        6u shouldNotBeIn zp1.free
 | 
						|
        35u shouldNotBeIn zp1.free
 | 
						|
        50u shouldBeIn zp1.free
 | 
						|
        100u shouldBeIn zp1.free
 | 
						|
        49u shouldBeIn zp1.free
 | 
						|
        101u shouldBeIn zp1.free
 | 
						|
        200u shouldBeIn zp1.free
 | 
						|
        255u shouldBeIn zp1.free
 | 
						|
        199u shouldBeIn zp1.free
 | 
						|
        val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp2.availableBytes() shouldBe 105
 | 
						|
        4u shouldNotBeIn zp2.free
 | 
						|
        5u shouldNotBeIn zp2.free
 | 
						|
        6u shouldNotBeIn zp2.free
 | 
						|
        35u shouldNotBeIn zp2.free
 | 
						|
        50u shouldNotBeIn zp2.free
 | 
						|
        100u shouldNotBeIn zp2.free
 | 
						|
        49u shouldBeIn zp2.free
 | 
						|
        101u shouldBeIn zp2.free
 | 
						|
        200u shouldNotBeIn zp2.free
 | 
						|
        255u shouldNotBeIn zp2.free
 | 
						|
        199u shouldBeIn zp2.free
 | 
						|
        val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp2.availableBytes() shouldBe 105
 | 
						|
        4u shouldBeIn zp3.free
 | 
						|
        5u shouldBeIn zp3.free
 | 
						|
        6u shouldBeIn zp3.free
 | 
						|
        35u shouldNotBeIn zp3.free
 | 
						|
    }
 | 
						|
 | 
						|
    test("testBasicsafeAllocation") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp.availableBytes() shouldBe 15
 | 
						|
        zp.hasByteAvailable() shouldBe true
 | 
						|
        zp.hasWordAvailable() shouldBe true
 | 
						|
 | 
						|
        var result = zp.allocate("", DataType.FLOAT, null, null, errors)
 | 
						|
        result.expectError { "expect allocation error: in regular zp there aren't 5 sequential bytes free" }
 | 
						|
 | 
						|
        (0 until zp.availableBytes()).forEach {
 | 
						|
            val alloc = zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
            alloc.getOrElse { throw it }
 | 
						|
        }
 | 
						|
        zp.availableBytes() shouldBe 0
 | 
						|
        zp.hasByteAvailable() shouldBe false
 | 
						|
        zp.hasWordAvailable() shouldBe false
 | 
						|
        result = zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
        result.expectError { "expected allocation error" }
 | 
						|
        result = zp.allocate("", DataType.UWORD, null, null, errors)
 | 
						|
        result.expectError { "expected allocation error" }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testFullAllocation") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp.availableBytes() shouldBe 205
 | 
						|
        zp.hasByteAvailable() shouldBe true
 | 
						|
        zp.hasWordAvailable() shouldBe true
 | 
						|
        var result = zp.allocate("", DataType.UWORD, null, null, errors)
 | 
						|
        zp.availableBytes() shouldBe 203
 | 
						|
        val loc = result.getOrElse { throw it } .address
 | 
						|
        loc shouldBeGreaterThan 3u
 | 
						|
        loc shouldNotBeIn zp.free
 | 
						|
        val num = zp.availableBytes() / 2
 | 
						|
 | 
						|
        (0..num-3).forEach {
 | 
						|
            zp.allocate("", DataType.UWORD, null, null, errors)
 | 
						|
        }
 | 
						|
        zp.availableBytes() shouldBe 7
 | 
						|
 | 
						|
        // can't allocate because no more sequential bytes, only fragmented
 | 
						|
        result = zp.allocate("", DataType.UWORD, null, null, errors)
 | 
						|
        result.expectError { "should give allocation error" }
 | 
						|
 | 
						|
        (0..6).forEach {
 | 
						|
            zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
        }
 | 
						|
 | 
						|
        zp.availableBytes() shouldBe 0
 | 
						|
        zp.hasByteAvailable() shouldBe false
 | 
						|
        zp.hasWordAvailable() shouldBe false
 | 
						|
        result = zp.allocate("", DataType.UBYTE, null, null, errors)
 | 
						|
        result.expectError { "should give allocation error" }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testEfficientAllocation") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed,  true, false, false, c64target, 999u, 0xffffu))
 | 
						|
        zp.availableBytes() shouldBe 15
 | 
						|
        zp.allocate("", DataType.WORD,  null, null, errors).getOrElse{throw it}.address shouldBe 0x04u
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au
 | 
						|
        zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu
 | 
						|
        zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u
 | 
						|
        zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xa6u
 | 
						|
        zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u
 | 
						|
        zp.availableBytes() shouldBe 0
 | 
						|
    }
 | 
						|
 | 
						|
    test("testReservedLocations") {
 | 
						|
        val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, c64target, 999u, 0xffffu))
 | 
						|
        withClue("zp _B1 and _REG must be next to each other to create a word") {
 | 
						|
            zp.SCRATCH_B1 + 1u shouldBe zp.SCRATCH_REG
 | 
						|
        }
 | 
						|
    }
 | 
						|
})
 | 
						|
 | 
						|
 | 
						|
class TestCx16Zeropage: FunSpec({
 | 
						|
    val errors = ErrorReporterForTests()
 | 
						|
    val cx16target = Cx16Target()
 | 
						|
 | 
						|
    test("testReservedLocations") {
 | 
						|
        val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        withClue("zp _B1 and _REG must be next to each other to create a word") {
 | 
						|
            zp.SCRATCH_B1 + 1u shouldBe zp.SCRATCH_REG
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    test("testFreeSpacesBytes") {
 | 
						|
        val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        zp1.availableBytes() shouldBe 86
 | 
						|
        val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        zp2.availableBytes() shouldBe 173
 | 
						|
        val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        zp3.availableBytes() shouldBe 214
 | 
						|
        zp3.allocate("test", DataType.UBYTE, null, null, errors)
 | 
						|
        zp3.availableBytes() shouldBe 213
 | 
						|
        zp3.allocate("test2", DataType.UBYTE, null, null, errors)
 | 
						|
        zp3.availableBytes() shouldBe 212
 | 
						|
    }
 | 
						|
 | 
						|
    test("testReservedSpace") {
 | 
						|
        val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        zp1.availableBytes() shouldBe 214
 | 
						|
        0x22u shouldNotBeIn zp1.free
 | 
						|
        0x23u shouldNotBeIn zp1.free
 | 
						|
        0x24u shouldBeIn zp1.free
 | 
						|
        0x80u shouldBeIn zp1.free
 | 
						|
        0xffu shouldBeIn zp1.free
 | 
						|
        0x02u shouldNotBeIn zp1.free
 | 
						|
        0x21u shouldNotBeIn zp1.free
 | 
						|
    }
 | 
						|
 | 
						|
    test("preallocated zp vars") {
 | 
						|
        val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, false, cx16target, 999u, 0xffffu))
 | 
						|
        zp1.allocatedVariables["test"] shouldBe null
 | 
						|
        zp1.allocatedVariables["cx16.r0"] shouldNotBe null
 | 
						|
        zp1.allocatedVariables["cx16.r15"] shouldNotBe null
 | 
						|
        zp1.allocatedVariables["cx16.r0L"] shouldNotBe null
 | 
						|
        zp1.allocatedVariables["cx16.r15L"] shouldNotBe null
 | 
						|
        zp1.allocatedVariables["cx16.r0sH"] shouldNotBe null
 | 
						|
        zp1.allocatedVariables["cx16.r15sH"] shouldNotBe null
 | 
						|
    }
 | 
						|
})
 |