From c13b7fd88307ee4e9c826e6974b87ab9dc58dd73 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 10 Feb 2022 21:36:28 +0100 Subject: [PATCH] report free/occupied Zeropage space at end of compilation --- .../codegen/cpu6502/ProgramAndVarsGen.kt | 13 ++- .../codegen/cpu6502/VariableAllocator.kt | 79 ++++++++++++++++--- compiler/src/prog8/compiler/Compiler.kt | 12 +-- docs/source/todo.rst | 2 +- examples/test.p8 | 61 ++------------ 5 files changed, 89 insertions(+), 78 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index b3bc40ca2..59e526ba9 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -39,6 +39,7 @@ internal class ProgramAndVarsGen( require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"} allocator.allocateZeropageVariables() + header() val allBlocks = program.allBlocks if(allBlocks.first().name != "main") @@ -63,7 +64,8 @@ internal class ProgramAndVarsGen( asmgen.out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}") asmgen.out("; assembler syntax is for the 64tasm cross-assembler") asmgen.out("; output options: output=${options.output} launcher=${options.launcher} zp=${options.zeropage}") - asmgen.out("\n.cpu '$cpu'\n.enc 'none'\n") + asmgen.out("") + asmgen.out(".cpu '$cpu'\n.enc 'none'\n") program.actualLoadAddress = program.definedLoadAddress if (program.actualLoadAddress == 0u) // fix load address @@ -153,7 +155,8 @@ internal class ProgramAndVarsGen( } private fun block2asm(block: Block) { - asmgen.out("\n\n; ---- block: '${block.name}' ----") + asmgen.out("") + asmgen.out("; ---- block: '${block.name}' ----") if(block.address!=null) asmgen.out("* = ${block.address!!.toHex()}") else { @@ -172,7 +175,8 @@ internal class ProgramAndVarsGen( asmsubs2asm(block.statements) nonZpVariables2asm(block) - asmgen.out("\n; subroutines in this block") + asmgen.out("") + asmgen.out("; subroutines in this block") // First translate regular statements, and then put the subroutines at the end. // (regular statements = everything except the initialization assignments; @@ -365,7 +369,8 @@ internal class ProgramAndVarsGen( } private fun nonZpVariables2asm(variables: List) { - asmgen.out("\n; non-zeropage variables") + asmgen.out("") + asmgen.out("; non-zeropage variables") val (stringvars, othervars) = variables.partition { it.type==DataType.STR } stringvars.forEach { val stringvalue = it.initialValue as StringLiteralValue diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index 0bd862d7d..901db9d83 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -1,9 +1,8 @@ package prog8.codegen.cpu6502 -import com.github.michaelbull.result.onFailure -import prog8.ast.base.ArrayDatatypes -import prog8.ast.base.DataType -import prog8.ast.base.IntegerDatatypes +import com.github.michaelbull.result.fold +import com.github.michaelbull.result.onSuccess +import prog8.ast.base.* import prog8.ast.expressions.StringLiteralValue import prog8.ast.statements.Subroutine import prog8.ast.statements.ZeropageWish @@ -41,20 +40,52 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, vars.subroutineVars.asSequence().flatMap { it.value } ).toList() + val numberOfAllocatableVariables = allVariables.size + val totalAllocatedMemorySize = allVariables.sumOf { memsize(it) } + val varsRequiringZp = allVariables.filter { it.zp == ZeropageWish.REQUIRE_ZEROPAGE } val varsPreferringZp = allVariables.filter { it.zp == ZeropageWish.PREFER_ZEROPAGE } val varsDontCare = allVariables.filter { it.zp == ZeropageWish.DONTCARE } + val numberOfExplicitNonZpVariables = allVariables.count { it.zp == ZeropageWish.NOT_IN_ZEROPAGE } + require(varsDontCare.size + varsRequiringZp.size + varsPreferringZp.size + numberOfExplicitNonZpVariables == numberOfAllocatableVariables) + + var numVariablesAllocatedInZP: Int = 0 + var numberOfNonIntegerVariables: Int = 0 varsRequiringZp.forEach { variable -> val numElements = numArrayElements(variable) - val result = zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors) - result.onFailure { errors.err(it.message!!, variable.position) } + val result = zeropage.allocate( + variable.scopedname, + variable.type, + variable.scope, + numElements, + variable.initialValue, + variable.position, + errors + ) + result.fold( + success = { + numVariablesAllocatedInZP++ + }, + failure = { + errors.err(it.message!!, variable.position) + } + ) } if(errors.noErrors()) { varsPreferringZp.forEach { variable -> val numElements = numArrayElements(variable) - zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors) + val result = zeropage.allocate( + variable.scopedname, + variable.type, + variable.scope, + numElements, + variable.initialValue, + variable.position, + errors + ) + result.onSuccess { numVariablesAllocatedInZP++ } // no need to check for allocation error, if there is one, just allocate in normal system ram. } @@ -63,14 +94,40 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, if(errors.noErrors()) { for (variable in varsDontCare) { if(variable.type in IntegerDatatypes) { - val numElements = numArrayElements(variable) - zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors) - if(zeropage.free.isEmpty()) + if(zeropage.free.isEmpty()) { break - } + } else { + val numElements = numArrayElements(variable) + val result = zeropage.allocate( + variable.scopedname, + variable.type, + variable.scope, + numElements, + variable.initialValue, + variable.position, + errors + ) + result.onSuccess { numVariablesAllocatedInZP++ } + } + } else + numberOfNonIntegerVariables++ } } } + + println(" number of allocated vars: $numberOfAllocatableVariables total size: $totalAllocatedMemorySize") + println(" put into zeropage: $numVariablesAllocatedInZP, non-zp allocatable: ${numberOfNonIntegerVariables+numberOfExplicitNonZpVariables}") + println(" zeropage free space: ${zeropage.free.size} bytes") + } + + private fun memsize(variable: IVariablesAndConsts.StaticVariable): Int { + return when(variable.type) { + in NumericDatatypes -> + options.compTarget.memorySize(variable.type) + in ArrayDatatypes -> variable.arraysize!! * options.compTarget.memorySize(ArrayToElementTypes.getValue(variable.type)) + DataType.STR -> (variable.initialValue as StringLiteralValue).value.length + 1 + else -> 0 + } } internal fun isZpVar(scopedName: List) = scopedName in zeropage.variables diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 81c8aeae2..41430d283 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -112,31 +112,31 @@ fun compileProgram(args: CompilerArguments): CompilationResult { println("\nTotal compilation+assemble time: ${round(seconds*100.0)/100.0} sec.") return CompilationResult(true, program, programName, compTarget, importedFiles) } catch (px: ParseError) { - System.err.print("\u001b[91m") // bright red + System.err.print("\n\u001b[91m") // bright red System.err.println("${px.position.toClickableStr()} parse error: ${px.message}".trim()) System.err.print("\u001b[0m") // reset } catch (ac: AbortCompilation) { if(!ac.message.isNullOrEmpty()) { - System.err.print("\u001b[91m") // bright red + System.err.print("\n\u001b[91m") // bright red System.err.println(ac.message) System.err.print("\u001b[0m") // reset } } catch (nsf: NoSuchFileException) { - System.err.print("\u001b[91m") // bright red + System.err.print("\n\u001b[91m") // bright red System.err.println("File not found: ${nsf.message}") System.err.print("\u001b[0m") // reset } catch (ax: AstException) { - System.err.print("\u001b[91m") // bright red + System.err.print("\n\u001b[91m") // bright red System.err.println(ax.toString()) System.err.print("\u001b[0m") // reset } catch (x: Exception) { - print("\u001b[91m") // bright red + print("\n\u001b[91m") // bright red println("\n* internal error *") print("\u001b[0m") // reset System.out.flush() throw x } catch (x: NotImplementedError) { - print("\u001b[91m") // bright red + print("\n\u001b[91m") // bright red println("\n* internal error: missing feature/code *") print("\u001b[0m") // reset System.out.flush() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 74ea4ca59..73d1958f2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- make it so that subroutine parameters as variables can again be allocated in ZP, if there's still space +... Need help with diff --git a/examples/test.p8 b/examples/test.p8 index f92a820bd..91eae5b7c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,63 +1,12 @@ -%import floats -%import textio %zeropage basicsafe main { - ubyte @zp mainglobal1=10 - float @shared fl1 = floats.TWOPI - - uword @shared m1 = memory("ee", 200, 0) - - uword [2] nullwords - ubyte [2] nullbytes - uword [2] valuewords = [1111,22222] - ubyte [2] valuebytes = [111,222] - str name = "irmen" - - uword [2] @requirezp zpnullwords - ubyte [2] @requirezp zpnullbytes - uword [2] @requirezp zpvaluewords = [11111,22222] - ubyte [2] @requirezp zpvaluebytes = [111,222] - str @requirezp zpname = "irmenzp" - sub start() { - prog8_lib.P8ZP_SCRATCH_B1 = 1 - prog8_lib.P8ZP_SCRATCH_W1 = 1111 - str alsoname = "also name" - - txt.print(alsoname) - txt.print(zpname) - txt.print("internedstring") - txt.spc() - txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_B1, true) - txt.spc() - txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_W1, true) - txt.spc() - txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_W2, true) - txt.nl() - - txt.print_uw(nullwords[1]) - txt.nl() - txt.print_ub(nullbytes[1]) - txt.nl() - txt.print_uw(valuewords[1]) - txt.nl() - txt.print_ub(valuebytes[1]) - txt.nl() - txt.print(name) - txt.nl() - txt.nl() - - txt.print_uw(zpnullwords[1]) - txt.nl() - txt.print_ub(zpnullbytes[1]) - txt.nl() - txt.print_uw(zpvaluewords[1]) - txt.nl() - txt.print_ub(zpvaluebytes[1]) - txt.nl() - txt.print(zpname) - txt.nl() + cx16.r0=0 + void routine22(1,2,3,4,5) + } + sub routine22(ubyte aa1, ubyte aa2, ubyte aa3, ubyte aa4, ubyte aa5) -> ubyte { + return aa1+aa2+aa3+aa4+aa5 } }