From 3e1a7c61021cfa9ac9ee578800d5858d34fb8320 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 28 Mar 2022 23:49:44 +0200 Subject: [PATCH] fix vm signed comparisons --- .../prog8/codegen/virtual/BuiltinFuncGen.kt | 7 + .../prog8/codegen/virtual/ExpressionGen.kt | 14 +- compiler/res/prog8lib/virtual/syslib.p8 | 23 +- docs/source/todo.rst | 3 +- examples/test.p8 | 39 +--- virtualmachine/src/prog8/vm/Assembler.kt | 4 +- virtualmachine/src/prog8/vm/Instructions.kt | 9 +- virtualmachine/src/prog8/vm/Memory.kt | 26 ++- virtualmachine/src/prog8/vm/Registers.kt | 22 +- virtualmachine/src/prog8/vm/SysCalls.kt | 31 ++- virtualmachine/src/prog8/vm/VirtualMachine.kt | 211 ++++++++++-------- 11 files changed, 234 insertions(+), 155 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt index 4ea695ab3..7a32f956d 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt @@ -92,6 +92,13 @@ internal class BuiltinFuncGen(val codeGen: CodeGen, val exprGen: ExpressionGen) code += exprGen.translateExpression(call.args.single(), addressReg, regUsage) code += VmCodeInstruction(Instruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)) } + "mkword" -> { + val msbReg = regUsage.nextFree() + val lsbReg = regUsage.nextFree() + code += exprGen.translateExpression(call.args[0], msbReg, regUsage) + code += exprGen.translateExpression(call.args[1], lsbReg, regUsage) + code += VmCodeInstruction(Instruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg, reg3=lsbReg)) + } else -> { TODO("builtinfunc ${call.name}") // code += VmCodeInstruction(Instruction(Opcode.NOP)) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index ea1057e0f..a21463e1d 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -233,7 +233,8 @@ internal class ExpressionGen(val codeGen: CodeGen) { val rightCode = translateExpression(binExpr.right, rightResultReg, regUsage) code += leftCode code += rightCode - val vmDt = codeGen.vmType(binExpr.type) + val vmDt = codeGen.vmType(binExpr.left.type) + val signed = binExpr.left.type in SignedDatatypes when(binExpr.operator) { "+" -> { code += VmCodeInstruction(Instruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) @@ -263,7 +264,8 @@ internal class ExpressionGen(val codeGen: CodeGen) { code += VmCodeInstruction(Instruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) } ">>" -> { - code += VmCodeInstruction(Instruction(Opcode.LSR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) + val opc = if(signed) Opcode.ASR else Opcode.LSR + code += VmCodeInstruction(Instruction(opc, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) } "==" -> { code += VmCodeInstruction(Instruction(Opcode.SEQ, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) @@ -272,19 +274,19 @@ internal class ExpressionGen(val codeGen: CodeGen) { code += VmCodeInstruction(Instruction(Opcode.SNE, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) } "<" -> { - val ins = if(binExpr.type in SignedDatatypes) Opcode.SLTS else Opcode.SLT + val ins = if(signed) 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 + val ins = if(signed) 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 + val ins = if(signed) 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 + val ins = if(signed) Opcode.SGES else Opcode.SGE code += VmCodeInstruction(Instruction(ins, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)) } else -> throw AssemblyError("weird operator ${binExpr.operator}") diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index cba444dd2..7e229b4cd 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -32,6 +32,9 @@ sys { const ubyte SC_GFX_ENABLE = 8 const ubyte SC_GFX_CLEAR = 9 const ubyte SC_GFX_PLOT = 10 + const ubyte SC_RND = 11 + const ubyte SC_WAIT = 12 + const ubyte SC_WAITVSYNC = 13 sub reset_system() { @@ -41,24 +44,34 @@ sys { sub wait(uword jiffies) { ; --- wait approximately the given number of jiffies (1/60th seconds) - ; TODO + syscall1(SC_WAIT, jiffies) } sub waitvsync() { ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. - ; TODO + syscall(SC_WAITVSYNC) } sub memcopy(uword source, uword target, uword count) { - ; TODO + repeat count { + @(target) = @(source) + source++ + target++ + } } sub memset(uword mem, uword numbytes, ubyte value) { - ; TODO + repeat numbytes { + @(mem) = value + mem++ + } } sub memsetw(uword mem, uword numwords, uword value) { - ; TODO + repeat numwords { + pokew(mem, value) + mem+=2 + } } sub exit(ubyte returnvalue) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8cd0b7580..94b8b8a8c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm codegen: fix ifelse comparisons such as if x< 0 - vm codegen: fix primes endless loop stuck on '2' - x16: check additional FP lib changes https://github.com/commanderx16/x16-rom/commit/ae608673f0210953172d6837acfbb231d62ddbd1 and https://github.com/commanderx16/x16-docs/commit/21238aedc641da91df88e04c4ce9bf3324a3c12d @@ -13,6 +12,7 @@ For next release broken examples: amiga, colorbars, cube3d, highresbitmap, rasterbars, tehtriz, testgfx2, testvtui can we make the code read the new layout from vera registers instead of hardcoding it? - x16: check new ZP free addresses https://github.com/commanderx16/x16-docs/commit/541f2ce9e61d1d0d0e157d7f52fe16bc0895e6f0 + and https://www.commanderx16.com/forum/index.php?/topic/363-keep-zero-page-empty-as-much-as-possible/#comment-18561 - x16: optimize diskio load_raw because headerless files are now supported https://github.com/commanderx16/x16-rom/pull/216 note: must still work on c64/c128 that don't have this! - major compiler version bump once X16 r39 rom is officially finalized @@ -23,6 +23,7 @@ For next release - vm codegen: postincrdecr arrayvalue - vm: support no globals re-init option - vm: how to remove all unused subroutines? (for asm, 64tass used to do this) +- vm: rather than being able to jump to any 'address' (IPTR), use 'blocks' - vm codegen/assembler: variable memory locations should also be referenced by the variable name instead of just the address - when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed. It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed. diff --git a/examples/test.p8 b/examples/test.p8 index c531d21f2..bdb7e3ed0 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,39 +4,13 @@ main { sub start() { - - byte bb = -9 - word ww = -1234 - if bb<0 { - txt.print("bb <0!\n") - } else { - txt.print("comparison error!\n") - } - if ww<0 { - txt.print("ww <0!\n") - } else { - txt.print("comparison error!\n") - } - if bb>0 { - txt.print("comparison error!\n") - } else { - txt.print("bb not >0\n") - } - if ww>0 { - txt.print("comparison error!\n") - } else { - txt.print("ww not >0\n") - } - - txt.print_w(ww) - txt.spc() - ww <<= 3 - txt.print_w(ww) + ubyte x1 = $ea + ubyte x2 = $31 + uword uw = mkword(x1, $99) + txt.print_uwhex(uw, true) txt.nl() - txt.print_b(bb) - txt.spc() - bb <<= 3 - txt.print_b(bb) + uw = mkword(x1, x2) + txt.print_uwhex(uw, true) txt.nl() sys.exit(99) @@ -80,6 +54,7 @@ main { ; sys.exit(99) + ; the "pixelshader": ; syscall1(8, 0) ; enable lo res creen ; ubyte shifter ; diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index 82d45c070..f5c3860e0 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -32,14 +32,14 @@ class Assembler { "ubyte", "byte" -> { val array = values.split(',').map { parseValue(it.trim(), 0) } for (value in array) { - memory.setB(address, value.toUByte()) + memory.setUB(address, value.toUByte()) address++ } } "uword", "word" -> { val array = values.split(',').map { parseValue(it.trim(), 0) } for (value in array) { - memory.setW(address, value.toUShort()) + memory.setUW(address, value.toUShort()) address++ } } diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index a36f35d01..e0ddaecb3 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -115,11 +115,11 @@ and reg1, reg2, reg3 - reg1 = reg2 bitwise and reg3 or reg1, reg2, reg3 - reg1 = reg2 bitwise or reg3 xor reg1, reg2, reg3 - reg1 = reg2 bitwise xor reg3 lsr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits +asr reg1, reg2, reg3 - reg1 = shift reg2 right by reg3 bits (signed) lsl reg1, reg2, reg3 - reg1 = shift reg2 left by reg3 bits ror reg1, reg2, reg3 - reg1 = rotate reg2 right by reg3 bits, not using carry rol reg1, reg2, reg3 - reg1 = rotate reg2 left by reg3 bits, not using carry -TODO add asr? (arithmetical shift right, so with sign bit) TODO also add ror/rol variants using the carry bit? These do map directly on 6502 and 68k instructions. @@ -131,6 +131,7 @@ breakpoint - trigger a breakpoint copy reg1, reg2, length - copy memory from ptrs in reg1 to reg3, length bytes copyz reg1, reg2 - copy memory from ptrs in reg1 to reg3, stop after first 0-byte swap [b, w] reg1, reg2 - reg1 = swapped lsb and msb from register reg2 (16 bits) or lsw and msw (32 bits) +concat [b, w] reg1, reg2, reg3 - reg1 = concatenated lsb/lsw of reg2 and lsb/lsw of reg3 into new word or int (int not yet implemented, requires 32bits regs) push [b, w] reg1 - push value in reg1 on the stack pop [b, w] reg1 - pop value from stack into reg1 @@ -143,7 +144,6 @@ enum class Opcode { LOADI, LOADX, LOADR, - SWAPREG, STOREM, STOREI, STOREX, @@ -194,6 +194,7 @@ enum class Opcode { AND, OR, XOR, + ASR, LSR, LSL, ROR, @@ -202,6 +203,8 @@ enum class Opcode { PUSH, POP, SWAP, + SWAPREG, + CONCAT, COPY, COPYZ, BREAKPOINT @@ -321,6 +324,7 @@ val instructionFormats = mutableMapOf( Opcode.AND to InstructionFormat(BW, true, true, true, false), Opcode.OR to InstructionFormat(BW, true, true, true, false), Opcode.XOR to InstructionFormat(BW, true, true, true, false), + Opcode.ASR to InstructionFormat(BW, true, true, true, false), Opcode.LSR to InstructionFormat(BW, true, true, true, false), Opcode.LSL to InstructionFormat(BW, true, true, true, false), Opcode.ROR to InstructionFormat(BW, true, true, true, false), @@ -331,5 +335,6 @@ val instructionFormats = mutableMapOf( Opcode.SWAP to InstructionFormat(BW, true, true, false, false), Opcode.PUSH to InstructionFormat(BW, true, false, false, false), Opcode.POP to InstructionFormat(BW, true, false, false, false), + Opcode.CONCAT to InstructionFormat(BW, true, true, true, false), Opcode.BREAKPOINT to InstructionFormat(NN, false, false, false, false) ) diff --git a/virtualmachine/src/prog8/vm/Memory.kt b/virtualmachine/src/prog8/vm/Memory.kt index d8917d587..fcfcf5ce4 100644 --- a/virtualmachine/src/prog8/vm/Memory.kt +++ b/virtualmachine/src/prog8/vm/Memory.kt @@ -10,23 +10,41 @@ class Memory { mem.fill(0u) } - fun getB(address: Int): UByte { + fun getUB(address: Int): UByte { return mem[address] } - fun setB(address: Int, value: UByte) { + fun getSB(address: Int): Byte { + return mem[address].toByte() + } + + fun setUB(address: Int, value: UByte) { mem[address] = value } - fun getW(address: Int): UShort { + fun setSB(address: Int, value: Byte) { + mem[address] = value.toUByte() + } + + fun getUW(address: Int): UShort { return (256u*mem[address] + mem[address+1]).toUShort() } - fun setW(address: Int, value: UShort) { + fun getSW(address: Int): Short { + return (mem[address].toInt()*256 + mem[address+1].toInt()).toShort() + } + + fun setUW(address: Int, value: UShort) { mem[address] = (value.toInt() ushr 8).toUByte() mem[address+1] = value.toUByte() } + fun setSW(address: Int, value: Short) { + val uv = value.toUShort() + mem[address] = (uv.toInt() ushr 8).toUByte() + mem[address+1] = uv.toUByte() + } + // for now, no LONG 32-bits and no FLOAT support. // fun getL(address: Int): UInt { // return mem[address+3] + 256u*mem[address+2] + 65536u*mem[address+1] + 16777216u*mem[address] diff --git a/virtualmachine/src/prog8/vm/Registers.kt b/virtualmachine/src/prog8/vm/Registers.kt index a404019e4..c99e3ae28 100644 --- a/virtualmachine/src/prog8/vm/Registers.kt +++ b/virtualmachine/src/prog8/vm/Registers.kt @@ -10,15 +10,27 @@ class Registers { registers.fill(0u) } - fun setB(reg: Int, value: UByte) { + fun setUB(reg: Int, value: UByte) { registers[reg] = registers[reg] and 0xff00u or value.toUShort() } - fun setW(reg: Int, value: UShort) { + fun setSB(reg: Int, value: Byte) { + registers[reg] = registers[reg] and 0xff00u or (value.toUShort() and 0x00ffu) + } + + fun setUW(reg: Int, value: UShort) { registers[reg] = value } - fun getB(reg: Int) = registers[reg].toUByte() + fun setSW(reg: Int, value: Short) { + registers[reg] = value.toUShort() + } - fun getW(reg: Int) = registers[reg] -} \ No newline at end of file + fun getUB(reg: Int) = registers[reg].toUByte() + + fun getSB(reg: Int) = registers[reg].toByte() + + fun getUW(reg: Int) = registers[reg] + + fun getSW(reg: Int) = registers[reg].toShort() +} diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 82a32f0f0..0942d81a9 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -17,7 +17,9 @@ SYSCALLS: 8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480 9 = gfx_clear ; clear graphics window with shade in r0.b 10 = gfx_plot ; plot pixel in graphics window, r0.w/r1.w contain X and Y coordinates, r2.b contains brightness -11 = rnd ; random BYTE +11 = rnd ; random BYTE +12 = wait ; wait certain amount of jiffies (1/60 sec) +13 = waitvsync ; wait on vsync */ enum class Syscall { @@ -33,6 +35,8 @@ enum class Syscall { GFX_CLEAR, GFX_PLOT, RND, + WAIT, + WAITVSYNC } object SysCalls { @@ -45,13 +49,13 @@ object SysCalls { vm.exit() } Syscall.PRINT_C -> { - val char = vm.registers.getB(0).toInt() + val char = vm.registers.getUB(0).toInt() print(Char(char)) } Syscall.PRINT_S -> { - var addr = vm.registers.getW(0).toInt() + var addr = vm.registers.getUW(0).toInt() while(true) { - val char = vm.memory.getB(addr).toInt() + val char = vm.memory.getUB(addr).toInt() if(char==0) break print(Char(char)) @@ -59,29 +63,34 @@ object SysCalls { } } Syscall.PRINT_U8 -> { - print(vm.registers.getB(0)) + print(vm.registers.getUB(0)) } Syscall.PRINT_U16 -> { - print(vm.registers.getW(0)) + print(vm.registers.getUW(0)) } Syscall.INPUT -> { var input = readln() - val maxlen = vm.registers.getB(1).toInt() + val maxlen = vm.registers.getUB(1).toInt() if(maxlen>0) input = input.substring(0, min(input.length, maxlen)) - vm.memory.setString(vm.registers.getW(0).toInt(), input, true) - vm.registers.setW(65535, input.length.toUShort()) + vm.memory.setString(vm.registers.getUW(0).toInt(), input, true) + vm.registers.setUW(65535, input.length.toUShort()) } Syscall.SLEEP -> { - val duration = vm.registers.getW(0).toLong() + val duration = vm.registers.getUW(0).toLong() Thread.sleep(duration) } Syscall.GFX_ENABLE -> vm.gfx_enable() Syscall.GFX_CLEAR -> vm.gfx_clear() Syscall.GFX_PLOT -> vm.gfx_plot() Syscall.RND -> { - vm.registers.setB(0, (Random.nextInt() ushr 3).toUByte()) + vm.registers.setUB(0, (Random.nextInt() ushr 3).toUByte()) } + Syscall.WAIT -> { + val millis = vm.registers.getUW(0).toLong() * 1000/60 + Thread.sleep(millis) + } + Syscall.WAITVSYNC -> vm.waitvsync() else -> TODO("syscall ${call.name}") } } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 77388bc1c..5448d9500 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -1,5 +1,6 @@ package prog8.vm +import java.awt.Toolkit import java.util.* import kotlin.math.roundToInt @@ -60,7 +61,7 @@ class VirtualMachine(val memory: Memory, program: List) { } fun exit() { - throw ProgramExitException(registers.getW(0).toInt()) + throw ProgramExitException(registers.getUW(0).toInt()) } fun step(count: Int=1) { @@ -132,11 +133,13 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.AND -> InsAND(ins) Opcode.OR -> InsOR(ins) Opcode.XOR -> InsXOR(ins) + Opcode.ASR -> InsASR(ins) Opcode.LSR -> InsLSR(ins) Opcode.LSL -> InsLSL(ins) Opcode.ROR -> InsROR(ins) Opcode.ROL -> InsROL(ins) Opcode.SWAP -> InsSWAP(ins) + Opcode.CONCAT -> InsCONCAT(ins) Opcode.PUSH -> InsPUSH(ins) Opcode.POP -> InsPOP(ins) Opcode.COPY -> InsCOPY(ins) @@ -148,8 +151,8 @@ class VirtualMachine(val memory: Memory, program: List) { 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()) + VmDataType.BYTE -> registers.setUB(reg, value.toUByte()) + VmDataType.WORD -> registers.setUW(reg, value.toUShort()) } } @@ -158,8 +161,8 @@ class VirtualMachine(val memory: Memory, program: List) { throw StackOverflowError("valuestack limit 128 exceeded") val value = when(i.type!!) { - VmDataType.BYTE -> registers.getB(i.reg1!!).toInt() - VmDataType.WORD -> registers.getW(i.reg1!!).toInt() + VmDataType.BYTE -> registers.getUB(i.reg1!!).toInt() + VmDataType.WORD -> registers.getUW(i.reg1!!).toInt() } valueStack.push(value) pc++ @@ -189,32 +192,32 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsLOADM(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, memory.getB(i.value!!)) - VmDataType.WORD -> registers.setW(i.reg1!!, memory.getW(i.value!!)) + VmDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.value!!)) + VmDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.value!!)) } pc++ } private fun InsLOADI(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, memory.getB(registers.getW(i.reg2!!).toInt())) - VmDataType.WORD -> registers.setW(i.reg1!!, memory.getW(registers.getW(i.reg2!!).toInt())) + VmDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(registers.getUW(i.reg2!!).toInt())) + VmDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(registers.getUW(i.reg2!!).toInt())) } pc++ } private fun InsLOADX(i: Instruction) { when (i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, memory.getB(i.value!! + registers.getW(i.reg2!!).toInt())) - VmDataType.WORD -> registers.setW(i.reg1!!, memory.getW(i.value!! + registers.getW(i.reg2!!).toInt())) + VmDataType.BYTE -> registers.setUB(i.reg1!!, memory.getUB(i.value!! + registers.getUW(i.reg2!!).toInt())) + VmDataType.WORD -> registers.setUW(i.reg1!!, memory.getUW(i.value!! + registers.getUW(i.reg2!!).toInt())) } pc++ } private fun InsLOADR(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, registers.getB(i.reg2!!)) - VmDataType.WORD -> registers.setW(i.reg1!!, registers.getW(i.reg2!!)) + VmDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg2!!)) + VmDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg2!!)) } pc++ } @@ -222,14 +225,14 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsSWAPREG(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> { - val oldR2 = registers.getB(i.reg2!!) - registers.setB(i.reg2, registers.getB(i.reg1!!)) - registers.setB(i.reg1, oldR2) + val oldR2 = registers.getUB(i.reg2!!) + registers.setUB(i.reg2, registers.getUB(i.reg1!!)) + registers.setUB(i.reg1, oldR2) } VmDataType.WORD -> { - val oldR2 = registers.getW(i.reg2!!) - registers.setW(i.reg2, registers.getW(i.reg1!!)) - registers.setW(i.reg1, oldR2) + val oldR2 = registers.getUW(i.reg2!!) + registers.setUW(i.reg2, registers.getUW(i.reg1!!)) + registers.setUW(i.reg1, oldR2) } } pc++ @@ -237,47 +240,47 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsSTOREM(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> memory.setB(i.value!!, registers.getB(i.reg1!!)) - VmDataType.WORD -> memory.setW(i.value!!, registers.getW(i.reg1!!)) + VmDataType.BYTE -> memory.setUB(i.value!!, registers.getUB(i.reg1!!)) + VmDataType.WORD -> memory.setUW(i.value!!, registers.getUW(i.reg1!!)) } pc++ } private fun InsSTOREI(i: Instruction) { when (i.type!!) { - VmDataType.BYTE -> memory.setB(registers.getW(i.reg2!!).toInt(), registers.getB(i.reg1!!)) - VmDataType.WORD -> memory.setW(registers.getW(i.reg2!!).toInt(), registers.getW(i.reg1!!)) + VmDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), registers.getUB(i.reg1!!)) + VmDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt(), registers.getUW(i.reg1!!)) } pc++ } private fun InsSTOREX(i: Instruction) { when (i.type!!) { - VmDataType.BYTE -> memory.setB(registers.getW(i.reg2!!).toInt() + i.value!!, registers.getB(i.reg1!!)) - VmDataType.WORD -> memory.setW(registers.getW(i.reg2!!).toInt() + i.value!!, registers.getW(i.reg1!!)) + VmDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + i.value!!, registers.getUB(i.reg1!!)) + VmDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt() + i.value!!, registers.getUW(i.reg1!!)) } pc++ } private fun InsSTOREZ(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> memory.setB(i.value!!, 0u) - VmDataType.WORD -> memory.setW(i.value!!, 0u) + VmDataType.BYTE -> memory.setUB(i.value!!, 0u) + VmDataType.WORD -> memory.setUW(i.value!!, 0u) } } private fun InsSTOREZI(i: Instruction) { when (i.type!!) { - VmDataType.BYTE -> memory.setB(registers.getW(i.reg2!!).toInt(), 0u) - VmDataType.WORD -> memory.setW(registers.getW(i.reg2!!).toInt(), 0u) + VmDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), 0u) + VmDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt(), 0u) } pc++ } private fun InsSTOREZX(i: Instruction) { when (i.type!!) { - VmDataType.BYTE -> memory.setB(registers.getW(i.reg2!!).toInt() + i.value!!, 0u) - VmDataType.WORD -> memory.setW(registers.getW(i.reg2!!).toInt() + i.value!!, 0u) + VmDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + i.value!!, 0u) + VmDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt() + i.value!!, 0u) } pc++ } @@ -287,7 +290,7 @@ class VirtualMachine(val memory: Memory, program: List) { } private fun InsJUMPI(i: Instruction) { - pc = registers.getW(i.reg1!!).toInt() + pc = registers.getUW(i.reg1!!).toInt() } private fun InsCALL(i: Instruction) { @@ -297,7 +300,7 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsCALLI(i: Instruction) { callStack.push(pc+1) - pc = registers.getW(i.reg1!!).toInt() + pc = registers.getUW(i.reg1!!).toInt() } private fun InsRETURN() { @@ -310,13 +313,13 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsBZ(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> { - if(registers.getB(i.reg1!!)==0.toUByte()) + if(registers.getUB(i.reg1!!)==0.toUByte()) pc = i.value!! else pc++ } VmDataType.WORD -> { - if(registers.getW(i.reg1!!)==0.toUShort()) + if(registers.getUW(i.reg1!!)==0.toUShort()) pc = i.value!! else pc++ @@ -327,13 +330,13 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsBNZ(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> { - if(registers.getB(i.reg1!!)!=0.toUByte()) + if(registers.getUB(i.reg1!!)!=0.toUByte()) pc = i.value!! else pc++ } VmDataType.WORD -> { - if(registers.getW(i.reg1!!)!=0.toUShort()) + if(registers.getUW(i.reg1!!)!=0.toUShort()) pc = i.value!! else pc++ @@ -498,24 +501,24 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsINC(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (registers.getB(i.reg1)+1u).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (registers.getW(i.reg1)+1u).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1)+1u).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1)+1u).toUShort()) } pc++ } private fun InsDEC(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (registers.getB(i.reg1)-1u).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (registers.getW(i.reg1)-1u).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (registers.getUB(i.reg1)-1u).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (registers.getUW(i.reg1)-1u).toUShort()) } pc++ } private fun InsNEG(i: Instruction) { when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (-registers.getB(i.reg1).toInt()).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (-registers.getW(i.reg1).toInt()).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1).toInt()).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (-registers.getUW(i.reg1).toInt()).toUShort()) } pc++ } @@ -553,8 +556,8 @@ class VirtualMachine(val memory: Memory, program: List) { } private fun arithByte(operator: String, reg1: Int, reg2: Int, reg3: Int?, value: UByte?) { - val left = registers.getB(reg2) - val right = value ?: registers.getB(reg3!!) + val left = registers.getUB(reg2) + val right = value ?: registers.getUB(reg3!!) val result = when(operator) { "+" -> left + right "-" -> left - right @@ -569,12 +572,12 @@ class VirtualMachine(val memory: Memory, program: List) { } else -> TODO("operator $operator") } - registers.setB(reg1, result.toUByte()) + registers.setUB(reg1, result.toUByte()) } private fun arithWord(operator: String, reg1: Int, reg2: Int, reg3: Int?, value: UShort?) { - val left = registers.getW(reg2) - val right = value ?: registers.getW(reg3!!) + val left = registers.getUW(reg2) + val right = value ?: registers.getUW(reg3!!) val result = when(operator) { "+" -> left + right "-" -> left - right @@ -589,7 +592,7 @@ class VirtualMachine(val memory: Memory, program: List) { } else -> TODO("operator $operator") } - registers.setW(reg1, result.toUShort()) + registers.setUW(reg1, result.toUShort()) } private fun InsSUB(i: Instruction) { @@ -602,7 +605,7 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsEXT(i: Instruction) { when(i.type!!){ - VmDataType.BYTE -> registers.setW(i.reg1!!, registers.getB(i.reg1).toUShort()) + VmDataType.BYTE -> registers.setUW(i.reg1!!, registers.getUB(i.reg1).toUShort()) VmDataType.WORD -> TODO("ext.w requires 32 bits registers") } pc++ @@ -610,7 +613,7 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsEXTS(i: Instruction) { when(i.type!!){ - VmDataType.BYTE -> registers.setW(i.reg1!!, (registers.getB(i.reg1).toByte()).toUShort()) + VmDataType.BYTE -> registers.setSW(i.reg1!!, registers.getSB(i.reg1).toShort()) VmDataType.WORD -> TODO("ext.w requires 32 bits registers") } pc++ @@ -619,8 +622,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsAND(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left and right).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (left and right).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left and right).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left and right).toUShort()) } pc++ } @@ -628,8 +631,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsOR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left or right).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (left or right).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left or right).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left or right).toUShort()) } pc++ } @@ -637,8 +640,17 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsXOR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left xor right).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (left xor right).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left xor right).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left xor right).toUShort()) + } + pc++ + } + + private fun InsASR(i: Instruction) { + val (left: Int, right: Int) = getLogicalOperandsS(i) + when(i.type!!) { + VmDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte()) + VmDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort()) } pc++ } @@ -646,8 +658,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsLSR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left shr right.toInt()).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (left shr right.toInt()).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort()) } pc++ } @@ -655,8 +667,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsLSL(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left shl right.toInt()).toUByte()) - VmDataType.WORD -> registers.setW(i.reg1!!, (left shl right.toInt()).toUShort()) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left shl right.toInt()).toUByte()) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left shl right.toInt()).toUShort()) } pc++ } @@ -664,8 +676,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsROR(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left.rotateRight(right.toInt()).toUByte())) - VmDataType.WORD -> registers.setW(i.reg1!!, (left.rotateRight(right.toInt()).toUShort())) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateRight(right.toInt()).toUByte())) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateRight(right.toInt()).toUShort())) } pc++ } @@ -673,8 +685,8 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsROL(i: Instruction) { val (left: UInt, right: UInt) = getLogicalOperandsU(i) when(i.type!!) { - VmDataType.BYTE -> registers.setB(i.reg1!!, (left.rotateLeft(right.toInt()).toUByte())) - VmDataType.WORD -> registers.setW(i.reg1!!, (left.rotateLeft(right.toInt()).toUShort())) + VmDataType.BYTE -> registers.setUB(i.reg1!!, (left.rotateLeft(right.toInt()).toUByte())) + VmDataType.WORD -> registers.setUW(i.reg1!!, (left.rotateLeft(right.toInt()).toUShort())) } pc++ } @@ -682,9 +694,21 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsSWAP(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> { - val value = registers.getW(i.reg2!!) + val value = registers.getUW(i.reg2!!) val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt() - registers.setW(i.reg1!!, newValue.toUShort()) + registers.setUW(i.reg1!!, newValue.toUShort()) + } + VmDataType.WORD -> TODO("swap.w requires 32-bits registers") + } + pc++ + } + + private fun InsCONCAT(i: Instruction) { + when(i.type!!) { + VmDataType.BYTE -> { + val msb = registers.getUB(i.reg2!!) + val lsb = registers.getUB(i.reg3!!) + registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort()) } VmDataType.WORD -> TODO("swap.w requires 32-bits registers") } @@ -696,13 +720,13 @@ class VirtualMachine(val memory: Memory, program: List) { private fun InsCOPYZ(i: Instruction) = doCopy(i.reg1!!, i.reg2!!, null, true) private fun doCopy(reg1: Int, reg2: Int, length: Int?, untilzero: Boolean) { - var from = registers.getW(reg1).toInt() - var to = registers.getW(reg2).toInt() + var from = registers.getUW(reg1).toInt() + var to = registers.getUW(reg2).toInt() if(untilzero) { while(true) { - val char = memory.getB(from).toInt() - memory.setB(to, char.toUByte()) - if(char==0) + val char = memory.getUB(from) + memory.setUB(to, char) + if(char.toInt()==0) break from++ to++ @@ -710,8 +734,8 @@ class VirtualMachine(val memory: Memory, program: List) { } else { var len = length!! while(len>0) { - val char = memory.getB(from).toInt() - memory.setB(to, char.toUByte()) + val char = memory.getUB(from) + memory.setUB(to, char) from++ to++ len-- @@ -722,40 +746,49 @@ class VirtualMachine(val memory: Memory, program: List) { 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()) + VmDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) + VmDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(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()) + VmDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt()) + VmDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(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()) + VmDataType.BYTE -> Pair(registers.getUB(i.reg2!!).toUInt(), registers.getUB(i.reg3!!).toUInt()) + VmDataType.WORD -> Pair(registers.getUW(i.reg2!!).toUInt(), registers.getUW(i.reg3!!).toUInt()) null -> throw IllegalArgumentException("need type for logical instruction") } } + private fun getLogicalOperandsS(i: Instruction): Pair { + return when(i.type) { + VmDataType.BYTE -> Pair(registers.getSB(i.reg2!!).toInt(), registers.getSB(i.reg3!!).toInt()) + VmDataType.WORD -> Pair(registers.getSW(i.reg2!!).toInt(), registers.getSW(i.reg3!!).toInt()) + 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()) + VmDataType.BYTE -> Triple(ins.reg1!!, registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt()) + VmDataType.WORD -> Triple(ins.reg1!!, registers.getSW(ins.reg2!!).toInt(), registers.getSW(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()) + VmDataType.BYTE -> Triple(ins.reg1!!, registers.getUB(ins.reg2!!).toUInt(), registers.getUB(ins.reg3!!).toUInt()) + VmDataType.WORD -> Triple(ins.reg1!!, registers.getUW(ins.reg2!!).toUInt(), registers.getUW(ins.reg3!!).toUInt()) null -> throw IllegalArgumentException("need type for branch instruction") } } @@ -763,7 +796,7 @@ class VirtualMachine(val memory: Memory, program: List) { private var window: GraphicsWindow? = null fun gfx_enable() { - window = when(registers.getB(0).toInt()) { + window = when(registers.getUB(0).toInt()) { 0 -> GraphicsWindow(320, 240, 3) 1 -> GraphicsWindow(640, 480, 2) else -> throw IllegalArgumentException("invalid screen mode") @@ -772,14 +805,18 @@ class VirtualMachine(val memory: Memory, program: List) { } fun gfx_clear() { - window?.clear(registers.getB(0).toInt()) + window?.clear(registers.getUB(0).toInt()) } fun gfx_plot() { - window?.plot(registers.getW(0).toInt(), registers.getW(1).toInt(), registers.getB(2).toInt()) + window?.plot(registers.getUW(0).toInt(), registers.getUW(1).toInt(), registers.getUB(2).toInt()) } fun gfx_close() { window?.close() } + + fun waitvsync() { + Toolkit.getDefaultToolkit().sync() // not really the same as wait on vsync, but there's noting else + } }