mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 02:16:41 +00:00
working on vm
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user