From e41d6787bb868afcce8d46b554e20c04e1ebed5a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 27 Mar 2022 14:23:01 +0200 Subject: [PATCH] working on vm --- codeAst/src/prog8/code/SymbolTable.kt | 6 + codeAst/src/prog8/code/ast/AstExpressions.kt | 4 +- .../prog8/codegen/virtual/ExpressionGen.kt | 44 +++- .../astprocessing/SymbolTableMaker.kt | 4 + examples/test.p8 | 60 ++--- virtualmachine/src/prog8/vm/Instructions.kt | 30 +++ virtualmachine/src/prog8/vm/VirtualMachine.kt | 206 +++++++++++++----- 7 files changed, 267 insertions(+), 87 deletions(-) diff --git a/codeAst/src/prog8/code/SymbolTable.kt b/codeAst/src/prog8/code/SymbolTable.kt index d101a1d37..7c4c70b5e 100644 --- a/codeAst/src/prog8/code/SymbolTable.kt +++ b/codeAst/src/prog8/code/SymbolTable.kt @@ -161,6 +161,12 @@ class StStaticVariable(name: String, require(arraysize == initialArrayValue.size) if(arraysize!=null || initialArrayValue!=null) require(initialStringValue==null && initialNumericValue==null) + if(initialNumericValue!=null) + require(dt in NumericDatatypes) + if(initialArrayValue!=null || arraysize!=null) + require(dt in ArrayDatatypes) + if(initialStringValue!=null) + require(dt == DataType.STR) } override fun printProperties() { diff --git a/codeAst/src/prog8/code/ast/AstExpressions.kt b/codeAst/src/prog8/code/ast/AstExpressions.kt index 2169e7c26..ddb2815a3 100644 --- a/codeAst/src/prog8/code/ast/AstExpressions.kt +++ b/codeAst/src/prog8/code/ast/AstExpressions.kt @@ -58,8 +58,8 @@ class PtBinaryExpression(val operator: String, type: DataType, position: Positio class PtContainmentCheck(position: Position): PtExpression(DataType.UBYTE, position) { val element: PtExpression get() = children[0] as PtExpression - val iterable: PtExpression - get() = children[0] as PtExpression + val iterable: PtIdentifier + get() = children[0] as PtIdentifier } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index d93b37afb..62f472399 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -1,10 +1,12 @@ package prog8.codegen.virtual +import prog8.code.StStaticVariable import prog8.code.StSub import prog8.code.ast.* import prog8.code.core.AssemblyError import prog8.code.core.DataType import prog8.code.core.PassByValueDatatypes +import prog8.code.core.SignedDatatypes import prog8.vm.Instruction import prog8.vm.Opcode import prog8.vm.VmDataType @@ -54,7 +56,7 @@ internal class ExpressionGen(val codeGen: CodeGen) { is PtBinaryExpression -> code += translate(expr, resultRegister, regUsage) is PtBuiltinFunctionCall -> code += translate(expr, resultRegister, regUsage) is PtFunctionCall -> code += translate(expr, resultRegister, regUsage) - is PtContainmentCheck -> TODO() + is PtContainmentCheck -> code += translate(expr, resultRegister, regUsage) is PtPipe -> TODO() is PtRange, is PtArrayLiteral, @@ -64,6 +66,21 @@ internal class ExpressionGen(val codeGen: CodeGen) { return code } + private fun translate(check: PtContainmentCheck, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { + val iterableIdent = check.iterable + val iterable = codeGen.symbolTable.flat.getValue(iterableIdent.targetName) as StStaticVariable + when(iterable.dt) { + DataType.STR -> println("CONTAINMENT CHECK ${check.element} in string $iterable ${iterable.initialStringValue}") + DataType.ARRAY_UB -> println("CONTAINMENT CHECK ${check.element} in UB-array $iterable ${iterable.initialArrayValue}") + DataType.ARRAY_B -> println("CONTAINMENT CHECK ${check.element} in B-array $iterable ${iterable.initialArrayValue}") + DataType.ARRAY_UW -> println("CONTAINMENT CHECK ${check.element} in UW-array $iterable ${iterable.initialArrayValue}") + DataType.ARRAY_W -> println("CONTAINMENT CHECK ${check.element} in W-array $iterable ${iterable.initialArrayValue}") + DataType.ARRAY_F -> TODO("containment check in float-array") + else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${iterableIdent.targetName}") + } + return VmCodeChunk() + } + private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk { val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type) val vmDt = codeGen.vmType(arrayIx.type) @@ -194,9 +211,9 @@ internal class ExpressionGen(val codeGen: CodeGen) { val code = VmCodeChunk() val leftResultReg = regUsage.nextFree() val rightResultReg = regUsage.nextFree() + // TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. val leftCode = translateExpression(binExpr.left, leftResultReg, regUsage) val rightCode = translateExpression(binExpr.right, rightResultReg, regUsage) - // TODO: optimized codegen when left or right operand is known 0 or 1 or whatever. code += leftCode code += rightCode val vmDt = codeGen.vmType(binExpr.type) @@ -231,7 +248,28 @@ internal class ExpressionGen(val codeGen: CodeGen) { ">>" -> { code += VmCodeInstruction(Instruction(Opcode.LSR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) } - // TODO the other operators: "==", "!=", "<", ">", "<=", ">=" + "==" -> { + code += VmCodeInstruction(Instruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } + "!=" -> { + code += VmCodeInstruction(Instruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } + "<" -> { + val ins = if(binExpr.type in SignedDatatypes) Opcode.SLTS else Opcode.SLT + code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } + ">" -> { + val ins = if(binExpr.type in SignedDatatypes) Opcode.SGTS else Opcode.SGT + code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } + "<=" -> { + val ins = if(binExpr.type in SignedDatatypes) Opcode.SLES else Opcode.SLE + code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } + ">=" -> { + val ins = if(binExpr.type in SignedDatatypes) Opcode.SGES else Opcode.SGE + code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + } else -> TODO("operator ${binExpr.operator}") } return code diff --git a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt b/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt index b138af5ad..aefe0c3fc 100644 --- a/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SymbolTableMaker.kt @@ -6,6 +6,8 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor import prog8.code.* +import prog8.code.core.ArrayDatatypes +import prog8.code.core.ElementToArrayTypes import prog8.code.core.Position import java.util.* @@ -59,6 +61,8 @@ internal class SymbolTableMaker: IAstVisitor { val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding) val initialArrayLit = decl.value as? ArrayLiteral val initialArray = makeInitialArray(initialArrayLit) + if(decl.isArray && decl.datatype !in ArrayDatatypes) + throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}") StStaticVariable(decl.name, decl.datatype, initialNumeric, initialString, initialArray, decl.arraysize?.constIndex(), decl.zeropage, decl.position) } VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position) diff --git a/examples/test.p8 b/examples/test.p8 index 5f92d2645..bb5244bc5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,3 @@ -%import floats %import textio ; NOTE: meant to test to virtual machine output target (use -target vitual) @@ -7,34 +6,43 @@ main { sub start() { txt.clear_screen() txt.print("Welcome to a prog8 pixel shader :-)\n") - float fl = 9.9 - fl = floats.pow(fl, 3.0) - txt.print("fl=") - floats.print_f(fl) + ubyte bb = 4 + ubyte[] array = [1,2,3,4,5,6] + str tekst = "test" + uword ww = 19 + bb = bb in "teststring" + bb++ + bb = bb in [1,2,3,4,5,6] + bb++ + bb = bb in array + bb++ + bb = bb in tekst + txt.print("bb=") + txt.print_ub(bb) txt.nl() sys.exit(99) -; syscall1(8, 0) ; enable lo res creen -; ubyte shifter -; -; shifter >>= 1 -; -; repeat { -; uword xx -; uword yy = 0 -; repeat 240 { -; xx = 0 -; repeat 320 { -; syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel -; xx++ -; } -; yy++ -; } -; shifter+=4 -; -; txt.print_ub(shifter) -; txt.nl() -; } + syscall1(8, 0) ; enable lo res creen + ubyte shifter + + shifter >>= 1 + + repeat { + uword xx + uword yy = 0 + repeat 240 { + xx = 0 + repeat 320 { + syscall3(10, xx, yy, xx*yy + shifter) ; plot pixel + xx++ + } + yy++ + } + shifter+=4 + + txt.print_ub(shifter) + txt.nl() + } } } diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 0ba91933b..eeeac7a7e 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -74,6 +74,16 @@ bgt reg1, reg2, value - jump to location in program given by val bgts reg1, reg2, value - jump to location in program given by value, if reg1 > reg2 (signed) bge reg1, reg2, value - jump to location in program given by value, if reg1 >= reg2 (unsigned) bges reg1, reg2, value - jump to location in program given by value, if reg1 >= reg2 (signed) +seq reg1, reg2, reg3 - set reg=1 if reg2 == reg3, otherwise set reg1=0 +sne reg1, reg2, reg3 - set reg=1 if reg2 != reg3, otherwise set reg1=0 +slt reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (unsigned), otherwise set reg1=0 +slts reg1, reg2, reg3 - set reg=1 if reg2 < reg3 (signed), otherwise set reg1=0 +sle reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (unsigned), otherwise set reg1=0 +sles reg1, reg2, reg3 - set reg=1 if reg2 <= reg3 (signed), otherwise set reg1=0 +sgt reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (unsigned), otherwise set reg1=0 +sgts reg1, reg2, reg3 - set reg=1 if reg2 > reg3 (signed), otherwise set reg1=0 +sge reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (unsigned), otherwise set reg1=0 +sges reg1, reg2, reg3 - set reg=1 if reg2 >= reg3 (signed), otherwise set reg1=0 TODO: support for the prog8 special branching instructions if_XX (bcc, bcs etc.) but we don't have any 'processor flags' whatsoever in the vm so it's a bit weird @@ -159,6 +169,16 @@ enum class Opcode { BLES, BGE, BGES, + SEQ, + SNE, + SLT, + SLTS, + SGT, + SGTS, + SLE, + SLES, + SGE, + SGES, INC, DEC, @@ -271,6 +291,16 @@ val instructionFormats = mutableMapOf( Opcode.BLES to InstructionFormat(BW, true, true, false, true ), Opcode.BGE to InstructionFormat(BW, true, true, false, true ), Opcode.BGES to InstructionFormat(BW, true, true, false, true ), + Opcode.SEQ to InstructionFormat(BW, true, true, true, false), + Opcode.SNE to InstructionFormat(BW, true, true, true, false), + Opcode.SLT to InstructionFormat(BW, true, true, true, false), + Opcode.SLTS to InstructionFormat(BW, true, true, true, false), + Opcode.SGT to InstructionFormat(BW, true, true, true, false), + Opcode.SGTS to InstructionFormat(BW, true, true, true, false), + Opcode.SLE to InstructionFormat(BW, true, true, true, false), + Opcode.SLES to InstructionFormat(BW, true, true, true, false), + Opcode.SGE to InstructionFormat(BW, true, true, true, false), + Opcode.SGES to InstructionFormat(BW, true, true, true, false), Opcode.INC to InstructionFormat(BW, true, false, false, false), Opcode.DEC to InstructionFormat(BW, true, false, false, false), diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 8866e1aeb..77388bc1c 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -108,6 +108,17 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.BLES -> InsBLES(ins) Opcode.BGE -> InsBGEU(ins) Opcode.BGES -> InsBGES(ins) + Opcode.SEQ -> InsSEQ(ins) + Opcode.SNE -> InsSNE(ins) + Opcode.SLT -> InsSLT(ins) + Opcode.SLTS -> InsSLTS(ins) + Opcode.SGT -> InsSGT(ins) + Opcode.SGTS -> InsSGTS(ins) + Opcode.SLE -> InsSLE(ins) + Opcode.SLES -> InsSLES(ins) + Opcode.SGE -> InsSGE(ins) + Opcode.SGES -> InsSGES(ins) + Opcode.INC -> InsINC(ins) Opcode.DEC -> InsDEC(ins) Opcode.NEG -> InsNEG(ins) @@ -135,37 +146,33 @@ class VirtualMachine(val memory: Memory, program: List) { } } - private fun InsPUSH(ins: Instruction) { + private inline fun setResultReg(reg: Int, value: Int, type: VmDataType) { + when(type) { + VmDataType.BYTE -> registers.setB(reg, value.toUByte()) + VmDataType.WORD -> registers.setW(reg, value.toUShort()) + } + } + + private fun InsPUSH(i: Instruction) { if(valueStack.size>=128) throw StackOverflowError("valuestack limit 128 exceeded") - val value = when(ins.type!!) { - VmDataType.BYTE -> { - registers.getB(ins.reg1!!).toInt() - } - VmDataType.WORD -> { - registers.getW(ins.reg1!!).toInt() - } + val value = when(i.type!!) { + VmDataType.BYTE -> registers.getB(i.reg1!!).toInt() + VmDataType.WORD -> registers.getW(i.reg1!!).toInt() } valueStack.push(value) pc++ } - private fun InsPOP(ins: Instruction) { + private fun InsPOP(i: Instruction) { val value = valueStack.pop() - when(ins.type!!) { - VmDataType.BYTE -> { - registers.setB(ins.reg1!!, value.toUByte()) - } - VmDataType.WORD -> { - registers.setW(ins.reg1!!, value.toUShort()) - } - } + setResultReg(i.reg1!!, value, i.type!!) pc++ } - private fun InsSYSCALL(ins: Instruction) { - val call = Syscall.values()[ins.value!!] + private fun InsSYSCALL(i: Instruction) { + val call = Syscall.values()[i.value!!] SysCalls.call(call, this) pc++ } @@ -176,10 +183,7 @@ class VirtualMachine(val memory: Memory, program: List) { } private fun InsLOAD(i: Instruction) { - when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, i.value!!.toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, i.value!!.toUShort()) - } + setResultReg(i.reg1!!, i.value!!, i.type!!) pc++ } @@ -198,6 +202,7 @@ class VirtualMachine(val memory: Memory, program: List) { } pc++ } + private fun InsLOADX(i: Instruction) { when (i.type!!) { VmDataType.BYTE -> registers.setB(i.reg1!!, memory.getB(i.value!! + registers.getW(i.reg2!!).toInt())) @@ -268,6 +273,7 @@ class VirtualMachine(val memory: Memory, program: List) { } pc++ } + private fun InsSTOREZX(i: Instruction) { when (i.type!!) { VmDataType.BYTE -> memory.setB(registers.getW(i.reg2!!).toInt() + i.value!!, 0u) @@ -343,30 +349,6 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } - private fun getBranchOperands(i: Instruction): Pair { - return when(i.type) { - VmDataType.BYTE -> Pair(registers.getB(i.reg1!!).toInt(), registers.getB(i.reg2!!).toInt()) - VmDataType.WORD -> Pair(registers.getW(i.reg1!!).toInt(), registers.getW(i.reg2!!).toInt()) - null -> throw IllegalArgumentException("need type for branch instruction") - } - } - - private fun getBranchOperandsU(i: Instruction): Pair { - return when(i.type) { - VmDataType.BYTE -> Pair(registers.getB(i.reg1!!).toUInt(), registers.getB(i.reg2!!).toUInt()) - VmDataType.WORD -> Pair(registers.getW(i.reg1!!).toUInt(), registers.getW(i.reg2!!).toUInt()) - null -> throw IllegalArgumentException("need type for branch instruction") - } - } - - private fun getLogicalOperandsU(i: Instruction): Pair { - return when(i.type) { - VmDataType.BYTE -> Pair(registers.getB(i.reg2!!).toUInt(), registers.getB(i.reg3!!).toUInt()) - VmDataType.WORD -> Pair(registers.getW(i.reg2!!).toUInt(), registers.getW(i.reg3!!).toUInt()) - null -> throw IllegalArgumentException("need type for logical instruction") - } - } - private fun InsBNE(i: Instruction) { val (left: Int, right: Int) = getBranchOperands(i) if(left!=right) @@ -442,6 +424,78 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsSEQ(i: Instruction) { + val (resultReg: Int, left: Int, right: Int) = getSetOnConditionOperands(i) + val value = if(left==right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSNE(i: Instruction) { + val (resultReg: Int, left: Int, right: Int) = getSetOnConditionOperands(i) + val value = if(left!=right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSLT(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperandsU(i) + val value = if(leftright) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSGTS(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperands(i) + val value = if(left>right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSLE(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperandsU(i) + val value = if(left<=right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSLES(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperands(i) + val value = if(left<=right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + } + + private fun InsSGE(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperandsU(i) + val value = if(left>=right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + + } + + private fun InsSGES(i: Instruction) { + val (resultReg, left, right) = getSetOnConditionOperands(i) + val value = if(left>=right) 1 else 0 + setResultReg(resultReg, value, i.type!!) + pc++ + + } + private fun InsINC(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> registers.setB(i.reg1!!, (registers.getB(i.reg1)+1u).toUByte()) @@ -625,6 +679,18 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsSWAP(i: Instruction) { + when(i.type!!) { + VmDataType.BYTE -> { + val value = registers.getW(i.reg2!!) + val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt() + registers.setW(i.reg1!!, newValue.toUShort()) + } + VmDataType.WORD -> TODO("swap.w requires 32-bits registers") + } + pc++ + } + private fun InsCOPY(i: Instruction) = doCopy(i.reg1!!, i.reg2!!, i.reg3!!, false) private fun InsCOPYZ(i: Instruction) = doCopy(i.reg1!!, i.reg2!!, null, true) @@ -654,16 +720,44 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } - private fun InsSWAP(i: Instruction) { - when(i.type!!) { - VmDataType.BYTE -> { - val value = registers.getW(i.reg2!!) - val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt() - registers.setW(i.reg1!!, newValue.toUShort()) - } - VmDataType.WORD -> TODO("swap.w requires 32-bits registers") + private fun getBranchOperands(i: Instruction): Pair { + return when(i.type) { + VmDataType.BYTE -> Pair(registers.getB(i.reg1!!).toInt(), registers.getB(i.reg2!!).toInt()) + VmDataType.WORD -> Pair(registers.getW(i.reg1!!).toInt(), registers.getW(i.reg2!!).toInt()) + null -> throw IllegalArgumentException("need type for branch instruction") + } + } + + private fun getBranchOperandsU(i: Instruction): Pair { + return when(i.type) { + VmDataType.BYTE -> Pair(registers.getB(i.reg1!!).toUInt(), registers.getB(i.reg2!!).toUInt()) + VmDataType.WORD -> Pair(registers.getW(i.reg1!!).toUInt(), registers.getW(i.reg2!!).toUInt()) + null -> throw IllegalArgumentException("need type for branch instruction") + } + } + + private fun getLogicalOperandsU(i: Instruction): Pair { + return when(i.type) { + VmDataType.BYTE -> Pair(registers.getB(i.reg2!!).toUInt(), registers.getB(i.reg3!!).toUInt()) + VmDataType.WORD -> Pair(registers.getW(i.reg2!!).toUInt(), registers.getW(i.reg3!!).toUInt()) + null -> throw IllegalArgumentException("need type for logical instruction") + } + } + + private fun getSetOnConditionOperands(ins: Instruction): Triple { + return when(ins.type) { + VmDataType.BYTE -> Triple(ins.reg1!!, registers.getB(ins.reg2!!).toInt(), registers.getB(ins.reg3!!).toInt()) + VmDataType.WORD -> Triple(ins.reg1!!, registers.getW(ins.reg2!!).toInt(), registers.getW(ins.reg3!!).toInt()) + null -> throw IllegalArgumentException("need type for branch instruction") + } + } + + private fun getSetOnConditionOperandsU(ins: Instruction): Triple { + return when(ins.type) { + VmDataType.BYTE -> Triple(ins.reg1!!, registers.getB(ins.reg2!!).toUInt(), registers.getB(ins.reg3!!).toUInt()) + VmDataType.WORD -> Triple(ins.reg1!!, registers.getW(ins.reg2!!).toUInt(), registers.getW(ins.reg3!!).toUInt()) + null -> throw IllegalArgumentException("need type for branch instruction") } - pc++ } private var window: GraphicsWindow? = null