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()); }
private void SetZero(int value) { Flags &= ~VmFlags.Zero; if (value == 0) Flags |= VmFlags.Zero; }
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; }
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); } }