private ByteBlock GetValue(Operand op) { ByteBlock result = ByteBlock.Empty; switch (op.Type) { case Operand.OperandType.AddressBlock: break; case Operand.OperandType.Register: return this.ReadRegister(op.Value.ToByte()); case Operand.OperandType.StackIndex: break; case Operand.OperandType.NumericByte: case Operand.OperandType.NumericSByte: case Operand.OperandType.NumericShort: case Operand.OperandType.NumericUShort: case Operand.OperandType.NumericInt: case Operand.OperandType.NumericUInt: case Operand.OperandType.NumericLong: case Operand.OperandType.NumericULong: case Operand.OperandType.NumericFloat: case Operand.OperandType.NumericDouble: case Operand.OperandType.LPString: return op.Value; default: throw new ArgumentException(); } 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 } } }
public void Execute() { ushort fullopcode = this.ReadUShort(); byte type = (byte)(fullopcode >> 8); byte opcode = (byte)((fullopcode << 8) >> 8); ushort arity = 0; switch (type) { case 0x00: // Control flow instruction CFOpcode cfopcode = (CFOpcode)opcode; switch (cfopcode) { case CFOpcode.NOP: break; case CFOpcode.RET: case CFOpcode.END: // no operands break; case CFOpcode.JMP: case CFOpcode.JMPA: case CFOpcode.CALL: case CFOpcode.CALLA: // one operand, etc arity = 1; break; case CFOpcode.JZ: case CFOpcode.JNZ: arity = 2; break; case CFOpcode.JE: case CFOpcode.JNE: case CFOpcode.JLT: case CFOpcode.JGT: case CFOpcode.JLTE: case CFOpcode.JGTE: arity = 3; break; default: throw new ArgumentOutOfRangeException(); // will likely change } break; case 0x01: // data instructions DataOpcode dopcode = (DataOpcode)opcode; switch (dopcode & (DataOpcode)0xE0) // seems only the top 3 bits are needed { case (DataOpcode)0x00: // stack arithmetic (or a move) if (dopcode == DataOpcode.MOV) { arity = 2; } break; case (DataOpcode)0x40: // long arithmetic switch (dopcode) { case DataOpcode.INVL: case DataOpcode.NOTL: case DataOpcode.BWNOTL: arity = 2; break; default: if (dopcode > (DataOpcode)0x54) { throw new ArgumentOutOfRangeException(); } else { arity = 3; break; } } break; case (DataOpcode)0x80: // stack operations if (dopcode == DataOpcode.ARRAYALLOC) { arity = 2; } else { arity = 1; } break; case (DataOpcode)0xA0: // conversions arity = 2; break; } break; case 0x02: // system instructions SysOpcode sopcode = (SysOpcode)opcode; arity = 1; break; default: throw new ArgumentOutOfRangeException(); } if (arity > 0) { Operand[] operands = new Operand[arity]; byte flags = this.ReadByte(); int i; for (i = 1; i <= arity; i++) { switch (flags >> 6) { case 0: // memory addr operands[i] = new Operand(this, Operand.OperandType.AddressBlock); // addressblock code to be redone break; case 1: // register operands[i] = new Operand(this, Operand.OperandType.Register); break; case 2: // stack index operands[i] = new Operand(this, Operand.OperandType.StackIndex); break; case 3: // literal byte valuetype = this.ReadByte(); operands[i] = new Operand(this, (Operand.OperandType)(valuetype - 3)); break; } flags <<= 2; } // check operand types } }