From e8ba21d3badd9d2a73b5baf79cb0705ed1f84fba Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 5 Oct 2018 13:58:37 +0200 Subject: [PATCH] made a lot more opcodes type-specific --- compiler/src/prog8/ast/AST.kt | 1 - compiler/src/prog8/compiler/Compiler.kt | 207 ++++++++-- compiler/src/prog8/parser/prog8Lexer.java | 11 +- compiler/src/prog8/parser/prog8Parser.java | 14 +- compiler/src/prog8/stackvm/StackVm.kt | 339 ++++++++++++++--- compiler/test/StackVMOpcodeTests.kt | 421 +++++++-------------- 6 files changed, 622 insertions(+), 371 deletions(-) diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 84bceff8b..d2e4a488e 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -3,7 +3,6 @@ package prog8.ast import org.antlr.v4.runtime.ParserRuleContext import org.antlr.v4.runtime.tree.TerminalNode import prog8.compiler.HeapValues -import prog8.compiler.target.c64.Mflpt5 import prog8.compiler.target.c64.Petscii import prog8.compiler.unescape import prog8.functions.BuiltinFunctions diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index ad6a55bd2..7d2fe437e 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -635,12 +635,54 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, } "msb" -> stackvmProg.instr(Opcode.MSB) "lsb" -> stackvmProg.instr(Opcode.LSB) - "lsl" -> stackvmProg.instr(Opcode.SHL) - "lsr" -> stackvmProg.instr(Opcode.SHR) - "rol" -> stackvmProg.instr(Opcode.ROL) - "ror" -> stackvmProg.instr(Opcode.ROR) - "rol2" -> stackvmProg.instr(Opcode.ROL2) - "ror2" -> stackvmProg.instr(Opcode.ROR2) + "lsl" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.SHL) + DataType.WORD -> stackvmProg.instr(Opcode.SHL_W) + else -> throw CompilerException("wrong datatype") + } + } + "lsr" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.SHR) + DataType.WORD -> stackvmProg.instr(Opcode.SHR_W) + else -> throw CompilerException("wrong datatype") + } + } + "rol" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.ROL) + DataType.WORD -> stackvmProg.instr(Opcode.ROL_W) + else -> throw CompilerException("wrong datatype") + } + } + "ror" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.ROR) + DataType.WORD -> stackvmProg.instr(Opcode.ROR_W) + else -> throw CompilerException("wrong datatype") + } + } + "rol2" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.ROL2) + DataType.WORD -> stackvmProg.instr(Opcode.ROL2_W) + else -> throw CompilerException("wrong datatype") + } + } + "ror2" -> { + val arg = args.single() + when (arg.resultingDatatype(namespace, heap)) { + DataType.BYTE -> stackvmProg.instr(Opcode.ROR2) + DataType.WORD -> stackvmProg.instr(Opcode.ROR2_W) + else -> throw CompilerException("wrong datatype") + } + } "set_carry" -> stackvmProg.instr(Opcode.SEC) "clear_carry" -> stackvmProg.instr(Opcode.CLC) "set_irqd" -> stackvmProg.instr(Opcode.SEI) @@ -666,6 +708,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) if(leftDt !in validDt || rightDt !in validDt) throw CompilerException("invalid datatype(s) for operand(s)") + if(leftDt!=rightDt) + throw CompilerException("operands have different datatypes") val opcode = when(operator) { // todo variants depending on leftdt/rightdt (b/w/f) "+" -> Opcode.ADD @@ -675,18 +719,96 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, "//" -> Opcode.FLOORDIV "%" -> Opcode.REMAINDER "**" -> Opcode.POW - "&" -> Opcode.BITAND - "|" -> Opcode.BITOR - "^" -> Opcode.BITXOR - "and" -> Opcode.AND - "or" -> Opcode.OR - "xor" -> Opcode.XOR - "<" -> Opcode.LESS - ">" -> Opcode.GREATER - "<=" -> Opcode.LESSEQ - ">=" -> Opcode.GREATEREQ - "==" -> Opcode.EQUAL - "!=" -> Opcode.NOTEQUAL + "&" -> { + when(leftDt) { + DataType.BYTE -> Opcode.BITAND + DataType.WORD -> Opcode.BITAND_W + else -> throw CompilerException("only byte/word possible") + } + } + "|" -> { + when(leftDt) { + DataType.BYTE -> Opcode.BITOR + DataType.WORD -> Opcode.BITOR_W + else -> throw CompilerException("only byte/word possible") + } + } + "^" -> { + when(leftDt) { + DataType.BYTE -> Opcode.BITXOR + DataType.WORD -> Opcode.BITXOR_W + else -> throw CompilerException("only byte/word possible") + } + } + "and" -> { + when(leftDt) { + DataType.BYTE -> Opcode.AND + DataType.WORD -> Opcode.AND_W + else -> throw CompilerException("only byte/word possible") + } + } + "or" -> { + when(leftDt) { + DataType.BYTE -> Opcode.OR + DataType.WORD -> Opcode.OR_W + else -> throw CompilerException("only byte/word possible") + } + } + "xor" -> { + when(leftDt) { + DataType.BYTE -> Opcode.XOR + DataType.WORD -> Opcode.XOR_W + else -> throw CompilerException("only byte/word possible") + } + } + "<" -> { + when(leftDt) { + DataType.BYTE -> Opcode.LESS + DataType.WORD -> Opcode.LESS_W + DataType.FLOAT -> Opcode.LESS_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + ">" -> { + when(leftDt) { + DataType.BYTE -> Opcode.GREATER + DataType.WORD -> Opcode.GREATER_W + DataType.FLOAT -> Opcode.GREATER_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "<=" -> { + when(leftDt) { + DataType.BYTE -> Opcode.LESSEQ + DataType.WORD -> Opcode.LESSEQ_W + DataType.FLOAT -> Opcode.LESSEQ_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + ">=" -> { + when(leftDt) { + DataType.BYTE -> Opcode.GREATEREQ + DataType.WORD -> Opcode.GREATEREQ_W + DataType.FLOAT -> Opcode.GREATEREQ_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "==" -> { + when (leftDt) { + DataType.BYTE -> Opcode.EQUAL + DataType.WORD -> Opcode.EQUAL_W + DataType.FLOAT -> Opcode.EQUAL_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "!=" -> { + when (leftDt) { + DataType.BYTE -> Opcode.NOTEQUAL + DataType.WORD -> Opcode.NOTEQUAL_W + DataType.FLOAT -> Opcode.NOTEQUAL_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } else -> throw FatalAstException("const evaluation for invalid operator $operator") } stackvmProg.instr(opcode) @@ -698,8 +820,20 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, val opcode = when(operator) { "+" -> Opcode.NOP "-" -> Opcode.NEG // todo b/w/f - "~" -> Opcode.INV // todo b/w - "not" -> Opcode.NOT // todo b/w (convert float to byte) + "~" -> { + when(operandDt) { + DataType.BYTE -> Opcode.INV + DataType.WORD -> Opcode.INV_W + else -> throw CompilerException("only byte/word possible") + } + } + "not" -> { + when(operandDt) { + DataType.BYTE -> Opcode.NOT + DataType.WORD -> Opcode.NOT_W + else -> throw CompilerException("only byte/word possible") + } + } else -> throw FatalAstException("const evaluation for invalid prefix operator $operator") } stackvmProg.instr(opcode) @@ -844,7 +978,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false) } - translateAugAssignOperator(stmt.aug_op) + translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap)) } // pop the result value back into the assignment target @@ -867,7 +1001,12 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, } } - private fun translateAugAssignOperator(aug_op: String) { + private fun translateAugAssignOperator(aug_op: String, valueDt: DataType?) { + if(valueDt==null) + throw CompilerException("value datatype not known") + val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) + if(valueDt !in validDt) + throw CompilerException("invalid datatype(s) for operand(s)") val opcode = when(aug_op) { "+=" -> Opcode.ADD "-=" -> Opcode.SUB @@ -875,9 +1014,27 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, "//=" -> Opcode.FLOORDIV "*=" -> Opcode.MUL "**=" -> Opcode.POW - "&=" -> Opcode.BITAND - "|=" -> Opcode.BITOR - "^=" -> Opcode.BITXOR + "&=" -> { + when(valueDt) { + DataType.BYTE -> Opcode.BITAND + DataType.WORD -> Opcode.BITAND_W + else -> throw CompilerException("only byte/word possible") + } + } + "|=" -> { + when(valueDt) { + DataType.BYTE -> Opcode.BITOR + DataType.WORD -> Opcode.BITOR_W + else -> throw CompilerException("only byte/word possible") + } + } + "^=" -> { + when(valueDt) { + DataType.BYTE -> Opcode.BITXOR + DataType.WORD -> Opcode.BITXOR_W + else -> throw CompilerException("only byte/word possible") + } + } else -> throw CompilerException("invalid aug assignment operator $aug_op") } stackvmProg.instr(opcode) diff --git a/compiler/src/prog8/parser/prog8Lexer.java b/compiler/src/prog8/parser/prog8Lexer.java index 2df8649ff..e91c2ec5d 100644 --- a/compiler/src/prog8/parser/prog8Lexer.java +++ b/compiler/src/prog8/parser/prog8Lexer.java @@ -1,13 +1,12 @@ // Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7 package prog8.parser; -import org.antlr.v4.runtime.Lexer; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.TokenStream; + import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.LexerATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class prog8Lexer extends Lexer { diff --git a/compiler/src/prog8/parser/prog8Parser.java b/compiler/src/prog8/parser/prog8Parser.java index c3ef3f19a..c93e82623 100644 --- a/compiler/src/prog8/parser/prog8Parser.java +++ b/compiler/src/prog8/parser/prog8Parser.java @@ -1,13 +1,15 @@ // Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7 package prog8.parser; -import org.antlr.v4.runtime.atn.*; -import org.antlr.v4.runtime.dfa.DFA; + import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.misc.*; -import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.tree.TerminalNode; + import java.util.List; -import java.util.Iterator; -import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class prog8Parser extends Parser { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index d6b294979..52b1de2d9 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -43,34 +43,50 @@ enum class Opcode { NEG, // todo b/w/f // bit shifts and bitwise arithmetic - SHL, // todo b/w + SHL, + SHL_W, SHL_MEM, SHL_MEM_W, - SHL_VAR, // todo b/w - SHR, // todo b/w + SHL_VAR, + SHL_VAR_W, + SHR, + SHR_W, SHR_MEM, SHR_MEM_W, - SHR_VAR, // todo b/w - ROL, // todo b/w + SHR_VAR, + SHR_VAR_W, + ROL, + ROL_W, ROL_MEM, ROL_MEM_W, - ROL_VAR, // todo b/w - ROR, // todo b/w + ROL_VAR, + ROL_VAR_W, + ROR, + ROR_W, ROR_MEM, ROR_MEM_W, - ROR_VAR, // todo b/w - ROL2, // todo b/w + ROR_VAR, + ROR_VAR_W, + ROL2, + ROL2_W, ROL2_MEM, ROL2_MEM_W, - ROL2_VAR, // todo b/w - ROR2, // todo b/w + ROL2_VAR, + ROL2_VAR_W, + ROR2, + ROR2_W, ROR2_MEM, ROR2_MEM_W, - ROR2_VAR, // todo b/w - BITAND, // todo b/w - BITOR, // todo b/w - BITXOR, // todo b/w - INV, // todo b/w + ROR2_VAR, + ROR2_VAR_W, + BITAND, + BITAND_W, + BITOR, + BITOR_W, + BITXOR, + BITXOR_W, + INV, + INV_W, LSB, MSB, @@ -81,10 +97,14 @@ enum class Opcode { W2FLOAT, // convert word into floating point // logical operations - AND, // todo b/w (convert float to byte) - OR, // todo b/w (convert float to byte) - XOR, // todo b/w (convert float to byte) - NOT, // todo b/w (convert float to byte) + AND, + AND_W, + OR, + OR_W, + XOR, + XOR_W, + NOT, + NOT_W, // increment, decrement INC, @@ -101,12 +121,24 @@ enum class Opcode { DEC_VAR_F, // comparisons - LESS, // todo b/w/f ? - GREATER, // todo b/w/f ? - LESSEQ, // todo b/w/f ? - GREATEREQ, // todo b/w/f ? - EQUAL, // todo b/w/f ? - NOTEQUAL, // todo b/w/f ? + LESS, + LESS_W, + LESS_F, + GREATER, + GREATER_W, + GREATER_F, + LESSEQ, + LESSEQ_W, + LESSEQ_F, + GREATEREQ, + GREATEREQ_W, + GREATEREQ_F, + EQUAL, + EQUAL_W, + EQUAL_F, + NOTEQUAL, + NOTEQUAL_W, + NOTEQUAL_F, // array access READ_INDEXED_VAR, @@ -145,8 +177,9 @@ enum class Opcode { val opcodesWithVarArgument = setOf( Opcode.INC_VAR, Opcode.INC_VAR_W, Opcode.DEC_VAR, Opcode.DEC_VAR_W, - Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR, - Opcode.ROL2_VAR, Opcode.ROR2_VAR, + Opcode.SHR_VAR, Opcode.SHR_VAR_W, Opcode.SHL_VAR, Opcode.SHL_VAR_W, + Opcode.ROL_VAR, Opcode.ROL_VAR_W, Opcode.ROR_VAR, Opcode.ROR_VAR_W, + Opcode.ROL2_VAR, Opcode.ROL2_VAR_W, Opcode.ROR2_VAR, Opcode.ROR2_VAR_W, Opcode.POP_VAR, Opcode.POP_VAR_W, Opcode.POP_VAR_F, Opcode.PUSH_VAR, Opcode.PUSH_VAR_W, Opcode.PUSH_VAR_F, Opcode.READ_INDEXED_VAR, Opcode.READ_INDEXED_VAR_W, Opcode.READ_INDEXED_VAR_F, @@ -479,56 +512,116 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.SHL -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + evalstack.push(v.shl()) + } + Opcode.SHL_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) evalstack.push(v.shl()) } Opcode.SHR -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + evalstack.push(v.shr()) + } + Opcode.SHR_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) evalstack.push(v.shr()) } Opcode.ROL -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + val (result, newCarry) = v.rol(P_carry) + this.P_carry = newCarry + evalstack.push(result) + } + Opcode.ROL_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) val (result, newCarry) = v.rol(P_carry) this.P_carry = newCarry evalstack.push(result) } Opcode.ROL2 -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + evalstack.push(v.rol2()) + } + Opcode.ROL2_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) evalstack.push(v.rol2()) } Opcode.ROR -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + val (result, newCarry) = v.ror(P_carry) + this.P_carry = newCarry + evalstack.push(result) + } + Opcode.ROR_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) val (result, newCarry) = v.ror(P_carry) this.P_carry = newCarry evalstack.push(result) } Opcode.ROR2 -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + evalstack.push(v.ror2()) + } + Opcode.ROR2_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) evalstack.push(v.ror2()) } Opcode.BITAND -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.bitand(top)) + } + Opcode.BITAND_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.bitand(top)) } Opcode.BITOR -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.bitor(top)) + } + Opcode.BITOR_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.bitor(top)) } Opcode.BITXOR -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.bitxor(top)) + } + Opcode.BITXOR_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.bitxor(top)) } Opcode.INV -> { val v = evalstack.pop() - // todo b/w + checkDt(v, DataType.BYTE) + evalstack.push(v.inv()) + } + Opcode.INV_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) evalstack.push(v.inv()) } Opcode.INC -> { @@ -705,36 +798,70 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.SHL_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + variables[ins.callLabel!!] = variable.shl() + } + Opcode.SHL_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) variables[ins.callLabel!!] = variable.shl() } Opcode.SHR_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + variables[ins.callLabel!!] = variable.shr() + } + Opcode.SHR_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) variables[ins.callLabel!!] = variable.shr() } Opcode.ROL_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + val (newValue, newCarry) = variable.rol(P_carry) + variables[ins.callLabel!!] = newValue + P_carry = newCarry + } + Opcode.ROL_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) val (newValue, newCarry) = variable.rol(P_carry) variables[ins.callLabel!!] = newValue P_carry = newCarry } Opcode.ROR_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + val (newValue, newCarry) = variable.ror(P_carry) + variables[ins.callLabel!!] = newValue + P_carry = newCarry + } + Opcode.ROR_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) val (newValue, newCarry) = variable.ror(P_carry) variables[ins.callLabel!!] = newValue P_carry = newCarry } Opcode.ROL2_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + variables[ins.callLabel!!] = variable.rol2() + } + Opcode.ROL2_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) variables[ins.callLabel!!] = variable.rol2() } Opcode.ROR2_VAR -> { val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") - // todo b/w + checkDt(variable, DataType.BYTE) + variables[ins.callLabel!!] = variable.ror2() + } + Opcode.ROR2_VAR_W -> { + val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}") + checkDt(variable, DataType.WORD) variables[ins.callLabel!!] = variable.ror2() } Opcode.INC_VAR -> { @@ -779,52 +906,156 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.AND -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.and(top)) + } + Opcode.AND_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.and(top)) } Opcode.OR -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.or(top)) + } + Opcode.OR_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.or(top)) } Opcode.XOR -> { val (top, second) = evalstack.pop2() - // todo b/w + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(second.xor(top)) + } + Opcode.XOR_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) evalstack.push(second.xor(top)) } Opcode.NOT -> { val value = evalstack.pop() - // todo b/w + checkDt(value, DataType.BYTE) + evalstack.push(value.not()) + } + Opcode.NOT_W -> { + val value = evalstack.pop() + checkDt(value, DataType.WORD) evalstack.push(value.not()) } Opcode.LESS -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0)) + } + Opcode.LESS_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0)) + } + Opcode.LESS_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0)) } Opcode.GREATER -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0)) + } + Opcode.GREATER_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0)) + } + Opcode.GREATER_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0)) } Opcode.LESSEQ -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0)) + } + Opcode.LESSEQ_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0)) + } + Opcode.LESSEQ_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0)) } Opcode.GREATEREQ -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0)) + } + Opcode.GREATEREQ_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0)) + } + Opcode.GREATEREQ_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0)) } Opcode.EQUAL -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0)) + } + Opcode.EQUAL_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0)) + } + Opcode.EQUAL_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0)) } Opcode.NOTEQUAL -> { val (top, second) = evalstack.pop2() - // todo b/w/f? + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) + evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0)) + } + Opcode.NOTEQUAL_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0)) + } + Opcode.NOTEQUAL_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0)) } Opcode.B2WORD -> { diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index 58a16d1a3..f3a7fc644 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -17,21 +17,27 @@ import kotlin.test.* SHL_MEM, SHL_MEM_W, SHL_VAR, + SHL_VAR_W, SHR_MEM, SHR_MEM_W, SHR_VAR, + SHR_VAR_W, ROL_MEM, ROL_MEM_W, ROL_VAR, + ROL_VAR_W, ROR_MEM, ROR_MEM_W, ROR_VAR, + ROR_VAR_W, ROL2_MEM, ROL2_MEM_W, ROL2_VAR, + ROL2_VAR_W, ROR2_MEM, ROR2_MEM_W, ROR2_VAR, + ROR2_VAR_W **/ @@ -306,19 +312,19 @@ class TestStackVmOpcodes { @Test fun testBitand() { testBinaryOperator(Value(DataType.BYTE, 0b10011111), Opcode.BITAND, Value(DataType.BYTE, 0b11111101), Value(DataType.BYTE, 0b10011101)) - testBinaryOperator(Value(DataType.WORD, 0b0011001011110001), Opcode.BITAND, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0000000010010001)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011110001), Opcode.BITAND_W, Value(DataType.WORD, 0b1110000010011101), Value(DataType.WORD, 0b0010000010010001)) } @Test fun testBitor() { testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10011101)) - testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITOR, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0011001011111101)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITOR_W, Value(DataType.WORD, 0b1000000010011101), Value(DataType.WORD, 0b1011001011111101)) } @Test fun testBitxor() { testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITXOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10001100)) - testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITXOR, Value(DataType.BYTE, 0b10001100), Value(DataType.WORD, 0b0011001001101100)) + testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITXOR_W, Value(DataType.WORD, 0b1000000010001100), Value(DataType.WORD, 0b1011001001101100)) } @Test @@ -326,14 +332,9 @@ class TestStackVmOpcodes { testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) testBinaryOperator(Value(DataType.BYTE, 0), Opcode.AND, Value(DataType.BYTE, 101), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.WORD, 0), Opcode.AND, Value(DataType.WORD, 101), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.AND, Value(DataType.FLOAT, 101.11), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.STR, 222), Opcode.AND, Value(DataType.STR, 333), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.AND, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.AND_W, Value(DataType.WORD, 101), Value(DataType.BYTE, 0)) } @Test @@ -341,14 +342,9 @@ class TestStackVmOpcodes { testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 0), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.WORD, 0), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.STR, 222), Opcode.OR, Value(DataType.STR, 333), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.OR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.OR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) } @Test @@ -356,24 +352,17 @@ class TestStackVmOpcodes { testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1)) testBinaryOperator(Value(DataType.BYTE, 0), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.WORD, 0), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1)) - testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.STR, 222), Opcode.XOR, Value(DataType.STR, 333), Value(DataType.BYTE, 0)) - testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.XOR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 0), Opcode.XOR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0)) } @Test fun testNot() { testUnaryOperator(Value(DataType.BYTE, 0), Opcode.NOT, Value(DataType.BYTE, 1)) testUnaryOperator(Value(DataType.BYTE, 20), Opcode.NOT, Value(DataType.BYTE, 0)) - testUnaryOperator(Value(DataType.WORD, 0), Opcode.NOT, Value(DataType.BYTE, 1)) - testUnaryOperator(Value(DataType.WORD, 5000), Opcode.NOT, Value(DataType.BYTE, 0)) - testUnaryOperator(Value(DataType.FLOAT, 0.0), Opcode.NOT, Value(DataType.BYTE, 1)) - testUnaryOperator(Value(DataType.FLOAT, 5000.0), Opcode.NOT, Value(DataType.BYTE, 0)) + testUnaryOperator(Value(DataType.WORD, 0), Opcode.NOT_W, Value(DataType.BYTE, 1)) + testUnaryOperator(Value(DataType.WORD, 5000), Opcode.NOT_W, Value(DataType.BYTE, 0)) } @Test @@ -406,7 +395,7 @@ class TestStackVmOpcodes { @Test fun testInv() { testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV, Value(DataType.BYTE, 0x84)) - testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV, Value(DataType.WORD, 0xf033)) + testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_W, Value(DataType.WORD, 0xf033)) } @Test @@ -586,182 +575,74 @@ class TestStackVmOpcodes { @Test fun testLess() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 2), - Value(DataType.WORD, 20), // 1 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 1 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 21), // 0 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 0 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21.0001) // 1 - ) - val expected = listOf(1, 0, 1, 1, 0, 0, 1) - testComparisonOperator(values, expected, Opcode.LESS) - - val valuesInvalid = listOf( - Value(DataType.STR, 333), - Value(DataType.STR, 333) - ) - assertFailsWith { - testComparisonOperator(valuesInvalid, listOf(0), Opcode.LESS) // can't order strings - } + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.LESS, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESS, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.LESS_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 1)) } @Test fun testLessEq() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 21), - Value(DataType.WORD, 20), // 0 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 1 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 22), // 1 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 1 - Value(DataType.BYTE, 22), - Value(DataType.FLOAT, 21.999) // 0 - ) - val expected = listOf(1,1,0,1,1,1,0) - testComparisonOperator(values, expected, Opcode.LESSEQ) - - val valuesInvalid = listOf( - Value(DataType.STR, 333), - Value(DataType.STR, 333) - ) - assertFailsWith { - testComparisonOperator(valuesInvalid, listOf(0), Opcode.LESSEQ) // can't order strings - } + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.LESSEQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESSEQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.LESSEQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.LESSEQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESSEQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESSEQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 20.999), Value(DataType.BYTE, 0)) } @Test fun testGreater() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 20), - Value(DataType.WORD, 2), // 1 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 0 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 20), // 1 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 0 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 20.9999) // 1 - ) - val expected = listOf(0, 0, 1, 0, 1, 0, 1) - testComparisonOperator(values, expected, Opcode.GREATER) - - val valuesInvalid = listOf( - Value(DataType.STR, 333), - Value(DataType.STR, 333) - ) - assertFailsWith { - testComparisonOperator(valuesInvalid, listOf(0), Opcode.GREATER) // can't order strings - } + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.GREATER, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATER, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.GREATER_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.GREATER_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATER_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATER_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 20.999), Value(DataType.BYTE, 1)) } @Test fun testGreaterEq() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 21), - Value(DataType.WORD, 20), // 1 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 0 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 22), // 0 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 1 - Value(DataType.BYTE, 22), - Value(DataType.FLOAT, 21.999) // 1 - ) - val expected = listOf(0,1,1,0,0,1,1) - testComparisonOperator(values, expected, Opcode.GREATEREQ) - - val valuesInvalid = listOf( - Value(DataType.STR, 333), - Value(DataType.STR, 333) - ) - assertFailsWith { - testComparisonOperator(valuesInvalid, listOf(0), Opcode.GREATEREQ) // can't order strings - } + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.GREATEREQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATEREQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.GREATEREQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATEREQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 0)) } @Test fun testEqual() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 21), - Value(DataType.WORD, 20), // 0 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 0 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 21), // 1 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 1 - Value(DataType.BYTE, 22), - Value(DataType.FLOAT, 21.999) // 0 - ) - val expected = listOf(0,1,0,0,1,1,0) - testComparisonOperator(values, expected, Opcode.EQUAL) - - val valuesInvalid = listOf( - Value(DataType.STR, 111), - Value(DataType.STR, 222), // 0 - Value(DataType.STR, 333), - Value(DataType.STR, 333) // 1 - ) - testComparisonOperator(valuesInvalid, listOf(0, 1), Opcode.EQUAL) + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.EQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.EQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.EQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.EQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.EQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.EQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 0)) } @Test fun testNotEqual() { - val values = listOf( - Value(DataType.BYTE, 0), - Value(DataType.BYTE, 1), // 1 - Value(DataType.BYTE, 1), - Value(DataType.BYTE, 1), // 0 - Value(DataType.BYTE, 21), - Value(DataType.WORD, 20), // 1 - Value(DataType.WORD, 20), - Value(DataType.BYTE, 21), // 1 - Value(DataType.WORD, 21), - Value(DataType.BYTE, 21), // 0 - Value(DataType.BYTE, 21), - Value(DataType.FLOAT, 21), // 0 - Value(DataType.BYTE, 22), - Value(DataType.FLOAT, 21.999) // 1 - ) - val expected = listOf(1,0,1,1,0,0,1) - testComparisonOperator(values, expected, Opcode.NOTEQUAL) - - val valuesInvalid = listOf( - Value(DataType.STR, 111), - Value(DataType.STR, 222), // 1 - Value(DataType.STR, 333), - Value(DataType.STR, 333) // 0 - ) - testComparisonOperator(valuesInvalid, listOf(1, 0), Opcode.NOTEQUAL) + testBinaryOperator(Value(DataType.BYTE, 0), Opcode.NOTEQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.BYTE, 1), Opcode.NOTEQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.WORD, 2), Opcode.NOTEQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 20), Opcode.NOTEQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.NOTEQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1)) + testBinaryOperator(Value(DataType.WORD, 21), Opcode.NOTEQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0)) + testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 1)) } @Test @@ -964,11 +845,11 @@ class TestStackVmOpcodes { Instruction(Opcode.SHR), // 0 Instruction(Opcode.SHR), // 0 Instruction(Opcode.DISCARD), - Instruction(Opcode.SHR), // 30502 + Instruction(Opcode.SHR_W), // 30502 Instruction(Opcode.DISCARD_W), - Instruction(Opcode.SHR), // 1 - Instruction(Opcode.SHR), // 0 - Instruction(Opcode.SHR), // 0 + Instruction(Opcode.SHR_W), // 1 + Instruction(Opcode.SHR_W), // 0 + Instruction(Opcode.SHR_W), // 0 Instruction(Opcode.DISCARD_W), Instruction(Opcode.SHR) // error on float ) @@ -1004,11 +885,11 @@ class TestStackVmOpcodes { Instruction(Opcode.DISCARD), Instruction(Opcode.SHL), // 6 Instruction(Opcode.DISCARD), - Instruction(Opcode.SHL), // 56474 + Instruction(Opcode.SHL_W), // 56474 Instruction(Opcode.DISCARD_W), - Instruction(Opcode.SHL), // 6 + Instruction(Opcode.SHL_W), // 6 Instruction(Opcode.DISCARD_W), - Instruction(Opcode.SHL) // error on float + Instruction(Opcode.SHL_W) // error on float ) vm.load(makeProg(ins), null) vm.step(6) @@ -1061,23 +942,23 @@ class TestStackVmOpcodes { val ins2 = mutableListOf( Instruction(Opcode.CLC), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)), - Instruction(Opcode.ROR), // 0b0100100110000110 c=1 - Instruction(Opcode.ROR), // 0b1010010011000011 c=0 - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR), - Instruction(Opcode.ROR) // 0b1001001100001101 c=0 (original value after 17 rors) + Instruction(Opcode.ROR_W), // 0b0100100110000110 c=1 + Instruction(Opcode.ROR_W), // 0b1010010011000011 c=0 + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W), + Instruction(Opcode.ROR_W) // 0b1001001100001101 c=0 (original value after 17 rors) ) vm.load(makeProg(ins2), null) vm.step(3) @@ -1126,23 +1007,23 @@ class TestStackVmOpcodes { val ins2 = mutableListOf( Instruction(Opcode.CLC), Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)), - Instruction(Opcode.ROL), // 0b0010011000011010 c=1 - Instruction(Opcode.ROL), // 0b0100110000110101 c=0 - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL), - Instruction(Opcode.ROL) // 0b1001001100001101 c=0 (original value after 17 rors) + Instruction(Opcode.ROL_W), // 0b0010011000011010 c=1 + Instruction(Opcode.ROL_W), // 0b0100110000110101 c=0 + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W), + Instruction(Opcode.ROL_W) // 0b1001001100001101 c=0 (original value after 17 rors) ) vm.load(makeProg(ins2), null) vm.step(3) @@ -1183,22 +1064,22 @@ class TestStackVmOpcodes { val ins2 = mutableListOf( Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)), - Instruction(Opcode.ROR2), // 0b1100100110000110 - Instruction(Opcode.ROR2), // 0b0110010011000011 - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2), - Instruction(Opcode.ROR2) // 0b1001001100001101 (original value after 16 rors) + Instruction(Opcode.ROR2_W), // 0b1100100110000110 + Instruction(Opcode.ROR2_W), // 0b0110010011000011 + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W), + Instruction(Opcode.ROR2_W) // 0b1001001100001101 (original value after 16 rors) ) vm.load(makeProg(ins2), null) vm.step(2) @@ -1235,22 +1116,22 @@ class TestStackVmOpcodes { val ins2 = mutableListOf( Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)), - Instruction(Opcode.ROL2), // 0b0010011000011011 - Instruction(Opcode.ROL2), // 0b0100110000110110 - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2), - Instruction(Opcode.ROL2) // 0b1001001100001101 (original value after 16 rols) + Instruction(Opcode.ROL2_W), // 0b0010011000011011 + Instruction(Opcode.ROL2_W), // 0b0100110000110110 + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W), + Instruction(Opcode.ROL2_W) // 0b1001001100001101 (original value after 16 rols) ) vm.load(makeProg(ins2), null) vm.step(2) @@ -1273,24 +1154,6 @@ class TestStackVmOpcodes { } } - private fun testComparisonOperator(values: List, expected: List, operator: Opcode) { - assertEquals(values.size, expected.size*2) - val ins = mutableListOf() - val vars = values.iterator() - while(vars.hasNext()) { - var nextvar = vars.next() - ins.add(Instruction(pushOpcode(nextvar.type), nextvar)) - nextvar = vars.next() - ins.add(Instruction(pushOpcode(nextvar.type), nextvar)) - ins.add(Instruction(operator)) - } - vm.load(makeProg(ins), null) - for(expectedValue in expected) { - vm.step(3) - assertEquals(Value(DataType.BYTE, expectedValue), vm.evalstack.pop()) - } - } - private fun testBinaryOperator(left: Value, operator: Opcode, right: Value, result: Value) { val program=makeProg(mutableListOf( Instruction(pushOpcode(left.type), left),