#pragma once #include "pch.h" #include "Core/Debugger/DebugTypes.h" #include "Core/Debugger/Debugger.h" #include "Core/Debugger/DebugUtilities.h" #include "Core/Shared/EmulatorLock.h" #include "Core/Shared/Interfaces/IConsole.h" #include "Core/Shared/Audio/AudioPlayerTypes.h" #include "Utilities/Timer.h" #include "Utilities/safe_ptr.h" #include "Utilities/SimpleLock.h" #include "Utilities/VirtualFile.h" class Debugger; class DebugHud; class SoundMixer; class VideoRenderer; class VideoDecoder; class NotificationManager; class EmuSettings; class SaveStateManager; class RewindManager; class BatteryManager; class CheatManager; class MovieManager; class HistoryViewer; class FrameLimiter; class DebugStats; class BaseControlManager; class VirtualFile; class BaseVideoFilter; class ShortcutKeyHandler; class SystemActionManager; class AudioPlayerHud; class GameServer; class GameClient; class IInputRecorder; class IInputProvider; struct RomInfo; struct TimingInfo; enum class MemoryOperationType; enum class MemoryType; enum class EventType; enum class ConsoleRegion; enum class ConsoleType; enum class HashType; enum class TapeRecorderAction; struct ConsoleMemoryInfo { void* Memory; uint32_t Size; }; class Emulator { private: friend class DebuggerRequest; friend class EmulatorLock; unique_ptr _emuThread; unique_ptr _audioPlayerHud; safe_ptr _console; shared_ptr _shortcutKeyHandler; safe_ptr _debugger; shared_ptr _systemActionManager; const unique_ptr _settings; const unique_ptr _debugHud; const unique_ptr _scriptHud; const unique_ptr _notificationManager; const unique_ptr _batteryManager; const unique_ptr _soundMixer; const unique_ptr _videoRenderer; const unique_ptr _videoDecoder; const unique_ptr _saveStateManager; const unique_ptr _cheatManager; const unique_ptr _movieManager; const unique_ptr _historyViewer; const shared_ptr _gameServer; const shared_ptr _gameClient; const shared_ptr _rewindManager; thread::id _emulationThreadId; atomic _lockCounter; SimpleLock _runLock; SimpleLock _loadLock; SimpleLock _debuggerLock; atomic _stopFlag; atomic _paused; atomic _pauseOnNextFrame; atomic _threadPaused; atomic _debugRequestCount; atomic _blockDebuggerRequestCount; atomic _isRunAheadFrame; bool _frameRunning = false; RomInfo _rom; ConsoleType _consoleType = {}; ConsoleMemoryInfo _consoleMemory[DebugUtilities::GetMemoryTypeCount()] = {}; unique_ptr _stats; unique_ptr _frameLimiter; Timer _lastFrameTimer; double _frameDelay = 0; uint32_t _autoSaveStateFrameCounter = 0; int32_t _stopCode = 0; void WaitForLock(); void WaitForPauseEnd(); void ProcessAutoSaveState(); bool ProcessSystemActions(); void RunFrameWithRunAhead(); void BlockDebuggerRequests(); void ResetDebugger(bool startDebugger = false); double GetFrameDelay(); void TryLoadRom(VirtualFile& romFile, LoadRomResult& result, unique_ptr& console, bool useFileSignature); template void TryLoadRom(VirtualFile& romFile, LoadRomResult& result, unique_ptr& console, bool useFileSignature); void InitConsole(unique_ptr& newConsole, ConsoleMemoryInfo originalConsoleMemory[], bool preserveRom); bool InternalLoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom = true, bool forPowerCycle = false); public: Emulator(); ~Emulator(); void Initialize(bool enableShortcuts = true); void Release(); void Run(); void Stop(bool sendNotification, bool preventRecentGameSave = false, bool saveBattery = true); void OnBeforeSendFrame(); void ProcessEndOfFrame(); void Reset(); void ReloadRom(bool forPowerCycle); void PowerCycle(); void PauseOnNextFrame(); void Pause(); void Resume(); bool IsPaused(); bool LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom = true, bool forPowerCycle = false); RomInfo& GetRomInfo() { return _rom; } string GetHash(HashType type); uint32_t GetCrc32(); PpuFrameInfo GetPpuFrame(); ConsoleRegion GetRegion(); shared_ptr GetConsole(); IConsole* GetConsoleUnsafe(); ConsoleType GetConsoleType(); vector GetCpuTypes(); uint64_t GetMasterClock(); uint32_t GetMasterClockRate(); EmulatorLock AcquireLock(bool allowDebuggerLock = true); void Lock(); void Unlock(); bool IsThreadPaused(); void SuspendDebugger(bool release); void Serialize(ostream& out, bool includeSettings, int compressionLevel = 1); bool Deserialize(istream& in, uint32_t fileFormatVersion, bool includeSettings, optional consoleType = std::nullopt); SoundMixer* GetSoundMixer() { return _soundMixer.get(); } VideoRenderer* GetVideoRenderer() { return _videoRenderer.get(); } VideoDecoder* GetVideoDecoder() { return _videoDecoder.get(); } ShortcutKeyHandler* GetShortcutKeyHandler() { return _shortcutKeyHandler.get(); } NotificationManager* GetNotificationManager() { return _notificationManager.get(); } EmuSettings* GetSettings() { return _settings.get(); } SaveStateManager* GetSaveStateManager() { return _saveStateManager.get(); } RewindManager* GetRewindManager() { return _rewindManager.get(); } DebugHud* GetDebugHud() { return _debugHud.get(); } DebugHud* GetScriptHud() { return _scriptHud.get(); } BatteryManager* GetBatteryManager() { return _batteryManager.get(); } CheatManager* GetCheatManager() { return _cheatManager.get(); } MovieManager* GetMovieManager() { return _movieManager.get(); } HistoryViewer* GetHistoryViewer() { return _historyViewer.get(); } GameServer* GetGameServer() { return _gameServer.get(); } GameClient* GetGameClient() { return _gameClient.get(); } shared_ptr GetSystemActionManager() { return _systemActionManager; } BaseVideoFilter* GetVideoFilter(); void InputBarcode(uint64_t barcode, uint32_t digitCount); void ProcessTapeRecorderAction(TapeRecorderAction action, string filename); ShortcutState IsShortcutAllowed(EmulatorShortcut shortcut, uint32_t shortcutParam); bool IsKeyboardConnected(); void InitDebugger(); void StopDebugger(); DebuggerRequest GetDebugger(bool autoInit = false); bool IsDebugging() { return !!_debugger; } Debugger* InternalGetDebugger() { return _debugger.get(); } thread::id GetEmulationThreadId() { return _emulationThreadId; } bool IsEmulationThread(); int32_t GetStopCode() { return _stopCode; } void SetStopCode(int32_t stopCode); void RegisterMemory(MemoryType type, void* memory, uint32_t size); ConsoleMemoryInfo GetMemory(MemoryType type); AudioTrackInfo GetAudioTrackInfo(); void ProcessAudioPlayerAction(AudioPlayerActionParams p); AudioPlayerHud* GetAudioPlayerHud() { return _audioPlayerHud.get(); } bool IsRunning() { return _console != nullptr; } bool IsRunAheadFrame() { return _isRunAheadFrame; } TimingInfo GetTimingInfo(CpuType cpuType); uint32_t GetFrameCount(); uint32_t GetLagCounter(); void ResetLagCounter(); bool HasControlDevice(ControllerType type); void RegisterInputRecorder(IInputRecorder* recorder); void UnregisterInputRecorder(IInputRecorder* recorder); void RegisterInputProvider(IInputProvider* provider); void UnregisterInputProvider(IInputProvider* provider); double GetFps(); template __forceinline void ProcessInstruction() { if(_debugger) { _debugger->ProcessInstruction(); } } template __forceinline void ProcessMemoryRead(uint32_t addr, T& value, MemoryOperationType opType) { if(_debugger) { _debugger->ProcessMemoryRead(addr, value, opType); } } template __forceinline bool ProcessMemoryWrite(uint32_t addr, T& value, MemoryOperationType opType) { if(_debugger) { return _debugger->ProcessMemoryWrite(addr, value, opType); } return true; } template __forceinline void ProcessIdleCycle() { if(_debugger) { _debugger->ProcessIdleCycle(); } } template __forceinline void ProcessHaltedCpu() { if(_debugger) { _debugger->ProcessHaltedCpu(); } } template __forceinline void ProcessPpuRead(uint32_t addr, T& value, MemoryType memoryType, MemoryOperationType opType = MemoryOperationType::Read) { if(_debugger) { _debugger->ProcessPpuRead(addr, value, memoryType, opType); } } template __forceinline void ProcessPpuWrite(uint32_t addr, T& value, MemoryType memoryType) { if(_debugger) { _debugger->ProcessPpuWrite(addr, value, memoryType); } } template __forceinline void ProcessPpuCycle() { if(_debugger) { _debugger->ProcessPpuCycle(); } } __forceinline void DebugLog(string log) { if(_debugger) { _debugger->Log(log); } } template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type, std::optional cpuType = std::nullopt); template void AddDebugEvent(DebugEventType evtType); void BreakIfDebugging(CpuType sourceCpu, BreakSource source); }; enum class HashType { Sha1, Sha1Cheat };