even more opcodes type-specific

This commit is contained in:
Irmen de Jong 2018-10-05 16:57:13 +02:00
parent e8ba21d3ba
commit 52e1661c8e
5 changed files with 334 additions and 198 deletions

View File

@ -309,6 +309,24 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
}
}
private fun opcodeAdd(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.ADD_B
DataType.WORD -> Opcode.ADD_W
DataType.FLOAT -> Opcode.ADD_F
else -> throw CompilerException("invalid dt $dt")
}
}
private fun opcodeSub(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.SUB_B
DataType.WORD -> Opcode.SUB_W
DataType.FLOAT -> Opcode.SUB_F
else -> throw CompilerException("invalid dt $dt")
}
}
private fun opcodePushvar(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.PUSH_VAR
@ -711,14 +729,62 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
if(leftDt!=rightDt)
throw CompilerException("operands have different datatypes")
val opcode = when(operator) {
// todo variants depending on leftdt/rightdt (b/w/f)
"+" -> Opcode.ADD
"-" -> Opcode.SUB
"*" -> Opcode.MUL
"/" -> Opcode.DIV
"//" -> Opcode.FLOORDIV
"%" -> Opcode.REMAINDER
"**" -> Opcode.POW
"+" -> {
when(leftDt) {
DataType.BYTE -> Opcode.ADD_B
DataType.WORD -> Opcode.ADD_W
DataType.FLOAT -> Opcode.ADD_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"-" -> {
when(leftDt) {
DataType.BYTE -> Opcode.SUB_B
DataType.WORD -> Opcode.SUB_W
DataType.FLOAT -> Opcode.SUB_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"*" -> {
when(leftDt) {
DataType.BYTE -> Opcode.MUL_B
DataType.WORD -> Opcode.MUL_W
DataType.FLOAT -> Opcode.MUL_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"/" -> {
when(leftDt) {
DataType.BYTE -> Opcode.DIV_B
DataType.WORD -> Opcode.DIV_W
DataType.FLOAT -> Opcode.DIV_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"//" -> {
when(leftDt) {
DataType.BYTE -> Opcode.FLOORDIV_B
DataType.WORD -> Opcode.FLOORDIV_W
DataType.FLOAT -> Opcode.FLOORDIV_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"%" -> {
when(leftDt) {
DataType.BYTE -> Opcode.REMAINDER_B
DataType.WORD -> Opcode.REMAINDER_W
DataType.FLOAT -> Opcode.REMAINDER_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"**" -> {
when(leftDt) {
DataType.BYTE -> Opcode.POW_B
DataType.WORD -> Opcode.POW_W
DataType.FLOAT -> Opcode.POW_F
else -> throw CompilerException("only byte/word/float possible")
}
}
"&" -> {
when(leftDt) {
DataType.BYTE -> Opcode.BITAND
@ -819,7 +885,14 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
throw CompilerException("operand datatype not known")
val opcode = when(operator) {
"+" -> Opcode.NOP
"-" -> Opcode.NEG // todo b/w/f
"-" -> {
when (operandDt) {
DataType.BYTE -> Opcode.NEG_B
DataType.WORD -> Opcode.NEG_W
DataType.FLOAT -> Opcode.NEG_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"~" -> {
when(operandDt) {
DataType.BYTE -> Opcode.INV
@ -858,9 +931,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
// calc matrix index i=y*columns+x
// (the const-folding will have removed this for us when both x and y are constants)
translate(y)
stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!))
stackvmProg.instr(Opcode.MUL)
stackvmProg.instr(Opcode.ADD)
stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!))
stackvmProg.instr(Opcode.MUL_W)
stackvmProg.instr(Opcode.ADD_W)
}
if(write)
@ -921,8 +994,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
val opcode = opcodePush(one.type)
stackvmProg.instr(opcode, one)
when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.ADD)
"--" -> stackvmProg.instr(Opcode.SUB)
"++" -> stackvmProg.instr(opcodeAdd(one.type))
"--" -> stackvmProg.instr(opcodeSub(one.type))
}
translate(stmt.target.arrayindexed!!, true)
}
@ -1008,12 +1081,54 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
if(valueDt !in validDt)
throw CompilerException("invalid datatype(s) for operand(s)")
val opcode = when(aug_op) {
"+=" -> Opcode.ADD
"-=" -> Opcode.SUB
"/=" -> Opcode.DIV
"//=" -> Opcode.FLOORDIV
"*=" -> Opcode.MUL
"**=" -> Opcode.POW
"+=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.ADD_B
DataType.WORD -> Opcode.ADD_W
DataType.FLOAT -> Opcode.ADD_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"-=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.SUB_B
DataType.WORD -> Opcode.SUB_W
DataType.FLOAT -> Opcode.SUB_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"/=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.DIV_B
DataType.WORD -> Opcode.DIV_W
DataType.FLOAT -> Opcode.DIV_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"//=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.FLOORDIV_B
DataType.WORD -> Opcode.FLOORDIV_W
DataType.FLOAT -> Opcode.FLOORDIV_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"*=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.MUL_B
DataType.WORD -> Opcode.MUL_W
DataType.FLOAT -> Opcode.MUL_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"**=" -> {
when (valueDt) {
DataType.BYTE -> Opcode.POW_B
DataType.WORD -> Opcode.POW_W
DataType.FLOAT -> Opcode.POW_F
else -> throw CompilerException("only byte/word/lfoat possible")
}
}
"&=" -> {
when(valueDt) {
DataType.BYTE -> Opcode.BITAND
@ -1200,7 +1315,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value.
stackvmProg.instr(opcodePush(zero.type), Value(zero.type, numElements))
stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar)
stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(opcodeSub(zero.type))
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
stackvmProg.label(breakLabel)
@ -1248,13 +1363,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
range.step>1 -> {
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step))
stackvmProg.instr(Opcode.ADD)
stackvmProg.instr(opcodeSub(varDt))
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
}
range.step<1 -> {
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step)))
stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(opcodeSub(varDt))
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
}
}
@ -1262,7 +1377,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value.
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.last+range.step))
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(opcodeSub(varDt))
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
stackvmProg.label(breakLabel)

View File

@ -33,14 +33,30 @@ enum class Opcode {
POP_VAR_F, // pop float value into variable
// numeric arithmetic
ADD, // todo b/w/f
SUB, // todo b/w/f
MUL, // todo b/w/f
DIV, // todo b/w/f
FLOORDIV, // todo b/w/f
REMAINDER, // todo b/w/f
POW, // todo b/w/f
NEG, // todo b/w/f
ADD_B,
ADD_W,
ADD_F,
SUB_B,
SUB_W,
SUB_F,
MUL_B,
MUL_W,
MUL_F,
DIV_B,
DIV_W,
DIV_F,
FLOORDIV_B,
FLOORDIV_W,
FLOORDIV_F,
REMAINDER_B,
REMAINDER_W,
REMAINDER_F,
POW_B,
POW_W,
POW_F,
NEG_B,
NEG_W,
NEG_F,
// bit shifts and bitwise arithmetic
SHL,
@ -470,44 +486,145 @@ class StackVm(private var traceOutputFile: String?) {
val address = ins.arg!!.integerValue()
mem.setFloat(address, value.numericValue().toDouble())
}
Opcode.ADD -> {
Opcode.ADD_B -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.add(top))
}
Opcode.SUB -> {
Opcode.ADD_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.add(top))
}
Opcode.ADD_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.add(top))
}
Opcode.SUB_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.sub(top))
}
Opcode.MUL -> {
Opcode.SUB_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.sub(top))
}
Opcode.SUB_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.sub(top))
}
Opcode.MUL_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.mul(top))
}
Opcode.DIV -> {
Opcode.MUL_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.mul(top))
}
Opcode.MUL_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.mul(top))
}
Opcode.DIV_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.div(top))
}
Opcode.FLOORDIV -> {
Opcode.DIV_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.div(top))
}
Opcode.DIV_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.div(top))
}
Opcode.FLOORDIV_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.floordiv(top))
}
Opcode.REMAINDER -> {
Opcode.FLOORDIV_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.floordiv(top))
}
Opcode.FLOORDIV_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.floordiv(top))
}
Opcode.REMAINDER_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.remainder(top))
}
Opcode.POW -> {
Opcode.REMAINDER_W -> {
val (top, second) = evalstack.pop2()
// todo b/w/f
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.remainder(top))
}
Opcode.REMAINDER_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.remainder(top))
}
Opcode.POW_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
evalstack.push(second.pow(top))
}
Opcode.NEG -> {
Opcode.POW_W -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
evalstack.push(second.pow(top))
}
Opcode.POW_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
checkDt(second, DataType.FLOAT)
evalstack.push(second.pow(top))
}
Opcode.NEG_B -> {
val v = evalstack.pop()
// todo b/w/f
checkDt(v, DataType.BYTE)
evalstack.push(v.neg())
}
Opcode.NEG_W -> {
val v = evalstack.pop()
checkDt(v, DataType.WORD)
evalstack.push(v.neg())
}
Opcode.NEG_F -> {
val v = evalstack.pop()
checkDt(v, DataType.FLOAT)
evalstack.push(v.neg())
}
Opcode.SHL -> {

View File

@ -97,17 +97,11 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
}
private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value {
if(leftDt!=rightDt)
throw VmExecutionException("left and right datatypes are not the same")
if(result.toDouble() < 0 ) {
return when(leftDt) {
DataType.BYTE -> {
// BYTE can become WORD if right operand is WORD, or when value is too large for byte
when(rightDt) {
DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255)
DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535)
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision")
else -> throw VmExecutionException("$op on non-numeric result type")
}
}
DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255)
DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("$op on non-numeric type")
@ -115,22 +109,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
}
return when(leftDt) {
DataType.BYTE -> {
// BYTE can become WORD if right operand is WORD, or when value is too large for byte
if(result.toDouble() >= 256 && rightDt!=DataType.FLOAT)
return Value(DataType.WORD, result)
when(rightDt) {
DataType.BYTE -> Value(DataType.BYTE, result)
DataType.WORD -> Value(DataType.WORD, result)
DataType.FLOAT -> throw VmExecutionException("floating point loss of precision on byte")
else -> throw VmExecutionException("$op on non-numeric result type")
}
}
DataType.WORD -> {
if(rightDt==DataType.FLOAT)
throw VmExecutionException("floating point loss of precision on word")
Value(DataType.WORD, result)
}
DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255)
DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535)
DataType.FLOAT -> Value(DataType.FLOAT, result)
else -> throw VmExecutionException("$op on non-numeric type")
}

