Example #1
0
        public VirtualMachine(int memorySize)
        {
            if (memorySize < 512 * 1024)
                throw new ArgumentOutOfRangeException("memorySize", "VM should have at least 512kB of memory");

            Registers = new int[(int)Register.Count];
            Memory = new byte[memorySize];

            IP = 0;
            SP = Memory.Length;

            Flags = VmFlags.None;
            IVT = 0;

            _instruction = new Instruction(this);
            _interruptsEnabled = false;
            _interrupted = false;
            _devices = new IDevice[16];

            Attach(this);

            _timer = new Devices.Timer();
            Attach(_timer);

            Attach(new Devices.SysCall());
        }
Example #2
0
 private void SetZero(int value)
 {
     Flags &= ~VmFlags.Zero;
     if (value == 0)
         Flags |= VmFlags.Zero;
 }
Example #3
0
        private void InterruptReturn()
        {
            for (var i = (int)Register.R0; i <= (int)Register.BP; i++)
            {
                Registers[i] = Pop();
            }

            Flags = (VmFlags)Pop();
            IP = Pop();
            SP = Pop();

            Interrupted = false;
        }
Example #4
0
        public void Step()
        {
            _errorIp = IP;

            try
            {
                if (_interruptsEnabled && !Interrupted)
                {
                    for (var i = 0; i < _devices.Length; i++)
                    {
                        var device = _devices[i];
                        if (device == null || !device.InterruptRequest)
                            continue;

                        Interrupt(device.Id);
                        device.HandleInterruptRequest(this);
                        return;
                    }
                }

                _instruction.Decode();
                IP += _instruction.Length;
                //Console.WriteLine(_instruction);

                int result;
                switch (_instruction.Opcode)
                {
                    case Opcode.Mov:
                        _instruction.Left.Set(_instruction.Right.Get());
                        break;
                    case Opcode.Add:
                        result = _instruction.Left.Get() + _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Sub:
                        result = _instruction.Left.Get() - _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Mul:
                        result = _instruction.Left.Get() * _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Div:
                        result = _instruction.Left.Get() / _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Rem:
                        result = _instruction.Left.Get() % _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Inc:
                        result = _instruction.Left.Get() + 1;
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Dec:
                        result = _instruction.Left.Get() - 1;
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Not:
                        result = ~_instruction.Left.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.And:
                        result = _instruction.Left.Get() & _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Or:
                        result = _instruction.Left.Get() | _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Xor:
                        result = _instruction.Left.Get() ^ _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Shl:
                        result = _instruction.Left.Get() << _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Shr:
                        result = _instruction.Left.Get() >> _instruction.Right.Get();
                        _instruction.Left.Set(result);
                        SetZero(result);
                        break;
                    case Opcode.Push:
                        Push(_instruction.Left.Get());
                        break;
                    case Opcode.Pop:
                        _instruction.Left.Set(Pop());
                        break;
                    case Opcode.Jmp:
                        IP = _instruction.Left.Get();
                        break;
                    case Opcode.Call:
                        Push(IP);
                        IP = _instruction.Left.Get();
                        break;
                    case Opcode.Ret:
                        IP = Pop();
                        break;
                    case Opcode.Cmp:
                        var cmpValL = _instruction.Left.Get();
                        var cmpValR = _instruction.Right.Get();

                        Flags = VmFlags.None;
                        if (cmpValL == 0)
                            Flags |= VmFlags.Zero;
                        if (cmpValL == cmpValR)
                            Flags |= VmFlags.Equal;
                        if (cmpValL > cmpValR)
                            Flags |= VmFlags.Above;
                        if (cmpValL < cmpValR)
                            Flags |= VmFlags.Below;
                        break;
                    case Opcode.Jz:
                        if ((Flags & VmFlags.Zero) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Jnz:
                        if ((Flags & VmFlags.Zero) == 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Je:
                        if ((Flags & VmFlags.Equal) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Jne:
                        if ((Flags & VmFlags.Equal) == 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Ja:
                        if ((Flags & VmFlags.Above) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Jae:
                        if ((Flags & VmFlags.Above) != 0 || (Flags & VmFlags.Equal) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Jb:
                        if ((Flags & VmFlags.Below) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Jbe:
                        if ((Flags & VmFlags.Below) != 0 || (Flags & VmFlags.Equal) != 0)
                            IP = _instruction.Left.Get();
                        break;
                    case Opcode.Rand:
                        _instruction.Left.Set(Random.Next(int.MinValue, int.MaxValue));
                        break;
                    case Opcode.Int:
                        var intVal = _instruction.Left.Get();
                        if (intVal < 0 || intVal >= _devices.Length || _devices[intVal] == null)
                            break;
                        _devices[intVal].HandleInterrupt(this);
                        break;
                    case Opcode.Iret:
                        InterruptReturn();
                        break;
                    case Opcode.Ivt:
                        IVT = _instruction.Left.Get();
                        break;
                    case Opcode.Abs:
                        _instruction.Left.Set(Math.Abs(_instruction.Left.Get()));
                        break;
                    case Opcode.Retn:
                        IP = Pop();
                        SP += _instruction.Left.Get();
                        break;
                    case Opcode.Xchg:
                        var xt = _instruction.Left.Get();
                        _instruction.Left.Set(_instruction.Right.Get());
                        _instruction.Right.Set(xt);
                        break;
                    case Opcode.Cmpxchg:
                        if (Registers[(int)Register.R0] == _instruction.Left.Get())
                        {
                            Flags |= VmFlags.Equal;
                            _instruction.Left.Set(_instruction.Right.Get());
                        }
                        else
                        {
                            Flags &= ~VmFlags.Equal;
                            Registers[(int)Register.R0] = _instruction.Left.Get();
                        }
                        break;
                    case Opcode.Pusha:
                        for (var i = (int)Register.R9; i >= (int)Register.R0; i--)
                        {
                            Push(Registers[i]);
                        }
                        break;
                    case Opcode.Popa:
                        for (var i = (int)Register.R0; i <= (int)Register.R9; i++)
                        {
                            Registers[i] = Pop();
                        }
                        break;
                    case Opcode.Sti:
                        _interruptsEnabled = true;
                        break;
                    case Opcode.Cli:
                        _interruptsEnabled = false;
                        break;
                    case Opcode.Neg:
                        _instruction.Left.Set(0 - _instruction.Left.Get());
                        break;
                    default:
                        throw new VirtualMachineException(_errorIp, "Bad opcode id");
                }
            }
            catch (VirtualMachineInvalidOpcode)
            {
                Exception(ExceptionCode.InvalidOpcode);
            }
            catch (IndexOutOfRangeException)
            {
                Exception(ExceptionCode.MemoryBounds);
            }
            catch (DivideByZeroException)
            {
                Exception(ExceptionCode.DivideByZero);
            }
            catch (VirtualMachineException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new VirtualMachineException(_errorIp, "Error: " + e);
            }
        }