From 1e0ce40d1d6607c66745ffaddbc7cf44fb08259d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 16 Oct 2018 22:49:19 +0200 Subject: [PATCH] included libs are now carried over to asm properly --- compiler/examples/test.p8 | 40 +++++++++++------ compiler/src/prog8/ast/StmtReorderer.kt | 13 ++++-- compiler/src/prog8/compiler/Compiler.kt | 11 +++-- .../intermediate/IntermediateProgram.kt | 43 ++++++++++++------- .../src/prog8/compiler/target/c64/AsmGen.kt | 12 +++++- 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 2ee5b855a..99f018279 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -1,26 +1,42 @@ %import c64utils -~ main $c800 { +~ block2 $4000 { + return +} +~ block3 $3000 { + return +} + +~ blockNoAddr1 { + return +} + +~ blockNoAddr2 { + return +} + +~ block4 $6000 { + return +} + +~ blockNoAddr3 { + return +} + + +~ main { sub start() { const ubyte screen_color = 9 const ubyte border_color = 2 const ubyte cursor_color = 7 - memory ubyte screen = $d021 - memory ubyte border = $d020 - memory ubyte cursor = 646 - screen = screen_color - border = border_color - cursor = cursor_color + c64.BGCOL0 = screen_color + c64.EXTCOL = border_color + c64.COLOR = cursor_color return } } - -~ block2 $c000 { - return -} - diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index b69d6dd13..66864d8fd 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -4,7 +4,8 @@ import prog8.compiler.HeapValues class StatementReorderer(private val namespace: INameScope, private val heap: HeapValues): IAstProcessor { // Reorders the statements in a way the compiler needs. - // - 'main' block must be the very first statement. + // - 'main' block must be the very first statement UNLESS it has an address set. + // - blocks are ordered by address, where blocks without address are put at the end. // - in every scope: // -- the directives '%output', '%launcher', '%zeropage', '%zpreserved', '%address' and '%option' will come first. // -- all vardecls then follow. @@ -18,9 +19,15 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He override fun process(module: Module) { super.process(module) + + val (blocks, other) = module.statements.partition { it is Block } + module.statements = other.plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList() + val mainBlock = module.statements.single { it is Block && it.name=="main" } - module.statements.remove(mainBlock) - module.statements.add(0, mainBlock) + if((mainBlock as Block).address==null) { + module.statements.remove(mainBlock) + module.statements.add(0, mainBlock) + } val varDecls = module.statements.filter { it is VarDecl } module.statements.removeAll(varDecls) module.statements.addAll(0, varDecls) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index a97da9eb5..45f745486 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -187,7 +187,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } private fun processVariables(scope: INameScope) { - for(variable in scope.statements.asSequence().filter {it is VarDecl && it.type==VarDeclType.VAR}.map { it as VarDecl }) + for(variable in scope.statements.asSequence().filter {it is VarDecl }.map { it as VarDecl }) prog.variable(variable.scopedname, variable) for(subscope in scope.subScopes()) processVariables(subscope.value) @@ -199,8 +199,13 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.line(subroutine.position) // note: the caller has already written the arguments into the subroutine's parameter variables. translate(subroutine.statements) - } else if(subroutine.isNotEmpty()) - throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") + } else { + // asmsub + if(subroutine.isNotEmpty()) + throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") + + prog.symbolDef(subroutine.scopedname, subroutine.asmAddress) + } return super.process(subroutine) } diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 40a077a9a..00a9fd912 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -13,6 +13,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap var address: Int?, val instructions: MutableList = mutableListOf(), val variables: MutableMap = mutableMapOf(), + val integerConstants: MutableMap = mutableMapOf(), val labels: MutableMap = mutableMapOf()) { val numVariables: Int @@ -245,25 +246,31 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap } fun variable(scopedname: String, decl: VarDecl) { - if(decl.type!=VarDeclType.VAR) - return // const and memory variables don't require storage - val value = when(decl.datatype) { - DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!) - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { - val litval = (decl.value as LiteralValue) - if(litval.heapId==null) - throw CompilerException("string should already be in the heap") - Value(decl.datatype, litval.heapId) + when(decl.type) { + VarDeclType.VAR -> { + val value = when(decl.datatype) { + DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!) + DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { + val litval = (decl.value as LiteralValue) + if(litval.heapId==null) + throw CompilerException("string should already be in the heap") + Value(decl.datatype, litval.heapId) + } + DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B, DataType.MATRIX_UB, + DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> { + val litval = (decl.value as LiteralValue) + if(litval.heapId==null) + throw CompilerException("array/matrix should already be in the heap") + Value(decl.datatype, litval.heapId) + } + } + currentBlock.variables[scopedname] = value } - DataType.ARRAY_B, DataType.ARRAY_W, DataType.MATRIX_B, DataType.MATRIX_UB, - DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> { - val litval = (decl.value as LiteralValue) - if(litval.heapId==null) - throw CompilerException("array/matrix should already be in the heap") - Value(decl.datatype, litval.heapId) + VarDeclType.CONST -> {} // constants are all folded away + VarDeclType.MEMORY -> { + currentBlock.integerConstants[scopedname] = (decl.value as LiteralValue).asIntegerValue!! } } - currentBlock.variables[scopedname] = value } fun instr(opcode: Opcode, arg: Value? = null, callLabel: String? = null) { @@ -280,6 +287,10 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap currentBlock.instructions.add(Instruction(Opcode.LINE, callLabel = "${position.line} ${position.file}")) } + fun symbolDef(name: String, value: Int) { + currentBlock.integerConstants[name] = value + } + fun newBlock(scopedname: String, shortname: String, address: Int?) { currentBlock = ProgramBlock(scopedname, shortname, address) blocks.add(currentBlock) diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 180437777..69c447e7a 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -28,12 +28,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, if(it.callLabel!=null) symname(it.callLabel, block) else null, if(it.callLabel2!=null) symname(it.callLabel2, block) else null) }.toMutableList() + val newConstants = block.integerConstants.map { symname(it.key, block) to it.value }.toMap().toMutableMap() newblocks.add(IntermediateProgram.ProgramBlock( block.scopedname, block.shortname, block.address, newinstructions, newvars, + newConstants, newlabels)) } program.blocks.clear() @@ -58,7 +60,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, output = File("${program.name}.asm").printWriter() output.use { header() - for(block in program.blocks) // todo sort by address (if specified) (blocks w/o address go LAST) + for(block in program.blocks) block2asm(block) } @@ -140,6 +142,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("* = ${block.address?.toHex()}") } out("${block.shortname}\t.proc\n") + out("\n; constants/memdefs/kernel subroutines") + memdefs2asm(block) out("\n; variables") vardecls2asm(block) out("") @@ -154,6 +158,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, out("\n\t.pend\n") } + private fun memdefs2asm(block: IntermediateProgram.ProgramBlock) { + for(m in block.integerConstants) { + out("\t${m.key} = ${m.value.toHex()}") + } + } + private fun vardecls2asm(block: IntermediateProgram.ProgramBlock) { val sortedVars = block.variables.toList().sortedBy { it.second.type } for (v in sortedVars) {