included libs are now carried over to asm properly

This commit is contained in:
Irmen de Jong 2018-10-16 22:49:19 +02:00
parent 529c525081
commit 1e0ce40d1d
5 changed files with 84 additions and 35 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -13,6 +13,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
var address: Int?,
val instructions: MutableList<Instruction> = mutableListOf(),
val variables: MutableMap<String, Value> = mutableMapOf(),
val integerConstants: MutableMap<String, Int> = mutableMapOf(),
val labels: MutableMap<String, Instruction> = 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)

View File

@ -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) {