diff --git a/compiler/src/prog8/compiler/target/c64/Commodore64.kt b/compiler/src/prog8/compiler/target/c64/Commodore64.kt index c65256c6f..a71dfe4f0 100644 --- a/compiler/src/prog8/compiler/target/c64/Commodore64.kt +++ b/compiler/src/prog8/compiler/target/c64/Commodore64.kt @@ -29,8 +29,8 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { const val SCRATCH_B1 = 0x02 const val SCRATCH_REG = 0x03 // temp storage for a register const val SCRATCH_REG_X = 0xfa // temp storage for register X (the evaluation stack pointer) - const val SCRATCH_W1 = 0xfb // $fb/$fc - const val SCRATCH_W2 = 0xfd // $fd/$fe + const val SCRATCH_W1 = 0xfb // $fb+$fc + const val SCRATCH_W2 = 0xfd // $fd+$fe } override val exitProgramStrategy: ExitProgramStrategy = when(options.zeropage) { @@ -49,19 +49,36 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1+1, SCRATCH_W2, SCRATCH_W2+1)) free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ } else { - if(options.zeropage == ZeropageType.KERNALSAFE) { - // add the Zp addresses that are just used by BASIC routines to the free list - free.addAll(listOf(0x09, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + if(options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) { + free.addAll(listOf(0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53, 0x6f, 0x70)) + 0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53, + 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, + 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, + 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff + // 0x90-0xfa is 'kernel work storage area' + )) } - else if(options.zeropage == ZeropageType.FLOATSAFE) { - TODO("reserve float zp locations") + + if(options.zeropage == ZeropageType.FLOATSAFE) { + // remove the zero page locations used for floating point operations from the free list + free.removeAll(listOf( + 0x12, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xf + )) } - // add the other free Zp addresses - // these are valid for the C-64 (when no RS232 I/O is performed): - free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0d, 0x0e, + + // add the other free Zp addresses, + // these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully: + free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e, 0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa, 0xb5, 0xb6, 0xf7, 0xf8, 0xf9)) } diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index 1026ccab7..f663441b4 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -138,23 +138,41 @@ class TestZeropage { assertFailsWith { zp.allocate("", DataType.FLOAT, null) } - val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true)) zp2.allocate("", DataType.FLOAT, null) } + @Test + fun testZpModesWithFloats() { + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false)) + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false)) + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false)) + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false)) + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true)) + assertFailsWith { + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) + } + assertFailsWith { + C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true)) + } + } + @Test fun testFreeSpaces() { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(19, zp1.available()) - val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true)) - assertEquals(67, zp2.available()) - val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) - assertEquals(238, zp3.available()) + assertEquals(20, zp1.available()) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false)) + assertEquals(95, zp2.available()) + val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false)) + assertEquals(129, zp3.available()) + val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false)) + assertEquals(238, zp4.available()) } @Test fun testReservedSpace() { - val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) + val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false)) assertEquals(238, zp1.available()) assertTrue(50 in zp1.free) assertTrue(100 in zp1.free) @@ -163,8 +181,7 @@ class TestZeropage { assertTrue(200 in zp1.free) assertTrue(255 in zp1.free) assertTrue(199 in zp1.free) - val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, - listOf(50 .. 100, 200..255), true)) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false)) assertEquals(139, zp2.available()) assertFalse(50 in zp2.free) assertFalse(100 in zp2.free) @@ -178,7 +195,7 @@ class TestZeropage { @Test fun testBasicsafeAllocation() { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(19, zp.available()) + assertEquals(20, zp.available()) zp.allocate("", DataType.FLOAT, null) assertFailsWith { @@ -201,32 +218,28 @@ class TestZeropage { @Test fun testFullAllocation() { - val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true)) + val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false)) assertEquals(238, zp.available()) - val loc = zp.allocate("", DataType.FLOAT, null) + val loc = zp.allocate("", DataType.UWORD, null) assertTrue(loc > 3) assertFalse(loc in zp.free) - val num = zp.available() / 5 - val rest = zp.available() % 5 + val num = zp.available() / 2 for(i in 0..num-4) { - zp.allocate("", DataType.FLOAT, null) + zp.allocate("", DataType.UWORD, null) } - assertEquals(18,zp.available()) + assertEquals(6,zp.available()) assertFailsWith { // can't allocate because no more sequential bytes, only fragmented - zp.allocate("", DataType.FLOAT, null) + zp.allocate("", DataType.UWORD, null) } - for(i in 0..13) { + for(i in 0..5) { zp.allocate("", DataType.UBYTE, null) } - zp.allocate("", DataType.UWORD, null) - assertEquals(2, zp.available()) - zp.allocate("", DataType.UBYTE, null) - zp.allocate("", DataType.UBYTE, null) + assertEquals(0, zp.available()) assertFailsWith { // no more space zp.allocate("", DataType.UBYTE, null) @@ -236,7 +249,7 @@ class TestZeropage { @Test fun testEfficientAllocation() { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) - assertEquals(19, zp.available()) + assertEquals(20, zp.available()) assertEquals(0x04, zp.allocate("", DataType.FLOAT, null)) assertEquals(0x09, zp.allocate("", DataType.UBYTE, null)) assertEquals(0x0d, zp.allocate("", DataType.UWORD, null)) @@ -245,6 +258,7 @@ class TestZeropage { assertEquals(0xa9, zp.allocate("", DataType.UWORD, null)) assertEquals(0xb5, zp.allocate("", DataType.UWORD, null)) assertEquals(0xf7, zp.allocate("", DataType.UWORD, null)) + assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null)) assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null)) assertEquals(0, zp.available()) }