working on vm translator

This commit is contained in:
Irmen de Jong 2022-03-22 01:41:23 +01:00
parent fd581ffc37
commit 06b38506d1
10 changed files with 326 additions and 152 deletions

View File

@ -2,22 +2,67 @@ package prog8.codegen.virtual
import prog8.code.core.CompilationOptions
import prog8.code.core.IAssemblyProgram
import prog8.vm.Instruction
import prog8.vm.Opcode
import java.io.BufferedWriter
import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
internal class AssemblyProgram(override val name: String,
private val allocations: VariableAllocator,
private val instructions: MutableList<String>
private val allocations: VariableAllocator
) : IAssemblyProgram {
private val globalInits = mutableListOf<VmCodeLine>()
private val blocks = mutableListOf<VmCodeChunk>()
override fun assemble(options: CompilationOptions): Boolean {
val outfile = options.outputDir / ("$name.p8virt")
println("write code to ${outfile}")
outfile.bufferedWriter().use {
allocations.asVmMemory().forEach { alloc -> it.write(alloc + "\n") }
it.write("------PROGRAM------\n")
instructions.forEach { ins -> it.write(ins + "\n") }
outfile.bufferedWriter().use { out ->
allocations.asVmMemory().forEach { (name, alloc) ->
out.write("; ${name.joinToString(".")}\n")
out.write(alloc + "\n")
}
out.write("------PROGRAM------\n")
out.write("; global var inits\n")
globalInits.forEach { out.writeLine(it) }
out.write("; actual program code\n")
blocks.asSequence().flatMap { it.lines }.forEach { line->out.writeLine(line) }
}
return true
}
private fun BufferedWriter.writeLine(line: VmCodeLine) {
when(line) {
is VmCodeComment -> write("; ${line.comment}\n")
is VmCodeInstruction -> write(line.ins.toString() + "\n")
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
is VmCodeOpcodeWithStringArg -> write("${line.opcode.name.lowercase()} ${line.arg}\n")
}
}
fun addGlobalInits(chunk: VmCodeChunk) = globalInits.addAll(chunk.lines)
fun addBlock(block: VmCodeChunk) = blocks.add(block)
}
internal sealed class VmCodeLine
internal class VmCodeInstruction(val ins: Instruction): VmCodeLine()
internal class VmCodeLabel(val name: List<String>): VmCodeLine()
internal class VmCodeComment(val comment: String): VmCodeLine()
internal class VmCodeOpcodeWithStringArg(val opcode: Opcode, val arg: String): VmCodeLine()
internal class VmCodeChunk {
val lines = mutableListOf<VmCodeLine>()
operator fun plusAssign(line: VmCodeLine) {
lines.add(line)
}
operator fun plusAssign(chunk: VmCodeChunk) {
lines.addAll(chunk.lines)
}
}

View File

@ -0,0 +1,43 @@
package prog8.codegen.virtual
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtNumber
import prog8.vm.Instruction
import prog8.vm.Opcode
internal class BuiltinFunctionsGen(val codegen: CodeGen) {
fun translate(call: PtBuiltinFunctionCall): VmCodeChunk {
val chunk = VmCodeChunk()
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall1" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall2" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
val vExpr2 = call.args[2] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall3" -> {
val vExpr = call.args[0] as PtNumber
val vExpr1 = call.args[1] as PtNumber
val vExpr2 = call.args[2] as PtNumber
val vExpr3 = call.args[3] as PtNumber
// TODO assign regs
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
else -> {
TODO("builtinfunc ${call.name}")
}
}
return chunk
}
}

View File

