/// <summary> /// Method used to Run the Emulator Task /// /// Task will run until the _powerOn value is set to false /// </summary> private void Run() { //Frame Timing Stopwatch var sw = Stopwatch.StartNew(); //CPU startup state is always at 4 cycles _cpu.Cycles = 4; int cpuTicks; while (_powerOn) { //If we're not idling (DMA), tick the CPU if (_cpuIdleCycles == 0) { cpuTicks = _cpu.Tick(); } else { //Otherwise, mark it as an idle cycle and carry on _cpuIdleCycles--; _cpu.Instruction.Cycles = 1; _cpu.Cycles++; cpuTicks = 1; } //Count how many cycles that instruction took and //execute that number of instruction * 3 for the PPU //We do ceiling since it's ok for the PPU to overshoot at this point for (var i = 0; i < cpuTicks * 3; i++) { _ppu.Tick(); } //If the PPU has signaled NMI, reset its status and signal the CPU if (_ppu.NMI) { _ppu.NMI = false; _cpu.NMI = true; } //Check to see if there's a frame in the PPU Frame Buffer //If there is, let's render it if (_ppu.FrameReady) { _processFrame(_ppu.FrameBuffer); _ppu.FrameReady = false; //Throttle our frame rate here to the desired rate (if required) switch (_enumEmulatorSpeed) { case enumEmulatorSpeed.Turbo: continue; case enumEmulatorSpeed.Normal when sw.ElapsedMilliseconds < 17: Thread.Sleep((int)(17 - sw.ElapsedMilliseconds)); break; case enumEmulatorSpeed.Half when sw.ElapsedMilliseconds < 32: Thread.Sleep((int)(32 - sw.ElapsedMilliseconds)); break; } sw.Restart(); } } }