diff --git a/codeCore/src/prog8/code/core/CompilationOptions.kt b/codeCore/src/prog8/code/core/CompilationOptions.kt index 3b5e5c026..342fcd384 100644 --- a/codeCore/src/prog8/code/core/CompilationOptions.kt +++ b/codeCore/src/prog8/code/core/CompilationOptions.kt @@ -8,6 +8,7 @@ class CompilationOptions(val output: OutputType, val launcher: CbmPrgLauncherType, val zeropage: ZeropageType, val zpReserved: List, + val zpAllowed: List, val floats: Boolean, val noSysInit: Boolean, val compTarget: ICompilationTarget, @@ -28,4 +29,8 @@ class CompilationOptions(val output: OutputType, init { compTarget.machine.initializeMemoryAreas(this) } + + companion object { + val AllZeropageAllowed: List = listOf(0u..255u) + } } diff --git a/codeCore/src/prog8/code/core/MemoryRegions.kt b/codeCore/src/prog8/code/core/MemoryRegions.kt index 2726eee4b..6283b98da 100644 --- a/codeCore/src/prog8/code/core/MemoryRegions.kt +++ b/codeCore/src/prog8/code/core/MemoryRegions.kt @@ -42,6 +42,13 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) { } } + fun retainAllowed() { + synchronized(this) { + for(allowed in options.zpAllowed) + free.retainAll { it in allowed } + } + } + fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty() fun hasWordAvailable(): Boolean { diff --git a/codeCore/src/prog8/code/target/atari/AtariZeropage.kt b/codeCore/src/prog8/code/target/atari/AtariZeropage.kt index 688ad8876..be2a8aa4c 100644 --- a/codeCore/src/prog8/code/target/atari/AtariZeropage.kt +++ b/codeCore/src/prog8/code/target/atari/AtariZeropage.kt @@ -48,6 +48,7 @@ class AtariZeropage(options: CompilationOptions) : Zeropage(options) { free.addAll(distinctFree) removeReservedFromFreePool() + retainAllowed() } override fun allocateCx16VirtualRegisters() { diff --git a/codeCore/src/prog8/code/target/c128/C128Zeropage.kt b/codeCore/src/prog8/code/target/c128/C128Zeropage.kt index 15bda59d6..463f2e196 100644 --- a/codeCore/src/prog8/code/target/c128/C128Zeropage.kt +++ b/codeCore/src/prog8/code/target/c128/C128Zeropage.kt @@ -69,6 +69,7 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) { free.addAll(distinctFree) removeReservedFromFreePool() + retainAllowed() } override fun allocateCx16VirtualRegisters() { diff --git a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt index 5f3bd194b..bd9a9506a 100644 --- a/codeCore/src/prog8/code/target/c64/C64Zeropage.kt +++ b/codeCore/src/prog8/code/target/c64/C64Zeropage.kt @@ -75,6 +75,8 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) { // in these cases there is enough space on the zero page to stick the cx16 virtual registers in there as well. allocateCx16VirtualRegisters() } + + retainAllowed() } override fun allocateCx16VirtualRegisters() { diff --git a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt index da07f14de..ee777ffd9 100644 --- a/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt +++ b/codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt @@ -47,8 +47,8 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { free.addAll(distinctFree) removeReservedFromFreePool() - allocateCx16VirtualRegisters() + retainAllowed() } } diff --git a/codeCore/src/prog8/code/target/pet/PETZeropage.kt b/codeCore/src/prog8/code/target/pet/PETZeropage.kt index 7889f36dc..8aa0d4f12 100644 --- a/codeCore/src/prog8/code/target/pet/PETZeropage.kt +++ b/codeCore/src/prog8/code/target/pet/PETZeropage.kt @@ -50,6 +50,7 @@ class PETZeropage(options: CompilationOptions) : Zeropage(options) { free.addAll(distinctFree) removeReservedFromFreePool() + retainAllowed() } override fun allocateCx16VirtualRegisters() { diff --git a/codeGenCpu6502/test/TestCodegen.kt b/codeGenCpu6502/test/TestCodegen.kt index f0d90ca12..de1abd65e 100644 --- a/codeGenCpu6502/test/TestCodegen.kt +++ b/codeGenCpu6502/test/TestCodegen.kt @@ -22,6 +22,7 @@ class TestCodegen: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, zpReserved = emptyList(), + zpAllowed = CompilationOptions.AllZeropageAllowed, floats = true, noSysInit = false, compTarget = target, diff --git a/codeGenIntermediate/test/TestIRPeepholeOpt.kt b/codeGenIntermediate/test/TestIRPeepholeOpt.kt index 0a318a8ee..c26eccc03 100644 --- a/codeGenIntermediate/test/TestIRPeepholeOpt.kt +++ b/codeGenIntermediate/test/TestIRPeepholeOpt.kt @@ -18,6 +18,7 @@ class TestIRPeepholeOpt: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), + CompilationOptions.AllZeropageAllowed, floats = false, noSysInit = true, compTarget = target, diff --git a/codeGenIntermediate/test/TestVmCodeGen.kt b/codeGenIntermediate/test/TestVmCodeGen.kt index 83e607651..4969ad5ac 100644 --- a/codeGenIntermediate/test/TestVmCodeGen.kt +++ b/codeGenIntermediate/test/TestVmCodeGen.kt @@ -19,6 +19,7 @@ class TestVmCodeGen: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, zpReserved = emptyList(), + zpAllowed = CompilationOptions.AllZeropageAllowed, floats = true, noSysInit = false, compTarget = target, diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index c3880ff18..9ce0ddb57 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -107,6 +107,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { if (args.writeAssembly) { + // re-initialize memory areas with final compilationOptions compilationOptions.compTarget.machine.initializeMemoryAreas(compilationOptions) program.processAstBeforeAsmGeneration(compilationOptions, args.errors) args.errors.report() @@ -301,6 +302,14 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget .map { it[0].int!!..it[1].int!! } .toList() + val zpAllowed = toplevelModule.statements + .asSequence() + .filter { it is Directive && it.directive == "%zpallowed" } + .map { (it as Directive).args } + .filter { it.size==2 && it[0].int!=null && it[1].int!=null } + .map { it[0].int!!..it[1].int!! } + .toList() + val outputType = if (outputTypeStr == null) { if(compTarget is AtariTarget) OutputType.XEX @@ -330,7 +339,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget return CompilationOptions( outputType, launcherType, - zpType, zpReserved, floatsEnabled, noSysInit, + zpType, zpReserved, zpAllowed, floatsEnabled, noSysInit, compTarget, 0u ) } diff --git a/compiler/src/prog8/compiler/ModuleImporter.kt b/compiler/src/prog8/compiler/ModuleImporter.kt index 6bc623602..7ff74a280 100644 --- a/compiler/src/prog8/compiler/ModuleImporter.kt +++ b/compiler/src/prog8/compiler/ModuleImporter.kt @@ -127,7 +127,7 @@ class ModuleImporter(private val program: Program, private fun removeDirectivesFromImportedModule(importedModule: Module) { // Most global directives don't apply for imported modules, so remove them - val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address") + val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%zpallowed", "%address") var directives = importedModule.statements.filterIsInstance() importedModule.statements.removeAll(directives.toSet()) directives = directives.filter{ it.directive !in moduleLevelDirectives } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 960980757..1a845cdd5 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -773,7 +773,7 @@ internal class AstChecker(private val program: Program, directive.args[0].name != "full") err("invalid zp type, expected basicsafe, floatsafe, kernalsafe, dontuse, or full") } - "%zpreserved" -> { + "%zpreserved", "%zpallowed" -> { if(directive.parent !is Module) err("this directive may only occur at module level") if(directive.args.size!=2 || directive.args[0].int==null || directive.args[1].int==null) diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 334454010..888671a33 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -22,7 +22,7 @@ internal class StatementReorderer( // - sorts the choices in when statement. // - insert AddressOf (&) expression where required (string params to a UWORD function param etc.). - private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%option") + private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%zpallowed", "%address", "%option") override fun after(module: Module, parent: Node): Iterable { val (blocks, other) = module.statements.partition { it is Block } diff --git a/compiler/test/TestGoldenRam.kt b/compiler/test/TestGoldenRam.kt index 98bed12a9..6fd17f899 100644 --- a/compiler/test/TestGoldenRam.kt +++ b/compiler/test/TestGoldenRam.kt @@ -16,6 +16,7 @@ class TestGoldenRam: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf((0x00u..0xffu)), + CompilationOptions.AllZeropageAllowed, floats = true, noSysInit = false, compTarget = VMTarget(), diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index b971e598f..d4ce81c86 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -33,6 +33,7 @@ class TestAbstractZeropage: FunSpec({ free.addAll(0u..255u) removeReservedFromFreePool() + retainAllowed() } override fun allocateCx16VirtualRegisters() { @@ -47,6 +48,7 @@ class TestAbstractZeropage: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf((0x50u..0x5fu)), + CompilationOptions.AllZeropageAllowed, floats = false, noSysInit = false, compTarget = DummyCompilationTarget, @@ -65,7 +67,7 @@ class TestC64Zeropage: FunSpec({ val c64target = C64Target() test("testNames") { - val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), + val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, floats = false, noSysInit = false, compTarget = c64target, loadAddress = 999u @@ -83,33 +85,33 @@ class TestC64Zeropage: FunSpec({ } 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(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) 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(), true, false, c64target, 999u)) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) 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(), true, false, c64target, 999u)) + val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) zp3.allocate("", DataType.FLOAT, null, null, errors) } test("testZpModesWithFloats") { - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, c64target, 999u)) - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, c64target, 999u)) - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, c64target, 999u)) - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) shouldThrow { - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), true, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) } shouldThrow { - C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, false, c64target, 999u)) + C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) } } test("testZpDontuse") { - 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(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) println(zp.free) zp.availableBytes() shouldBe 0 val result = zp.allocate("", DataType.BYTE, null, null, errors) @@ -117,13 +119,13 @@ class TestC64Zeropage: FunSpec({ } test("testFreeSpacesBytes") { - val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) + val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) zp1.availableBytes() shouldBe 17 - val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, c64target, 999u)) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp2.availableBytes() shouldBe 87 - val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, c64target, 999u)) + val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp3.availableBytes() shouldBe 96 - 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(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp4.availableBytes() shouldBe 207 zp4.allocate("test", DataType.UBYTE, null, null, errors) zp4.availableBytes() shouldBe 206 @@ -132,7 +134,7 @@ class TestC64Zeropage: FunSpec({ } test("testReservedSpace") { - val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) + val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp1.availableBytes() shouldBe 207 4u shouldNotBeIn zp1.free 35u shouldNotBeIn zp1.free @@ -143,7 +145,7 @@ class TestC64Zeropage: FunSpec({ 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), false, false, c64target, 999u)) + val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp2.availableBytes() shouldBe 107 4u shouldNotBeIn zp2.free 35u shouldNotBeIn zp2.free @@ -154,14 +156,14 @@ class TestC64Zeropage: FunSpec({ 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), false, false, c64target, 999u)) + val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, listOf(50u .. 100u, 200u..255u), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp2.availableBytes() shouldBe 107 4u shouldBeIn zp3.free 35u shouldNotBeIn zp3.free } test("testBasicsafeAllocation") { - 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(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) zp.availableBytes() shouldBe 17 zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true @@ -183,7 +185,7 @@ class TestC64Zeropage: FunSpec({ } test("testFullAllocation") { - 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(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) zp.availableBytes() shouldBe 207 zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true @@ -214,7 +216,7 @@ class TestC64Zeropage: FunSpec({ } 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(), CompilationOptions.AllZeropageAllowed, true, false, c64target, 999u)) zp.availableBytes() shouldBe 17 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 @@ -232,7 +234,7 @@ class TestC64Zeropage: FunSpec({ } test("testReservedLocations") { - val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, c64target, 999u)) + val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, c64target, 999u)) withClue("zp _B1 and _REG must be next to each other to create a word") { zp.SCRATCH_B1 + 1u shouldBe zp.SCRATCH_REG } @@ -245,18 +247,18 @@ class TestCx16Zeropage: FunSpec({ val cx16target = Cx16Target() test("testReservedLocations") { - val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, cx16target, 999u)) + val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u)) 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(), true, false, cx16target, 999u)) + val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, true, false, cx16target, 999u)) zp1.availableBytes() shouldBe 88 - val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, cx16target, 999u)) + val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u)) 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(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u)) zp3.availableBytes() shouldBe 216 zp3.allocate("test", DataType.UBYTE, null, null, errors) zp3.availableBytes() shouldBe 215 @@ -265,7 +267,7 @@ class TestCx16Zeropage: FunSpec({ } test("testReservedSpace") { - 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(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u)) zp1.availableBytes() shouldBe 216 0x22u shouldBeIn zp1.free 0x80u shouldBeIn zp1.free @@ -275,7 +277,7 @@ class TestCx16Zeropage: FunSpec({ } 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(), CompilationOptions.AllZeropageAllowed, false, false, cx16target, 999u)) zp1.allocatedVariables["test"] shouldBe null zp1.allocatedVariables["cx16.r0"] shouldNotBe null zp1.allocatedVariables["cx16.r15"] shouldNotBe null diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 3503ae2ee..9c1eaf5f9 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -74,7 +74,7 @@ class TestAsmGenSymbols: StringSpec({ fun createTestAsmGen6502(program: Program): AsmGen6502Internal { val errors = ErrorReporterForTests() - val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u) + val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), CompilationOptions.AllZeropageAllowed, false, true, C64Target(), 999u) val ptProgram = IntermediateAstMaker(program, errors).transform() val st = SymbolTableMaker(ptProgram, options).make() return AsmGen6502Internal(ptProgram, st, options, errors) diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 7996b4555..dd815091c 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -100,6 +100,12 @@ Directives Global setting, can occur multiple times. It allows you to reserve or 'block' a part of the zeropage so that it will not be used by the compiler. +.. data:: %zpallowed , + + Level: module. + Global setting, can occur multiple times. It allows you to designate a part of the zeropage that + the compiler is allowed to use (if other options don't prevent usage). + .. data:: %address
diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ee0db366e..872e02633 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,9 @@ TODO ==== -- add a %zpallowed option to specify the range of zeropage register that can be used (intersect with the actual available zp registers ofcourse) +- fix assembly error for uword[3] @zp @split word_addrs (not defined symbol 'p8_word_addrs_lsb') +- fix fill() to not access pixels outside of the screen (use virtual testmongfx first?) +- change fill() to use unsigned types for optimization, and re-check previous problem. - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction diff --git a/examples/test.p8 b/examples/test.p8 index 3ddb11afc..dbdd7b94c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,16 +1,10 @@ %import syslib -%import gfx2 -%import math +%zpreserved $a0,$ff +%zpallowed $70,$b0 main { sub start() { - void cx16.screen_mode(128, false) - - ubyte color repeat { - cx16.FB_cursor_position(math.rnd(), math.rnd()) - cx16.FB_set_pixel(color) - color++ } } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index ce7e060e6..a2312ad33 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -86,6 +86,7 @@ class IRFileReader { var launcher = CbmPrgLauncherType.NONE var zeropage = ZeropageType.FULL val zpReserved = mutableListOf() + val zpAllowed = mutableListOf() var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS var optimize = true var outputDir = Path("") @@ -112,6 +113,10 @@ class IRFileReader { val (zpstart, zpend) = value.split(',') zpReserved.add(UIntRange(zpstart.toUInt(), zpend.toUInt())) } + "zpAllowed" -> { + val (zpstart, zpend) = value.split(',') + zpAllowed.add(UIntRange(zpstart.toUInt(), zpend.toUInt())) + } "outputDir" -> outputDir = Path(value) "optimize" -> optimize = value.toBoolean() else -> throw IRParseException("illegal OPTION $name") @@ -124,6 +129,7 @@ class IRFileReader { launcher, zeropage, zpReserved, + zpAllowed, false, false, target, diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 0a9494a1c..c790fe33e 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -187,6 +187,9 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { for(range in irProgram.options.zpReserved) { xml.writeCharacters("zpReserved=${range.first},${range.last}\n") } + for(range in irProgram.options.zpAllowed) { + xml.writeCharacters("zpAllowed=${range.first},${range.last}\n") + } xml.writeCharacters("loadAddress=${irProgram.options.loadAddress.toHex()}\n") xml.writeCharacters("optimize=${irProgram.options.optimize}\n") xml.writeCharacters("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n") diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 764997695..73824793a 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -22,6 +22,7 @@ class TestIRFileInOut: FunSpec({ CbmPrgLauncherType.NONE, ZeropageType.DONTUSE, emptyList(), + CompilationOptions.AllZeropageAllowed, floats = false, noSysInit = true, compTarget = target, diff --git a/parser/antlr/Prog8ANTLR.g4 b/parser/antlr/Prog8ANTLR.g4 index fa9cc22fa..1825528b9 100644 --- a/parser/antlr/Prog8ANTLR.g4 +++ b/parser/antlr/Prog8ANTLR.g4 @@ -124,7 +124,7 @@ labeldef : identifier ':' ; unconditionaljump : 'goto' (integerliteral | scoped_identifier) ; directive : - directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' | + directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%zpallowed' | '%address' | '%import' | '%breakpoint' | '%asminclude' | '%asmbinary' | '%option' ) (directivearg? | directivearg (',' directivearg)*) ; diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index a304a545c..1110074ad 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -12,7 +12,7 @@