made more opcodes type-specific (will be needed for assembly generation later)

This commit is contained in:
Irmen de Jong 2018-10-04 02:17:18 +02:00
parent 4501276217
commit d2ffb1063b
4 changed files with 857 additions and 548 deletions

View File

@ -299,6 +299,107 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
private fun opcodePush(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.PUSH
DataType.WORD -> Opcode.PUSH_W
DataType.FLOAT -> Opcode.PUSH_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_W
}
}
private fun opcodePushvar(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.PUSH_VAR
DataType.WORD -> Opcode.PUSH_VAR_W
DataType.FLOAT -> Opcode.PUSH_VAR_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_VAR_W
}
}
private fun opcodePushvar(reg: Register): Opcode {
return when(reg) {
Register.A, Register.X, Register.Y -> Opcode.PUSH_VAR
Register.AX, Register.AY, Register.XY -> Opcode.PUSH_VAR_W
}
}
private fun opcodePopvar(reg: Register): Opcode {
return when(reg) {
Register.A, Register.X, Register.Y -> Opcode.POP_VAR
Register.AX, Register.AY, Register.XY -> Opcode.POP_VAR_W
}
}
private fun opcodeReadindexedvar(dt: DataType): Opcode {
return when (dt) {
DataType.ARRAY -> Opcode.READ_INDEXED_VAR
DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_W
DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_F
else -> throw CompilerException("invalid dt for indexed $dt")
}
}
private fun opcodeWriteindexedvar(dt: DataType): Opcode {
return when (dt) {
DataType.ARRAY -> Opcode.WRITE_INDEXED_VAR
DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_W
DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_F
else -> throw CompilerException("invalid dt for indexed $dt")
}
}
private fun opcodeDiscard(dt: DataType): Opcode {
return when(dt) {
DataType.BYTE -> Opcode.DISCARD
DataType.WORD -> Opcode.DISCARD_W
DataType.FLOAT -> Opcode.DISCARD_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.DISCARD_W
}
}
private fun opcodePopvar(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.POP_VAR
DataType.WORD -> Opcode.POP_VAR_W
DataType.FLOAT -> Opcode.POP_VAR_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.POP_VAR_W
}
}
private fun opcodeDecvar(reg: Register): Opcode {
return when(reg) {
Register.A, Register.X, Register.Y -> Opcode.DEC_VAR
Register.AX, Register.AY, Register.XY -> Opcode.DEC_VAR_W
}
}
private fun opcodeIncvar(reg: Register): Opcode {
return when(reg) {
Register.A, Register.X, Register.Y -> Opcode.INC_VAR
Register.AX, Register.AY, Register.XY -> Opcode.INC_VAR_W
}
}
private fun opcodeDecvar(dt: DataType): Opcode {
return when(dt) {
DataType.BYTE -> Opcode.DEC_VAR
DataType.WORD -> Opcode.DEC_VAR_W
else -> throw CompilerException("can't dec type $dt")
}
}
private fun opcodeIncvar(dt: DataType): Opcode {
return when(dt) {
DataType.BYTE -> Opcode.INC_VAR
DataType.WORD -> Opcode.INC_VAR_W
else -> throw CompilerException("can't inc type $dt")
}
}
private fun translate(stmt: Continue) { private fun translate(stmt: Continue) {
stackvmProg.line(stmt.position) stackvmProg.line(stmt.position)
@ -413,7 +514,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
private fun translate(expr: IExpression) { private fun translate(expr: IExpression) {
when(expr) { when(expr) {
is RegisterExpr -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = expr.register.toString()) is RegisterExpr -> {
val opcode = opcodePushvar(expr.register)
stackvmProg.instr(opcode, callLabel = expr.register.toString())
}
is PrefixExpression -> { is PrefixExpression -> {
translate(expr.expression) translate(expr.expression)
translatePrefixOperator(expr.operator) translatePrefixOperator(expr.operator)
@ -447,17 +551,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) { when(lv.type) {
DataType.BYTE -> stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, lv.bytevalue!!)) DataType.BYTE -> stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, lv.bytevalue!!))
DataType.WORD -> stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, lv.wordvalue!!)) DataType.WORD -> stackvmProg.instr(Opcode.PUSH_W, Value(DataType.WORD, lv.wordvalue!!))
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH, Value(DataType.FLOAT, lv.floatvalue!!)) DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_F, Value(DataType.FLOAT, lv.floatvalue!!))
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("string should have been moved into heap ${lv.position}") throw CompilerException("string should have been moved into heap ${lv.position}")
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId)) stackvmProg.instr(Opcode.PUSH_W, Value(lv.type, lv.heapId))
} }
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> { DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("array/matrix should have been moved into heap ${lv.position}") throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId)) stackvmProg.instr(Opcode.PUSH_W, Value(lv.type, lv.heapId))
} }
} }
} }
@ -469,8 +573,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
when (target) { when (target) {
is VarDecl -> { is VarDecl -> {
when (target.type) { when (target.type) {
VarDeclType.VAR -> VarDeclType.VAR -> {
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname) val opcode = opcodePushvar(target.datatype)
stackvmProg.instr(opcode, callLabel = target.scopedname)
}
VarDeclType.CONST -> VarDeclType.CONST ->
throw CompilerException("const ref should have been const-folded away") throw CompilerException("const ref should have been const-folded away")
VarDeclType.MEMORY -> { VarDeclType.MEMORY -> {
@ -504,8 +610,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
is Subroutine -> { is Subroutine -> {
translateSubroutineCall(targetStmt, stmt.arglist) translateSubroutineCall(targetStmt, stmt.arglist)
// make sure we clean up the unused result values from the stack. // make sure we clean up the unused result values from the stack.
for(rv in targetStmt.returnvalues) for(rv in targetStmt.returnvalues) {
stackvmProg.instr(Opcode.DISCARD) val opcode=opcodeDiscard(rv)
stackvmProg.instr(opcode)
}
} }
else -> else ->
throw AstException("invalid call target node type: ${targetStmt::class}") throw AstException("invalid call target node type: ${targetStmt::class}")
@ -545,7 +653,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
// evaluate the arguments and assign them into the subroutine's argument variables. // evaluate the arguments and assign them into the subroutine's argument variables.
for(arg in arguments.zip(subroutine.parameters)) { for(arg in arguments.zip(subroutine.parameters)) {
translate(arg.first) translate(arg.first)
stackvmProg.instr(Opcode.POP_VAR, callLabel = subroutine.scopedname+"."+arg.second.name) val opcode=opcodePopvar(arg.second.type)
stackvmProg.instr(opcode, callLabel = subroutine.scopedname+"."+arg.second.name)
} }
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname) stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
} }
@ -612,12 +721,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
if(write) if(write)
stackvmProg.instr(Opcode.WRITE_INDEXED_VAR, callLabel = variableName) stackvmProg.instr(opcodeWriteindexedvar(variable!!.datatype), callLabel = variableName)
else else
stackvmProg.instr(Opcode.READ_INDEXED_VAR, callLabel = variableName) stackvmProg.instr(opcodeReadindexedvar(variable!!.datatype), callLabel = variableName)
} }
private fun createSyscall(funcname: String) { private fun createSyscall(funcname: String) {
val function = ( val function = (
if (funcname.startsWith("_vm_")) if (funcname.startsWith("_vm_"))
@ -653,20 +761,22 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stackvmProg.line(stmt.position) stackvmProg.line(stmt.position)
when { when {
stmt.target.register!=null -> when(stmt.operator) { stmt.target.register!=null -> when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = stmt.target.register.toString()) "++" -> stackvmProg.instr(opcodeIncvar(stmt.target.register!!), callLabel = stmt.target.register.toString())
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = stmt.target.register.toString()) "--" -> stackvmProg.instr(opcodeDecvar(stmt.target.register!!), callLabel = stmt.target.register.toString())
} }
stmt.target.identifier!=null -> { stmt.target.identifier!=null -> {
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
when(stmt.operator) { when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = targetStatement.scopedname) "++" -> stackvmProg.instr(opcodeIncvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = targetStatement.scopedname) "--" -> stackvmProg.instr(opcodeDecvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
} }
} }
stmt.target.arrayindexed!=null -> { stmt.target.arrayindexed!=null -> {
// todo: generate more efficient bytecode for this? // todo: generate more efficient bytecode for this?
translate(stmt.target.arrayindexed!!, false) translate(stmt.target.arrayindexed!!, false)
stackvmProg.instr(Opcode.PUSH, Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1)) val one = Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1)
val opcode = opcodePush(one.type)
stackvmProg.instr(opcode, one)
when(stmt.operator) { when(stmt.operator) {
"++" -> stackvmProg.instr(Opcode.ADD) "++" -> stackvmProg.instr(Opcode.ADD)
"--" -> stackvmProg.instr(Opcode.SUB) "--" -> stackvmProg.instr(Opcode.SUB)
@ -711,11 +821,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stmt.target.identifier!=null -> { stmt.target.identifier!=null -> {
val target = stmt.target.identifier!!.targetStatement(namespace)!! val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) { when(target) {
is VarDecl -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname) is VarDecl -> {
val opcode = opcodePushvar(stmt.target.determineDatatype(namespace, heap, stmt))
stackvmProg.instr(opcode, callLabel = target.scopedname)
}
else -> throw CompilerException("invalid assignment target type ${target::class}") else -> throw CompilerException("invalid assignment target type ${target::class}")
} }
} }
stmt.target.register!=null -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = stmt.target.register.toString()) stmt.target.register!=null -> {
val opcode= opcodePushvar(stmt.target.register!!)
stackvmProg.instr(opcode, callLabel = stmt.target.register.toString())
}
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false) stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
} }
@ -727,11 +843,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
stmt.target.identifier!=null -> { stmt.target.identifier!=null -> {
val target = stmt.target.identifier!!.targetStatement(namespace)!! val target = stmt.target.identifier!!.targetStatement(namespace)!!
when(target) { when(target) {
is VarDecl -> stackvmProg.instr(Opcode.POP_VAR, callLabel = target.scopedname) is VarDecl -> {
val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt))
stackvmProg.instr(opcode, callLabel = target.scopedname)
}
else -> throw CompilerException("invalid assignment target type ${target::class}") else -> throw CompilerException("invalid assignment target type ${target::class}")
} }
} }
stmt.target.register!=null -> stackvmProg.instr(Opcode.POP_VAR, callLabel = stmt.target.register.toString()) stmt.target.register!=null -> {
val opcode=opcodePopvar(stmt.target.register!!)
stackvmProg.instr(opcode, callLabel = stmt.target.register.toString())
}
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, true) // write value to it stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, true) // write value to it
} }
} }
@ -835,13 +957,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
} }
} }
private fun translateForOverIterableVar(loop: ForLoop, varDt: DataType, iterableValue: LiteralValue) { private fun translateForOverIterableVar(loop: ForLoop, loopvarDt: DataType, iterableValue: LiteralValue) {
if(varDt==DataType.BYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.MATRIX)) if(loopvarDt==DataType.BYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.MATRIX))
throw CompilerException("loop variable type doesn't match iterableValue type (byte)") throw CompilerException("loop variable type doesn't match iterableValue type")
else if(varDt==DataType.WORD && iterableValue.type != DataType.ARRAY_W) else if(loopvarDt==DataType.WORD && iterableValue.type != DataType.ARRAY_W)
throw CompilerException("loop variable type doesn't match iterableValue type (word)") throw CompilerException("loop variable type doesn't match iterableValue type")
else if(varDt==DataType.FLOAT && iterableValue.type != DataType.ARRAY_F) else if(loopvarDt==DataType.FLOAT && iterableValue.type != DataType.ARRAY_F)
throw CompilerException("loop variable type doesn't match iterableValue type (float)") throw CompilerException("loop variable type doesn't match iterableValue type")
val numElements: Int val numElements: Int
val indexVar: String val indexVar: String
when(iterableValue.type) { when(iterableValue.type) {
@ -893,8 +1015,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
continueStmtLabelStack.push(continueLabel) continueStmtLabelStack.push(continueLabel)
breakStmtLabelStack.push(breakLabel) breakStmtLabelStack.push(breakLabel)
stackvmProg.instr(Opcode.PUSH, Value(if(numElements<=255) DataType.BYTE else DataType.WORD, 0)) val zero = Value(if(numElements<=255) DataType.BYTE else DataType.WORD, 0)
stackvmProg.instr(Opcode.POP_VAR, callLabel = indexVar) stackvmProg.instr(opcodePush(zero.type), zero)
stackvmProg.instr(opcodePopvar(zero.type), callLabel = indexVar)
stackvmProg.label(loopLabel) stackvmProg.label(loopLabel)
val assignTarget = if(loop.loopRegister!=null) val assignTarget = if(loop.loopRegister!=null)
AssignTarget(loop.loopRegister, null, null, loop.position) AssignTarget(loop.loopRegister, null, null, loop.position)
@ -906,11 +1029,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
translate(assignLv) translate(assignLv)
translate(loop.body) translate(loop.body)
stackvmProg.label(continueLabel) stackvmProg.label(continueLabel)
stackvmProg.instr(Opcode.INC_VAR, callLabel = indexVar) stackvmProg.instr(opcodeIncvar(zero.type), callLabel = indexVar)
// 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(Opcode.PUSH, Value(varDt, numElements)) stackvmProg.instr(opcodePush(zero.type), Value(zero.type, numElements))
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = indexVar) stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar)
stackvmProg.instr(Opcode.SUB) stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel) stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
@ -948,31 +1071,31 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
continueStmtLabelStack.push(continueLabel) continueStmtLabelStack.push(continueLabel)
breakStmtLabelStack.push(breakLabel) breakStmtLabelStack.push(breakLabel)
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.first)) stackvmProg.instr(opcodePush(varDt), Value(varDt, range.first))
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname) stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
stackvmProg.label(loopLabel) stackvmProg.label(loopLabel)
translate(body) translate(body)
stackvmProg.label(continueLabel) stackvmProg.label(continueLabel)
when { when {
range.step==1 -> stackvmProg.instr(Opcode.INC_VAR, callLabel = varname) range.step==1 -> stackvmProg.instr(opcodeIncvar(varDt), callLabel = varname)
range.step==-1 -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = varname) range.step==-1 -> stackvmProg.instr(opcodeDecvar(varDt), callLabel = varname)
range.step>1 -> { range.step>1 -> {
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname) stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.step)) stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step))
stackvmProg.instr(Opcode.ADD) stackvmProg.instr(Opcode.ADD)
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname) stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
} }
range.step<1 -> { range.step<1 -> {
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname) stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(Opcode.PUSH, Value(varDt, abs(range.step))) stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step)))
stackvmProg.instr(Opcode.SUB) stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname) stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
} }
} }
// 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(Opcode.PUSH, Value(varDt, range.last+range.step)) stackvmProg.instr(opcodePush(varDt), Value(varDt, range.last+range.step))
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname) stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
stackvmProg.instr(Opcode.SUB) stackvmProg.instr(Opcode.SUB)
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel) stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
@ -1083,9 +1206,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
postIncr.linkParents(range.parent) postIncr.linkParents(range.parent)
translate(postIncr) translate(postIncr)
if(lvTarget.register!=null) if(lvTarget.register!=null)
stackvmProg.instr(Opcode.PUSH_VAR, callLabel =lvTarget.register.toString()) stackvmProg.instr(opcodePushvar(lvTarget.register), callLabel =lvTarget.register.toString())
else else {
stackvmProg.instr(Opcode.PUSH_VAR, callLabel =targetStatement!!.scopedname) val opcode = opcodePushvar(targetStatement!!.datatype)
stackvmProg.instr(opcode, callLabel = targetStatement.scopedname)
}
val branch = BranchStatement( val branch = BranchStatement(
BranchCondition.NZ, BranchCondition.NZ,
listOf(Jump(null, null, loopLabel, range.position)), listOf(Jump(null, null, loopLabel, range.position)),

View File

@ -104,10 +104,7 @@ class Program (val name: String,
Instruction(opcode, callLabel = args) Instruction(opcode, callLabel = args)
} }
} }
Opcode.INC_VAR, Opcode.DEC_VAR, in opcodesWithVarArgument -> {
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR,
Opcode.READ_INDEXED_VAR, Opcode.WRITE_INDEXED_VAR -> {
val withoutQuotes = val withoutQuotes =
if(args!!.startsWith('"') && args.endsWith('"')) if(args!!.startsWith('"') && args.endsWith('"'))
args.substring(1, args.length-1) else args args.substring(1, args.length-1) else args

File diff suppressed because it is too large Load Diff

View File

@ -113,9 +113,18 @@ class TestStackVmOpcodes {
assertFalse(vm.P_irqd) assertFalse(vm.P_irqd)
} }
@Test
fun testPushWrongDt() {
val ins = mutableListOf(Instruction(Opcode.PUSH, Value(DataType.WORD, 4299)))
vm.load(makeProg(ins), null)
assertFailsWith<VmExecutionException> {
vm.step(1)
}
}
@Test @Test
fun testPush() { fun testPush() {
val ins = mutableListOf(Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999))) val ins = mutableListOf(Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.999)))
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
assertThat(vm.evalstack, empty()) assertThat(vm.evalstack, empty())
vm.step(1) vm.step(1)
@ -151,7 +160,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testPushVar() { fun testPushVar() {
val ins = mutableListOf(Instruction(Opcode.PUSH_VAR, callLabel = "varname")) val ins = mutableListOf(Instruction(Opcode.PUSH_VAR_F, callLabel = "varname"))
vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null) vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null)
assertEquals(7, vm.variables.size) assertEquals(7, vm.variables.size)
assertTrue(vm.variables.containsKey("varname")) assertTrue(vm.variables.containsKey("varname"))
@ -165,40 +174,12 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.FLOAT, 42.999), vm.variables["varname"]) assertEquals(Value(DataType.FLOAT, 42.999), vm.variables["varname"])
} }
@Test
fun testDup() {
val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)),
Instruction(Opcode.DUP))
vm.load(makeProg(ins), null)
assertThat(vm.evalstack, empty())
vm.step(2)
assertEquals(2, vm.evalstack.size)
assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop())
assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop())
}
@Test
fun testSwap() {
val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 9999)),
Instruction(Opcode.SWAP)
)
vm.load(makeProg(ins), null)
assertThat(vm.evalstack, empty())
vm.step(3)
assertEquals(2, vm.evalstack.size)
assertEquals(Value(DataType.BYTE, 123), vm.evalstack.pop())
assertEquals(Value(DataType.WORD, 9999), vm.evalstack.pop())
}
@Test @Test
fun testDiscard() { fun testDiscard() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.999)),
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 3.1415)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 3.1415)),
Instruction(Opcode.DISCARD)) Instruction(Opcode.DISCARD_F))
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
assertThat(vm.evalstack, empty()) assertThat(vm.evalstack, empty())
vm.step(2) vm.step(2)
@ -211,12 +192,12 @@ class TestStackVmOpcodes {
@Test @Test
fun testPopMem() { fun testPopMem() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.25)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.25)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x2000)), Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x2000)),
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x3000)), Instruction(Opcode.POP_MEM_W, Value(DataType.WORD, 0x3000)),
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x4000))) Instruction(Opcode.POP_MEM_F, Value(DataType.WORD, 0x4000)))
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
assertEquals(0, vm.mem.getWord(0x2000)) assertEquals(0, vm.mem.getWord(0x2000))
assertEquals(0, vm.mem.getWord(0x3000)) assertEquals(0, vm.mem.getWord(0x3000))
@ -233,12 +214,12 @@ class TestStackVmOpcodes {
@Test @Test
fun testPopVar() { fun testPopVar() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.25)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.25)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
Instruction(Opcode.POP_VAR, callLabel = "var1"), Instruction(Opcode.POP_VAR, callLabel = "var1"),
Instruction(Opcode.POP_VAR, callLabel = "var2"), Instruction(Opcode.POP_VAR_W, callLabel = "var2"),
Instruction(Opcode.POP_VAR, callLabel = "var3")) Instruction(Opcode.POP_VAR_F, callLabel = "var3"))
val vars = mapOf( val vars = mapOf(
"var1" to Value(DataType.BYTE, 0), "var1" to Value(DataType.BYTE, 0),
"var2" to Value(DataType.WORD, 0), "var2" to Value(DataType.WORD, 0),
@ -252,8 +233,8 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.FLOAT, 42.25), vm.variables["var3"]) assertEquals(Value(DataType.FLOAT, 42.25), vm.variables["var3"])
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
Instruction(Opcode.POP_VAR, callLabel = "var1")) Instruction(Opcode.POP_VAR_W, callLabel = "var1"))
val vars2 = mapOf( val vars2 = mapOf(
"var1" to Value(DataType.BYTE, 0) "var1" to Value(DataType.BYTE, 0)
) )
@ -505,65 +486,89 @@ class TestStackVmOpcodes {
Value(DataType.BYTE, 20)) Value(DataType.BYTE, 20))
val expected = listOf( val expected = listOf(
Value(DataType.BYTE, 0), Value(DataType.BYTE, 0),
Value(DataType.BYTE, 1),
Value(DataType.BYTE, 0), Value(DataType.BYTE, 0),
Value(DataType.BYTE, 1), Value(DataType.BYTE, 1),
Value(DataType.BYTE, 0), Value(DataType.BYTE, 0),
Value(DataType.BYTE, 1), Value(DataType.BYTE, 1),
Value(DataType.BYTE, 0), Value(DataType.BYTE, 0),
Value(DataType.BYTE, 1),
Value(DataType.BYTE, 0) Value(DataType.BYTE, 0)
) )
val operator = Opcode.NOT val operator = Opcode.NOT
testUnaryOperator(values, operator, expected) testUnaryOperator(values, operator, expected, listOf(DataType.BYTE, DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE))
} }
@Test @Test
fun testInc() { fun testInc() {
val values = listOf( val values = listOf(
Value(DataType.FLOAT, 2022.5),
Value(DataType.WORD, 65535),
Value(DataType.WORD, 999),
Value(DataType.BYTE, 255), Value(DataType.BYTE, 255),
Value(DataType.BYTE, 99) Value(DataType.BYTE, 99)
) )
val expected = listOf( val expected = listOf(
Value(DataType.BYTE, 100),
Value(DataType.BYTE, 0), Value(DataType.BYTE, 0),
Value(DataType.WORD, 1000), Value(DataType.BYTE, 100)
)
testUnaryOperator(values, Opcode.INC, expected)
val valuesw = listOf(
Value(DataType.WORD, 65535),
Value(DataType.WORD, 999)
)
val expectedw = listOf(
Value(DataType.WORD, 0), Value(DataType.WORD, 0),
Value(DataType.WORD, 1000)
)
testUnaryOperator(valuesw, Opcode.INC_W, expectedw)
val valuesf = listOf(
Value(DataType.FLOAT, -1.0),
Value(DataType.FLOAT, 2022.5)
)
val expectedf = listOf(
Value(DataType.FLOAT, 0.0),
Value(DataType.FLOAT, 2023.5) Value(DataType.FLOAT, 2023.5)
) )
val operator = Opcode.INC testUnaryOperator(valuesf, Opcode.INC_F, expectedf)
testUnaryOperator(values, operator, expected)
} }
@Test @Test
fun testDec() { fun testDec() {
val values = listOf( val values = listOf(
Value(DataType.FLOAT, 0.5),
Value(DataType.FLOAT, 123.456),
Value(DataType.WORD, 1000),
Value(DataType.WORD, 0),
Value(DataType.BYTE, 100), Value(DataType.BYTE, 100),
Value(DataType.BYTE, 0) Value(DataType.BYTE, 0)
) )
val expected = listOf( val expected = listOf(
Value(DataType.BYTE, 255),
Value(DataType.BYTE, 99), Value(DataType.BYTE, 99),
Value(DataType.WORD, 65535), Value(DataType.BYTE, 255)
Value(DataType.WORD, 999),
Value(DataType.FLOAT, 122.456),
Value(DataType.FLOAT, -0.5)
) )
val operator = Opcode.DEC testUnaryOperator(values, Opcode.DEC, expected)
testUnaryOperator(values, operator, expected)
val valuesw = listOf(
Value(DataType.WORD, 1000),
Value(DataType.WORD, 0)
)
val expectedw = listOf(
Value(DataType.WORD, 999),
Value(DataType.WORD, 65535)
)
testUnaryOperator(valuesw, Opcode.DEC_W, expectedw)
val valuesf = listOf(
Value(DataType.FLOAT, 0.5),
Value(DataType.FLOAT, 123.456)
)
val expectedf = listOf(
Value(DataType.FLOAT, -0.5),
Value(DataType.FLOAT, 122.456)
)
testUnaryOperator(valuesf, Opcode.DEC_F, expectedf)
} }
@Test @Test
fun testNeg() { fun testNeg() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 123.456)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 123.456)),
Instruction(Opcode.NEG), Instruction(Opcode.NEG),
Instruction(Opcode.NEG) Instruction(Opcode.NEG)
) )
@ -577,7 +582,7 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.FLOAT, 123.456), vm.evalstack.peek()) assertEquals(Value(DataType.FLOAT, 123.456), vm.evalstack.peek())
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 1234)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1234)),
Instruction(Opcode.NEG) Instruction(Opcode.NEG)
) )
vm.load(makeProg(ins2), null) vm.load(makeProg(ins2), null)
@ -597,7 +602,7 @@ class TestStackVmOpcodes {
fun testInv() { fun testInv() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 4044)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 4044)),
Instruction(Opcode.INV), Instruction(Opcode.INV),
Instruction(Opcode.INV), Instruction(Opcode.INV),
Instruction(Opcode.INV) Instruction(Opcode.INV)
@ -612,7 +617,7 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.BYTE, 0x84), vm.evalstack.pop()) assertEquals(Value(DataType.BYTE, 0x84), vm.evalstack.pop())
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1234.33)), Instruction(Opcode.PUSH_W, Value(DataType.FLOAT, 1234.33)), // todo should crash
Instruction(Opcode.INV) Instruction(Opcode.INV)
) )
vm.load(makeProg(ins2), null) vm.load(makeProg(ins2), null)
@ -624,9 +629,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testLsb() { fun testLsb() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1.23)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 1.23)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
Instruction(Opcode.LSB), Instruction(Opcode.LSB),
Instruction(Opcode.LSB), Instruction(Opcode.LSB),
Instruction(Opcode.LSB) Instruction(Opcode.LSB)
@ -644,9 +649,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testMsb() { fun testMsb() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1.23)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 1.23)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
Instruction(Opcode.MSB), Instruction(Opcode.MSB),
Instruction(Opcode.MSB), Instruction(Opcode.MSB),
Instruction(Opcode.MSB) Instruction(Opcode.MSB)
@ -664,7 +669,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testB2Word() { fun testB2Word() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
Instruction(Opcode.B2WORD), Instruction(Opcode.B2WORD),
Instruction(Opcode.B2WORD) Instruction(Opcode.B2WORD)
@ -680,7 +685,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testMSB2Word() { fun testMSB2Word() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
Instruction(Opcode.MSB2WORD), Instruction(Opcode.MSB2WORD),
Instruction(Opcode.MSB2WORD) Instruction(Opcode.MSB2WORD)
@ -696,7 +701,7 @@ class TestStackVmOpcodes {
@Test @Test
fun testB2Float() { fun testB2Float() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
Instruction(Opcode.B2FLOAT), Instruction(Opcode.B2FLOAT),
Instruction(Opcode.B2FLOAT) Instruction(Opcode.B2FLOAT)
@ -713,7 +718,7 @@ class TestStackVmOpcodes {
fun testW2Float() { fun testW2Float() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.BYTE, 11)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 11)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 12345)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 12345)),
Instruction(Opcode.W2FLOAT), Instruction(Opcode.W2FLOAT),
Instruction(Opcode.W2FLOAT) Instruction(Opcode.W2FLOAT)
) )
@ -725,76 +730,54 @@ class TestStackVmOpcodes {
} }
} }
@Test
fun testIncMemAndIncMemW() {
val ins = mutableListOf(
Instruction(Opcode.INC_MEM, Value(DataType.WORD, 0x2000)),
Instruction(Opcode.INC_MEM, Value(DataType.WORD, 0x2001)),
Instruction(Opcode.INC_MEM_W, Value(DataType.WORD, 0x3000)),
Instruction(Opcode.INC_MEM_W, Value(DataType.WORD, 0x3002))
)
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 255)),
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0xffff)))
vm.load(makeProg(ins, mem=mem), null)
vm.step(4)
assertEquals(101, vm.mem.getByte(0x2000))
assertEquals(0, vm.mem.getByte(0x2001))
assertEquals(0x42eb, vm.mem.getWord(0x3000))
assertEquals(0, vm.mem.getWord(0x3002))
}
@Test @Test
fun testIncVar() { fun testIncVar() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.INC_VAR, callLabel ="var1"), Instruction(Opcode.INC_VAR_W, callLabel ="var1"),
Instruction(Opcode.INC_VAR, callLabel ="var2"), Instruction(Opcode.INC_VAR, callLabel ="var2"),
Instruction(Opcode.INC_VAR, callLabel ="var1"), Instruction(Opcode.INC_VAR_F, callLabel ="var3"),
Instruction(Opcode.INC_VAR, callLabel ="var2")) Instruction(Opcode.INC_VAR_W, callLabel ="var1"),
Instruction(Opcode.INC_VAR, callLabel ="var2"),
Instruction(Opcode.INC_VAR_F, callLabel ="var3")
)
val vars = mapOf("var1" to Value(DataType.WORD, 65534), val vars = mapOf("var1" to Value(DataType.WORD, 65534),
"var2" to Value(DataType.BYTE, 254)) "var2" to Value(DataType.BYTE, 254),
"var3" to Value(DataType.FLOAT, -1.5)
)
vm.load(makeProg(ins, vars = vars), null) vm.load(makeProg(ins, vars = vars), null)
vm.step(2) vm.step(3)
assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"]) assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"])
assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"]) assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"])
vm.step(2) assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"])
vm.step(3)
assertEquals(Value(DataType.WORD, 0), vm.variables["var1"]) assertEquals(Value(DataType.WORD, 0), vm.variables["var1"])
assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"]) assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"])
assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"])
} }
@Test @Test
fun testDecVar() { fun testDecVar() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.DEC_VAR, callLabel = "var1"), Instruction(Opcode.DEC_VAR_W, callLabel = "var1"),
Instruction(Opcode.DEC_VAR, callLabel = "var2"), Instruction(Opcode.DEC_VAR, callLabel = "var2"),
Instruction(Opcode.DEC_VAR, callLabel = "var1"), Instruction(Opcode.DEC_VAR_F, callLabel = "var3"),
Instruction(Opcode.DEC_VAR, callLabel = "var2")) Instruction(Opcode.DEC_VAR_W, callLabel = "var1"),
Instruction(Opcode.DEC_VAR, callLabel = "var2"),
Instruction(Opcode.DEC_VAR_F, callLabel = "var3")
)
val vars = mapOf("var1" to Value(DataType.WORD,1), val vars = mapOf("var1" to Value(DataType.WORD,1),
"var2" to Value(DataType.BYTE, 1)) "var2" to Value(DataType.BYTE, 1),
"var3" to Value(DataType.FLOAT, 1.5)
)
vm.load(makeProg(ins, vars = vars), null) vm.load(makeProg(ins, vars = vars), null)
vm.step(2) vm.step(3)
assertEquals(Value(DataType.WORD, 0), vm.variables["var1"]) assertEquals(Value(DataType.WORD, 0), vm.variables["var1"])
assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"]) assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"])
vm.step(2) assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"])
vm.step(3)
assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"]) assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"])
assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"]) assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"])
} assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"])
@Test
fun testDecMemAndDecMemW() {
val ins = mutableListOf(
Instruction(Opcode.DEC_MEM, Value(DataType.WORD, 0x2000)),
Instruction(Opcode.DEC_MEM, Value(DataType.WORD, 0x2001)),
Instruction(Opcode.DEC_MEM_W, Value(DataType.WORD, 0x3000)),
Instruction(Opcode.DEC_MEM_W, Value(DataType.WORD, 0x3002))
)
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 0)),
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0)))
vm.load(makeProg(ins, mem=mem), null)
vm.step(4)
assertEquals(99, vm.mem.getByte(0x2000))
assertEquals(255, vm.mem.getByte(0x2001))
assertEquals(0x42e9, vm.mem.getWord(0x3000))
assertEquals(65535, vm.mem.getWord(0x3002))
} }
@Test @Test
@ -805,7 +788,7 @@ class TestStackVmOpcodes {
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)), Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)),
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)), Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 25544)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 25544)),
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_SIN.callNr)) Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_SIN.callNr))
) )
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
@ -1050,9 +1033,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testBZ() { fun testBZ() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
Instruction(Opcode.BZ, callLabel = "label"), Instruction(Opcode.BZ, callLabel = "label"),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
Instruction(Opcode.BZ, callLabel = "label"), Instruction(Opcode.BZ, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
@ -1070,9 +1053,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testBNZ() { fun testBNZ() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
Instruction(Opcode.BNZ, callLabel = "label"), Instruction(Opcode.BNZ, callLabel = "label"),
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
Instruction(Opcode.BNZ, callLabel = "label"), Instruction(Opcode.BNZ, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
@ -1090,11 +1073,11 @@ class TestStackVmOpcodes {
@Test @Test
fun testBNEG() { fun testBNEG() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.PUSH, Value(DataType.FLOAT, -99)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, -99)),
Instruction(Opcode.BNEG, callLabel = "label"), Instruction(Opcode.BNEG, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
@ -1114,9 +1097,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testBPOS() { fun testBPOS() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, -99)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, -99)),
Instruction(Opcode.BPOS, callLabel = "label"), Instruction(Opcode.BPOS, callLabel = "label"),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
Instruction(Opcode.BPOS, callLabel = "label"), Instruction(Opcode.BPOS, callLabel = "label"),
Instruction(Opcode.LINE, callLabel = "string1"), Instruction(Opcode.LINE, callLabel = "string1"),
Instruction(Opcode.TERMINATE), Instruction(Opcode.TERMINATE),
@ -1195,9 +1178,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testSHR() { fun testSHR() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 9.99)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 9.99)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 3)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 3)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 61005)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 61005)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)),
Instruction(Opcode.SHR), // 124 Instruction(Opcode.SHR), // 124
@ -1207,12 +1190,12 @@ class TestStackVmOpcodes {
Instruction(Opcode.SHR), // 0 Instruction(Opcode.SHR), // 0
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD),
Instruction(Opcode.SHR), // 30502 Instruction(Opcode.SHR), // 30502
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD_W),
Instruction(Opcode.SHR), // 1 Instruction(Opcode.SHR), // 1
Instruction(Opcode.SHR), // 0 Instruction(Opcode.SHR), // 0
Instruction(Opcode.SHR), // 0 Instruction(Opcode.SHR), // 0
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD_W),
Instruction(Opcode.SHR) // error Instruction(Opcode.SHR) // error on float
) )
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
vm.step(6) vm.step(6)
@ -1237,9 +1220,9 @@ class TestStackVmOpcodes {
@Test @Test
fun testSHL() { fun testSHL() {
val ins = mutableListOf( val ins = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 9.99)), Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 9.99)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 3)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 3)),
Instruction(Opcode.PUSH, Value(DataType.WORD, 61005)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 61005)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)),
Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)), Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)),
Instruction(Opcode.SHL), // 242 Instruction(Opcode.SHL), // 242
@ -1247,10 +1230,10 @@ class TestStackVmOpcodes {
Instruction(Opcode.SHL), // 6 Instruction(Opcode.SHL), // 6
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD),
Instruction(Opcode.SHL), // 56474 Instruction(Opcode.SHL), // 56474
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD_W),
Instruction(Opcode.SHL), // 6 Instruction(Opcode.SHL), // 6
Instruction(Opcode.DISCARD), Instruction(Opcode.DISCARD_W),
Instruction(Opcode.SHL) // error Instruction(Opcode.SHL) // error on float
) )
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
vm.step(6) vm.step(6)
@ -1302,7 +1285,7 @@ class TestStackVmOpcodes {
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.CLC), Instruction(Opcode.CLC),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
Instruction(Opcode.ROR), // 0b0100100110000110 c=1 Instruction(Opcode.ROR), // 0b0100100110000110 c=1
Instruction(Opcode.ROR), // 0b1010010011000011 c=0 Instruction(Opcode.ROR), // 0b1010010011000011 c=0
Instruction(Opcode.ROR), Instruction(Opcode.ROR),
@ -1367,7 +1350,7 @@ class TestStackVmOpcodes {
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.CLC), Instruction(Opcode.CLC),
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
Instruction(Opcode.ROL), // 0b0010011000011010 c=1 Instruction(Opcode.ROL), // 0b0010011000011010 c=1
Instruction(Opcode.ROL), // 0b0100110000110101 c=0 Instruction(Opcode.ROL), // 0b0100110000110101 c=0
Instruction(Opcode.ROL), Instruction(Opcode.ROL),
@ -1424,7 +1407,7 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek()) assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek())
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
Instruction(Opcode.ROR2), // 0b1100100110000110 Instruction(Opcode.ROR2), // 0b1100100110000110
Instruction(Opcode.ROR2), // 0b0110010011000011 Instruction(Opcode.ROR2), // 0b0110010011000011
Instruction(Opcode.ROR2), Instruction(Opcode.ROR2),
@ -1476,7 +1459,7 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek()) assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek())
val ins2 = mutableListOf( val ins2 = mutableListOf(
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
Instruction(Opcode.ROL2), // 0b0010011000011011 Instruction(Opcode.ROL2), // 0b0010011000011011
Instruction(Opcode.ROL2), // 0b0100110000110110 Instruction(Opcode.ROL2), // 0b0100110000110110
Instruction(Opcode.ROL2), Instruction(Opcode.ROL2),
@ -1505,13 +1488,36 @@ class TestStackVmOpcodes {
assertEquals(Value(DataType.WORD, 0b1001001100001101), vm.evalstack.peek()) assertEquals(Value(DataType.WORD, 0b1001001100001101), vm.evalstack.peek())
} }
private fun discardOpcode(dt: DataType): Opcode {
return when(dt) {
DataType.BYTE -> Opcode.DISCARD
DataType.WORD -> Opcode.DISCARD_W
DataType.FLOAT -> Opcode.DISCARD_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.DISCARD_W
}
}
private fun pushOpcode(dt: DataType): Opcode {
return when (dt) {
DataType.BYTE -> Opcode.PUSH
DataType.WORD -> Opcode.PUSH_W
DataType.FLOAT -> Opcode.PUSH_F
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_W
}
}
private fun testComparisonOperator(values: List<Value>, expected: List<Int>, operator: Opcode) { private fun testComparisonOperator(values: List<Value>, expected: List<Int>, operator: Opcode) {
assertEquals(values.size, expected.size*2) assertEquals(values.size, expected.size*2)
val ins = mutableListOf<Instruction>() val ins = mutableListOf<Instruction>()
val vars = values.iterator() val vars = values.iterator()
while(vars.hasNext()) { while(vars.hasNext()) {
ins.add(Instruction(Opcode.PUSH, vars.next())) var nextvar = vars.next()
ins.add(Instruction(Opcode.PUSH, vars.next())) ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
nextvar = vars.next()
ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
ins.add(Instruction(operator)) ins.add(Instruction(operator))
} }
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
@ -1524,8 +1530,9 @@ class TestStackVmOpcodes {
private fun testBinaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>) { private fun testBinaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>) {
assertEquals(valuesToPush.size, expected.size+1) assertEquals(valuesToPush.size, expected.size+1)
val ins = mutableListOf<Instruction>() val ins = mutableListOf<Instruction>()
for (value in valuesToPush) for (value in valuesToPush) {
ins.add(Instruction(Opcode.PUSH, value)) ins.add(Instruction(pushOpcode(value.type), value))
}
for (i in 1 until valuesToPush.size) for (i in 1 until valuesToPush.size)
ins.add(Instruction(operator)) ins.add(Instruction(operator))
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
@ -1540,19 +1547,23 @@ class TestStackVmOpcodes {
} }
} }
private fun testUnaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>) { private fun testUnaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>, expectedTypes: List<DataType>?=null) {
assertEquals(valuesToPush.size, expected.size) assertEquals(valuesToPush.size, expected.size)
val typesExpected = expectedTypes?.reversed() ?: expected.reversed().map{it.type}
val ins = mutableListOf<Instruction>() val ins = mutableListOf<Instruction>()
for (value in valuesToPush) for (value in valuesToPush) {
ins.add(Instruction(Opcode.PUSH, value)) ins.add(Instruction(pushOpcode(value.type), value))
for (i in 1..valuesToPush.size) { }
for (type in typesExpected) {
ins.add(Instruction(operator)) ins.add(Instruction(operator))
ins.add(Instruction(Opcode.DISCARD)) ins.add(Instruction(discardOpcode(type)))
} }
vm.load(makeProg(ins), null) vm.load(makeProg(ins), null)
vm.step(valuesToPush.size) vm.step(valuesToPush.size)
assertEquals(valuesToPush.size, vm.evalstack.size) assertEquals(valuesToPush.size, vm.evalstack.size)
for (expectedVal in expected) {
for (expectedVal in expected.reversed()) {
vm.step(1) vm.step(1)
assertEquals(expectedVal, vm.evalstack.peek()) assertEquals(expectedVal, vm.evalstack.peek())
vm.step(1) vm.step(1)