package prog8tests import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.empty import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import prog8.ast.ByteDatatypes import prog8.ast.DataType import prog8.ast.IterableDatatypes import prog8.ast.WordDatatypes import prog8.compiler.HeapValues import prog8.compiler.intermediate.Instruction import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Value import prog8.compiler.intermediate.ValueException import prog8.stackvm.* import kotlin.test.* /*** @todo opcodes still to be unit-tested: SHL_MEM_BYTE, SHL_MEM_WORD, SHL_VAR_BYTE, SHL_VAR_WORD, SHR_MEM_BYTE, SHR_MEM_WORD, SHR_VAR_BYTE, SHR_VAR_WORD, ROL_MEM_BYTE, ROL_MEM_WORD, ROL_VAR_BYTE, ROL_VAR_WORD, ROR_MEM, ROR_MEM_W, ROR_VAR, ROR_VAR_W, ROL2_MEM, ROL2_MEM_W, ROL2_VAR, ROL2_VAR_W, ROR2_MEM, ROR2_MEM_W, ROR2_VAR, ROR2_VAR_W and several others. **/ @TestInstance(TestInstance.Lifecycle.PER_CLASS) class TestStackVmOpcodes { private val vm = StackVm(null) private fun makeProg(ins: MutableList, vars: Map?=null, memoryPointers: Map>?=null, labels: Map?=null, mem: Map>?=null) : Program { val heap = HeapValues() return Program("test", ins, vars ?: mapOf(), memoryPointers ?: mapOf(), labels ?: mapOf(), mem ?: mapOf(), heap) } @Test fun testInitAndNop() { val ins = mutableListOf(Instruction(Opcode.NOP)) vm.load(makeProg(ins), null) assertEquals(3, vm.variables.size) assertTrue(vm.variables.containsKey("A")) vm.step(1) assertThat(vm.callstack, empty()) assertThat(vm.evalstack, empty()) assertFailsWith { vm.step() } } @Test fun testBreakpoint() { val ins = mutableListOf(Instruction(Opcode.BREAKPOINT)) vm.load(makeProg(ins), null) assertFailsWith { vm.step() } assertThat(vm.callstack, empty()) assertThat(vm.evalstack, empty()) } @Test fun testLine() { val ins = mutableListOf(Instruction(Opcode.LINE, callLabel = "line 99")) vm.load(makeProg(ins), null) assertEquals("", vm.sourceLine) vm.step(1) assertEquals("line 99", vm.sourceLine) } @Test fun testSECandSEIandCLCandCLI() { val ins = mutableListOf(Instruction(Opcode.SEC), Instruction(Opcode.SEI), Instruction(Opcode.CLC), Instruction(Opcode.CLI)) vm.load(makeProg(ins), null) assertFalse(vm.P_carry) assertFalse(vm.P_irqd) vm.step(1) assertTrue(vm.P_carry) assertFalse(vm.P_irqd) vm.step(1) assertTrue(vm.P_carry) assertTrue(vm.P_irqd) vm.step(1) assertFalse(vm.P_carry) assertTrue(vm.P_irqd) vm.step(1) assertFalse(vm.P_carry) assertFalse(vm.P_irqd) } @Test fun testPushWrongDt() { val ins = mutableListOf(Instruction(Opcode.PUSH_BYTE, Value(DataType.UWORD, 4299))) vm.load(makeProg(ins), null) assertFailsWith { vm.step(1) } } @Test fun testPush() { val ins = mutableListOf(Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 42.999))) vm.load(makeProg(ins), null) assertThat(vm.evalstack, empty()) vm.step(1) assertEquals(1, vm.evalstack.size) assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop()) } @Test fun testPushMem() { val ins = mutableListOf( Instruction(Opcode.PUSH_MEM_B, Value(DataType.UWORD, 0x2000)), Instruction(Opcode.PUSH_MEM_UB, Value(DataType.UWORD, 0x3000)), Instruction(Opcode.PUSH_MEM_W, Value(DataType.UWORD, 0x4000)), Instruction(Opcode.PUSH_MEM_UW, Value(DataType.UWORD, 0x5000)), Instruction(Opcode.PUSH_MEM_FLOAT, Value(DataType.UWORD, 0x6000)) ) val mem=mapOf(0x2000 to listOf(Value(DataType.UWORD, 0xc2ca)), 0x3000 to listOf(Value(DataType.UWORD, 0xc2ca)), 0x4000 to listOf(Value(DataType.UWORD, 0xc2ca)), 0x5000 to listOf(Value(DataType.UWORD, 0xc2ca)), 0x6000 to listOf(Value(DataType.FLOAT, 42.25))) vm.load(makeProg(ins, mem=mem), null) assertEquals(0xca, vm.mem.getUByte(0x2000)) assertEquals(0xc2, vm.mem.getUByte(0x2001)) assertEquals(0xca, vm.mem.getUByte(0x3000)) assertEquals(0xc2, vm.mem.getUByte(0x3001)) assertEquals(0xca, vm.mem.getUByte(0x4000)) assertEquals(0xc2, vm.mem.getUByte(0x4001)) assertEquals(0xca, vm.mem.getUByte(0x5000)) assertEquals(0xc2, vm.mem.getUByte(0x5001)) assertEquals(-54, vm.mem.getSByte(0x2000)) assertEquals(-62, vm.mem.getSByte(0x2001)) assertEquals(-54, vm.mem.getSByte(0x3000)) assertEquals(-62, vm.mem.getSByte(0x3001)) assertEquals(-54, vm.mem.getSByte(0x4000)) assertEquals(-62, vm.mem.getSByte(0x4001)) assertEquals(-54, vm.mem.getSByte(0x5000)) assertEquals(-62, vm.mem.getSByte(0x5001)) assertEquals(0xc2ca, vm.mem.getUWord(0x2000)) assertEquals(0xc2ca, vm.mem.getUWord(0x3000)) assertEquals(0xc2ca, vm.mem.getUWord(0x4000)) assertEquals(0xc2ca, vm.mem.getUWord(0x5000)) assertEquals(-15670, vm.mem.getSWord(0x2000)) assertEquals(-15670, vm.mem.getSWord(0x3000)) assertEquals(-15670, vm.mem.getSWord(0x4000)) assertEquals(-15670, vm.mem.getSWord(0x5000)) assertEquals(42.25, vm.mem.getFloat(0x6000)) assertThat(vm.evalstack, empty()) vm.step(5) assertEquals(5, vm.evalstack.size) assertEquals(Value(DataType.FLOAT, 42.25), vm.evalstack.pop()) assertEquals(Value(DataType.UWORD, 0xc2ca), vm.evalstack.pop()) assertEquals(Value(DataType.WORD, -15670), vm.evalstack.pop()) assertEquals(Value(DataType.UBYTE, 0xca), vm.evalstack.pop()) assertEquals(Value(DataType.BYTE, -54), vm.evalstack.pop()) } @Test fun testPushVar() { val ins = mutableListOf(Instruction(Opcode.PUSH_VAR_FLOAT, callLabel = "varname")) vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null) assertEquals(4, vm.variables.size) assertTrue(vm.variables.containsKey("varname")) assertTrue(vm.variables.containsKey("A")) assertEquals(Value(DataType.FLOAT, 42.999), vm.variables["varname"]) assertThat(vm.evalstack, empty()) vm.step(1) assertEquals(1, vm.evalstack.size) assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop()) assertEquals(Value(DataType.FLOAT, 42.999), vm.variables["varname"]) } @Test fun testDiscard() { val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 42.999)), Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 3.1415)), Instruction(Opcode.DISCARD_FLOAT)) vm.load(makeProg(ins), null) assertThat(vm.evalstack, empty()) vm.step(2) assertEquals(2, vm.evalstack.size) vm.step(1) assertEquals(1, vm.evalstack.size) assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop()) } @Test fun testPopMem() { val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 42.25)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xc2ca)), Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -23456)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -55)), Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2000)), Instruction(Opcode.POP_MEM_BYTE, Value(DataType.UWORD, 0x2001)), Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3000)), Instruction(Opcode.POP_MEM_WORD, Value(DataType.UWORD, 0x3002)), Instruction(Opcode.POP_MEM_FLOAT, Value(DataType.UWORD, 0x4000))) vm.load(makeProg(ins), null) assertEquals(0, vm.mem.getUWord(0x2000)) assertEquals(0, vm.mem.getUWord(0x2001)) assertEquals(0, vm.mem.getUWord(0x3000)) assertEquals(0, vm.mem.getUWord(0x3002)) assertEquals(0.0, vm.mem.getFloat(0x4000)) assertThat(vm.evalstack, empty()) vm.step(11) assertThat(vm.evalstack, empty()) assertEquals(201, vm.mem.getUByte(0x2000)) assertEquals(177, vm.mem.getUByte(0x2001)) assertEquals(-55, vm.mem.getSByte(0x2000)) assertEquals(-79, vm.mem.getSByte(0x2001)) assertEquals(42080, vm.mem.getUWord(0x3000)) assertEquals(0xc2ca, vm.mem.getUWord(0x3002)) assertEquals(-23456, vm.mem.getSWord(0x3000)) assertEquals(-15670, vm.mem.getSWord(0x3002)) assertEquals(42.25, vm.mem.getFloat(0x4000)) } @Test fun testPopVar() { val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 42.25)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0x42ea)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 123)), Instruction(Opcode.POP_VAR_BYTE, callLabel = "var1"), Instruction(Opcode.POP_VAR_WORD, callLabel = "var2"), Instruction(Opcode.POP_VAR_FLOAT, callLabel = "var3")) val vars = mapOf( "var1" to Value(DataType.UBYTE, 0), "var2" to Value(DataType.UWORD, 0), "var3" to Value(DataType.FLOAT, 0) ) vm.load(makeProg(ins, vars), null) assertEquals(6, vm.variables.size) vm.step(6) assertEquals(Value(DataType.UBYTE, 123), vm.variables["var1"]) assertEquals(Value(DataType.UWORD, 0x42ea), vm.variables["var2"]) assertEquals(Value(DataType.FLOAT, 42.25), vm.variables["var3"]) val ins2 = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0x42ea)), Instruction(Opcode.POP_VAR_WORD, callLabel = "var1")) val vars2 = mapOf( "var1" to Value(DataType.UBYTE, 0) ) vm.load(makeProg(ins2, vars2), null) assertEquals(4, vm.variables.size) assertFailsWith { vm.step(2) } } @Test fun testAdd() { testBinaryOperator(Value(DataType.UBYTE, 140), Opcode.ADD_UB, Value(DataType.UBYTE, 222), Value(DataType.UBYTE, 106)) testBinaryOperator(Value(DataType.UBYTE, 40), Opcode.ADD_UB, Value(DataType.UBYTE, 122), Value(DataType.UBYTE, 162)) testBinaryOperator(Value(DataType.UWORD, 4000), Opcode.ADD_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 4040)) testBinaryOperator(Value(DataType.UWORD, 24000), Opcode.ADD_UW, Value(DataType.UWORD, 55000), Value(DataType.UWORD, 13464)) testBinaryOperator(Value(DataType.FLOAT, 4000.0), Opcode.ADD_F, Value(DataType.FLOAT, 123.22), Value(DataType.FLOAT, 4123.22)) assertFailsWith { testBinaryOperator(Value(DataType.UWORD, 4000 + 40), Opcode.ADD_UW, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40))) } } @Test fun testSub() { testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.SUB_UB, Value(DataType.UBYTE, 70), Value(DataType.UBYTE, 180)) testBinaryOperator(Value(DataType.UWORD, 4000), Opcode.SUB_UW, Value(DataType.UWORD, 123), Value(DataType.UWORD, 4000 - 123)) testBinaryOperator(Value(DataType.FLOAT, 123.44), Opcode.SUB_F, Value(DataType.FLOAT, 23.44), Value(DataType.FLOAT, 100.0)) assertFailsWith { testBinaryOperator(Value(DataType.UWORD, 4000 - 40), Opcode.SUB_UW, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40))) } } @Test fun testMul() { testBinaryOperator(Value(DataType.UBYTE, 41), Opcode.MUL_UB, Value(DataType.UBYTE, 4), Value(DataType.UBYTE, 164)) testBinaryOperator(Value(DataType.UWORD, 401), Opcode.MUL_UW, Value(DataType.UWORD, 4), Value(DataType.UWORD, 401 * 4)) testBinaryOperator(Value(DataType.FLOAT, 40.1), Opcode.MUL_F, Value(DataType.FLOAT, 2.4), Value(DataType.FLOAT, 96.24)) assertFailsWith { testBinaryOperator(Value(DataType.UWORD, 401 * 4), Opcode.MUL_UW, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4))) } } @Test fun testDiv() { testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.IDIV_UB, Value(DataType.UBYTE, 12), Value(DataType.UBYTE, 20)) testBinaryOperator(Value(DataType.BYTE, 120), Opcode.IDIV_B, Value(DataType.BYTE, -9), Value(DataType.BYTE, -13)) testBinaryOperator(Value(DataType.UWORD, 3999), Opcode.IDIV_UW, Value(DataType.UWORD, 40), Value(DataType.UWORD, 99)) testBinaryOperator(Value(DataType.WORD, 3999), Opcode.IDIV_W, Value(DataType.WORD, -40), Value(DataType.WORD, -99)) testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25 / 99.0)) assertFailsWith { testBinaryOperator(Value(DataType.UWORD, 3333), Opcode.IDIV_UW, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) } } @Test fun testPow() { testBinaryOperator(Value(DataType.UBYTE, 3), Opcode.POW_UB, Value(DataType.UBYTE, 4), Value(DataType.UBYTE, 81)) testBinaryOperator(Value(DataType.UWORD, 3), Opcode.POW_UW, Value(DataType.UWORD, 4), Value(DataType.UWORD, 81)) testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW_F, Value(DataType.FLOAT, 81.0), Value(DataType.FLOAT, 2253.2402360440274)) } @Test fun testRemainder() { testBinaryOperator(Value(DataType.UBYTE, 250), Opcode.REMAINDER_UB, Value(DataType.UBYTE, 29), Value(DataType.UBYTE, 18)) testBinaryOperator(Value(DataType.UWORD, 500), Opcode.REMAINDER_UW, Value(DataType.UWORD, 29), Value(DataType.UWORD, 7)) } @Test fun testBitand() { testBinaryOperator(Value(DataType.UBYTE, 0b10011111), Opcode.BITAND_BYTE, Value(DataType.UBYTE, 0b11111101), Value(DataType.UBYTE, 0b10011101)) testBinaryOperator(Value(DataType.UWORD, 0b0011001011110001), Opcode.BITAND_WORD, Value(DataType.UWORD, 0b1110000010011101), Value(DataType.UWORD, 0b0010000010010001)) } @Test fun testBitor() { testBinaryOperator(Value(DataType.UBYTE, 0b00011101), Opcode.BITOR_BYTE, Value(DataType.UBYTE, 0b10010001), Value(DataType.UBYTE, 0b10011101)) testBinaryOperator(Value(DataType.UWORD, 0b0011001011100000), Opcode.BITOR_WORD, Value(DataType.UWORD, 0b1000000010011101), Value(DataType.UWORD, 0b1011001011111101)) } @Test fun testBitxor() { testBinaryOperator(Value(DataType.UBYTE, 0b00011101), Opcode.BITXOR_BYTE, Value(DataType.UBYTE, 0b10010001), Value(DataType.UBYTE, 0b10001100)) testBinaryOperator(Value(DataType.UWORD, 0b0011001011100000), Opcode.BITXOR_WORD, Value(DataType.UWORD, 0b1000000010001100), Value(DataType.UWORD, 0b1011001001101100)) } @Test fun testAnd() { testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.AND_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.AND_BYTE, Value(DataType.UBYTE, 0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.AND_BYTE, Value(DataType.UBYTE, 101), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.AND_WORD, Value(DataType.UWORD, 13455), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.AND_WORD, Value(DataType.UWORD, 0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 0), Opcode.AND_WORD, Value(DataType.UWORD, 101), Value(DataType.UBYTE, 0)) } @Test fun testOr() { testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.OR_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.OR_BYTE, Value(DataType.UBYTE, 0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.OR_BYTE, Value(DataType.UBYTE, 0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.OR_WORD, Value(DataType.UWORD, 13455), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.OR_WORD, Value(DataType.UWORD, 0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 0), Opcode.OR_WORD, Value(DataType.UWORD, 0), Value(DataType.UBYTE, 0)) } @Test fun testXor() { testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.XOR_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UBYTE, 200), Opcode.XOR_BYTE, Value(DataType.UBYTE, 0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.XOR_BYTE, Value(DataType.UBYTE, 0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.XOR_WORD, Value(DataType.UWORD, 13455), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 200), Opcode.XOR_WORD, Value(DataType.UWORD, 0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 0), Opcode.XOR_WORD, Value(DataType.UWORD, 0), Value(DataType.UBYTE, 0)) } @Test fun testNot() { testUnaryOperator(Value(DataType.UBYTE, 0), Opcode.NOT_BYTE, Value(DataType.UBYTE, 1)) testUnaryOperator(Value(DataType.UBYTE, 20), Opcode.NOT_BYTE, Value(DataType.UBYTE, 0)) testUnaryOperator(Value(DataType.UWORD, 0), Opcode.NOT_WORD, Value(DataType.UBYTE, 1)) testUnaryOperator(Value(DataType.UWORD, 5000), Opcode.NOT_WORD, Value(DataType.UBYTE, 0)) } @Test fun testNeg() { testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, -12)) testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG_W, Value(DataType.WORD, -1234)) testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG_F, Value(DataType.FLOAT, -123.456)) assertFailsWith { testUnaryOperator(Value(DataType.UBYTE, 12), Opcode.NEG_B, Value(DataType.UBYTE, 244)) } assertFailsWith { testUnaryOperator(Value(DataType.UWORD, 1234), Opcode.NEG_W, Value(DataType.UWORD, 64302)) } } @Test fun testInv() { testUnaryOperator(Value(DataType.UBYTE, 123), Opcode.INV_BYTE, Value(DataType.UBYTE, 0x84)) testUnaryOperator(Value(DataType.UWORD, 4044), Opcode.INV_WORD, Value(DataType.UWORD, 0xf033)) assertFailsWith { testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV_BYTE, Value(DataType.BYTE, 0x84)) } assertFailsWith { testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_WORD, Value(DataType.WORD, 0xf033)) } } @Test fun testMsb() { val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0x45)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)), Instruction(Opcode.MSB), Instruction(Opcode.MSB) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.UBYTE, 0xea), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } // @todo more conversion tests. @Test fun testB2Ub() { val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, -88)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, 127)), Instruction(Opcode.CAST_B_TO_UB), Instruction(Opcode.CAST_B_TO_UB) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.UBYTE, 127), vm.evalstack.pop()) vm.step(1) assertEquals(Value(DataType.UBYTE, 168), vm.evalstack.pop()) } @Test fun testUB2b() { val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 168)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 127)), Instruction(Opcode.CAST_UB_TO_B), Instruction(Opcode.CAST_UB_TO_B) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.BYTE, 127), vm.evalstack.pop()) vm.step(1) assertEquals(Value(DataType.BYTE, -88), vm.evalstack.pop()) } @Test fun testB2Word() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, 0x7a31)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, 127)), Instruction(Opcode.CAST_B_TO_W), Instruction(Opcode.CAST_B_TO_W) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.WORD, 127), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testUB2Uword() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0x45)), Instruction(Opcode.CAST_UB_TO_UW), Instruction(Opcode.CAST_UB_TO_UW) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.UWORD, 0x0045), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testB2Float() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, 0x7a31)), Instruction(Opcode.PUSH_BYTE, Value(DataType.BYTE, 127)), Instruction(Opcode.CAST_B_TO_F), Instruction(Opcode.CAST_B_TO_F) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.FLOAT, 127.0), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testUB2Float() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xea31)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.CAST_UB_TO_F), Instruction(Opcode.CAST_UB_TO_F) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.FLOAT, 177.0), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testW2Float() { val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_WORD, Value(DataType.WORD, -12345)), Instruction(Opcode.CAST_W_TO_F), Instruction(Opcode.CAST_W_TO_F) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.FLOAT, -12345.0), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testUW2Float() { val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 177)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 52345)), Instruction(Opcode.CAST_UW_TO_F), Instruction(Opcode.CAST_UW_TO_F) ) vm.load(makeProg(ins), null) vm.step(3) assertEquals(Value(DataType.FLOAT, 52345.0), vm.evalstack.pop()) assertFailsWith { vm.step(1) } } @Test fun testIncVar() { val ins = mutableListOf( Instruction(Opcode.INC_VAR_UW, callLabel = "var1"), Instruction(Opcode.INC_VAR_UB, callLabel = "var2"), Instruction(Opcode.INC_VAR_F, callLabel = "var3"), Instruction(Opcode.INC_VAR_UW, callLabel = "var1"), Instruction(Opcode.INC_VAR_UB, callLabel = "var2"), Instruction(Opcode.INC_VAR_F, callLabel = "var3") ) val vars = mapOf("var1" to Value(DataType.UWORD, 65534), "var2" to Value(DataType.UBYTE, 254), "var3" to Value(DataType.FLOAT, -1.5) ) vm.load(makeProg(ins, vars = vars), null) vm.step(3) assertEquals(Value(DataType.UWORD, 65535), vm.variables["var1"]) assertEquals(Value(DataType.UBYTE, 255), vm.variables["var2"]) assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"]) vm.step(3) assertEquals(Value(DataType.UWORD, 0), vm.variables["var1"]) assertEquals(Value(DataType.UBYTE, 0), vm.variables["var2"]) assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"]) } @Test fun testDecVar() { val ins = mutableListOf( Instruction(Opcode.DEC_VAR_UW, callLabel = "var1"), Instruction(Opcode.DEC_VAR_UB, callLabel = "var2"), Instruction(Opcode.DEC_VAR_F, callLabel = "var3"), Instruction(Opcode.DEC_VAR_UW, callLabel = "var1"), Instruction(Opcode.DEC_VAR_UB, callLabel = "var2"), Instruction(Opcode.DEC_VAR_F, callLabel = "var3") ) val vars = mapOf("var1" to Value(DataType.UWORD, 1), "var2" to Value(DataType.UBYTE, 1), "var3" to Value(DataType.FLOAT, 1.5) ) vm.load(makeProg(ins, vars = vars), null) vm.step(3) assertEquals(Value(DataType.UWORD, 0), vm.variables["var1"]) assertEquals(Value(DataType.UBYTE, 0), vm.variables["var2"]) assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"]) vm.step(3) assertEquals(Value(DataType.UWORD, 65535), vm.variables["var1"]) assertEquals(Value(DataType.UBYTE, 255), vm.variables["var2"]) assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"]) } @Test fun testSyscall() { val ins = mutableListOf( Instruction(Opcode.SYSCALL, Value(DataType.UBYTE, Syscall.FUNC_RNDF.callNr)), Instruction(Opcode.SYSCALL, Value(DataType.UBYTE, Syscall.FUNC_RNDW.callNr)), Instruction(Opcode.SYSCALL, Value(DataType.UBYTE, Syscall.FUNC_RND.callNr)), Instruction(Opcode.SYSCALL, Value(DataType.UBYTE, Syscall.FUNC_RND.callNr)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 25544)), Instruction(Opcode.SYSCALL, Value(DataType.UBYTE, Syscall.FUNC_SIN.callNr)) ) vm.load(makeProg(ins), null) vm.step(4) val rndb1 = vm.evalstack.pop() val rndb2 = vm.evalstack.pop() val rndw = vm.evalstack.pop() val rndf = vm.evalstack.pop() assertEquals(DataType.UBYTE, rndb1.type) assertEquals(DataType.UBYTE, rndb2.type) assertEquals(DataType.UWORD, rndw.type) assertEquals(DataType.FLOAT, rndf.type) assertNotEquals(rndb1.integerValue(), rndb2.integerValue()) // this *sometimes* fails when the two random numbers are the same by pure chance assertTrue(rndf.numericValue().toDouble() > 0.0 && rndf.numericValue().toDouble() < 1.0) vm.step(2) assertEquals(Value(DataType.FLOAT, 0.28582414234140724), vm.evalstack.pop()) } @Test fun testLess() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.LESS_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.LESS_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESS_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.BYTE, -2), Opcode.LESS_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.LESS_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.LESS_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.LESS_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.LESS_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.WORD, -2), Opcode.LESS_W, Value(DataType.WORD, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.001), Value(DataType.UBYTE, 1)) } @Test fun testLessEq() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.LESSEQ_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 1), Opcode.LESSEQ_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESSEQ_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, -2), Opcode.LESSEQ_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.LESSEQ_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.LESSEQ_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.LESSEQ_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.LESSEQ_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESSEQ_W, Value(DataType.WORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.WORD, -2), Opcode.LESSEQ_W, Value(DataType.WORD, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 20.999), Value(DataType.UBYTE, 0)) } @Test fun testGreater() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.GREATER_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UBYTE, 1), Opcode.GREATER_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATER_B, Value(DataType.BYTE, -1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, -1), Opcode.GREATER_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.GREATER_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.GREATER_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.GREATER_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.GREATER_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATER_W, Value(DataType.WORD, -21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.WORD, -2), Opcode.GREATER_W, Value(DataType.WORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 20.999), Value(DataType.UBYTE, 1)) } @Test fun testGreaterEq() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.GREATEREQ_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UBYTE, 1), Opcode.GREATEREQ_UB, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATEREQ_B, Value(DataType.BYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.BYTE, -11), Opcode.GREATEREQ_B, Value(DataType.BYTE, 11), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.GREATEREQ_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.GREATEREQ_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.GREATEREQ_UW, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.GREATEREQ_UW, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.WORD, -21), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.001), Value(DataType.UBYTE, 0)) } @Test fun testEqual() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.EQUAL_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UBYTE, 1), Opcode.EQUAL_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.EQUAL_WORD, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.EQUAL_WORD, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.EQUAL_WORD, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.EQUAL_WORD, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.UBYTE, 0)) } @Test fun testNotEqual() { testBinaryOperator(Value(DataType.UBYTE, 0), Opcode.NOTEQUAL_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UBYTE, 1), Opcode.NOTEQUAL_BYTE, Value(DataType.UBYTE, 1), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.UWORD, 2), Opcode.NOTEQUAL_WORD, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 20), Opcode.NOTEQUAL_WORD, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.NOTEQUAL_WORD, Value(DataType.UWORD, 20), Value(DataType.UBYTE, 1)) testBinaryOperator(Value(DataType.UWORD, 21), Opcode.NOTEQUAL_WORD, Value(DataType.UWORD, 21), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.UBYTE, 0)) testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.UBYTE, 1)) } @Test fun testBCC() { val ins = mutableListOf( Instruction(Opcode.SEC), Instruction(Opcode.BCC, callLabel = "label"), Instruction(Opcode.CLC), Instruction(Opcode.BCC, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testBCS() { val ins = mutableListOf( Instruction(Opcode.CLC), Instruction(Opcode.BCS, callLabel = "label"), Instruction(Opcode.SEC), Instruction(Opcode.BCS, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) assertFalse(vm.P_carry) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testJZ() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa01)), Instruction(Opcode.JZ, callLabel = "label"), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa00)), Instruction(Opcode.JZ, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testJNZ() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa00)), Instruction(Opcode.JNZ, callLabel = "label"), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa01)), Instruction(Opcode.JNZ, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testJZW() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa00)), Instruction(Opcode.JZW, callLabel = "label"), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0x0000)), Instruction(Opcode.JZW, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testJNZW() { val ins = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0x0000)), Instruction(Opcode.JNZW, callLabel = "label"), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0xaa00)), Instruction(Opcode.JNZW, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("", vm.sourceLine) vm.step(3) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testJump() { val ins = mutableListOf( Instruction(Opcode.JUMP, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string2")) val labels = mapOf("label" to ins.size-1) // points to the second LINE instruction vm.load(makeProg(ins, labels=labels), null) vm.step(2) assertEquals("string2", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testReturn() { val ins = mutableListOf( Instruction(Opcode.RETURN), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "string1") ) vm.load(makeProg(ins), null) assertFailsWith { vm.step(1) } vm.callstack.add(2) // set the LINE opcode as return instruction assertEquals("", vm.sourceLine) vm.step(2) assertEquals("string1", vm.sourceLine) assertEquals(0, vm.callstack.size) assertEquals(0, vm.evalstack.size) } @Test fun testCall() { val ins = mutableListOf( Instruction(Opcode.CALL, callLabel = "label"), Instruction(Opcode.LINE, callLabel = "returned"), Instruction(Opcode.TERMINATE), Instruction(Opcode.LINE, callLabel = "called"), Instruction(Opcode.RETURN) ) val labels = mapOf("label" to 3) // points to the LINE instruction vm.load(makeProg(ins, labels = labels), null) vm.step(1) assertEquals("", vm.sourceLine) assertEquals(1, vm.callstack.size) assertSame(1, vm.callstack.peek()) vm.step(1) assertEquals("called", vm.sourceLine) vm.step(1) assertEquals(0, vm.callstack.size) assertEquals("called", vm.sourceLine) vm.step(1) assertEquals("returned", vm.sourceLine) } @Test fun testSHIFTEDR() { // @todo test SHR signed byte + signed word val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 9.99)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 3)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 61005)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 3)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 249)), Instruction(Opcode.SHIFTEDR_UBYTE), // 124 Instruction(Opcode.DISCARD_BYTE), Instruction(Opcode.SHIFTEDR_UBYTE), // 1 Instruction(Opcode.SHIFTEDR_UBYTE), // 0 Instruction(Opcode.SHIFTEDR_UBYTE), // 0 Instruction(Opcode.DISCARD_BYTE), Instruction(Opcode.SHIFTEDR_UWORD), // 30502 Instruction(Opcode.DISCARD_WORD), Instruction(Opcode.SHIFTEDR_UWORD), // 1 Instruction(Opcode.SHIFTEDR_UWORD), // 0 Instruction(Opcode.SHIFTEDR_UWORD), // 0 Instruction(Opcode.DISCARD_WORD), Instruction(Opcode.SHIFTEDR_UWORD) // error on float ) vm.load(makeProg(ins), null) vm.step(6) assertEquals(Value(DataType.UBYTE, 124), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UBYTE, 1), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UBYTE, 0), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UWORD, 30502), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UWORD, 1), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UWORD, 0), vm.evalstack.peek()) vm.step(1) assertEquals(Value(DataType.FLOAT, 9.99), vm.evalstack.peek()) assertFailsWith { vm.step(1) // float shift error } } @Test fun testSHIFTEDL() { val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 9.99)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 3)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 61005)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 3)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 249)), Instruction(Opcode.SHIFTEDL_BYTE), // 242 Instruction(Opcode.DISCARD_BYTE), Instruction(Opcode.SHIFTEDL_BYTE), // 6 Instruction(Opcode.DISCARD_BYTE), Instruction(Opcode.SHIFTEDL_WORD), // 56474 Instruction(Opcode.DISCARD_WORD), Instruction(Opcode.SHIFTEDL_WORD), // 6 Instruction(Opcode.DISCARD_WORD), Instruction(Opcode.SHIFTEDL_WORD) // error on float ) vm.load(makeProg(ins), null) vm.step(6) assertEquals(Value(DataType.UBYTE, 242), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UBYTE, 6), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UWORD, 56474), vm.evalstack.peek()) vm.step(2) assertEquals(Value(DataType.UWORD, 6), vm.evalstack.peek()) vm.step(1) assertEquals(Value(DataType.FLOAT, 9.99), vm.evalstack.peek()) assertFailsWith { vm.step(1) // float shift error } } @Test fun testROR() { // 9/17-bit rotation right (using carry) val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0b10010011)), Instruction(Opcode.ROR_BYTE), // 0b01001001 c=1 Instruction(Opcode.ROR_BYTE), // 0b10100100 c=1 Instruction(Opcode.ROR_BYTE), // 0b11010010 c=0 Instruction(Opcode.ROR_BYTE), // 0b01101001 c=0 Instruction(Opcode.ROR_BYTE), // 0b00110100 c=1 Instruction(Opcode.ROR_BYTE), // 0b10011010 c=0 Instruction(Opcode.ROR_BYTE), // 0b01001101 c=0 Instruction(Opcode.ROR_BYTE), // 0b00100110 c=1 Instruction(Opcode.ROR_BYTE) // 0b10010011 c=0 (original value after 9 rors) ) vm.load(makeProg(ins), null) vm.step(2) assertEquals(Value(DataType.UBYTE, 0b01001001), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b10100100), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b11010010), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b01101001), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(5) assertEquals(Value(DataType.UBYTE, 0b10010011), vm.evalstack.peek()) assertFalse(vm.P_carry) val ins2 = mutableListOf( Instruction(Opcode.CLC), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0b1001001100001101)), Instruction(Opcode.ROR_WORD), // 0b0100100110000110 c=1 Instruction(Opcode.ROR_WORD), // 0b1010010011000011 c=0 Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD), Instruction(Opcode.ROR_WORD) // 0b1001001100001101 c=0 (original value after 17 rors) ) vm.load(makeProg(ins2), null) vm.step(3) assertEquals(Value(DataType.UWORD, 0b0100100110000110), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UWORD, 0b1010010011000011), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(15) assertEquals(Value(DataType.UWORD, 0b1001001100001101), vm.evalstack.peek()) assertFalse(vm.P_carry) } @Test fun testROL() { // 9/17-bit rotation left (using carry) val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0b10010011)), Instruction(Opcode.ROL_BYTE), // 0b00100110 c=1 Instruction(Opcode.ROL_BYTE), // 0b01001101 c=0 Instruction(Opcode.ROL_BYTE), // 0b10011010 c=0 Instruction(Opcode.ROL_BYTE), // 0b00110100 c=1 Instruction(Opcode.ROL_BYTE), // 0b01101001 c=0 Instruction(Opcode.ROL_BYTE), // 0b11010010 c=0 Instruction(Opcode.ROL_BYTE), // 0b10100100 c=1 Instruction(Opcode.ROL_BYTE), // 0b01001001 c=1 Instruction(Opcode.ROL_BYTE) // 0b10010011 c=0 (original value after 9 rors) ) vm.load(makeProg(ins), null) vm.step(2) assertEquals(Value(DataType.UBYTE, 0b00100110), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b01001101), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b10011010), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b00110100), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(5) assertEquals(Value(DataType.UBYTE, 0b10010011), vm.evalstack.peek()) assertFalse(vm.P_carry) val ins2 = mutableListOf( Instruction(Opcode.CLC), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0b1001001100001101)), Instruction(Opcode.ROL_WORD), // 0b0010011000011010 c=1 Instruction(Opcode.ROL_WORD), // 0b0100110000110101 c=0 Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD), Instruction(Opcode.ROL_WORD) // 0b1001001100001101 c=0 (original value after 17 rors) ) vm.load(makeProg(ins2), null) vm.step(3) assertEquals(Value(DataType.UWORD, 0b0010011000011010), vm.evalstack.peek()) assertTrue(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UWORD, 0b0100110000110101), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(15) assertEquals(Value(DataType.UWORD, 0b1001001100001101), vm.evalstack.peek()) assertFalse(vm.P_carry) } @Test fun testROR2() { // 8/16-bit rotation right val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0b10010011)), Instruction(Opcode.ROR2_BYTE), // 0b11001001 Instruction(Opcode.ROR2_BYTE), // 0b11100100 Instruction(Opcode.ROR2_BYTE), // 0b01110010 Instruction(Opcode.ROR2_BYTE), Instruction(Opcode.ROR2_BYTE), Instruction(Opcode.ROR2_BYTE), Instruction(Opcode.ROR2_BYTE), Instruction(Opcode.ROR2_BYTE) // 0b10010011 (original value after 8 rors) ) vm.load(makeProg(ins), null) vm.step(2) assertEquals(Value(DataType.UBYTE, 0b11001001), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b11100100), vm.evalstack.peek()) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b01110010), vm.evalstack.peek()) vm.step(5) assertEquals(Value(DataType.UBYTE, 0b10010011), vm.evalstack.peek()) val ins2 = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0b1001001100001101)), Instruction(Opcode.ROR2_WORD), // 0b1100100110000110 Instruction(Opcode.ROR2_WORD), // 0b0110010011000011 Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD), Instruction(Opcode.ROR2_WORD) // 0b1001001100001101 (original value after 16 rors) ) vm.load(makeProg(ins2), null) vm.step(2) assertEquals(Value(DataType.UWORD, 0b1100100110000110), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UWORD, 0b0110010011000011), vm.evalstack.peek()) vm.step(14) assertEquals(Value(DataType.UWORD, 0b1001001100001101), vm.evalstack.peek()) } @Test fun testROL2() { // 8/16-bit rotation left val ins = mutableListOf( Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 0b10010011)), Instruction(Opcode.ROL2_BYTE), // 0b00100111 Instruction(Opcode.ROL2_BYTE), // 0b01001110 Instruction(Opcode.ROL2_BYTE), Instruction(Opcode.ROL2_BYTE), Instruction(Opcode.ROL2_BYTE), Instruction(Opcode.ROL2_BYTE), Instruction(Opcode.ROL2_BYTE), Instruction(Opcode.ROL2_BYTE) // 0b10010011 (original value after 8 rols) ) vm.load(makeProg(ins), null) vm.step(2) assertEquals(Value(DataType.UBYTE, 0b00100111), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UBYTE, 0b01001110), vm.evalstack.peek()) vm.step(6) assertEquals(Value(DataType.UBYTE, 0b10010011), vm.evalstack.peek()) val ins2 = mutableListOf( Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 0b1001001100001101)), Instruction(Opcode.ROL2_WORD), // 0b0010011000011011 Instruction(Opcode.ROL2_WORD), // 0b0100110000110110 Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD), Instruction(Opcode.ROL2_WORD) // 0b1001001100001101 (original value after 16 rols) ) vm.load(makeProg(ins2), null) vm.step(2) assertEquals(Value(DataType.UWORD, 0b0010011000011011), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(1) assertEquals(Value(DataType.UWORD, 0b0100110000110110), vm.evalstack.peek()) assertFalse(vm.P_carry) vm.step(14) assertEquals(Value(DataType.UWORD, 0b1001001100001101), vm.evalstack.peek()) } private fun pushOpcode(dt: DataType): Opcode { return when (dt) { in ByteDatatypes -> Opcode.PUSH_BYTE in WordDatatypes -> Opcode.PUSH_WORD in IterableDatatypes -> Opcode.PUSH_WORD DataType.FLOAT -> Opcode.PUSH_FLOAT else -> throw IllegalArgumentException("invalid datatype") } } private fun testBinaryOperator(left: Value, operator: Opcode, right: Value, result: Value) { val program=makeProg(mutableListOf( Instruction(pushOpcode(left.type), left), Instruction(pushOpcode(right.type), right), Instruction(operator) )) vm.load(program, null) vm.step(3) assertEquals(1, vm.evalstack.size) assertEquals(result, vm.evalstack.pop()) } private fun testUnaryOperator(value: Value, operator: Opcode, result: Value) { val program=makeProg(mutableListOf( Instruction(pushOpcode(value.type), value), Instruction(operator) )) vm.load(program, null) vm.step(2) assertEquals(1, vm.evalstack.size) assertEquals(result, vm.evalstack.pop()) } }