mirror of
https://github.com/irmen/prog8.git
synced 2024-07-28 18:29:40 +00:00
even more opcodes type-specific
This commit is contained in:
parent
e8ba21d3ba
commit
52e1661c8e
@ -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)
|
||||
|
@ -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 -> {
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user