mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +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 {
|
private fun opcodePushvar(dt: DataType): Opcode {
|
||||||
return when (dt) {
|
return when (dt) {
|
||||||
DataType.BYTE -> Opcode.PUSH_VAR
|
DataType.BYTE -> Opcode.PUSH_VAR
|
||||||
@ -711,14 +729,62 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
if(leftDt!=rightDt)
|
if(leftDt!=rightDt)
|
||||||
throw CompilerException("operands have different datatypes")
|
throw CompilerException("operands have different datatypes")
|
||||||
val opcode = when(operator) {
|
val opcode = when(operator) {
|
||||||
// todo variants depending on leftdt/rightdt (b/w/f)
|
"+" -> {
|
||||||
"+" -> Opcode.ADD
|
when(leftDt) {
|
||||||
"-" -> Opcode.SUB
|
DataType.BYTE -> Opcode.ADD_B
|
||||||
"*" -> Opcode.MUL
|
DataType.WORD -> Opcode.ADD_W
|
||||||
"/" -> Opcode.DIV
|
DataType.FLOAT -> Opcode.ADD_F
|
||||||
"//" -> Opcode.FLOORDIV
|
else -> throw CompilerException("only byte/word/float possible")
|
||||||
"%" -> Opcode.REMAINDER
|
}
|
||||||
"**" -> Opcode.POW
|
}
|
||||||
|
"-" -> {
|
||||||
|
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) {
|
when(leftDt) {
|
||||||
DataType.BYTE -> Opcode.BITAND
|
DataType.BYTE -> Opcode.BITAND
|
||||||
@ -819,7 +885,14 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
throw CompilerException("operand datatype not known")
|
throw CompilerException("operand datatype not known")
|
||||||
val opcode = when(operator) {
|
val opcode = when(operator) {
|
||||||
"+" -> Opcode.NOP
|
"+" -> 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) {
|
when(operandDt) {
|
||||||
DataType.BYTE -> Opcode.INV
|
DataType.BYTE -> Opcode.INV
|
||||||
@ -858,9 +931,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
// calc matrix index i=y*columns+x
|
// calc matrix index i=y*columns+x
|
||||||
// (the const-folding will have removed this for us when both x and y are constants)
|
// (the const-folding will have removed this for us when both x and y are constants)
|
||||||
translate(y)
|
translate(y)
|
||||||
stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!))
|
stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!))
|
||||||
stackvmProg.instr(Opcode.MUL)
|
stackvmProg.instr(Opcode.MUL_W)
|
||||||
stackvmProg.instr(Opcode.ADD)
|
stackvmProg.instr(Opcode.ADD_W)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(write)
|
if(write)
|
||||||
@ -921,8 +994,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
val opcode = opcodePush(one.type)
|
val opcode = opcodePush(one.type)
|
||||||
stackvmProg.instr(opcode, one)
|
stackvmProg.instr(opcode, one)
|
||||||
when(stmt.operator) {
|
when(stmt.operator) {
|
||||||
"++" -> stackvmProg.instr(Opcode.ADD)
|
"++" -> stackvmProg.instr(opcodeAdd(one.type))
|
||||||
"--" -> stackvmProg.instr(Opcode.SUB)
|
"--" -> stackvmProg.instr(opcodeSub(one.type))
|
||||||
}
|
}
|
||||||
translate(stmt.target.arrayindexed!!, true)
|
translate(stmt.target.arrayindexed!!, true)
|
||||||
}
|
}
|
||||||
@ -1008,12 +1081,54 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
if(valueDt !in validDt)
|
if(valueDt !in validDt)
|
||||||
throw CompilerException("invalid datatype(s) for operand(s)")
|
throw CompilerException("invalid datatype(s) for operand(s)")
|
||||||
val opcode = when(aug_op) {
|
val opcode = when(aug_op) {
|
||||||
"+=" -> Opcode.ADD
|
"+=" -> {
|
||||||
"-=" -> Opcode.SUB
|
when (valueDt) {
|
||||||
"/=" -> Opcode.DIV
|
DataType.BYTE -> Opcode.ADD_B
|
||||||
"//=" -> Opcode.FLOORDIV
|
DataType.WORD -> Opcode.ADD_W
|
||||||
"*=" -> Opcode.MUL
|
DataType.FLOAT -> Opcode.ADD_F
|
||||||
"**=" -> Opcode.POW
|
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) {
|
when(valueDt) {
|
||||||
DataType.BYTE -> Opcode.BITAND
|
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.
|
// 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(opcodePush(zero.type), Value(zero.type, numElements))
|
||||||
stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar)
|
stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar)
|
||||||
stackvmProg.instr(Opcode.SUB)
|
stackvmProg.instr(opcodeSub(zero.type))
|
||||||
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||||
|
|
||||||
stackvmProg.label(breakLabel)
|
stackvmProg.label(breakLabel)
|
||||||
@ -1248,13 +1363,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
range.step>1 -> {
|
range.step>1 -> {
|
||||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step))
|
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step))
|
||||||
stackvmProg.instr(Opcode.ADD)
|
stackvmProg.instr(opcodeSub(varDt))
|
||||||
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
||||||
}
|
}
|
||||||
range.step<1 -> {
|
range.step<1 -> {
|
||||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step)))
|
stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step)))
|
||||||
stackvmProg.instr(Opcode.SUB)
|
stackvmProg.instr(opcodeSub(varDt))
|
||||||
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
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.
|
// 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(opcodePush(varDt), Value(varDt, range.last+range.step))
|
||||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||||
stackvmProg.instr(Opcode.SUB)
|
stackvmProg.instr(opcodeSub(varDt))
|
||||||
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||||
|
|
||||||
stackvmProg.label(breakLabel)
|
stackvmProg.label(breakLabel)
|
||||||
|
@ -33,14 +33,30 @@ enum class Opcode {
|
|||||||
POP_VAR_F, // pop float value into variable
|
POP_VAR_F, // pop float value into variable
|
||||||
|
|
||||||
// numeric arithmetic
|
// numeric arithmetic
|
||||||
ADD, // todo b/w/f
|
ADD_B,
|
||||||
SUB, // todo b/w/f
|
ADD_W,
|
||||||
MUL, // todo b/w/f
|
ADD_F,
|
||||||
DIV, // todo b/w/f
|
SUB_B,
|
||||||
FLOORDIV, // todo b/w/f
|
SUB_W,
|
||||||
REMAINDER, // todo b/w/f
|
SUB_F,
|
||||||
POW, // todo b/w/f
|
MUL_B,
|
||||||
NEG, // todo b/w/f
|
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
|
// bit shifts and bitwise arithmetic
|
||||||
SHL,
|
SHL,
|
||||||
@ -470,44 +486,145 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
val address = ins.arg!!.integerValue()
|
val address = ins.arg!!.integerValue()
|
||||||
mem.setFloat(address, value.numericValue().toDouble())
|
mem.setFloat(address, value.numericValue().toDouble())
|
||||||
}
|
}
|
||||||
Opcode.ADD -> {
|
Opcode.ADD_B -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
evalstack.push(second.add(top))
|
evalstack.push(second.add(top))
|
||||||
}
|
}
|
||||||
Opcode.SUB -> {
|
Opcode.ADD_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
evalstack.push(second.sub(top))
|
||||||
}
|
}
|
||||||
Opcode.MUL -> {
|
Opcode.SUB_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
evalstack.push(second.mul(top))
|
||||||
}
|
}
|
||||||
Opcode.DIV -> {
|
Opcode.MUL_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
evalstack.push(second.div(top))
|
||||||
}
|
}
|
||||||
Opcode.FLOORDIV -> {
|
Opcode.DIV_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
evalstack.push(second.floordiv(top))
|
||||||
}
|
}
|
||||||
Opcode.REMAINDER -> {
|
Opcode.FLOORDIV_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
evalstack.push(second.remainder(top))
|
||||||
}
|
}
|
||||||
Opcode.POW -> {
|
Opcode.REMAINDER_W -> {
|
||||||
val (top, second) = evalstack.pop2()
|
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))
|
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()
|
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())
|
evalstack.push(v.neg())
|
||||||
}
|
}
|
||||||
Opcode.SHL -> {
|
Opcode.SHL -> {
|
||||||
|
@ -97,40 +97,20 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value {
|
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 ) {
|
if(result.toDouble() < 0 ) {
|
||||||
return when(leftDt) {
|
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.BYTE -> Value(DataType.BYTE, result.toInt() and 255)
|
||||||
DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535)
|
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.WORD -> Value(DataType.WORD, result.toInt() and 65535)
|
|
||||||
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
||||||
else -> throw VmExecutionException("$op on non-numeric type")
|
else -> throw VmExecutionException("$op on non-numeric type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return when(leftDt) {
|
return when(leftDt) {
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255)
|
||||||
// BYTE can become WORD if right operand is WORD, or when value is too large for byte
|
DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535)
|
||||||
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.FLOAT -> Value(DataType.FLOAT, result)
|
DataType.FLOAT -> Value(DataType.FLOAT, result)
|
||||||
else -> throw VmExecutionException("$op on non-numeric type")
|
else -> throw VmExecutionException("$op on non-numeric type")
|
||||||
}
|
}
|
||||||
|
@ -253,60 +253,65 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAdd() {
|
fun testAdd() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000+40))
|
testBinaryOperator(Value(DataType.BYTE, 140), Opcode.ADD_B, Value(DataType.BYTE, 222), Value(DataType.BYTE, 106))
|
||||||
testBinaryOperator(Value(DataType.WORD, 4000+40), Opcode.ADD, Value(DataType.WORD, 123), Value(DataType.WORD, 4000+40+123))
|
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> {
|
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
|
@Test
|
||||||
fun testSub() {
|
fun testSub() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000-40))
|
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.SUB_B, Value(DataType.BYTE, 70), Value(DataType.BYTE, 180))
|
||||||
testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123))
|
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> {
|
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
|
@Test
|
||||||
fun testMul() {
|
fun testMul() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.BYTE, 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, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4))
|
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> {
|
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
|
@Test
|
||||||
fun testDiv() {
|
fun testDiv() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.BYTE, 40), Value(DataType.WORD, 99))
|
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.DIV_B, Value(DataType.BYTE, 12), Value(DataType.BYTE, 20))
|
||||||
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.WORD, 40), Value(DataType.WORD, 99))
|
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV_W, 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.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25/99.0))
|
||||||
assertFailsWith<VmExecutionException> {
|
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
|
@Test
|
||||||
fun testFloorDiv() {
|
fun testFloorDiv() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.BYTE, 99), Value(DataType.WORD, 40))
|
testBinaryOperator(Value(DataType.BYTE, 244), Opcode.FLOORDIV_B, Value(DataType.BYTE, 33), Value(DataType.BYTE, 7))
|
||||||
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.WORD, 99), Value(DataType.WORD, 40))
|
testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV_W, 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.FLOAT, 4000.25), Opcode.FLOORDIV_F, Value(DataType.FLOAT, 40.2), Value(DataType.FLOAT, 99.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPow() {
|
fun testPow() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.BYTE, 4), Value(DataType.WORD, 81))
|
testBinaryOperator(Value(DataType.BYTE, 3), Opcode.POW_B, Value(DataType.BYTE, 4), Value(DataType.BYTE, 81))
|
||||||
testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.WORD, 4), Value(DataType.WORD, 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, Value(DataType.BYTE, 81), Value(DataType.FLOAT, 2253.2402360440274))
|
testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW_F, Value(DataType.FLOAT, 81.0), Value(DataType.FLOAT, 2253.2402360440274))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testRemainder() {
|
fun testRemainder() {
|
||||||
testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.BYTE, 29), Value(DataType.BYTE, 7))
|
testBinaryOperator(Value(DataType.BYTE, 250), Opcode.REMAINDER_B, Value(DataType.BYTE, 29), Value(DataType.BYTE, 18))
|
||||||
testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.WORD, 29), Value(DataType.BYTE, 7))
|
testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER_W, Value(DataType.WORD, 29), Value(DataType.WORD, 7))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER, Value(DataType.BYTE, 7), Value(DataType.FLOAT, 6.5))
|
testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER_F, Value(DataType.FLOAT, 7.0), Value(DataType.FLOAT, 6.5))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -387,9 +392,9 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNeg() {
|
fun testNeg() {
|
||||||
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG, Value(DataType.BYTE, 244))
|
testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, 244))
|
||||||
testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG, Value(DataType.WORD, 64302))
|
testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG_W, Value(DataType.WORD, 64302))
|
||||||
testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG, Value(DataType.FLOAT, -123.456))
|
testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG_F, Value(DataType.FLOAT, -123.456))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -138,106 +138,25 @@ class TestStackVmValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testArithmeticByteFirstOperand() {
|
fun testNoDtConversion() {
|
||||||
var r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 120))
|
assertFailsWith<VmExecutionException> {
|
||||||
assertEquals(DataType.BYTE, r.type)
|
Value(DataType.WORD, 100).add(Value(DataType.BYTE, 120))
|
||||||
assertEquals(220, r.integerValue())
|
}
|
||||||
|
assertFailsWith<VmExecutionException> {
|
||||||
r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 199))
|
Value(DataType.BYTE, 100).add(Value(DataType.WORD, 120))
|
||||||
assertEquals(DataType.WORD, r.type)
|
}
|
||||||
assertEquals(299, r.integerValue())
|
assertFailsWith<VmExecutionException> {
|
||||||
|
Value(DataType.FLOAT, 100.22).add(Value(DataType.WORD, 120))
|
||||||
r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 88))
|
}
|
||||||
assertEquals(DataType.BYTE, r.type)
|
assertFailsWith<VmExecutionException> {
|
||||||
assertEquals(12, r.integerValue())
|
Value(DataType.WORD, 1002).add(Value(DataType.FLOAT, 120.22))
|
||||||
|
}
|
||||||
r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 188))
|
assertFailsWith<VmExecutionException> {
|
||||||
assertEquals(DataType.BYTE, r.type)
|
Value(DataType.FLOAT, 100.22).add(Value(DataType.BYTE, 120))
|
||||||
assertEquals(168, r.integerValue())
|
}
|
||||||
|
assertFailsWith<VmExecutionException> {
|
||||||
r = Value(DataType.BYTE, 5).mul(Value(DataType.BYTE, 33))
|
Value(DataType.BYTE, 12).add(Value(DataType.FLOAT, 120.22))
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user