working on vm

This commit is contained in:
Irmen de Jong
2022-03-19 01:20:01 +01:00
parent 4c1bb18956
commit 9b16d7c786
18 changed files with 277 additions and 27 deletions
@@ -6,25 +6,23 @@ import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
internal class AssemblyProgram(override val name: String) : IAssemblyProgram
{
internal class AssemblyProgram(override val name: String,
private val allocations: VariableAllocator,
private val instructions: MutableList<String>
) : IAssemblyProgram {
override fun assemble(options: CompilationOptions): Boolean {
val outfile = options.outputDir / ("$name.p8virt")
println("write code to ${outfile}")
outfile.bufferedWriter().use {
it.write(memsrc)
allocations.asVmMemory().forEach { alloc -> it.write(alloc + "\n") }
it.write("------PROGRAM------\n")
it.write(src)
instructions.forEach { ins -> it.write(ins + "\n") }
}
return true
}
}
val memsrc = """
$4000 strz "Hello from program! "derp" bye.\n"
$2000 ubyte 65,66,67,68,0
$2100 uword $1111,$2222,$3333,$4444
"""
val src = """
/*
; enable lores gfx screen
load r0, 0
syscall 8
@@ -53,3 +51,4 @@ load.w r0,0
return"""
}
*/
@@ -1,11 +1,15 @@
package prog8.codegen.virtual
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.mapError
import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyGenerator
import prog8.code.core.IAssemblyProgram
import prog8.code.core.IErrorReporter
import prog8.code.ast.*
import prog8.code.core.*
import prog8.vm.Instruction
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
class CodeGen(internal val program: PtProgram,
internal val symbolTable: SymbolTable,
@@ -13,8 +17,87 @@ class CodeGen(internal val program: PtProgram,
internal val errors: IErrorReporter
): IAssemblyGenerator {
override fun compileToAssembly(): IAssemblyProgram? {
private val instructions = mutableListOf<String>()
return AssemblyProgram(program.name)
override fun compileToAssembly(): IAssemblyProgram? {
instructions.clear()
val allocations = VariableAllocator(symbolTable, program, errors)
for (block in program.allBlocks())
translateNode(block)
return AssemblyProgram(program.name, allocations, instructions)
}
private fun out(ins: Instruction) {
instructions.add(ins.toString())
}
private fun out(ins: String) {
instructions.add(ins)
}
private fun translateNode(node: PtNode) {
when(node) {
is PtBlock -> translate(node)
is PtSub -> translate(node)
is PtVariable -> { /* var should be looked up via symbol table */ }
is PtMemMapped -> { /* memmapped var should be looked up via symbol table */ }
is PtConstant -> { /* constants have all been folded into the code */ }
is PtAsmSub -> translate(node)
is PtAssignTarget -> TODO()
is PtAssignment -> translate(node)
is PtBreakpoint -> TODO()
is PtConditionalBranch -> TODO()
is PtAddressOf -> TODO()
is PtArrayIndexer -> TODO()
is PtArrayLiteral -> TODO()
is PtBinaryExpression -> TODO()
is PtBuiltinFunctionCall -> TODO()
is PtContainmentCheck -> TODO()
is PtFunctionCall -> TODO()
is PtIdentifier -> TODO()
is PtMemoryByte -> TODO()
is PtNumber -> TODO()
is PtPipe -> TODO()
is PtPrefix -> TODO()
is PtRange -> TODO()
is PtString -> TODO()
is PtTypeCast -> TODO()
is PtForLoop -> TODO()
is PtGosub -> TODO()
is PtIfElse -> TODO()
is PtIncludeBinary -> TODO()
is PtJump -> TODO()
is PtNodeGroup -> TODO()
is PtNop -> { }
is PtPostIncrDecr -> TODO()
is PtProgram -> TODO()
is PtRepeatLoop -> TODO()
is PtReturn -> TODO()
is PtSubroutineParameter -> TODO()
is PtWhen -> TODO()
is PtWhenChoice -> TODO()
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target")
else -> TODO("missing codegen for $node")
}
}
private fun translate(sub: PtSub) {
out("; SUB: ${sub.scopedName} -> ${sub.returntype}")
}
private fun translate(asmsub: PtAsmSub) {
out("; ASMSUB: ${asmsub.scopedName} = ${asmsub.address} -> ${asmsub.retvalRegisters}")
}
private fun translate(assign: PtAssignment) {
out("; ASSIGN: ${assign.target.identifier?.targetName} = ${assign.value}")
}
private fun translate(block: PtBlock) {
out("\n; BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children) {
translateNode(child)
}
out("; BLOCK-END '${block.name}'\n")
}
}
@@ -0,0 +1,74 @@
package prog8.codegen.virtual
import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
import prog8.code.core.*
class VariableAllocator(private val st: SymbolTable, private val program: PtProgram, errors: IErrorReporter) {
private val allocations = mutableMapOf<List<String>, Int>()
val freeStart: Int
init {
var nextLocation = 0
for (variable in st.allVariables) {
val memsize =
when (variable.dt) {
DataType.STR -> variable.initialStringValue!!.first.length + 1 // include the zero byte
in NumericDatatypes -> program.memsizer.memorySize(variable.dt)
in ArrayDatatypes -> program.memsizer.memorySize(variable.dt, variable.arraysize!!)
else -> throw InternalCompilerException("weird dt")
}
allocations[variable.scopedName] = nextLocation
nextLocation += memsize
}
freeStart = nextLocation
}
fun asVmMemory(): List<String> {
/*
$4000 strz "Hello from program! "derp" bye.\n"
$2000 ubyte 65,66,67,68,0
$2100 uword $1111,$2222,$3333,$4444
*/
val mm = mutableListOf<String>()
for (variable in st.allVariables) {
val location = allocations.getValue(variable.scopedName)
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
DataType.BYTE, DataType.ARRAY_B -> "byte"
DataType.UWORD, DataType.ARRAY_UW -> "uword"
DataType.WORD, DataType.ARRAY_W -> "word"
DataType.FLOAT, DataType.ARRAY_F -> "float"
else -> throw InternalCompilerException("weird dt")
}
val value = when(variable.dt) {
DataType.FLOAT -> (variable.initialNumericValue ?: 0.0).toString()
in NumericDatatypes -> (variable.initialNumericValue ?: 0).toHex()
DataType.STR -> {
val encoded = program.encoding.encodeString(variable.initialStringValue!!.first, variable.initialStringValue!!.second)
encoded.joinToString(",") { it.toInt().toHex() } + ",0"
}
DataType.ARRAY_F -> {
if(variable.initialArrayValue!=null) {
variable.initialArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
(1..variable.arraysize!!).joinToString(",") { "0" }
}
}
in ArrayDatatypes -> {
if(variable.initialArrayValue!==null) {
variable.initialArrayValue!!.joinToString(",") { it.number!!.toHex() }
} else {
(1..variable.arraysize!!).joinToString(",") { "0" }
}
}
else -> throw InternalCompilerException("weird dt")
}
mm.add("${location.toHex()} $typeStr $value")
}
return mm
}
}