2019-02-12 22:13:09 -05:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Console.h"
|
|
|
|
#include "Cpu.h"
|
2019-02-16 11:23:01 -05:00
|
|
|
#include "Ppu.h"
|
|
|
|
#include "Spc.h"
|
2019-07-14 21:45:12 -04:00
|
|
|
#include "NecDsp.h"
|
2019-02-17 15:37:31 -05:00
|
|
|
#include "InternalRegisters.h"
|
2019-02-17 19:54:29 -05:00
|
|
|
#include "ControlManager.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "MemoryManager.h"
|
2019-02-19 21:09:12 -05:00
|
|
|
#include "DmaController.h"
|
2019-02-26 22:27:09 -05:00
|
|
|
#include "BaseCartridge.h"
|
|
|
|
#include "RamHandler.h"
|
2020-05-25 19:43:57 -04:00
|
|
|
#include "Gameboy.h"
|
|
|
|
#include "GbPpu.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "Debugger.h"
|
2019-03-01 20:27:49 -05:00
|
|
|
#include "DebugTypes.h"
|
2019-02-15 21:33:13 -05:00
|
|
|
#include "NotificationManager.h"
|
2019-02-16 11:23:01 -05:00
|
|
|
#include "SoundMixer.h"
|
2019-02-13 23:02:43 -05:00
|
|
|
#include "VideoDecoder.h"
|
|
|
|
#include "VideoRenderer.h"
|
|
|
|
#include "DebugHud.h"
|
2019-02-21 17:18:56 -05:00
|
|
|
#include "FrameLimiter.h"
|
2019-02-17 14:42:35 -05:00
|
|
|
#include "MessageManager.h"
|
2019-02-24 12:54:14 -05:00
|
|
|
#include "KeyManager.h"
|
2019-03-07 20:12:32 -05:00
|
|
|
#include "EventType.h"
|
2019-03-10 11:12:50 -04:00
|
|
|
#include "EmuSettings.h"
|
2019-03-12 09:15:57 -04:00
|
|
|
#include "SaveStateManager.h"
|
2019-03-10 17:39:14 -04:00
|
|
|
#include "DebugStats.h"
|
2019-03-12 09:15:57 -04:00
|
|
|
#include "CartTypes.h"
|
2019-03-12 12:06:42 -04:00
|
|
|
#include "RewindManager.h"
|
2019-03-12 09:15:57 -04:00
|
|
|
#include "ConsoleLock.h"
|
2019-08-09 16:25:59 -04:00
|
|
|
#include "MovieManager.h"
|
|
|
|
#include "BatteryManager.h"
|
2019-10-12 22:40:25 -04:00
|
|
|
#include "CheatManager.h"
|
2019-10-16 20:22:45 -04:00
|
|
|
#include "MovieManager.h"
|
2019-10-30 20:42:19 -04:00
|
|
|
#include "SystemActionManager.h"
|
2019-10-19 15:23:17 -04:00
|
|
|
#include "SpcHud.h"
|
2019-11-01 21:15:11 -04:00
|
|
|
#include "Msu1.h"
|
2019-03-12 09:15:57 -04:00
|
|
|
#include "../Utilities/Serializer.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
#include "../Utilities/Timer.h"
|
|
|
|
#include "../Utilities/VirtualFile.h"
|
2019-02-21 17:18:56 -05:00
|
|
|
#include "../Utilities/PlatformUtilities.h"
|
2019-02-24 23:53:14 -05:00
|
|
|
#include "../Utilities/FolderUtilities.h"
|
2019-02-12 22:13:09 -05:00
|
|
|
|
2019-07-16 19:08:16 -04:00
|
|
|
Console::Console()
|
|
|
|
{
|
2019-10-20 20:05:39 -04:00
|
|
|
_settings.reset(new EmuSettings(this));
|
2019-07-17 20:31:29 -04:00
|
|
|
|
2019-07-16 21:02:56 -04:00
|
|
|
_paused = false;
|
|
|
|
_pauseOnNextFrame = false;
|
|
|
|
_stopFlag = false;
|
2020-03-27 19:58:00 -04:00
|
|
|
_isRunAheadFrame = false;
|
2019-07-16 21:02:56 -04:00
|
|
|
_lockCounter = 0;
|
2020-05-14 19:34:14 -04:00
|
|
|
_threadPaused = false;
|
2019-07-16 19:08:16 -04:00
|
|
|
}
|
|
|
|
|
2019-02-26 22:27:09 -05:00
|
|
|
Console::~Console()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-13 23:02:43 -05:00
|
|
|
void Console::Initialize()
|
|
|
|
{
|
2019-03-12 09:15:57 -04:00
|
|
|
_lockCounter = 0;
|
|
|
|
|
2019-02-15 21:33:13 -05:00
|
|
|
_notificationManager.reset(new NotificationManager());
|
2019-08-09 16:25:59 -04:00
|
|
|
_batteryManager.reset(new BatteryManager());
|
2019-02-13 23:02:43 -05:00
|
|
|
_videoDecoder.reset(new VideoDecoder(shared_from_this()));
|
|
|
|
_videoRenderer.reset(new VideoRenderer(shared_from_this()));
|
2019-03-12 09:15:57 -04:00
|
|
|
_saveStateManager.reset(new SaveStateManager(shared_from_this()));
|
2019-03-10 17:39:14 -04:00
|
|
|
_soundMixer.reset(new SoundMixer(this));
|
2019-02-13 23:02:43 -05:00
|
|
|
_debugHud.reset(new DebugHud());
|
2019-10-12 22:40:25 -04:00
|
|
|
_cheatManager.reset(new CheatManager(this));
|
2019-10-16 20:22:45 -04:00
|
|
|
_movieManager.reset(new MovieManager(shared_from_this()));
|
2019-02-13 23:02:43 -05:00
|
|
|
|
|
|
|
_videoDecoder->StartThread();
|
|
|
|
_videoRenderer->StartThread();
|
|
|
|
}
|
|
|
|
|
2019-02-16 01:22:31 -05:00
|
|
|
void Console::Release()
|
|
|
|
{
|
2019-03-14 18:07:25 -04:00
|
|
|
Stop(true);
|
2019-02-16 01:22:31 -05:00
|
|
|
|
|
|
|
_videoDecoder->StopThread();
|
|
|
|
_videoRenderer->StopThread();
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2019-02-16 01:22:31 -05:00
|
|
|
_videoDecoder.reset();
|
|
|
|
_videoRenderer.reset();
|
|
|
|
_debugHud.reset();
|
|
|
|
_notificationManager.reset();
|
2019-03-12 09:15:57 -04:00
|
|
|
_saveStateManager.reset();
|
|
|
|
_soundMixer.reset();
|
|
|
|
_settings.reset();
|
2019-10-16 20:22:45 -04:00
|
|
|
_cheatManager.reset();
|
|
|
|
_movieManager.reset();
|
2019-02-16 01:22:31 -05:00
|
|
|
}
|
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
void Console::RunFrame()
|
|
|
|
{
|
2020-05-18 16:10:53 -04:00
|
|
|
_frameRunning = true;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
|
2020-05-18 16:10:53 -04:00
|
|
|
Gameboy* gameboy = _cart->GetGameboy();
|
2021-03-10 11:13:28 -05:00
|
|
|
while(_frameRunning) {
|
2020-05-18 16:10:53 -04:00
|
|
|
gameboy->Exec();
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
|
|
|
while(_frameRunning) {
|
2020-05-18 16:10:53 -04:00
|
|
|
_cpu->Exec();
|
|
|
|
}
|
2019-12-26 12:03:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
void Console::Run()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!_cpu) {
|
2019-02-12 22:13:09 -05:00
|
|
|
return;
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2019-07-13 13:43:56 -04:00
|
|
|
auto emulationLock = _emulationLock.AcquireSafe();
|
2019-10-22 19:53:18 -04:00
|
|
|
auto lock = _runLock.AcquireSafe();
|
2019-02-12 22:13:09 -05:00
|
|
|
|
|
|
|
_stopFlag = false;
|
2019-12-26 12:03:38 -05:00
|
|
|
_isRunAheadFrame = false;
|
2019-02-21 17:18:56 -05:00
|
|
|
|
|
|
|
PlatformUtilities::EnableHighResolutionTimer();
|
2019-02-12 22:13:09 -05:00
|
|
|
|
2019-03-08 17:08:28 -05:00
|
|
|
_videoDecoder->StartThread();
|
2019-03-07 20:12:32 -05:00
|
|
|
_emulationThreadId = std::this_thread::get_id();
|
|
|
|
|
2019-07-12 23:55:18 -04:00
|
|
|
_memoryManager->IncMasterClockStartup();
|
2019-10-16 20:22:45 -04:00
|
|
|
_controlManager->UpdateInputState();
|
2019-05-04 09:25:10 -04:00
|
|
|
|
2019-10-30 20:42:19 -04:00
|
|
|
_frameDelay = GetFrameDelay();
|
|
|
|
_stats.reset(new DebugStats());
|
|
|
|
_frameLimiter.reset(new FrameLimiter(_frameDelay));
|
|
|
|
_lastFrameTimer.Reset();
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
while(!_stopFlag) {
|
|
|
|
bool useRunAhead = _settings->GetEmulationConfig().RunAheadFrames > 0 && !_debugger && !_rewindManager->IsRewinding() && _settings->GetEmulationSpeed() > 0 && _settings->GetEmulationSpeed() <= 100;
|
|
|
|
if(useRunAhead) {
|
2019-12-26 12:03:38 -05:00
|
|
|
RunFrameWithRunAhead();
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-12-26 12:03:38 -05:00
|
|
|
RunFrame();
|
2020-10-07 23:10:29 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if (_historyViewer) {
|
2020-10-07 23:10:29 -04:00
|
|
|
_historyViewer->ProcessEndOfFrame();
|
|
|
|
}
|
2019-03-12 12:06:42 -04:00
|
|
|
_rewindManager->ProcessEndOfFrame();
|
2019-12-26 12:03:38 -05:00
|
|
|
ProcessSystemActions();
|
|
|
|
}
|
2019-03-12 12:06:42 -04:00
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
WaitForLock();
|
2019-03-12 13:13:32 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_pauseOnNextFrame) {
|
2019-12-26 12:03:38 -05:00
|
|
|
_pauseOnNextFrame = false;
|
|
|
|
_paused = true;
|
2019-02-21 17:18:56 -05:00
|
|
|
}
|
2019-12-26 12:03:38 -05:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_paused && !_stopFlag && !_debugger) {
|
2019-12-26 12:03:38 -05:00
|
|
|
WaitForPauseEnd();
|
2021-03-10 11:13:28 -05:00
|
|
|
}
|
2020-05-14 19:34:14 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_memoryManager->GetMasterClock() == 0) {
|
2020-05-14 19:34:14 -04:00
|
|
|
//After a reset or power cycle, run the PPU/etc ahead of the CPU (simulates delay CPU takes to get out of reset)
|
|
|
|
_memoryManager->IncMasterClockStartup();
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
2019-02-21 17:18:56 -05:00
|
|
|
|
2019-10-16 20:22:45 -04:00
|
|
|
_movieManager->Stop();
|
2019-08-09 16:25:59 -04:00
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
_emulationThreadId = thread::id();
|
|
|
|
|
2019-02-21 17:18:56 -05:00
|
|
|
PlatformUtilities::RestoreTimerResolution();
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
bool Console::ProcessSystemActions()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_controlManager->GetSystemActionManager()->IsResetPressed()) {
|
2019-12-26 12:03:38 -05:00
|
|
|
Reset();
|
|
|
|
return true;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else if(_controlManager->GetSystemActionManager()->IsPowerCyclePressed()) {
|
2019-12-26 12:03:38 -05:00
|
|
|
PowerCycle();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::RunFrameWithRunAhead()
|
|
|
|
{
|
|
|
|
stringstream runAheadState;
|
|
|
|
uint32_t frameCount = _settings->GetEmulationConfig().RunAheadFrames;
|
|
|
|
|
|
|
|
//Run a single frame and save the state (no audio/video)
|
|
|
|
_isRunAheadFrame = true;
|
|
|
|
RunFrame();
|
|
|
|
Serialize(runAheadState, 0);
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
while(frameCount > 1) {
|
2019-12-26 12:03:38 -05:00
|
|
|
//Run extra frames if the requested run ahead frame count is higher than 1
|
|
|
|
frameCount--;
|
|
|
|
RunFrame();
|
|
|
|
}
|
|
|
|
_isRunAheadFrame = false;
|
|
|
|
|
|
|
|
//Run one frame normally (with audio/video output)
|
|
|
|
RunFrame();
|
|
|
|
_rewindManager->ProcessEndOfFrame();
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
bool wasReset = ProcessSystemActions();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!wasReset) {
|
2019-12-26 12:03:38 -05:00
|
|
|
//Load the state we saved earlier
|
|
|
|
_isRunAheadFrame = true;
|
|
|
|
Deserialize(runAheadState, SaveStateManager::FileFormatVersion, false);
|
|
|
|
_isRunAheadFrame = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-30 20:42:19 -04:00
|
|
|
void Console::ProcessEndOfFrame()
|
|
|
|
{
|
|
|
|
#ifndef LIBRETRO
|
|
|
|
_cart->RunCoprocessors();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart->GetCoprocessor()) {
|
2019-10-30 20:42:19 -04:00
|
|
|
_cart->GetCoprocessor()->ProcessEndOfFrame();
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!_isRunAheadFrame) {
|
2019-12-26 12:03:38 -05:00
|
|
|
_frameLimiter->ProcessFrame();
|
2021-03-10 11:13:28 -05:00
|
|
|
while(_frameLimiter->WaitForNextFrame()) {
|
|
|
|
if(_stopFlag || _frameDelay != GetFrameDelay() || _paused || _pauseOnNextFrame || _lockCounter > 0) {
|
2019-12-26 12:03:38 -05:00
|
|
|
//Need to process another event, stop sleeping
|
|
|
|
break;
|
|
|
|
}
|
2019-11-13 20:52:26 -05:00
|
|
|
}
|
2019-10-30 20:42:19 -04:00
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
double newFrameDelay = GetFrameDelay();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(newFrameDelay != _frameDelay) {
|
2019-12-26 12:03:38 -05:00
|
|
|
_frameDelay = newFrameDelay;
|
|
|
|
_frameLimiter->SetDelay(_frameDelay);
|
|
|
|
}
|
2019-10-30 20:42:19 -04:00
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
PreferencesConfig cfg = _settings->GetPreferences();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(cfg.ShowDebugInfo) {
|
2019-12-26 12:03:38 -05:00
|
|
|
double lastFrameTime = _lastFrameTimer.GetElapsedMS();
|
|
|
|
_lastFrameTimer.Reset();
|
|
|
|
_stats->DisplayStats(this, lastFrameTime);
|
|
|
|
}
|
2019-10-30 20:42:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_controlManager->UpdateInputState();
|
|
|
|
_controlManager->UpdateControlDevices();
|
|
|
|
_internalRegisters->ProcessAutoJoypadRead();
|
|
|
|
#endif
|
2020-05-18 16:10:53 -04:00
|
|
|
_frameRunning = false;
|
2019-10-30 20:42:19 -04:00
|
|
|
}
|
|
|
|
|
2019-07-02 19:56:00 -04:00
|
|
|
void Console::RunSingleFrame()
|
|
|
|
{
|
|
|
|
//Used by Libretro
|
|
|
|
_emulationThreadId = std::this_thread::get_id();
|
2020-03-27 19:58:00 -04:00
|
|
|
_isRunAheadFrame = false;
|
2019-07-02 19:56:00 -04:00
|
|
|
|
2019-07-07 19:55:08 -04:00
|
|
|
_controlManager->UpdateInputState();
|
|
|
|
_internalRegisters->ProcessAutoJoypadRead();
|
|
|
|
|
2020-05-18 16:10:53 -04:00
|
|
|
RunFrame();
|
2019-07-02 19:56:00 -04:00
|
|
|
|
2019-07-30 22:34:52 -04:00
|
|
|
_cart->RunCoprocessors();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart->GetCoprocessor()) {
|
2019-07-30 22:34:52 -04:00
|
|
|
_cart->GetCoprocessor()->ProcessEndOfFrame();
|
|
|
|
}
|
|
|
|
|
2019-07-02 19:56:00 -04:00
|
|
|
_controlManager->UpdateControlDevices();
|
|
|
|
}
|
|
|
|
|
2019-03-14 18:07:25 -04:00
|
|
|
void Console::Stop(bool sendNotification)
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
|
|
|
_stopFlag = true;
|
2019-02-16 08:10:08 -05:00
|
|
|
|
2019-10-22 18:47:49 -04:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::BeforeGameUnload);
|
|
|
|
|
2019-02-16 08:10:08 -05:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-07-25 22:22:09 -04:00
|
|
|
debugger->SuspendDebugger(false);
|
2019-02-16 08:10:08 -05:00
|
|
|
debugger->Run();
|
|
|
|
}
|
|
|
|
|
2019-07-13 13:43:56 -04:00
|
|
|
_emulationLock.WaitForRelease();
|
2019-02-12 22:13:09 -05:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_emuThread) {
|
2019-10-22 19:53:18 -04:00
|
|
|
_emuThread->join();
|
|
|
|
_emuThread.release();
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart && !_settings->GetPreferences().DisableGameSelectionScreen) {
|
2019-05-04 16:54:53 -04:00
|
|
|
RomInfo romInfo = _cart->GetRomInfo();
|
|
|
|
_saveStateManager->SaveRecentGame(romInfo.RomFile.GetFileName(), romInfo.RomFile, romInfo.PatchFile);
|
2019-03-14 18:07:25 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(sendNotification) {
|
2019-03-30 22:41:37 -04:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop);
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:50:58 -04:00
|
|
|
_consoleType = ConsoleType::Snes;
|
2020-05-25 19:43:57 -04:00
|
|
|
_settings->ClearFlag(EmulationFlags::GameboyMode);
|
|
|
|
|
2019-02-26 22:27:09 -05:00
|
|
|
//Make sure we release both pointers to destroy the debugger before everything else
|
|
|
|
_debugger.reset();
|
|
|
|
debugger.reset();
|
|
|
|
|
2019-03-08 17:08:28 -05:00
|
|
|
_videoDecoder->StopThread();
|
2019-03-12 12:06:42 -04:00
|
|
|
_rewindManager.reset();
|
2019-03-08 17:08:28 -05:00
|
|
|
|
2019-02-12 22:13:09 -05:00
|
|
|
_cpu.reset();
|
2019-02-13 13:32:21 -05:00
|
|
|
_ppu.reset();
|
2019-02-16 11:23:01 -05:00
|
|
|
_spc.reset();
|
2019-02-16 01:16:57 -05:00
|
|
|
_cart.reset();
|
2019-02-17 15:37:31 -05:00
|
|
|
_internalRegisters.reset();
|
2019-02-17 19:54:29 -05:00
|
|
|
_controlManager.reset();
|
2019-02-12 22:13:09 -05:00
|
|
|
_memoryManager.reset();
|
2019-02-19 21:09:12 -05:00
|
|
|
_dmaController.reset();
|
2019-11-01 21:15:11 -04:00
|
|
|
_msu1.reset();
|
2019-02-24 12:54:14 -05:00
|
|
|
|
2019-10-19 15:23:17 -04:00
|
|
|
_soundMixer->StopAudio(true);
|
2019-03-14 18:07:25 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(sendNotification) {
|
2019-03-14 18:07:25 -04:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped);
|
|
|
|
}
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-03-16 12:20:18 -04:00
|
|
|
void Console::Reset()
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
2019-03-16 12:20:18 -04:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
|
2020-02-22 20:54:07 -05:00
|
|
|
_lockCounter++;
|
|
|
|
_runLock.Acquire();
|
2019-03-30 21:47:30 -04:00
|
|
|
|
2019-03-16 12:20:18 -04:00
|
|
|
_dmaController->Reset();
|
|
|
|
_internalRegisters->Reset();
|
|
|
|
_memoryManager->Reset();
|
|
|
|
_spc->Reset();
|
|
|
|
_ppu->Reset();
|
2019-07-30 22:34:52 -04:00
|
|
|
_cart->Reset();
|
2019-03-16 12:20:18 -04:00
|
|
|
//_controlManager->Reset();
|
|
|
|
|
2020-02-22 11:14:55 -05:00
|
|
|
//Reset cart before CPU to ensure correct memory mappings when fetching reset vector
|
|
|
|
_cpu->Reset();
|
|
|
|
|
2019-04-30 21:05:53 -04:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::GameReset);
|
2019-05-04 09:25:10 -04:00
|
|
|
ProcessEvent(EventType::Reset);
|
2019-04-30 21:05:53 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart->GetSpcData()) {
|
2019-10-19 15:23:17 -04:00
|
|
|
_spc->LoadSpcFile(_cart->GetSpcData());
|
|
|
|
_spcHud.reset(new SpcHud(this, _cart->GetSpcData()));
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-10-19 15:23:17 -04:00
|
|
|
_spcHud.reset();
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2020-02-22 20:54:07 -05:00
|
|
|
//Debugger was suspended in SystemActionManager::Reset(), resume debugger here
|
2019-07-16 22:38:39 -04:00
|
|
|
debugger->SuspendDebugger(true);
|
|
|
|
}
|
2020-02-22 20:54:07 -05:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
_runLock.Release();
|
2020-02-22 20:54:07 -05:00
|
|
|
_lockCounter--;
|
2019-03-16 12:20:18 -04:00
|
|
|
}
|
|
|
|
|
2020-02-22 20:54:07 -05:00
|
|
|
void Console::ReloadRom(bool forPowerCycle)
|
2019-03-16 12:20:18 -04:00
|
|
|
{
|
|
|
|
shared_ptr<BaseCartridge> cart = _cart;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(cart) {
|
2019-03-30 21:47:30 -04:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-03-30 21:47:30 -04:00
|
|
|
debugger->Run();
|
|
|
|
}
|
|
|
|
|
2019-03-16 12:20:18 -04:00
|
|
|
RomInfo info = cart->GetRomInfo();
|
|
|
|
Lock();
|
2020-02-22 20:54:07 -05:00
|
|
|
LoadRom(info.RomFile, info.PatchFile, false, forPowerCycle);
|
2019-03-16 12:20:18 -04:00
|
|
|
Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 20:54:07 -05:00
|
|
|
void Console::PowerCycle()
|
|
|
|
{
|
|
|
|
ReloadRom(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, bool forPowerCycle)
|
2019-03-16 12:20:18 -04:00
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart) {
|
2019-03-16 12:20:18 -04:00
|
|
|
//Make sure the battery is saved to disk before we load another game (or reload the same game)
|
|
|
|
_cart->SaveBattery();
|
|
|
|
}
|
|
|
|
|
2019-12-12 22:14:55 -05:00
|
|
|
bool result = false;
|
2021-03-10 11:13:28 -05:00
|
|
|
EmulationConfig orgConfig = _settings->GetEmulationConfig(); //backup emulation config (can be temporarily overriden to control the power on RAM state)
|
2020-02-22 20:54:07 -05:00
|
|
|
shared_ptr<BaseCartridge> cart = forPowerCycle ? _cart : BaseCartridge::CreateCartridge(this, romFile, patchFile);
|
2021-03-10 11:13:28 -05:00
|
|
|
if(cart) {
|
2020-06-23 18:34:03 -04:00
|
|
|
bool debuggerActive = _debugger != nullptr;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(stopRom) {
|
2019-12-26 13:57:05 -05:00
|
|
|
KeyManager::UpdateDevices();
|
2019-03-16 12:20:18 -04:00
|
|
|
Stop(false);
|
|
|
|
}
|
2019-10-22 19:53:18 -04:00
|
|
|
|
|
|
|
_cheatManager->ClearCheats(false);
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2019-03-22 21:12:58 -04:00
|
|
|
_cart = cart;
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2020-03-01 17:48:22 -05:00
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_debugger) {
|
2020-03-01 17:48:22 -05:00
|
|
|
//Reset debugger if it was running before
|
|
|
|
_debugger->Release();
|
|
|
|
_debugger.reset();
|
|
|
|
}
|
|
|
|
|
2019-08-09 16:25:59 -04:00
|
|
|
_batteryManager->Initialize(FolderUtilities::GetFilename(romFile.GetFileName(), false));
|
|
|
|
|
2019-03-22 21:12:58 -04:00
|
|
|
UpdateRegion();
|
2019-02-24 12:54:14 -05:00
|
|
|
|
2019-08-09 11:45:20 -04:00
|
|
|
_internalRegisters.reset(new InternalRegisters());
|
2019-04-10 20:45:59 -04:00
|
|
|
_memoryManager.reset(new MemoryManager());
|
2019-07-12 23:34:19 -04:00
|
|
|
_ppu.reset(new Ppu(this));
|
|
|
|
_controlManager.reset(new ControlManager(this));
|
2019-02-24 19:57:34 -05:00
|
|
|
_dmaController.reset(new DmaController(_memoryManager.get()));
|
2019-07-12 23:34:19 -04:00
|
|
|
_spc.reset(new Spc(this));
|
2019-02-19 21:09:12 -05:00
|
|
|
|
2019-11-01 21:15:11 -04:00
|
|
|
_msu1.reset(Msu1::Init(romFile, _spc.get()));
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart->GetSpcData()) {
|
2019-10-19 15:23:17 -04:00
|
|
|
_spc->LoadSpcFile(_cart->GetSpcData());
|
|
|
|
_spcHud.reset(new SpcHud(this, _cart->GetSpcData()));
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-10-19 15:23:17 -04:00
|
|
|
_spcHud.reset();
|
|
|
|
}
|
|
|
|
|
2019-07-06 09:29:35 -04:00
|
|
|
_cpu.reset(new Cpu(this));
|
2019-07-12 23:34:19 -04:00
|
|
|
_memoryManager->Initialize(this);
|
2019-08-09 11:45:20 -04:00
|
|
|
_internalRegisters->Initialize(this);
|
2019-02-15 00:08:50 -05:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) {
|
2020-05-18 16:10:53 -04:00
|
|
|
_cart->GetGameboy()->PowerOn();
|
2020-06-20 23:20:03 -04:00
|
|
|
_consoleType = _cart->GetGameboy()->IsCgb() ? ConsoleType::GameboyColor : ConsoleType::Gameboy;
|
2020-05-18 16:10:53 -04:00
|
|
|
_settings->SetFlag(EmulationFlags::GameboyMode);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-06-20 23:20:03 -04:00
|
|
|
_consoleType = ConsoleType::Snes;
|
2020-05-18 16:10:53 -04:00
|
|
|
_settings->ClearFlag(EmulationFlags::GameboyMode);
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debuggerActive) {
|
2020-05-21 20:57:00 -04:00
|
|
|
GetDebugger();
|
|
|
|
}
|
|
|
|
|
|
|
|
_ppu->PowerOn();
|
|
|
|
_cpu->PowerOn();
|
|
|
|
|
2019-03-22 21:12:58 -04:00
|
|
|
_rewindManager.reset(new RewindManager(shared_from_this()));
|
|
|
|
_notificationManager->RegisterNotificationListener(_rewindManager);
|
|
|
|
|
|
|
|
_controlManager->UpdateControlDevices();
|
2021-03-10 11:13:28 -05:00
|
|
|
|
2019-03-22 21:12:58 -04:00
|
|
|
UpdateRegion();
|
|
|
|
|
2020-02-22 20:54:07 -05:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::GameLoaded, (void*)forPowerCycle);
|
2019-10-20 20:05:39 -04:00
|
|
|
|
2019-03-12 13:13:32 -04:00
|
|
|
_paused = false;
|
2019-03-14 18:07:25 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!forPowerCycle) {
|
2020-02-22 20:54:07 -05:00
|
|
|
string modelName = _region == ConsoleRegion::Pal ? "PAL" : "NTSC";
|
|
|
|
string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")";
|
2021-03-10 11:13:28 -05:00
|
|
|
MessageManager::DisplayMessage(messageTitle, FolderUtilities::GetFilename(GetRomInfo().RomFile.GetFileName(), false));
|
2020-02-22 20:54:07 -05:00
|
|
|
}
|
2019-03-31 15:59:13 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(stopRom) {
|
|
|
|
#ifndef LIBRETRO
|
2019-10-22 19:53:18 -04:00
|
|
|
_emuThread.reset(new thread(&Console::Run, this));
|
2021-03-10 11:13:28 -05:00
|
|
|
#endif
|
2019-10-22 19:53:18 -04:00
|
|
|
}
|
2019-12-12 22:14:55 -05:00
|
|
|
result = true;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-12-12 22:14:55 -05:00
|
|
|
MessageManager::DisplayMessage("Error", "CouldNotLoadFile", romFile.GetFileName());
|
2019-03-12 09:15:57 -04:00
|
|
|
}
|
2019-03-14 18:07:25 -04:00
|
|
|
|
2019-12-12 22:14:55 -05:00
|
|
|
_settings->SetEmulationConfig(orgConfig);
|
|
|
|
return result;
|
2019-03-12 09:15:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
RomInfo Console::GetRomInfo()
|
|
|
|
{
|
|
|
|
shared_ptr<BaseCartridge> cart = _cart;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(cart) {
|
2019-03-12 09:15:57 -04:00
|
|
|
return cart->GetRomInfo();
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-03-12 09:15:57 -04:00
|
|
|
return {};
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-18 16:10:53 -04:00
|
|
|
uint64_t Console::GetMasterClock()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode) && _cart->GetGameboy()) {
|
2020-05-18 16:10:53 -04:00
|
|
|
return _cart->GetGameboy()->GetCycleCount();
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
return _memoryManager->GetMasterClock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:25:35 -04:00
|
|
|
uint32_t Console::GetMasterClockRate()
|
|
|
|
{
|
|
|
|
return _masterClockRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsoleRegion Console::GetRegion()
|
|
|
|
{
|
|
|
|
return _region;
|
|
|
|
}
|
|
|
|
|
2020-06-20 23:20:03 -04:00
|
|
|
ConsoleType Console::GetConsoleType()
|
|
|
|
{
|
|
|
|
return _consoleType;
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:25:35 -04:00
|
|
|
void Console::UpdateRegion()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
switch(_settings->GetEmulationConfig().Region) {
|
|
|
|
case ConsoleRegion::Auto: _region = _cart->GetRegion(); break;
|
2019-03-14 15:25:35 -04:00
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
default:
|
|
|
|
case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; break;
|
|
|
|
case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; break;
|
2019-03-14 15:25:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_masterClockRate = _region == ConsoleRegion::Pal ? 21281370 : 21477270;
|
|
|
|
}
|
|
|
|
|
2020-02-05 18:57:20 -05:00
|
|
|
double Console::GetFps()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
|
2020-05-18 16:10:53 -04:00
|
|
|
return 59.72750056960583;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
|
|
|
if(_region == ConsoleRegion::Ntsc) {
|
2020-05-18 16:10:53 -04:00
|
|
|
return _settings->GetVideoConfig().IntegerFpsMode ? 60.0 : 60.0988118623484;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
return _settings->GetVideoConfig().IntegerFpsMode ? 50.0 : 50.00697796826829;
|
|
|
|
}
|
2020-02-05 18:57:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 17:56:54 -04:00
|
|
|
double Console::GetFrameDelay()
|
|
|
|
{
|
|
|
|
uint32_t emulationSpeed = _settings->GetEmulationSpeed();
|
|
|
|
double frameDelay;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(emulationSpeed == 0) {
|
2019-03-11 17:56:54 -04:00
|
|
|
frameDelay = 0;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-03-14 15:25:35 -04:00
|
|
|
UpdateRegion();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
|
2020-05-18 16:10:53 -04:00
|
|
|
frameDelay = 16.74270629882813;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
|
|
|
switch(_region) {
|
|
|
|
default:
|
|
|
|
case ConsoleRegion::Ntsc: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 16.6666666666666666667 : 16.63926405550947; break;
|
|
|
|
case ConsoleRegion::Pal: frameDelay = _settings->GetVideoConfig().IntegerFpsMode ? 20 : 19.99720882631146; break;
|
2020-05-18 16:10:53 -04:00
|
|
|
}
|
2019-03-14 15:25:35 -04:00
|
|
|
}
|
|
|
|
frameDelay /= (emulationSpeed / 100.0);
|
2019-03-11 17:56:54 -04:00
|
|
|
}
|
|
|
|
return frameDelay;
|
|
|
|
}
|
|
|
|
|
2020-10-06 22:57:19 -04:00
|
|
|
HistoryViewer* Console::GetHistoryViewer()
|
|
|
|
{
|
|
|
|
return _historyViewer.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::CopyRewindData(shared_ptr<Console> sourceConsole)
|
|
|
|
{
|
2020-10-07 23:10:29 -04:00
|
|
|
sourceConsole->Lock();
|
|
|
|
Lock();
|
2020-10-06 22:57:19 -04:00
|
|
|
|
|
|
|
//Disable battery saving for this instance
|
|
|
|
_batteryManager->SetSaveEnabled(false);
|
|
|
|
_historyViewer.reset(new HistoryViewer(shared_from_this()));
|
|
|
|
sourceConsole->GetRewindManager()->CopyHistory(_historyViewer);
|
|
|
|
|
2020-10-07 23:10:29 -04:00
|
|
|
Unlock();
|
|
|
|
sourceConsole->Unlock();
|
2020-10-06 22:57:19 -04:00
|
|
|
}
|
|
|
|
|
2019-07-16 21:02:56 -04:00
|
|
|
void Console::PauseOnNextFrame()
|
|
|
|
{
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
|
2020-07-08 21:25:23 -04:00
|
|
|
debugger->Step(CpuType::Gameboy, 144, StepType::SpecificScanline);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
debugger->Step(CpuType::Cpu, 240, StepType::SpecificScanline);
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-07-16 21:02:56 -04:00
|
|
|
_pauseOnNextFrame = true;
|
|
|
|
_paused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 13:13:32 -04:00
|
|
|
void Console::Pause()
|
|
|
|
{
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
|
2020-05-18 16:10:53 -04:00
|
|
|
debugger->Step(CpuType::Gameboy, 1, StepType::Step);
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
debugger->Step(CpuType::Cpu, 1, StepType::Step);
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-03-12 13:13:32 -04:00
|
|
|
_paused = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::Resume()
|
|
|
|
{
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-03-12 13:13:32 -04:00
|
|
|
debugger->Run();
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-03-12 13:13:32 -04:00
|
|
|
_paused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::IsPaused()
|
|
|
|
{
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-03-12 13:13:32 -04:00
|
|
|
return debugger->IsExecutionStopped();
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2019-03-12 13:13:32 -04:00
|
|
|
return _paused;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::WaitForPauseEnd()
|
|
|
|
{
|
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::GamePaused);
|
|
|
|
|
|
|
|
//Prevent audio from looping endlessly while game is paused
|
|
|
|
_soundMixer->StopAudio();
|
|
|
|
_runLock.Release();
|
|
|
|
|
|
|
|
PlatformUtilities::EnableScreensaver();
|
|
|
|
PlatformUtilities::RestoreTimerResolution();
|
2021-03-10 11:13:28 -05:00
|
|
|
while(_paused && !_stopFlag && !_debugger) {
|
2019-03-12 13:13:32 -04:00
|
|
|
//Sleep until emulation is resumed
|
|
|
|
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
|
|
|
|
}
|
|
|
|
|
|
|
|
PlatformUtilities::DisableScreensaver();
|
2020-04-25 14:12:32 -04:00
|
|
|
_runLock.Acquire();
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!_stopFlag) {
|
2020-02-05 21:30:16 -05:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::GameResumed);
|
|
|
|
}
|
2019-03-12 13:13:32 -04:00
|
|
|
}
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
ConsoleLock Console::AcquireLock()
|
|
|
|
{
|
|
|
|
return ConsoleLock(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::Lock()
|
|
|
|
{
|
2019-10-06 20:41:48 -04:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-10-06 20:41:48 -04:00
|
|
|
debugger->SuspendDebugger(false);
|
|
|
|
}
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
_lockCounter++;
|
|
|
|
_runLock.Acquire();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::Unlock()
|
|
|
|
{
|
2019-10-06 20:41:48 -04:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
2019-10-06 20:41:48 -04:00
|
|
|
debugger->SuspendDebugger(true);
|
|
|
|
}
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
_runLock.Release();
|
|
|
|
_lockCounter--;
|
|
|
|
}
|
|
|
|
|
2020-05-14 19:34:14 -04:00
|
|
|
bool Console::IsThreadPaused()
|
|
|
|
{
|
|
|
|
return !_emuThread || _threadPaused;
|
|
|
|
}
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
void Console::WaitForLock()
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_lockCounter > 0) {
|
2019-03-12 09:15:57 -04:00
|
|
|
//Need to temporarely pause the emu (to save/load a state, etc.)
|
|
|
|
_runLock.Release();
|
|
|
|
|
2020-05-14 19:34:14 -04:00
|
|
|
_threadPaused = true;
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
//Spin wait until we are allowed to start again
|
2021-03-10 11:13:28 -05:00
|
|
|
while(_lockCounter > 0) {}
|
2019-03-12 09:15:57 -04:00
|
|
|
|
2020-05-14 19:34:14 -04:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(debugger) {
|
|
|
|
while(debugger->HasBreakRequest()) {}
|
2020-05-14 19:34:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_threadPaused = false;
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
_runLock.Acquire();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
void Console::Serialize(ostream &out, int compressionLevel)
|
2019-03-12 09:15:57 -04:00
|
|
|
{
|
|
|
|
Serializer serializer(SaveStateManager::FileFormatVersion);
|
2020-05-18 16:10:53 -04:00
|
|
|
bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode);
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!isGameboyMode) {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_cpu.get());
|
|
|
|
serializer.Stream(_memoryManager.get());
|
|
|
|
serializer.Stream(_ppu.get());
|
|
|
|
serializer.Stream(_dmaController.get());
|
|
|
|
serializer.Stream(_internalRegisters.get());
|
|
|
|
serializer.Stream(_cart.get());
|
|
|
|
serializer.Stream(_controlManager.get());
|
|
|
|
serializer.Stream(_spc.get());
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_msu1) {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_msu1.get());
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_cart.get());
|
|
|
|
serializer.Stream(_controlManager.get());
|
2019-11-01 21:15:11 -04:00
|
|
|
}
|
2019-12-26 12:03:38 -05:00
|
|
|
serializer.Save(out, compressionLevel);
|
2019-03-12 09:15:57 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
void Console::Deserialize(istream &in, uint32_t fileFormatVersion, bool compressed)
|
2019-03-12 09:15:57 -04:00
|
|
|
{
|
2019-12-26 12:03:38 -05:00
|
|
|
Serializer serializer(in, fileFormatVersion, compressed);
|
2020-05-18 16:10:53 -04:00
|
|
|
bool isGameboyMode = _settings->CheckFlag(EmulationFlags::GameboyMode);
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!isGameboyMode) {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_cpu.get());
|
|
|
|
serializer.Stream(_memoryManager.get());
|
|
|
|
serializer.Stream(_ppu.get());
|
|
|
|
serializer.Stream(_dmaController.get());
|
|
|
|
serializer.Stream(_internalRegisters.get());
|
|
|
|
serializer.Stream(_cart.get());
|
|
|
|
serializer.Stream(_controlManager.get());
|
|
|
|
serializer.Stream(_spc.get());
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_msu1) {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_msu1.get());
|
|
|
|
}
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
serializer.Stream(_cart.get());
|
|
|
|
serializer.Stream(_controlManager.get());
|
2019-11-01 21:15:11 -04:00
|
|
|
}
|
2019-03-12 12:06:42 -04:00
|
|
|
_notificationManager->SendNotification(ConsoleNotificationType::StateLoaded);
|
2019-03-12 09:15:57 -04:00
|
|
|
}
|
|
|
|
|
2019-02-16 11:23:01 -05:00
|
|
|
shared_ptr<SoundMixer> Console::GetSoundMixer()
|
|
|
|
{
|
|
|
|
return _soundMixer;
|
|
|
|
}
|
|
|
|
|
2019-02-13 23:02:43 -05:00
|
|
|
shared_ptr<VideoRenderer> Console::GetVideoRenderer()
|
|
|
|
{
|
|
|
|
return _videoRenderer;
|
|
|
|
}
|
|
|
|
|
|
|
|
shared_ptr<VideoDecoder> Console::GetVideoDecoder()
|
|
|
|
{
|
|
|
|
return _videoDecoder;
|
|
|
|
}
|
|
|
|
|
2019-02-15 21:33:13 -05:00
|
|
|
shared_ptr<NotificationManager> Console::GetNotificationManager()
|
|
|
|
{
|
|
|
|
return _notificationManager;
|
|
|
|
}
|
|
|
|
|
2019-03-10 11:12:50 -04:00
|
|
|
shared_ptr<EmuSettings> Console::GetSettings()
|
|
|
|
{
|
|
|
|
return _settings;
|
|
|
|
}
|
|
|
|
|
2019-03-12 09:15:57 -04:00
|
|
|
shared_ptr<SaveStateManager> Console::GetSaveStateManager()
|
|
|
|
{
|
|
|
|
return _saveStateManager;
|
|
|
|
}
|
|
|
|
|
2019-03-12 12:06:42 -04:00
|
|
|
shared_ptr<RewindManager> Console::GetRewindManager()
|
|
|
|
{
|
|
|
|
return _rewindManager;
|
|
|
|
}
|
|
|
|
|
2019-02-13 23:02:43 -05:00
|
|
|
shared_ptr<DebugHud> Console::GetDebugHud()
|
|
|
|
{
|
|
|
|
return _debugHud;
|
|
|
|
}
|
|
|
|
|
2019-08-09 16:25:59 -04:00
|
|
|
shared_ptr<BatteryManager> Console::GetBatteryManager()
|
|
|
|
{
|
|
|
|
return _batteryManager;
|
|
|
|
}
|
|
|
|
|
2019-10-12 22:40:25 -04:00
|
|
|
shared_ptr<CheatManager> Console::GetCheatManager()
|
|
|
|
{
|
|
|
|
return _cheatManager;
|
|
|
|
}
|
|
|
|
|
2019-10-16 20:22:45 -04:00
|
|
|
shared_ptr<MovieManager> Console::GetMovieManager()
|
|
|
|
{
|
|
|
|
return _movieManager;
|
|
|
|
}
|
|
|
|
|
2019-02-13 18:44:39 -05:00
|
|
|
shared_ptr<Cpu> Console::GetCpu()
|
|
|
|
{
|
|
|
|
return _cpu;
|
|
|
|
}
|
|
|
|
|
2019-02-13 13:32:21 -05:00
|
|
|
shared_ptr<Ppu> Console::GetPpu()
|
|
|
|
{
|
|
|
|
return _ppu;
|
|
|
|
}
|
|
|
|
|
2019-02-16 11:23:01 -05:00
|
|
|
shared_ptr<Spc> Console::GetSpc()
|
|
|
|
{
|
|
|
|
return _spc;
|
|
|
|
}
|
|
|
|
|
2019-02-15 21:33:13 -05:00
|
|
|
shared_ptr<BaseCartridge> Console::GetCartridge()
|
|
|
|
{
|
|
|
|
return _cart;
|
|
|
|
}
|
|
|
|
|
2019-02-13 23:02:43 -05:00
|
|
|
shared_ptr<MemoryManager> Console::GetMemoryManager()
|
|
|
|
{
|
|
|
|
return _memoryManager;
|
|
|
|
}
|
|
|
|
|
2019-02-17 15:37:31 -05:00
|
|
|
shared_ptr<InternalRegisters> Console::GetInternalRegisters()
|
|
|
|
{
|
|
|
|
return _internalRegisters;
|
|
|
|
}
|
|
|
|
|
2019-02-17 19:54:29 -05:00
|
|
|
shared_ptr<ControlManager> Console::GetControlManager()
|
|
|
|
{
|
|
|
|
return _controlManager;
|
|
|
|
}
|
|
|
|
|
2019-02-19 21:09:12 -05:00
|
|
|
shared_ptr<DmaController> Console::GetDmaController()
|
|
|
|
{
|
|
|
|
return _dmaController;
|
|
|
|
}
|
|
|
|
|
2019-11-01 21:15:11 -04:00
|
|
|
shared_ptr<Msu1> Console::GetMsu1()
|
|
|
|
{
|
|
|
|
return _msu1;
|
|
|
|
}
|
|
|
|
|
2019-02-16 00:47:53 -05:00
|
|
|
shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
2019-02-12 22:13:09 -05:00
|
|
|
{
|
2019-02-16 00:47:53 -05:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!debugger && autoStart) {
|
2019-02-16 00:47:53 -05:00
|
|
|
//Lock to make sure we don't try to start debuggers in 2 separate threads at once
|
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
|
|
|
debugger = _debugger;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(!debugger) {
|
2019-02-16 00:47:53 -05:00
|
|
|
debugger.reset(new Debugger(shared_from_this()));
|
|
|
|
_debugger = debugger;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return debugger;
|
2019-02-12 22:13:09 -05:00
|
|
|
}
|
|
|
|
|
2019-03-16 12:20:18 -04:00
|
|
|
void Console::StopDebugger()
|
|
|
|
{
|
2019-10-06 20:41:48 -04:00
|
|
|
//Pause/unpause the regular emulation thread based on the debugger's pause state
|
|
|
|
_paused = IsPaused();
|
|
|
|
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
debugger->SuspendDebugger(false);
|
|
|
|
Lock();
|
2019-03-16 12:20:18 -04:00
|
|
|
_debugger.reset();
|
2019-10-06 20:41:48 -04:00
|
|
|
|
|
|
|
Unlock();
|
2019-03-16 12:20:18 -04:00
|
|
|
}
|
|
|
|
|
2019-04-06 17:38:14 -04:00
|
|
|
bool Console::IsDebugging()
|
|
|
|
{
|
|
|
|
return _debugger != nullptr;
|
|
|
|
}
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
thread::id Console::GetEmulationThreadId()
|
|
|
|
{
|
|
|
|
return _emulationThreadId;
|
|
|
|
}
|
|
|
|
|
2019-02-17 15:02:33 -05:00
|
|
|
bool Console::IsRunning()
|
|
|
|
{
|
|
|
|
return _cpu != nullptr;
|
|
|
|
}
|
|
|
|
|
2019-12-26 12:03:38 -05:00
|
|
|
bool Console::IsRunAheadFrame()
|
|
|
|
{
|
|
|
|
return _isRunAheadFrame;
|
|
|
|
}
|
|
|
|
|
2020-05-18 16:10:53 -04:00
|
|
|
uint32_t Console::GetFrameCount()
|
|
|
|
{
|
|
|
|
shared_ptr<BaseCartridge> cart = _cart;
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_settings->CheckFlag(EmulationFlags::GameboyMode) && cart->GetGameboy()) {
|
2020-05-25 19:43:57 -04:00
|
|
|
GbPpu* ppu = cart->GetGameboy()->GetPpu();
|
|
|
|
return ppu ? ppu->GetFrameCount() : 0;
|
2021-03-10 11:13:28 -05:00
|
|
|
} else {
|
2020-05-18 16:10:53 -04:00
|
|
|
shared_ptr<Ppu> ppu = _ppu;
|
|
|
|
return ppu ? ppu->GetFrameCount() : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
template<CpuType type>
|
2019-03-24 16:42:52 -04:00
|
|
|
void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_debugger) {
|
2019-07-25 22:22:09 -04:00
|
|
|
_debugger->ProcessInterrupt<type>(originalPc, currentPc, forNmi);
|
2019-03-24 16:42:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 20:12:32 -05:00
|
|
|
void Console::ProcessEvent(EventType type)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(type == EventType::EndFrame && _spcHud) {
|
2020-05-18 16:10:53 -04:00
|
|
|
_spcHud->Draw(GetFrameCount());
|
2019-10-19 15:23:17 -04:00
|
|
|
}
|
|
|
|
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_debugger) {
|
2019-03-07 20:12:32 -05:00
|
|
|
_debugger->ProcessEvent(type);
|
|
|
|
}
|
2019-07-25 22:22:09 -04:00
|
|
|
}
|
|
|
|
|
2020-06-07 16:34:23 -04:00
|
|
|
void Console::BreakImmediately(BreakSource source)
|
|
|
|
{
|
2021-03-10 11:13:28 -05:00
|
|
|
if(_debugger) {
|
2020-06-07 16:34:23 -04:00
|
|
|
_debugger->BreakImmediately(source);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-25 22:22:09 -04:00
|
|
|
template void Console::ProcessMemoryRead<CpuType::Cpu>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
|
|
|
template void Console::ProcessMemoryRead<CpuType::Sa1>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
|
|
|
template void Console::ProcessMemoryRead<CpuType::Spc>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2019-07-30 22:34:52 -04:00
|
|
|
template void Console::ProcessMemoryRead<CpuType::Gsu>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-02-23 21:50:55 -05:00
|
|
|
template void Console::ProcessMemoryRead<CpuType::NecDsp>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-02-24 22:00:52 -05:00
|
|
|
template void Console::ProcessMemoryRead<CpuType::Cx4>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-05-18 16:10:53 -04:00
|
|
|
template void Console::ProcessMemoryRead<CpuType::Gameboy>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2019-07-25 22:22:09 -04:00
|
|
|
|
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Cpu>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Sa1>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Spc>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2019-07-30 22:34:52 -04:00
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Gsu>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-02-23 21:50:55 -05:00
|
|
|
template void Console::ProcessMemoryWrite<CpuType::NecDsp>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-02-24 22:00:52 -05:00
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Cx4>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2020-05-18 16:10:53 -04:00
|
|
|
template void Console::ProcessMemoryWrite<CpuType::Gameboy>(uint32_t addr, uint8_t value, MemoryOperationType opType);
|
2019-07-25 22:22:09 -04:00
|
|
|
|
|
|
|
template void Console::ProcessInterrupt<CpuType::Cpu>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
|
2020-05-21 20:57:00 -04:00
|
|
|
template void Console::ProcessInterrupt<CpuType::Sa1>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
|
|
|
|
template void Console::ProcessInterrupt<CpuType::Gameboy>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
|