ir: Block can now contain inline binary

This commit is contained in:
Irmen de Jong 2022-11-12 20:17:23 +01:00
parent d8e785aed0
commit d08451bccc
6 changed files with 29 additions and 19 deletions

View File

@ -75,12 +75,12 @@ class IRCodeGen(
// make sure that first chunks in Blocks and Subroutines share the name of the block/sub as label. // make sure that first chunks in Blocks and Subroutines share the name of the block/sub as label.
irProg.blocks.forEach { block -> irProg.blocks.forEach { block ->
if(block.inlineAssembly.isNotEmpty()) { if(block.inlineAssemblies.isNotEmpty()) {
val first = block.inlineAssembly.first() val first = block.inlineAssemblies.first()
if(first.label==null) { if(first.label==null) {
val replacement = IRInlineAsmChunk(block.name, first.assembly, first.isIR, first.next) val replacement = IRInlineAsmChunk(block.name, first.assembly, first.isIR, first.next)
block.inlineAssembly.removeAt(0) block.inlineAssemblies.removeAt(0)
block.inlineAssembly.add(0, replacement) block.inlineAssemblies.add(0, replacement)
} else if(first.label != block.name) { } else if(first.label != block.name) {
throw AssemblyError("first chunk in block has label that differs from block name") throw AssemblyError("first chunk in block has label that differs from block name")
} }

View File

@ -3,7 +3,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- IRBlock should be able to contain inline binary data (with optional label etc)
- 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) - 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
then we can get rid of the instruction lists in the machinedefinitions as well. This is already no problem at all in the IR codegen. then we can get rid of the instruction lists in the machinedefinitions as well. This is already no problem at all in the IR codegen.
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code - create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code

View File

@ -320,6 +320,7 @@ class IRFileReader {
"SUB" -> block += parseSubroutine(reader) "SUB" -> block += parseSubroutine(reader)
"ASMSUB" -> block += parseAsmSubroutine(reader) "ASMSUB" -> block += parseAsmSubroutine(reader)
"INLINEASM" -> block += parseInlineAssembly(reader) "INLINEASM" -> block += parseInlineAssembly(reader)
"BYTES" -> block += parseBinaryBytes(reader)
else -> throw IRParseException("invalid line in BLOCK: ${reader.peek()}") else -> throw IRParseException("invalid line in BLOCK: ${reader.peek()}")
} }
skipText(reader) skipText(reader)

View File

@ -46,7 +46,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private fun writeBlocks() { private fun writeBlocks() {
irProgram.blocks.forEach { block -> irProgram.blocks.forEach { block ->
out.write("\n<BLOCK NAME=\"${block.name}\" ADDRESS=\"${block.address?.toHex()}\" ALIGN=\"${block.alignment}\" POS=\"${block.position}\">\n") out.write("\n<BLOCK NAME=\"${block.name}\" ADDRESS=\"${block.address?.toHex()}\" ALIGN=\"${block.alignment}\" POS=\"${block.position}\">\n")
block.inlineAssembly.forEach { block.inlineAssemblies.forEach {
writeInlineAsm(it) writeInlineAsm(it)
} }
block.subroutines.forEach { block.subroutines.forEach {
@ -82,6 +82,9 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
writeInlineAsm(it.asmChunk) writeInlineAsm(it.asmChunk)
out.write("</ASMSUB>\n") out.write("</ASMSUB>\n")
} }
block.inlineBinaries.forEach {
writeInlineBytes(it)
}
out.write("</BLOCK>\n") out.write("</BLOCK>\n")
} }
} }

View File

@ -80,8 +80,9 @@ class IRProgram(val name: String,
if(globalInits.next==null) { if(globalInits.next==null) {
val firstBlock = blocks.firstOrNull() val firstBlock = blocks.firstOrNull()
if(firstBlock!=null) { if(firstBlock!=null) {
if(firstBlock.inlineAssembly.isNotEmpty()) { // TODO what is the first chunk in a block?
globalInits.next = firstBlock.inlineAssembly.first() if(firstBlock.inlineAssemblies.isNotEmpty()) {
globalInits.next = firstBlock.inlineAssemblies.first()
} else if(firstBlock.subroutines.isNotEmpty()) { } else if(firstBlock.subroutines.isNotEmpty()) {
val firstSub = firstBlock.subroutines.first() val firstSub = firstBlock.subroutines.first()
if(firstSub.chunks.isNotEmpty()) if(firstSub.chunks.isNotEmpty())
@ -140,10 +141,11 @@ class IRProgram(val name: String,
fun validate() { fun validate() {
blocks.forEach { block -> blocks.forEach { block ->
if(block.inlineAssembly.isNotEmpty()) { // TODO what is the *first* chunk in the block?
require(block.inlineAssembly.first().label == block.name) { "first block chunk should have block name as its label" } if(block.inlineAssemblies.isNotEmpty()) {
require(block.inlineAssemblies.first().label == block.name) { "first block chunk should have block name as its label" }
} }
block.inlineAssembly.forEach { chunk -> block.inlineAssemblies.forEach { chunk ->
require(chunk.instructions.isEmpty()) require(chunk.instructions.isEmpty())
} }
block.subroutines.forEach { sub -> block.subroutines.forEach { sub ->
@ -187,7 +189,7 @@ class IRProgram(val name: String,
globalInits.instructions.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) } globalInits.instructions.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) }
blocks.forEach { blocks.forEach {
it.inlineAssembly.forEach { chunk -> addUsed(chunk.usedRegisters()) } it.inlineAssemblies.forEach { chunk -> addUsed(chunk.usedRegisters()) }
it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) } it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) }
it.asmSubroutines.forEach { asmsub -> addUsed(asmsub.usedRegisters()) } it.asmSubroutines.forEach { asmsub -> addUsed(asmsub.usedRegisters()) }
} }
@ -202,10 +204,11 @@ class IRBlock(
val alignment: BlockAlignment, val alignment: BlockAlignment,
val position: Position val position: Position
) { ) {
// TODO not separate lists but just a single list of chunks, like IRSubroutine? // TODO not separate lists but just a single list of chunks, like IRSubroutine? (but these are not all chunks...)
val inlineAssembly = mutableListOf<IRInlineAsmChunk>() val inlineAssemblies = mutableListOf<IRInlineAsmChunk>()
val subroutines = mutableListOf<IRSubroutine>() val subroutines = mutableListOf<IRSubroutine>()
val asmSubroutines = mutableListOf<IRAsmSubroutine>() val asmSubroutines = mutableListOf<IRAsmSubroutine>()
val inlineBinaries = mutableListOf<IRInlineBinaryChunk>()
enum class BlockAlignment { enum class BlockAlignment {
NONE, NONE,
@ -217,14 +220,15 @@ class IRBlock(
subroutines += sub subroutines += sub
} }
operator fun plusAssign(sub: IRAsmSubroutine) { asmSubroutines += sub } operator fun plusAssign(sub: IRAsmSubroutine) { asmSubroutines += sub }
operator fun plusAssign(asm: IRInlineAsmChunk) { inlineAssembly += asm } operator fun plusAssign(asm: IRInlineAsmChunk) { inlineAssemblies += asm }
operator fun plusAssign(binary: IRInlineBinaryChunk) { TODO("IR BLOCK can't contain inline binary data yet") } operator fun plusAssign(binary: IRInlineBinaryChunk) { inlineBinaries += binary }
fun isEmpty(): Boolean { fun isEmpty(): Boolean {
val noAsm = inlineAssembly.isEmpty() || inlineAssembly.all { it.isEmpty() } val noAsm = inlineAssemblies.isEmpty() || inlineAssemblies.all { it.isEmpty() }
val noSubs = subroutines.isEmpty() || subroutines.all { it.isEmpty() } val noSubs = subroutines.isEmpty() || subroutines.all { it.isEmpty() }
val noAsmSubs = asmSubroutines.isEmpty() || asmSubroutines.all { it.isEmpty() } val noAsmSubs = asmSubroutines.isEmpty() || asmSubroutines.all { it.isEmpty() }
return noAsm && noSubs && noAsmSubs val noBins = inlineBinaries.isEmpty() || inlineBinaries.all { it.isEmpty() }
return noAsm && noSubs && noAsmSubs && noBins
} }
} }

View File

@ -37,7 +37,7 @@ class VmProgramLoader {
if(block.address!=null) if(block.address!=null)
throw IRParseException("blocks cannot have a load address for vm: ${block.name}") throw IRParseException("blocks cannot have a load address for vm: ${block.name}")
block.inlineAssembly.forEach { block.inlineAssemblies.forEach {
val replacement = addAssemblyToProgram(it, programChunks, variableAddresses) val replacement = addAssemblyToProgram(it, programChunks, variableAddresses)
chunkReplacements += replacement chunkReplacements += replacement
} }
@ -62,6 +62,9 @@ class VmProgramLoader {
chunkReplacements += replacement chunkReplacements += replacement
} }
} }
block.inlineBinaries.forEach {
throw IRParseException("inline binary data not yet supported in the VM") // TODO
}
} }
pass2translateSyscalls(programChunks) pass2translateSyscalls(programChunks)