@ -5,6 +5,8 @@ import prog8.code.ast.*
import prog8.code.core.*
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.DataType
class CodeGen(internal val program: PtProgram,
internal val symbolTable: SymbolTable,
@ -12,6 +14,9 @@ class CodeGen(internal val program: PtProgram,
internal val errors: IErrorReporter
): IAssemblyGenerator {
internal val allocations = VariableAllocator(symbolTable, program, errors)
private val builtinFunctions = BuiltinFunctionsGen(this)
private val expressionEval = ExpressionGen(this, builtinFunctions)
private val instructions = mutableListOf<String>()
init {
@ -21,54 +26,76 @@ class CodeGen(internal val program: PtProgram,
override fun compileToAssembly(): IAssemblyProgram? {
instructions.clear()
val allocations = VariableAllocator(symbolTable, program, errors)
val vmprog = AssemblyProgram(program.name, allocations)
outComment("GLOBAL VARS INITS")
program.allBlocks().forEach {
it.children
.singleOrNull { node->node is PtScopeVarsInit }
?.let { inits->
translateNode(inits)
?.let { inits ->
vmprog.addGlobalInits(translate(inits as PtScopeVarsInit))
it.children.remove(inits)
}
}
outComment("PROGRAM CODE")
for (block in program.allBlocks()) {
translateNode(block)
vmprog.addBlock(translate(block))
}
return AssemblyProgram(program.name, allocations, instructions)
return vmprog
}
private fun out(ins: Instruction) {
instructions.add(ins.toString())
private fun translate(assignment: PtAssignment): VmCodeChunk {
val chunk = VmCodeChunk()
val (expressionChunk, resultRegister) = expressionEval.translateExpression(assignment.value)
chunk += expressionChunk
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
val vmDt = vmType(assignment.value.type)
if(ident!=null) {
val address = allocations.get(ident.targetName)
val ins = Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
chunk += VmCodeInstruction(ins)
}
else if(array!=null) {
TODO("assign to array")
}
else if(memory!=null) {
val ins =
if(memory.address is PtNumber) {
Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
// TODO make sure the registers used in this eval don't overlap with the one above
val (addrExpressionChunk, addressRegister) = expressionEval.translateExpression(assignment.value)
chunk += addrExpressionChunk
Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
}
chunk += VmCodeInstruction(ins)
}
else
throw AssemblyError("weird assigntarget")
return chunk
}
private fun outComment(ins: String) {
instructions.add("; $ins")
}
private fun translateNode(node: PtNode) {
when(node) {
private fun translateNode(node: PtNode): VmCodeChunk {
return when(node) {
is PtBlock -> translate(node)
is PtSub -> translate(node)
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
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 PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table
is PtVariable -> VmCodeChunk() // var should be looked up via symbol table
is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table
is PtConstant -> VmCodeChunk() // constants have all been folded into the code
is PtAssignTarget -> TODO()
is PtAssignment -> translate(node)
is PtScopeVarsInit -> translate(node)
is PtBreakpoint -> translate(node)
is PtConditionalBranch -> TODO()
is PtAddressOf -> TODO()
is PtArrayIndexer -> TODO()
is PtArrayLiteral -> TODO()
is PtBinaryExpression -> TODO()
is PtBuiltinFunctionCall -> TODO()
is PtBuiltinFunctionCall -> builtinFunctions.translate(node)
is PtContainmentCheck -> TODO()
is PtFunctionCall -> TODO()
is PtFunctionCall -> translate(node)
is PtIdentifier -> TODO()
is PtMemoryByte -> TODO()
is PtNumber -> TODO()
@ -78,55 +105,103 @@ class CodeGen(internal val program: PtProgram,
is PtString -> TODO()
is PtTypeCast -> TODO()
is PtForLoop -> TODO()
is PtGosub -> TODO()
is PtGosub -> translate(node)
is PtIfElse -> TODO()
is PtIncludeBinary -> TODO()
is PtJump -> TODO()
is PtNodeGroup -> TODO()
is PtNop -> { }
is PtNop -> VmCodeChunk()
is PtPostIncrDecr -> TODO()
is PtProgram -> TODO()
is PtRepeatLoop -> TODO()
is PtReturn -> TODO()
is PtReturn -> translate(node)
is PtSubroutineParameter -> TODO()
is PtWhen -> TODO()
is PtWhenChoice -> TODO()
is PtLabel -> TODO()
is PtBreakpoint -> TODO()
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target")
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target")
is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target")
else -> TODO("missing codegen for $node")
}
}
private fun translate(breakpoint: PtBreakpoint) {
out(Instruction(Opcode.BREAKPOINT))
private fun translate(fcall: PtFunctionCall): VmCodeChunk {
val chunk = VmCodeChunk()
// TODO evaluate function call arguments
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(fcall.functionName))
return chunk
}
private fun translate(init: PtScopeVarsInit) {
init.children.forEach { translateNode(it) }
private fun translate(gosub: PtGosub): VmCodeChunk {
val chunk = VmCodeChunk()
if(gosub.address!=null)
throw AssemblyError("cannot gosub to a memory address in the vm target")
else if(gosub.identifier!=null) {
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier!!.targetName))
} else if(gosub.generatedLabel!=null) {
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(listOf(gosub.generatedLabel!!)))
}
return chunk
}
private fun translate(sub: PtSub) {
outComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
private fun translate(ret: PtReturn): VmCodeChunk {
val chunk = VmCodeChunk()
val value = ret.value
if(value!=null) {
val (expressionChunk, resultRegister) = expressionEval.translateExpression(value)
chunk += expressionChunk
if(resultRegister!=0)
chunk += VmCodeInstruction(Instruction(Opcode.LOADR, vmType(value.type), reg1=0, reg2=resultRegister))
}
chunk += VmCodeInstruction(Instruction(Opcode.RETURN))
return chunk
}
internal fun vmType(type: prog8.code.core.DataType): DataType {
return when(type) {
prog8.code.core.DataType.UBYTE,
prog8.code.core.DataType.BYTE -> DataType.BYTE
prog8.code.core.DataType.UWORD,
prog8.code.core.DataType.WORD -> DataType.WORD
in PassByReferenceDatatypes -> DataType.WORD
else -> throw AssemblyError("no vm datatype for $type")
}
}
private fun translate(init: PtScopeVarsInit): VmCodeChunk {
val chunk = VmCodeChunk()
init.children.forEach { chunk += translateNode(it) }
return chunk
}
private fun translate(sub: PtSub): VmCodeChunk {
val chunk = VmCodeChunk()
chunk += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
chunk += VmCodeLabel(sub.scopedName)
sub.children
.singleOrNull { it is PtScopeVarsInit }
?.let { inits ->
sub.children.remove(inits)
translateNode(inits)
chunk += translateNode(inits)
}
// TODO rest
outComment("SUB-END ${sub.scopedName}\n")
}
private fun translate(assign: PtAssignment) {
outComment("ASSIGN: ${assign.target.identifier?.targetName} = ${assign.value}")
}
private fun translate(block: PtBlock) {
outComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children) {
translateNode(child)
for (child in sub.children) {
chunk += translateNode(child)
}
outComment("BLOCK-END '${block.name}'\n")
chunk += VmCodeComment("SUB-END '${sub.name}'")
return chunk
}
private fun translate(block: PtBlock): VmCodeChunk {
val chunk = VmCodeChunk()
chunk += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children)
chunk += translateNode(child)
chunk += VmCodeComment("BLOCK-END '${block.name}'")
return chunk
}
internal fun gosubArg(targetName: List<String>) = "_${targetName.joinToString(".")}"
}

View File

@ -0,0 +1,83 @@
package prog8.codegen.virtual
import prog8.code.ast.*
import prog8.code.core.AssemblyError
import prog8.vm.Instruction
import prog8.vm.Opcode
internal class ExpressionGen(val codeGen: CodeGen, val builtinFunctions: BuiltinFunctionsGen) {
fun translateExpression(expr: PtExpression): Pair<VmCodeChunk, Int> {
// TODO("Not yet implemented")
val chunk = VmCodeChunk()
val vmDt = codeGen.vmType(expr.type)
val resultRegister = 0 // TODO need a way to make this dynamic to avoid clobbering existing registers
fun process(code: VmCodeChunk, actualResultReg: Int) {
chunk += code
if(actualResultReg!=resultRegister)
chunk += VmCodeInstruction(Instruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=actualResultReg))
}
when (expr) {
is PtNumber -> {
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()))
}
is PtIdentifier -> {
val mem = codeGen.allocations.get(expr.targetName)
chunk += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem))
}
is PtAddressOf -> {
val mem = codeGen.allocations.get(expr.identifier.targetName)
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
}
is PtMemoryByte -> {
val (addressExprCode, addressRegister) = translateExpression(expr.address)
process(addressExprCode, addressRegister)
}
is PtTypeCast -> TODO()
is PtPrefix -> TODO()
is PtArrayIndexer -> TODO()
is PtBinaryExpression -> {
val (exprCode, functionResultReg) = translate(expr)
process(exprCode, functionResultReg)
}
is PtBuiltinFunctionCall -> TODO()
is PtContainmentCheck -> TODO()
is PtFunctionCall -> {
val (callCode, functionResultReg) = translate(expr)
process(callCode, functionResultReg)
}
is PtPipe -> TODO()
is PtRange -> TODO()
is PtArrayLiteral -> TODO()
is PtString -> TODO()
else -> throw AssemblyError("weird expression")
}
return Pair(chunk, resultRegister)
}
private fun translate(binExpr: PtBinaryExpression): Pair<VmCodeChunk, Int> {
val chunk = VmCodeChunk()
val (leftCode, leftResultReg) = translateExpression(binExpr.left)
val (rightCode, rightResultReg) = translateExpression(binExpr.right)
chunk += leftCode
chunk += rightCode
val resultRegister = 0 // TODO binexpr result can't always be in r0...
when(binExpr.operator) {
"+" -> {
chunk += VmCodeInstruction(Instruction(Opcode.ADD, codeGen.vmType(binExpr.type), reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
else -> TODO("operator ${binExpr.operator}")
}
return Pair(chunk, resultRegister)
}
private fun translate(fcall: PtFunctionCall): Pair<VmCodeChunk, Int> {
require(!fcall.void)
val chunk = VmCodeChunk()
// TODO evaluate arguments
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, codeGen.gosubArg(fcall.functionName))
return Pair(chunk, 0) // TODO function result always in r0?
}
}

View File

@ -27,13 +27,10 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg
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>()
fun get(name: List<String>) = allocations.getValue(name)
fun asVmMemory(): List<Pair<List<String>, String>> {
val mm = mutableListOf<Pair<List<String>, String>>()
for (variable in st.allVariables) {
val location = allocations.getValue(variable.scopedName)
val typeStr = when(variable.dt) {
@ -67,7 +64,7 @@ $2100 uword $1111,$2222,$3333,$4444
}
else -> throw InternalCompilerException("weird dt")
}
mm.add("${location.toHex()} $typeStr $value")
mm.add(Pair(variable.scopedName, "${location.toHex()} $typeStr $value"))
}
return mm
}

View File

@ -3,6 +3,10 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- first for virtual target: do not create tempvars for return statements (StatementOptimizer)
maybe other places as well?
- in new AST: combine param assignments + GoSub, back into PtFunctionCall node. PtGosub node should not exist.
...

View File

@ -1,65 +1,16 @@
%import textio
main {
ubyte[256] sieve
ubyte candidate_prime = 2 ; is increased in the loop
ubyte variable = 42
sub start() {
sys.memset(sieve, 256, false) ; clear the sieve, to reset starting situation on subsequent runs
txt.print("value=")
txt.print_ub(variable)
syscall(1)
syscall1(1, 1111)
syscall2(1, 1111, 2222)
syscall3(1, 1111, 2222, 3333)
%breakpoint
%asmbinary "LICENSE", 10 ,1
%asm {{
nop
}}
; calculate primes
txt.print("prime numbers up to 255:\n\n")
ubyte amount=0
repeat {
ubyte prime = find_next_prime()
if prime==0
break
txt.print_ub(prime)
txt.print(", ")
amount++
}
txt.nl()
txt.print("number of primes (expected 54): ")
txt.print_ub(amount)
txt.nl()
uword[] @shared array = [111,222,333,444,555]
amount = amount |> sin8u() |> cos8u() |> sin8u()
; test_stack.test()
variable = foo()
}
sub find_next_prime() -> ubyte {
while sieve[candidate_prime] {
candidate_prime++
if candidate_prime==0
return 0 ; we wrapped; no more primes available in the sieve
}
; found next one, mark the multiples and return it.
sieve[candidate_prime] = true
uword multiple = candidate_prime
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
}
return candidate_prime
sub foo() -> ubyte {
return variable+1
}
}

View File

@ -12,7 +12,7 @@ class Assembler {
fun initializeMemory(memsrc: String, memory: Memory) {
val instrPattern = Regex("""(.+?)\s+([a-z]+)\s+(.+)""", RegexOption.IGNORE_CASE)
for(line in memsrc.lines()) {
if(line.isBlank())
if(line.isBlank() || line.startsWith(';'))
continue
val match = instrPattern.matchEntire(line.trim())
if(match==null)
@ -54,7 +54,7 @@ class Assembler {
placeholders.clear()
val program = mutableListOf<Instruction>()
val instructionPattern = Regex("""([a-z]+)(\.b|\.w)?(.*)""", RegexOption.IGNORE_CASE)
val labelPattern = Regex("""_([a-z0-9]+):""")
val labelPattern = Regex("""_([a-z0-9\._]+):""")
for (line in source.lines()) {
if(line.isBlank() || line.startsWith(';'))
continue

View File

@ -24,7 +24,7 @@ Currently NO support for 24 or 32 bits, and FLOATING POINT is not implemented ye
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
LOAD/STORE -- all have type b/w/f. (note: float not yet implemented)
LOAD/STORE -- all have type b/w
load reg1, value - load immediate value into register
@ -49,9 +49,9 @@ Subroutine parameters set in Reg 0, 1, 2... before gosub.
Return value in Reg 0 before return.
jump location - continue running at instruction number given by location
jumpi reg1 - continue running at instruction number given by reg1
jumpi reg1 - continue running at instruction number in reg1
gosub location - save current instruction location+1, continue execution at location
gosubi reg1 - gosub to subroutine at instruction number given by reg1
gosubi reg1 - gosub to subroutine at instruction number in reg1
syscall value - do a systemcall identified by call number
return - restore last saved instruction location and continue at that instruction
@ -70,14 +70,12 @@ bge reg1, reg2, value - jump to location in program given by val
bges reg1, reg2, value - jump to location in program given by value, if reg1 >= reg2 (signed)
ARITHMETIC - all have a type of b/w/f. (note: float not yet implemented)
(note: for calculations, all types -result, and both operands- are identical)
INTEGER ARITHMETIC - all have a type of b/w.
(note: the types of the result and both operands, are all identical UNLESS OTHERWISE NOTED).
neg reg1, reg2 - reg1 = sign negation of reg2
add reg1, reg2, reg3 - reg1 = reg2+reg3 (unsigned + signed)
addi reg1, reg2, value - reg1 = reg2+value (unsigned + signed)
sub reg1, reg2, reg3 - reg1 = reg2-reg3 (unsigned + signed)
subi reg1, reg2, value - reg1 = reg2-value (unsigned + signed)
ext reg1, reg2 - reg1 = unsigned extension of reg2 (which in practice just means clearing the MSB / MSW) (latter not yet implemented as we don't have longs yet)
exts reg1, reg2 - reg1 = signed extension of reg2 (byte to word, or word to long) (note: latter ext.w, not yet implemented as we don't have longs yet)
mul reg1, reg2, reg3 - unsigned multiply reg1=reg2*reg3 note: byte*byte->byte, no type extension to word!
@ -145,9 +143,7 @@ enum class Opcode {
NEG,
ADD,
ADDI,
SUB,
SUBI,
MUL,
DIV,
EXT,
@ -171,7 +167,7 @@ enum class Opcode {
enum class DataType {
BYTE,
WORD
// TODO add LONG? FLOAT?
// TODO add INT (32-bit)?
}
data class Instruction(
@ -190,22 +186,22 @@ data class Instruction(
else -> result.add(" ")
}
reg1?.let {
result.add(it.toString())
result.add("r$it")
result.add(",")
}
reg2?.let {
result.add(it.toString())
result.add("r$it")
result.add(",")
}
reg3?.let {
result.add(it.toString())
result.add("r$it")
result.add(",")
}
value?.let {
result.add(it.toString())
}
if(result.last() == ",")
result.dropLast(1)
result.removeLast()
return result.joinToString("").trimEnd()
}
}
@ -253,9 +249,7 @@ val instructionFormats = mutableMapOf(
Opcode.NEG to InstructionFormat(BW, true, true, false, false),
Opcode.ADD to InstructionFormat(BW, true, true, true, false),
Opcode.ADDI to InstructionFormat(BW, true, true, false, true ),
Opcode.SUB to InstructionFormat(BW, true, true, true, false),
Opcode.SUBI to InstructionFormat(BW, true, true, false, true ),
Opcode.MUL to InstructionFormat(BW, true, true, true, false),
Opcode.DIV to InstructionFormat(BW, true, true, true, false),
Opcode.EXT to InstructionFormat(BW, true, true, false, false),

View File

@ -109,9 +109,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
Opcode.BGES -> InsBGES(ins)
Opcode.NEG -> InsNEG(ins)
Opcode.ADD -> InsADD(ins)
Opcode.ADDI -> InsADDI(ins)
Opcode.SUB -> InsSUB(ins)
Opcode.SUBI -> InsSUBI(ins)
Opcode.MUL -> InsMul(ins)
Opcode.DIV -> InsDiv(ins)
Opcode.EXT -> InsEXT(ins)
@ -474,14 +472,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
registers.setW(reg1, result.toUShort())
}
private fun InsADDI(i: Instruction) {
when(i.type!!) {
DataType.BYTE -> arithByte("+", i.reg1!!, i.reg2!!, null, i.value!!.toUByte())
DataType.WORD -> arithWord("+", i.reg1!!, i.reg2!!, null, i.value!!.toUShort())
}
pc++
}
private fun InsSUB(i: Instruction) {
when(i.type!!) {
DataType.BYTE -> arithByte("-", i.reg1!!, i.reg2!!, i.reg3!!, null)
@ -490,14 +480,6 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
pc++
}
private fun InsSUBI(i: Instruction) {
when(i.type!!) {
DataType.BYTE -> arithByte("-", i.reg1!!, i.reg2!!, null, i.value!!.toUByte())
DataType.WORD -> arithWord("-", i.reg1!!, i.reg2!!, null, i.value!!.toUShort())
}
pc++
}
private fun InsEXT(i: Instruction) {
when(i.type!!){
DataType.BYTE -> registers.setW(i.reg1!!, registers.getB(i.reg2!!).toUShort())