View File

@ -253,60 +253,65 @@ class TestStackVmOpcodes {
@Test
fun testAdd() {
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000+40))
testBinaryOperator(Value(DataType.WORD, 4000+40), Opcode.ADD, Value(DataType.WORD, 123), Value(DataType.WORD, 4000+40+123))
testBinaryOperator(Value(DataType.BYTE, 140), Opcode.ADD_B, Value(DataType.BYTE, 222), Value(DataType.BYTE, 106))
testBinaryOperator(Value(DataType.BYTE, 40), Opcode.ADD_B, Value(DataType.BYTE, 122), Value(DataType.BYTE, 162))
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD_W, Value(DataType.WORD, 40), Value(DataType.WORD, 4040))
testBinaryOperator(Value(DataType.WORD, 24000), Opcode.ADD_W, Value(DataType.WORD, 55000), Value(DataType.WORD, 13464))
testBinaryOperator(Value(DataType.FLOAT, 4000.0), Opcode.ADD_F, Value(DataType.FLOAT, 123.22), Value(DataType.FLOAT, 4123.22))
assertFailsWith<VmExecutionException> {
testBinaryOperator(Value(DataType.WORD, 4000 + 40), Opcode.ADD, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40)))
testBinaryOperator(Value(DataType.WORD, 4000 + 40), Opcode.ADD_W, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40)))
}
}
@Test
fun testSub() {
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000-40))
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123))
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.SUB_B, Value(DataType.BYTE, 70), Value(DataType.BYTE, 180))
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB_W, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123))
testBinaryOperator(Value(DataType.FLOAT, 123.44), Opcode.SUB_F, Value(DataType.FLOAT, 23.44), Value(DataType.FLOAT, 100.0))
assertFailsWith<VmExecutionException> {
testBinaryOperator(Value(DataType.WORD, 4000 - 40), Opcode.SUB, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40)))
testBinaryOperator(Value(DataType.WORD, 4000 - 40), Opcode.SUB_W, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40)))
}
}
@Test
fun testMul() {
testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.BYTE, 4), Value(DataType.WORD, 401*4))
testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4))
testBinaryOperator(Value(DataType.BYTE, 41), Opcode.MUL_B, Value(DataType.BYTE, 4), Value(DataType.BYTE, 164))
testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL_W, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4))
testBinaryOperator(Value(DataType.FLOAT, 40.1), Opcode.MUL_F, Value(DataType.FLOAT, 2.4), Value(DataType.FLOAT, 96.24))
assertFailsWith<VmExecutionException> {
testBinaryOperator(Value(DataType.WORD, 401 * 4), Opcode.MUL, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4)))
testBinaryOperator(Value(DataType.WORD, 401 * 4), Opcode.MUL_W, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4)))
}
}
@Test
fun testDiv() {
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.BYTE, 40), Value(DataType.WORD, 99))
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.WORD, 40), Value(DataType.WORD, 99))
testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV, Value(DataType.WORD, 99), Value(DataType.FLOAT, 42.25/99))
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.DIV_B, Value(DataType.BYTE, 12), Value(DataType.BYTE, 20))
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV_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<VmExecutionException> {
testBinaryOperator(Value(DataType.WORD, 3333), Opcode.DIV, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22))
testBinaryOperator(Value(DataType.WORD, 3333), Opcode.DIV_W, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22))
}
}
@Test
fun testFloorDiv() {
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.BYTE, 99), Value(DataType.WORD, 40))
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.WORD, 99), Value(DataType.WORD, 40))
testBinaryOperator(Value(DataType.FLOAT, 4000.25), Opcode.FLOORDIV, Value(DataType.BYTE, 40), Value(DataType.FLOAT, 100.0))
testBinaryOperator(Value(DataType.BYTE, 244), Opcode.FLOORDIV_B, Value(DataType.BYTE, 33), Value(DataType.BYTE, 7))
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV_W, Value(DataType.WORD, 99), Value(DataType.WORD, 40))
testBinaryOperator(Value(DataType.FLOAT, 4000.25), Opcode.FLOORDIV_F, Value(DataType.FLOAT, 40.2), Value(DataType.FLOAT, 99.0))
}
@Test
fun testPow() {
testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.BYTE, 4), Value(DataType.WORD, 81))
testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.WORD, 4), Value(DataType.WORD, 81))
testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW, Value(DataType.BYTE, 81), Value(DataType.FLOAT, 2253.2402360440274))
testBinaryOperator(Value(DataType.BYTE, 3), Opcode.POW_B, Value(DataType.BYTE, 4), Value(DataType.BYTE, 81))
testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW_W, Value(DataType.WORD, 4), Value(DataType.WORD, 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.WORD, 500), Opcode.REMAINDER, Value(DataType.BYTE, 29), Value(DataType.BYTE, 7))
testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.WORD, 29), Value(DataType.BYTE, 7))
testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER, Value(DataType.BYTE, 7), Value(DataType.FLOAT, 6.5))
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.REMAINDER_B, Value(DataType.BYTE, 29), Value(DataType.BYTE, 18))
testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER_W, Value(DataType.WORD, 29), Value(DataType.WORD, 7))
testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER_F, Value(DataType.FLOAT, 7.0), Value(DataType.FLOAT, 6.5))
}
@Test
@ -387,9 +392,9 @@ class TestStackVmOpcodes {
@Test
fun testNeg() {
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG, Value(DataType.BYTE, 244))
testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG, Value(DataType.WORD, 64302))
testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG, Value(DataType.FLOAT, -123.456))
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, 244))
testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG_W, Value(DataType.WORD, 64302))
testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG_F, Value(DataType.FLOAT, -123.456))
}
@Test

