context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading;
  
  namespace GruntXProductions.Quasar.VM
  {
      public partial class Emulator
      {
          private QuasarRam memory;
          private PeripheralController peripheralController;
          private List<Device> devices = new List<Device>();
          private Stack stack;
  
          private uint ivtRegister;
          private uint pageDirectory;
          private uint controlRegister;
          private InterruptController interruptController;
  
          private bool cpuException = false;
          private bool doubleFault = false;
  
          private long instructionsPerSecond = 100000;
  
          private uint[] userRegisters = new uint[16];
          private uint[] supervisorRegisters = new uint[16];
          private bool halted = false;
          private bool on = false;
  
          private static Opcode[] PrivillagedInstructions = new Opcode[]{Opcode.SURF, Opcode.SSRF, Opcode.SIVT,
  Opcode.SPDR, Opcode.SCTL, Opcode.LURF, Opcode.LSRF, Opcode.LIVT, Opcode.LCTL, Opcode.LPDR, Opcode.OUT,
  Opcode.OUT, Opcode.IN, Opcode.IRTN, Opcode.WAIT};
  
          private System.Timers.Timer clock;
  
          public uint InterruptVectorTable
          {
              get
              {
                  return this.ivtRegister;
              }
          }
  
          public uint PageDirectory
          {
              get
              {
                  return this.pageDirectory;
              }
          }
  
          public uint ControlRegister
          {
              get
              {
                  return this.controlRegister;
              }
          }
  
          public PeripheralController PeripheralController
          {
              get
              {
                  return this.peripheralController;
              }
          }
  
          public QuasarRam Memory
          {
              get
              {
                  return this.memory;
              }
          }
  
          public Stack Stack
          {
              get
              {
                  return this.stack;
              }
          }
  
          public InterruptController InterruptController
          {
              get
              {
                  return this.interruptController;
              }
          }
  
          public Emulator(QuasarRam memory)
          {
              Console.WriteLine(memory.Limit.ToString("x8"));
              this.memory = memory;
              this.peripheralController = new PeripheralController(this);
              this.interruptController = new InterruptController();
              this.RegisterDevice(this.interruptController);
              this.RegisterDevice(this.peripheralController);
              this.RegisterDevice(new DeviceIntervalTimer());
          }
  
          public uint GetGeneralPurposeRegister(Register reg)
          {
              if (IsSupervisor())
                  return supervisorRegisters[(int)reg];
              else
                  return userRegisters[(int)reg];
          }
  
          public uint SetGeneralPurposeRegister(Register reg, uint val)
          {
              uint prev = GetGeneralPurposeRegister(reg);
              if (IsSupervisor())
                  supervisorRegisters[(int)reg] = val;
              else
                  userRegisters[(int)reg] = val;
              return prev;
          }
  
          public bool IsSupervisor()
          {
              return (controlRegister & 0x1) == 0;
          }
  
          public void RegisterDevice(Device dev)
          {
              this.devices.Add(dev);
          }
  
          public void Emulate()
          {
              this.Reset();
              int msecond = System.DateTime.Now.Millisecond;
              clock = new System.Timers.Timer(100);
              clock.Elapsed += new System.Timers.ElapsedEventHandler(cpuTick);
              this.clock.AutoReset = true;
              clock.Start();
              while (true)
                  System.Threading.Thread.Sleep(0x1000);
          }
  
          public void Halt()
          {
              this.halted = true;
              this.clock.Enabled = false;
              this.clock.Stop();
          }
  
          public void Continue()
          {
              this.halted = false;
              this.clock.Start();
          }
  
          public void Step()
          {
              updateDevices();
              uint pc = GetGeneralPurposeRegister(Register.R15);
              Instruction ins = Instruction.Fetch(this.memory, pc);
              Console.WriteLine(ins.OperationCode);
              pc += (uint)ins.Size;
              SetGeneralPurposeRegister(Register.R15, pc);
              decodeInstruction(ins);
              Halt();
          }
  
  
          public void Power(bool on)
          {
              if (!on && this.on)
                  this.Reset();
              this.on = on;
          }
  
          private void cpuTick(object o, System.Timers.ElapsedEventArgs args)
          {
              this.clock.Enabled = false;
  
              try
              {
                  for (int i = 0; i < this.instructionsPerSecond / 100; i++)
                  {
                      updateDevices();
                      if (!halted)
                      {
                          uint pc = GetGeneralPurposeRegister(Register.R15);
                          Instruction ins = Instruction.Fetch(this.memory, pc);
                          Console.WriteLine(ins.OperationCode);
                          pc += (uint)ins.Size;
                          SetGeneralPurposeRegister(Register.R15, pc);
                          decodeInstruction(ins);
                      }
  
                  }
              }
              catch (DivideByZeroException)
              {
                  Trap(0x01);
              }
              catch (InvalidOpcodeException)
              {
                  Trap(0x02);
              }
              catch (SegmentationFaultException ex)
              {
                  Trap(0x03, ex.FaultingAddress);
              }
              catch (PageFaultException ex)
              {
                  Trap(0x04, ex.FaultingAddress);
              }
              catch (GeneralProtectionException ex)
              {
                  Trap(0x05, (uint)ex.Opcode);
              }
              catch (Exception ex)
              {
                  fatalException(ex.Message);
              }
  
              this.clock.Enabled = true;
          }
  
          private void fatalException(string format, params object[] args)
          {
              Console.Error.WriteLine("fatal exception: " + format, args);
  
              for (int i = 0; i < 16; i++)
              {
                  Console.WriteLine("r{0}:\t0x{1:X8}", i, GetGeneralPurposeRegister((Register)i));
              }
              Environment.Exit(-1);
          }
  
          public void Interrupt(byte intnum)
          {
              this.halted = false;
              uint oldCtl = controlRegister;
              controlRegister &= ~0x01u;
              stack.PushInt32(oldCtl);
  
gt:             for (int i = 0; i < 16; i++)