private void SimulationThread() { double delay_time; m_disassembler = new Z80Disassembler(); m_disassembler.ReadByte = ReadMemory; m_stopwatch = new Stopwatch(); m_instruction_start_pc = TVC.CPU.Registers.PC; m_instruction_t_cycle = 0; m_debug_event_timestamp = DateTime.Now; delay_time = 0; while (m_thread_running) { // handle execution state change switch (m_execution_state_request) { // change to pause state case ExecutionStateRequest.Pause: m_execution_state_request = ExecutionStateRequest.NoChange; m_last_execution_state = m_execution_state; m_execution_state = ExecutionState.Paused; m_execution_state_changed_event.Set(); break; case ExecutionStateRequest.Restore: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = m_last_execution_state; m_execution_state_changed_event.Set(); break; // change to running case ExecutionStateRequest.Run: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = ExecutionState.Running; m_execution_state_changed_event.Set(); break; // full speed run case ExecutionStateRequest.RunFullSpeed: m_execution_state_request = ExecutionStateRequest.NoChange; m_execution_state = ExecutionState.RunningFullSpeed; m_execution_state_changed_event.Set(); break; // resets computer case ExecutionStateRequest.Reset: m_execution_state_request = ExecutionStateRequest.NoChange; TVC.Reset(); m_execution_state_changed_event.Set(); break; // no change case ExecutionStateRequest.NoChange: // do nothing break; } // execute according the execution state switch (m_execution_state) { case ExecutionState.Running: { uint ellapsed_tick; //m_stopwatch.Restart(); ellapsed_tick = RunOneFrame(); GenerateDebugEvent(false); //m_stopwatch.Stop(); //delay_time += TVC.CPUTickToMillisec(ellapsed_tick) - m_stopwatch.Elapsed.TotalMilliseconds; m_thread_event.WaitOne(1000); /* * if (delay_time > 0) * { * int delay = (int)Math.Truncate(delay_time); * * m_stopwatch.Restart(); * m_thread_event.WaitOne(delay); * m_stopwatch.Stop(); * delay_time -= m_stopwatch.Elapsed.TotalMilliseconds; * } * else * { * // execution is behind the schedule -> no delay * m_thread_event.WaitOne(0); * * delay_time = 0; * } */ } break; case ExecutionState.RunningFullSpeed: RunOneFrame(); GenerateDebugEvent(false); m_thread_event.WaitOne(0); break; case ExecutionState.Paused: m_thread_event.WaitOne(1000); break; } } }
/// <summary> /// Runs simulation for one video frame /// </summary> private uint RunOneFrame() { uint current_instruction_t_cycle; uint frame_start_cycle = m_cpu_t_cycle; bool breakpoint_exit = false; bool frame_finished = false; while (m_thread_running && !breakpoint_exit && !frame_finished) { m_target_cycle += 200; //TODO: calculate from video timing TVC.Memory.VideoMemAccessCount = 0; frame_finished = TVC.Video.RenderScanline(); do { current_instruction_t_cycle = TVC.CPU.Step(); m_cpu_t_cycle += current_instruction_t_cycle; m_instruction_t_cycle += current_instruction_t_cycle; if (TVC.CPU.InstructionDone) { AddInstructionToExecutionHistory(m_instruction_start_pc, m_instruction_t_cycle); m_instruction_start_pc = TVC.CPU.Registers.PC; m_instruction_t_cycle = 0; if (TVC.CPU.Registers.PC == BreakpointAddress) { breakpoint_exit = true; m_execution_state = ExecutionState.Paused; } // do sound interrupt handling TVC.Sound.PeriodicCallback(); } // handle pending interrupts if (TVC.Interrupt.IsIntActive()) { m_cpu_t_cycle += (uint)TVC.CPU.Int(); } // do sound interrupt handling if (TVC.Sound != null) { TVC.Sound.PeriodicCallback(); } // handle clock stretching (video memory access) if (TVC.Memory.VideoMemAccessCount > 0) { m_cpu_t_cycle += (uint)(TVC.Memory.VideoMemAccessCount + 1); TVC.Memory.VideoMemAccessCount = 0; } } while (((long)m_target_cycle - m_cpu_t_cycle) > 0 && m_thread_running && !breakpoint_exit); TVC.PeriodicCallback(); TVC.Keyboard.Update(); TVC.Sound.PeriodicCallback(); } if (breakpoint_exit) { GenerateDebugEvent(true); } // return frame total cycle return(m_cpu_t_cycle - frame_start_cycle); }
public void Initialize() { TVC.Initialize(); DebuggerBreakEvent?.Invoke(TVC); }