View File

@ -138,106 +138,25 @@ class TestStackVmValue {
}
@Test
fun testArithmeticByteFirstOperand() {
var r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 120))
assertEquals(DataType.BYTE, r.type)
assertEquals(220, r.integerValue())
r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 199))
assertEquals(DataType.WORD, r.type)
assertEquals(299, r.integerValue())
r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 88))
assertEquals(DataType.BYTE, r.type)
assertEquals(12, r.integerValue())
r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 188))
assertEquals(DataType.BYTE, r.type)
assertEquals(168, r.integerValue())
r = Value(DataType.BYTE, 5).mul(Value(DataType.BYTE, 33))
assertEquals(DataType.BYTE, r.type)
assertEquals(165, r.integerValue())
r = Value(DataType.BYTE, 22).mul(Value(DataType.BYTE, 33))
assertEquals(DataType.WORD, r.type)
assertEquals(726, r.integerValue())
r = Value(DataType.BYTE, 233).div(Value(DataType.BYTE, 12))
assertEquals(DataType.BYTE, r.type)
assertEquals(19, r.integerValue())
r = Value(DataType.BYTE, 233).div(Value(DataType.BYTE, 0))
assertEquals(DataType.BYTE, r.type)
assertEquals(255, r.integerValue())
r = Value(DataType.BYTE, 233).floordiv(Value(DataType.BYTE, 19))
assertEquals(DataType.BYTE, r.type)
assertEquals(12, r.integerValue())
r = Value(DataType.BYTE, 100).add(Value(DataType.WORD, 120))
assertEquals(DataType.WORD, r.type)
assertEquals(220, r.integerValue())
r = Value(DataType.BYTE, 100).add(Value(DataType.WORD, 199))
assertEquals(DataType.WORD, r.type)
assertEquals(299, r.integerValue())
r = Value(DataType.BYTE, 100).sub(Value(DataType.WORD, 88))
assertEquals(DataType.WORD, r.type)
assertEquals(12, r.integerValue())
r = Value(DataType.BYTE, 100).sub(Value(DataType.WORD, 188))
assertEquals(DataType.WORD, r.type)
assertEquals(65448, r.integerValue())
r = Value(DataType.BYTE, 5).mul(Value(DataType.WORD, 33))
assertEquals(DataType.WORD, r.type)
assertEquals(165, r.integerValue())
r = Value(DataType.BYTE, 22).mul(Value(DataType.WORD, 33))
assertEquals(DataType.WORD, r.type)
assertEquals(726, r.integerValue())
r = Value(DataType.BYTE, 233).div(Value(DataType.WORD, 12))
assertEquals(DataType.BYTE, r.type)
assertEquals(19, r.integerValue())
r = Value(DataType.BYTE, 233).div(Value(DataType.WORD, 0))
assertEquals(DataType.BYTE, r.type)
assertEquals(255, r.integerValue())
r = Value(DataType.BYTE, 233).floordiv(Value(DataType.WORD, 19))
assertEquals(DataType.BYTE, r.type)
assertEquals(12, r.integerValue())
}
@Test
fun testArithmeticWordFirstOperand() {
var r = Value(DataType.WORD, 100).add(Value(DataType.BYTE, 120))
assertEquals(DataType.WORD, r.type)
assertEquals(220, r.integerValue())
r = Value(DataType.WORD, 100).div(Value(DataType.BYTE, 10))
assertEquals(DataType.WORD, r.type)
assertEquals(10, r.integerValue())
r = Value(DataType.WORD, 100).div(Value(DataType.BYTE, 0))
assertEquals(DataType.WORD, r.type)
assertEquals(65535, r.integerValue())
r = Value(DataType.WORD, 100).div(Value(DataType.WORD, 0))
assertEquals(DataType.WORD, r.type)
assertEquals(65535, r.integerValue())
r = Value(DataType.WORD, 33445).floordiv(Value(DataType.WORD, 123))
assertEquals(DataType.WORD, r.type)
assertEquals(271, r.integerValue())
r = Value(DataType.WORD, 33445).floordiv(Value(DataType.WORD, 999))
assertEquals(DataType.WORD, r.type)
assertEquals(33, r.integerValue())
fun testNoDtConversion() {
assertFailsWith<VmExecutionException> {
Value(DataType.WORD, 100).add(Value(DataType.BYTE, 120))
}
assertFailsWith<VmExecutionException> {
Value(DataType.BYTE, 100).add(Value(DataType.WORD, 120))
}
assertFailsWith<VmExecutionException> {
Value(DataType.FLOAT, 100.22).add(Value(DataType.WORD, 120))
}
assertFailsWith<VmExecutionException> {
Value(DataType.WORD, 1002).add(Value(DataType.FLOAT, 120.22))
}
assertFailsWith<VmExecutionException> {
Value(DataType.FLOAT, 100.22).add(Value(DataType.BYTE, 120))
}
assertFailsWith<VmExecutionException> {
Value(DataType.BYTE, 12).add(Value(DataType.FLOAT, 120.22))
}
}
@Test