private ulong UnsignedArithmetic(DataOpcode opcode, ulong left, ulong right) { ulong result = 0ul; switch (opcode) { case DataOpcode.MOV: break; case DataOpcode.ADD: case DataOpcode.ADDL: result = left + right; break; case DataOpcode.SUB: case DataOpcode.SUBL: result = left - right; break; case DataOpcode.MULT: case DataOpcode.MULTL: result = left * right; break; case DataOpcode.DIV: case DataOpcode.DIVL: result = left / right; break; case DataOpcode.MOD: case DataOpcode.MODL: result = left % right; break; case DataOpcode.INV: case DataOpcode.INVL: throw new ArgumentException("can't invert an unsigned number"); //maybe use something other than ArgumentException case DataOpcode.EQ: case DataOpcode.EQL: result = left == right ? 1UL : 0UL; break; case DataOpcode.INEQ: case DataOpcode.INEQL: result = left == right ? 0UL : 1UL; break; case DataOpcode.LT: case DataOpcode.LTL: result = left < right ? 1UL : 0UL; break; case DataOpcode.GT: case DataOpcode.GTL: result = left > right ? 1UL : 0UL; break; case DataOpcode.LTEQ: case DataOpcode.LTEQL: result = left > right ? 0UL : 1UL; break; case DataOpcode.GTEQ: case DataOpcode.GTEQL: result = left < right ? 0UL : 1UL; break; case DataOpcode.AND: case DataOpcode.ANDL: result = (left != 0UL && right != 0UL) ? 1UL : 0UL; break; case DataOpcode.OR: case DataOpcode.ORL: result = (left != 0UL && right != 0UL) ? 1UL : 0UL; break; case DataOpcode.NOT: case DataOpcode.NOTL: result = (left != 0UL) ? 0UL : 1UL; break; case DataOpcode.BWNOT: case DataOpcode.BWNOTL: result = ~left; break; case DataOpcode.BWAND: case DataOpcode.BWANDL: result = left & right; break; case DataOpcode.BWOR: case DataOpcode.BWORL: result = left | right; break; case DataOpcode.BWXOR: case DataOpcode.BWXORL: result = left ^ right; break; case DataOpcode.BWLSHIFT: case DataOpcode.BWLSHIFTL: result = left << (int)right; // max 63 bits break; case DataOpcode.BWRSHIFT: case DataOpcode.BWRSHIFTL: result = left >> (int)right; break; case DataOpcode.PUSH: break; case DataOpcode.POP: break; case DataOpcode.PEEK: break; case DataOpcode.STACKALLOC: break; case DataOpcode.ARRAYALLOC: break; case DataOpcode.DEREF: break; case DataOpcode.ARRAYACCESS: break; case DataOpcode.CBYTE: break; case DataOpcode.CSBYTE: break; case DataOpcode.CSHORT: break; case DataOpcode.CUSHORT: break; case DataOpcode.CINT: break; case DataOpcode.CUINT: break; case DataOpcode.CLONG: break; case DataOpcode.CULONG: break; case DataOpcode.CSING: break; case DataOpcode.CDOUBLE: break; default: break; } return result; }
private void LongArithmeticInstruction(DataOpcode opcode, Operand left, Operand right, Operand dest) { if (left.Type == Operand.OperandType.LPString || right.Type == Operand.OperandType.LPString) { throw new ArgumentException("can't do arithmetic on strings"); } if (dest.Type != Operand.OperandType.AddressBlock && dest.Type != Operand.OperandType.Register && dest.Type != Operand.OperandType.StackIndex) { throw new ArgumentException("can't assign to a literal"); } ByteBlock op1 = GetValue(left); ByteBlock op2 = GetValue(right); ulong uresult; long sresult; double fresult; ByteBlock result; if ((left.Type == Operand.OperandType.NumericByte || left.Type == Operand.OperandType.NumericUShort || left.Type == Operand.OperandType.NumericUInt || left.Type == Operand.OperandType.NumericULong || left.Type == Operand.OperandType.Register || left.Type == Operand.OperandType.AddressBlock) && (right.Type == Operand.OperandType.NumericByte || right.Type == Operand.OperandType.NumericUShort || right.Type == Operand.OperandType.NumericUInt || right.Type == Operand.OperandType.NumericULong || right.Type == Operand.OperandType.Register || right.Type == Operand.OperandType.AddressBlock)) // for now, register & memory values are only treated as ulongs. Fix { uresult = UnsignedArithmetic(opcode, op1.ToULong(), op2.ToULong()); if (dest.Type == Operand.OperandType.Register) { result = new ByteBlock(uresult); WriteRegister((byte)dest.Value, result); } else { // this.Memory.WriteULongAt(uresult, (int)(((AddressBlock)dest.Value).Address)); fix } } else if ((left.Type == Operand.OperandType.NumericSByte || left.Type == Operand.OperandType.NumericShort || left.Type == Operand.OperandType.NumericInt || left.Type == Operand.OperandType.NumericLong) && (right.Type == Operand.OperandType.NumericSByte || right.Type == Operand.OperandType.NumericShort || right.Type == Operand.OperandType.NumericInt || right.Type == Operand.OperandType.NumericLong)) { sresult = SignedArithmetic(opcode, op1.ToLong(), op2.ToLong()); if (dest.Type == Operand.OperandType.Register) { result = new ByteBlock(sresult); WriteRegister((byte)dest.Value, result); } else { // this.Memory.WriteLongAt(sresult, (int)(((AddressBlock)dest.Value).Address)); fix } } else { fresult = FPArithmetic(opcode, op1.ToDouble(), op2.ToDouble()); if (dest.Type == Operand.OperandType.Register) { result = new ByteBlock(fresult); WriteRegister((byte)dest.Value, result); } else { // this.Memory.WriteDoubleAt(fresult, (int)(((AddressBlock)dest.Value).Address)); fix } } }
// I don't like this repetition private long SignedArithmetic(DataOpcode opcode, long left, long right) { long result = 0L; switch (opcode) { case DataOpcode.MOV: break; case DataOpcode.ADD: case DataOpcode.ADDL: result = left + right; break; case DataOpcode.SUB: case DataOpcode.SUBL: result = left - right; break; case DataOpcode.MULT: case DataOpcode.MULTL: result = left * right; break; case DataOpcode.DIV: case DataOpcode.DIVL: result = left / right; break; case DataOpcode.MOD: case DataOpcode.MODL: result = left % right; break; case DataOpcode.INV: case DataOpcode.INVL: result = -left; break; case DataOpcode.EQ: case DataOpcode.EQL: result = left == right ? 1L : 0L; break; case DataOpcode.INEQ: case DataOpcode.INEQL: result = left == right ? 0L : 1L; break; case DataOpcode.LT: case DataOpcode.LTL: result = left < right ? 1L : 0L; break; case DataOpcode.GT: case DataOpcode.GTL: result = left > right ? 1L : 0L; break; case DataOpcode.LTEQ: case DataOpcode.LTEQL: result = left > right ? 0L : 1L; break; case DataOpcode.GTEQ: case DataOpcode.GTEQL: result = left < right ? 0L : 1L; break; case DataOpcode.AND: case DataOpcode.ANDL: result = (left != 0L && right != 0L) ? 1L : 0L; break; case DataOpcode.OR: case DataOpcode.ORL: result = (left != 0L && right != 0L) ? 1L : 0L; break; case DataOpcode.NOT: case DataOpcode.NOTL: result = (left != 0L) ? 0L : 1L; break; case DataOpcode.BWNOT: case DataOpcode.BWNOTL: result = ~left; break; case DataOpcode.BWAND: case DataOpcode.BWANDL: result = left & right; break; case DataOpcode.BWOR: case DataOpcode.BWORL: result = left | right; break; case DataOpcode.BWXOR: case DataOpcode.BWXORL: result = left ^ right; break; case DataOpcode.BWLSHIFT: case DataOpcode.BWLSHIFTL: result = left << (int)right; // max 63 bits break; case DataOpcode.BWRSHIFT: case DataOpcode.BWRSHIFTL: result = left >> (int)right; break; case DataOpcode.PUSH: break; case DataOpcode.POP: break; case DataOpcode.PEEK: break; case DataOpcode.STACKALLOC: break; case DataOpcode.ARRAYALLOC: break; case DataOpcode.DEREF: break; case DataOpcode.ARRAYACCESS: break; case DataOpcode.CBYTE: break; case DataOpcode.CSBYTE: break; case DataOpcode.CSHORT: break; case DataOpcode.CUSHORT: break; case DataOpcode.CINT: break; case DataOpcode.CUINT: break; case DataOpcode.CLONG: break; case DataOpcode.CULONG: break; case DataOpcode.CSING: break; case DataOpcode.CDOUBLE: break; default: break; } return result; }
private double FPArithmetic(DataOpcode opcode, double left, double right) { double result = 0d; switch (opcode) { case DataOpcode.MOV: break; case DataOpcode.ADD: case DataOpcode.ADDL: result = left + right; break; case DataOpcode.SUB: case DataOpcode.SUBL: result = left - right; break; case DataOpcode.MULT: case DataOpcode.MULTL: result = left * right; break; case DataOpcode.DIV: case DataOpcode.DIVL: result = left / right; break; case DataOpcode.MOD: case DataOpcode.MODL: result = left % right; break; case DataOpcode.INV: case DataOpcode.INVL: result = -left; break; case DataOpcode.EQ: case DataOpcode.EQL: result = left == right ? 1.0 : 0.0; break; case DataOpcode.INEQ: case DataOpcode.INEQL: result = left == right ? 0.0 : 1.0; break; case DataOpcode.LT: case DataOpcode.LTL: result = left < right ? 1.0 : 0.0; break; case DataOpcode.GT: case DataOpcode.GTL: result = left > right ? 1.0 : 0.0; break; case DataOpcode.LTEQ: case DataOpcode.LTEQL: result = left > right ? 0.0 : 1.0; break; case DataOpcode.GTEQ: case DataOpcode.GTEQL: result = left < right ? 0.0 : 1.0; break; case DataOpcode.AND: case DataOpcode.ANDL: result = (left != 0.0 && right != 0.0) ? 1.0 : 0.0; break; case DataOpcode.OR: case DataOpcode.ORL: result = (left != 0.0 && right != 0.0) ? 1.0 : 0.0; break; case DataOpcode.NOT: case DataOpcode.NOTL: result = (left != 0.0) ? 0.0 : 1.0; break; case DataOpcode.BWNOT: case DataOpcode.BWNOTL: case DataOpcode.BWAND: case DataOpcode.BWANDL: case DataOpcode.BWOR: case DataOpcode.BWORL: case DataOpcode.BWXOR: case DataOpcode.BWXORL: case DataOpcode.BWLSHIFT: case DataOpcode.BWLSHIFTL: case DataOpcode.BWRSHIFT: case DataOpcode.BWRSHIFTL: throw new ArgumentException("can't do Boolean operations on floating-point values"); case DataOpcode.PUSH: break; case DataOpcode.POP: break; case DataOpcode.PEEK: break; case DataOpcode.STACKALLOC: break; case DataOpcode.ARRAYALLOC: break; case DataOpcode.DEREF: break; case DataOpcode.ARRAYACCESS: break; case DataOpcode.CBYTE: break; case DataOpcode.CSBYTE: break; case DataOpcode.CSHORT: break; case DataOpcode.CUSHORT: break; case DataOpcode.CINT: break; case DataOpcode.CUINT: break; case DataOpcode.CLONG: break; case DataOpcode.CULONG: break; case DataOpcode.CSING: break; case DataOpcode.CDOUBLE: break; default: break; } return result; }