2014-06-14 15:27:55 +00:00
|
|
|
#include "stdafx.h"
|
2015-07-02 03:17:14 +00:00
|
|
|
#include <thread>
|
2014-06-14 15:27:55 +00:00
|
|
|
#include "Console.h"
|
2015-07-02 03:17:14 +00:00
|
|
|
#include "BaseMapper.h"
|
2016-05-01 00:08:53 +00:00
|
|
|
#include "ControlManager.h"
|
|
|
|
#include "VsControlManager.h"
|
2014-06-24 06:47:32 +00:00
|
|
|
#include "MapperFactory.h"
|
2015-07-02 03:17:14 +00:00
|
|
|
#include "Debugger.h"
|
2015-07-18 00:58:57 +00:00
|
|
|
#include "MessageManager.h"
|
2016-01-29 01:47:16 +00:00
|
|
|
#include "RomLoader.h"
|
2015-07-18 00:58:57 +00:00
|
|
|
#include "EmulationSettings.h"
|
2014-06-23 23:02:09 +00:00
|
|
|
#include "../Utilities/Timer.h"
|
2014-07-09 22:29:07 +00:00
|
|
|
#include "../Utilities/FolderUtilities.h"
|
2016-08-30 01:07:52 +00:00
|
|
|
#include "../Utilities/PlatformUtilities.h"
|
2015-08-15 01:50:14 +00:00
|
|
|
#include "HdPpu.h"
|
2016-06-26 00:46:54 +00:00
|
|
|
#include "NsfPpu.h"
|
2016-01-15 00:33:16 +00:00
|
|
|
#include "SoundMixer.h"
|
2016-06-26 00:46:54 +00:00
|
|
|
#include "NsfMapper.h"
|
2016-09-02 23:36:37 +00:00
|
|
|
#include "ShortcutKeyHandler.h"
|
2014-06-14 15:27:55 +00:00
|
|
|
|
2015-07-06 02:23:44 +00:00
|
|
|
shared_ptr<Console> Console::Instance(new Console());
|
2014-06-21 23:03:13 +00:00
|
|
|
|
2015-07-06 02:23:44 +00:00
|
|
|
Console::Console()
|
2014-06-14 15:27:55 +00:00
|
|
|
{
|
2014-07-09 22:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Console::~Console()
|
|
|
|
{
|
|
|
|
Movie::Stop();
|
2016-06-05 18:36:20 +00:00
|
|
|
SoundMixer::StopRecording();
|
2014-07-09 22:29:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-02 03:17:14 +00:00
|
|
|
shared_ptr<Console> Console::GetInstance()
|
2014-07-09 22:29:07 +00:00
|
|
|
{
|
|
|
|
return Console::Instance;
|
|
|
|
}
|
|
|
|
|
2015-07-21 03:20:41 +00:00
|
|
|
void Console::Release()
|
|
|
|
{
|
|
|
|
Console::Instance.reset(new Console());
|
|
|
|
}
|
|
|
|
|
2016-06-18 00:53:05 +00:00
|
|
|
void Console::Initialize(string romFilename, stringstream *filestream, string ipsFilename, int32_t archiveFileIndex)
|
2014-07-09 22:29:07 +00:00
|
|
|
{
|
2016-06-19 20:55:26 +00:00
|
|
|
SoundMixer::StopAudio();
|
|
|
|
|
2016-07-26 23:19:28 +00:00
|
|
|
if(_mapper) {
|
|
|
|
//Ensure we save any battery file before loading a new game
|
|
|
|
_mapper->SaveBattery();
|
|
|
|
}
|
|
|
|
|
2015-07-05 23:05:33 +00:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
|
2016-06-18 00:53:05 +00:00
|
|
|
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFilename, filestream, ipsFilename, archiveFileIndex);
|
2015-12-26 22:11:00 +00:00
|
|
|
|
2014-07-10 23:25:35 +00:00
|
|
|
if(mapper) {
|
2015-12-27 23:41:38 +00:00
|
|
|
_romFilepath = romFilename;
|
2015-08-31 01:04:21 +00:00
|
|
|
|
2016-09-01 00:54:38 +00:00
|
|
|
_autoSaveManager.reset(new AutoSaveManager());
|
2015-08-31 01:04:21 +00:00
|
|
|
VideoDecoder::GetInstance()->StopThread();
|
2014-06-22 12:38:42 +00:00
|
|
|
|
2014-07-10 23:25:35 +00:00
|
|
|
_mapper = mapper;
|
|
|
|
_memoryManager.reset(new MemoryManager(_mapper));
|
|
|
|
_cpu.reset(new CPU(_memoryManager.get()));
|
2015-08-15 01:50:14 +00:00
|
|
|
if(HdNesPack::HasHdPack(_romFilepath)) {
|
|
|
|
_ppu.reset(new HdPpu(_memoryManager.get()));
|
2016-06-26 00:46:54 +00:00
|
|
|
} else if(NsfMapper::GetInstance()) {
|
|
|
|
//Disable most of the PPU for NSFs
|
|
|
|
_ppu.reset(new NsfPpu(_memoryManager.get()));
|
2015-08-15 01:50:14 +00:00
|
|
|
} else {
|
|
|
|
_ppu.reset(new PPU(_memoryManager.get()));
|
|
|
|
}
|
2014-07-10 23:25:35 +00:00
|
|
|
_apu.reset(new APU(_memoryManager.get()));
|
2014-06-23 02:15:35 +00:00
|
|
|
|
2016-06-16 01:59:34 +00:00
|
|
|
_controlManager.reset(_mapper->GetGameSystem() == GameSystem::VsUniSystem ? new VsControlManager() : new ControlManager());
|
2016-06-22 23:23:08 +00:00
|
|
|
_controlManager->UpdateControlDevices();
|
2014-06-21 19:43:41 +00:00
|
|
|
|
2014-07-10 23:25:35 +00:00
|
|
|
_memoryManager->RegisterIODevice(_ppu.get());
|
|
|
|
_memoryManager->RegisterIODevice(_apu.get());
|
|
|
|
_memoryManager->RegisterIODevice(_controlManager.get());
|
2016-06-26 00:46:54 +00:00
|
|
|
_memoryManager->RegisterIODevice(_mapper.get());
|
2014-06-19 23:58:15 +00:00
|
|
|
|
2016-07-10 23:15:00 +00:00
|
|
|
_model = NesModel::Auto;
|
2016-02-11 02:41:51 +00:00
|
|
|
UpdateNesModel(false);
|
2016-01-23 05:52:06 +00:00
|
|
|
|
2015-07-06 02:23:44 +00:00
|
|
|
_initialized = true;
|
2016-01-29 03:34:23 +00:00
|
|
|
|
2016-06-04 12:55:52 +00:00
|
|
|
if(_debugger) {
|
2016-07-31 18:31:44 +00:00
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
2016-06-04 12:55:52 +00:00
|
|
|
StopDebugger();
|
|
|
|
GetDebugger();
|
|
|
|
}
|
|
|
|
|
2016-01-29 03:34:23 +00:00
|
|
|
ResetComponents(false);
|
2016-01-23 05:52:06 +00:00
|
|
|
|
2015-08-31 01:04:21 +00:00
|
|
|
VideoDecoder::GetInstance()->StartThread();
|
2015-07-06 02:23:44 +00:00
|
|
|
|
2015-12-27 23:41:38 +00:00
|
|
|
FolderUtilities::AddKnowGameFolder(FolderUtilities::GetFolderName(romFilename));
|
2016-07-10 23:15:00 +00:00
|
|
|
|
|
|
|
string modelName = _model == NesModel::PAL ? "PAL" : (_model == NesModel::Dendy ? "Dendy" : "NTSC");
|
|
|
|
string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")";
|
|
|
|
MessageManager::DisplayMessage(messageTitle, FolderUtilities::GetFilename(_mapper->GetRomName(), false));
|
2016-06-12 22:11:31 +00:00
|
|
|
if(EmulationSettings::GetOverclockRate() != 100) {
|
|
|
|
MessageManager::DisplayMessage("ClockRate", std::to_string(EmulationSettings::GetOverclockRate()) + "%");
|
|
|
|
}
|
2014-07-10 23:25:35 +00:00
|
|
|
} else {
|
2016-02-19 18:05:04 +00:00
|
|
|
MessageManager::DisplayMessage("Error", "CouldNotLoadFile", FolderUtilities::GetFilename(romFilename, true));
|
2014-07-10 23:25:35 +00:00
|
|
|
}
|
2015-07-06 02:23:44 +00:00
|
|
|
}
|
2014-07-01 16:44:01 +00:00
|
|
|
|
2016-08-21 02:07:56 +00:00
|
|
|
void Console::LoadROM(string filepath, stringstream *filestream, int32_t archiveFileIndex, string ipsFile)
|
2015-12-27 23:41:38 +00:00
|
|
|
{
|
|
|
|
Console::Pause();
|
2016-08-21 02:07:56 +00:00
|
|
|
Instance->Initialize(filepath, filestream, ipsFile, archiveFileIndex);
|
2015-07-06 02:23:44 +00:00
|
|
|
Console::Resume();
|
2014-06-14 15:27:55 +00:00
|
|
|
}
|
|
|
|
|
2015-07-11 12:27:22 +00:00
|
|
|
bool Console::LoadROM(string filename, uint32_t crc32Hash)
|
2014-06-14 15:27:55 +00:00
|
|
|
{
|
2015-07-11 12:27:22 +00:00
|
|
|
string currentRomFilepath = Console::GetROMPath();
|
|
|
|
string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath);
|
2015-07-06 02:23:44 +00:00
|
|
|
if(!currentRomFilepath.empty()) {
|
2016-06-18 00:53:05 +00:00
|
|
|
if(Console::GetCrc32() == crc32Hash) {
|
2015-07-06 02:23:44 +00:00
|
|
|
//Current game matches, no need to do anything
|
|
|
|
return true;
|
|
|
|
}
|
2016-02-09 04:34:48 +00:00
|
|
|
}
|
2015-07-06 02:23:44 +00:00
|
|
|
|
2016-06-18 00:53:05 +00:00
|
|
|
int32_t archiveFileIndex = -1;
|
2016-02-09 04:34:48 +00:00
|
|
|
for(string folder : FolderUtilities::GetKnowGameFolders()) {
|
2016-06-18 00:53:05 +00:00
|
|
|
string match = RomLoader::FindMatchingRomInFolder(folder, filename, crc32Hash, true, archiveFileIndex);
|
2015-07-06 02:23:44 +00:00
|
|
|
if(!match.empty()) {
|
2016-06-18 00:53:05 +00:00
|
|
|
Console::LoadROM(match, nullptr, archiveFileIndex);
|
2015-07-06 02:23:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-09 04:34:48 +00:00
|
|
|
//Perform slow CRC32 search for ROM
|
2015-07-11 12:27:22 +00:00
|
|
|
for(string folder : FolderUtilities::GetKnowGameFolders()) {
|
2016-06-18 00:53:05 +00:00
|
|
|
string match = RomLoader::FindMatchingRomInFolder(folder, filename, crc32Hash, false, archiveFileIndex);
|
2016-02-09 04:34:48 +00:00
|
|
|
if(!match.empty()) {
|
2016-06-18 00:53:05 +00:00
|
|
|
Console::LoadROM(match, nullptr, archiveFileIndex);
|
2016-02-09 04:34:48 +00:00
|
|
|
return true;
|
2015-07-06 02:23:44 +00:00
|
|
|
}
|
2014-07-09 22:29:07 +00:00
|
|
|
}
|
2016-02-09 04:34:48 +00:00
|
|
|
|
2015-07-06 02:23:44 +00:00
|
|
|
return false;
|
2014-07-09 22:29:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-11 12:27:22 +00:00
|
|
|
string Console::GetROMPath()
|
2014-07-09 22:29:07 +00:00
|
|
|
{
|
2015-07-11 12:27:22 +00:00
|
|
|
return Instance->_romFilepath;
|
2014-06-14 15:27:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-18 00:53:05 +00:00
|
|
|
string Console::GetRomName()
|
|
|
|
{
|
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->GetRomName();
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-29 01:47:16 +00:00
|
|
|
uint32_t Console::GetCrc32()
|
|
|
|
{
|
2016-06-18 00:53:05 +00:00
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->GetCrc32();
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-29 01:47:16 +00:00
|
|
|
}
|
|
|
|
|
2016-07-10 13:05:41 +00:00
|
|
|
uint32_t Console::GetPrgCrc32()
|
|
|
|
{
|
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->GetPrgCrc32();
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-02 03:54:31 +00:00
|
|
|
NesModel Console::GetModel()
|
|
|
|
{
|
|
|
|
return Instance->_model;
|
|
|
|
}
|
|
|
|
|
2015-07-05 23:35:38 +00:00
|
|
|
void Console::Reset(bool softReset)
|
2014-06-14 15:27:55 +00:00
|
|
|
{
|
2014-07-01 22:05:54 +00:00
|
|
|
Movie::Stop();
|
2016-06-05 18:36:20 +00:00
|
|
|
SoundMixer::StopRecording();
|
|
|
|
|
2015-07-06 02:23:44 +00:00
|
|
|
if(Instance->_initialized) {
|
2015-07-02 03:17:14 +00:00
|
|
|
Console::Pause();
|
2015-12-26 22:11:00 +00:00
|
|
|
if(softReset) {
|
|
|
|
Instance->ResetComponents(softReset);
|
|
|
|
} else {
|
|
|
|
//Full reset of all objects to ensure the emulator always starts in the exact same state
|
|
|
|
Instance->Initialize(Instance->_romFilepath);
|
|
|
|
}
|
2015-07-02 03:17:14 +00:00
|
|
|
Console::Resume();
|
2014-07-01 16:44:01 +00:00
|
|
|
}
|
2014-06-14 15:27:55 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 17:30:02 +00:00
|
|
|
void Console::ResetComponents(bool softReset)
|
2014-06-24 06:47:32 +00:00
|
|
|
{
|
2015-07-06 02:23:44 +00:00
|
|
|
Movie::Stop();
|
2016-06-05 18:36:20 +00:00
|
|
|
SoundMixer::StopRecording();
|
2015-07-06 02:23:44 +00:00
|
|
|
|
2016-07-17 18:07:22 +00:00
|
|
|
_memoryManager->Reset(softReset);
|
2014-06-24 06:47:32 +00:00
|
|
|
_ppu->Reset();
|
2015-07-19 05:30:13 +00:00
|
|
|
_apu->Reset(softReset);
|
2015-07-02 03:17:14 +00:00
|
|
|
_cpu->Reset(softReset);
|
2016-06-22 02:13:26 +00:00
|
|
|
_controlManager->Reset(softReset);
|
2016-07-10 22:22:37 +00:00
|
|
|
|
|
|
|
_lagCounter = 0;
|
2016-09-01 00:54:38 +00:00
|
|
|
|
2016-01-15 00:33:16 +00:00
|
|
|
SoundMixer::StopAudio(true);
|
2015-08-25 00:27:07 +00:00
|
|
|
|
2015-07-02 03:17:14 +00:00
|
|
|
if(softReset) {
|
2016-11-22 05:14:49 +00:00
|
|
|
if(_debugger) {
|
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
|
|
|
StopDebugger();
|
|
|
|
GetDebugger();
|
|
|
|
}
|
|
|
|
|
2015-07-02 03:17:14 +00:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameReset);
|
|
|
|
} else {
|
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameLoaded);
|
|
|
|
}
|
2014-06-24 06:47:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-21 01:48:55 +00:00
|
|
|
void Console::Stop()
|
|
|
|
{
|
|
|
|
_stop = true;
|
2016-07-31 18:31:44 +00:00
|
|
|
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
if(debugger) {
|
|
|
|
debugger->Run();
|
2015-08-22 02:42:44 +00:00
|
|
|
}
|
2015-07-05 23:12:41 +00:00
|
|
|
_stopLock.Acquire();
|
|
|
|
_stopLock.Release();
|
2014-06-21 23:03:13 +00:00
|
|
|
}
|
|
|
|
|
2014-07-01 16:44:01 +00:00
|
|
|
void Console::Pause()
|
|
|
|
{
|
2016-07-31 18:31:44 +00:00
|
|
|
shared_ptr<Debugger> debugger = Console::Instance->_debugger;
|
|
|
|
if(debugger) {
|
2015-08-22 02:42:44 +00:00
|
|
|
//Make sure debugger resumes if we try to pause the emu, otherwise we will get deadlocked.
|
2016-07-31 18:31:44 +00:00
|
|
|
debugger->Suspend();
|
2015-08-22 02:42:44 +00:00
|
|
|
}
|
2015-07-06 02:23:44 +00:00
|
|
|
Console::Instance->_pauseLock.Acquire();
|
|
|
|
//Spin wait until emu pauses
|
|
|
|
Console::Instance->_runLock.Acquire();
|
2014-07-01 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::Resume()
|
|
|
|
{
|
2015-07-06 02:23:44 +00:00
|
|
|
Console::Instance->_runLock.Release();
|
|
|
|
Console::Instance->_pauseLock.Release();
|
2016-06-04 12:55:52 +00:00
|
|
|
|
2016-07-31 18:31:44 +00:00
|
|
|
shared_ptr<Debugger> debugger = Console::Instance->_debugger;
|
|
|
|
if(debugger) {
|
2016-06-04 12:55:52 +00:00
|
|
|
//Make sure debugger resumes if we try to pause the emu, otherwise we will get deadlocked.
|
2016-07-31 18:31:44 +00:00
|
|
|
debugger->Resume();
|
2016-06-04 12:55:52 +00:00
|
|
|
}
|
2014-07-01 16:44:01 +00:00
|
|
|
}
|
|
|
|
|
2014-06-14 15:27:55 +00:00
|
|
|
void Console::Run()
|
|
|
|
{
|
2014-06-21 19:43:41 +00:00
|
|
|
Timer clockTimer;
|
2015-07-22 03:05:27 +00:00
|
|
|
double targetTime;
|
|
|
|
uint32_t lastFrameNumber = -1;
|
2016-09-01 00:54:38 +00:00
|
|
|
|
2016-09-02 23:36:37 +00:00
|
|
|
ShortcutKeyHandler shortcutKeyHandler;
|
2016-09-01 00:54:38 +00:00
|
|
|
_autoSaveManager.reset(new AutoSaveManager());
|
2015-07-15 01:51:39 +00:00
|
|
|
|
2015-07-05 23:05:33 +00:00
|
|
|
_runLock.Acquire();
|
|
|
|
_stopLock.Acquire();
|
2014-07-06 23:54:47 +00:00
|
|
|
|
2016-07-10 23:15:00 +00:00
|
|
|
targetTime = GetFrameDelay();
|
2015-07-22 03:05:27 +00:00
|
|
|
|
2015-08-31 01:04:21 +00:00
|
|
|
VideoDecoder::GetInstance()->StartThread();
|
2016-08-30 01:07:52 +00:00
|
|
|
|
|
|
|
PlatformUtilities::DisableScreensaver();
|
2015-08-31 01:04:21 +00:00
|
|
|
|
2014-06-21 19:43:41 +00:00
|
|
|
while(true) {
|
2016-02-12 03:59:31 +00:00
|
|
|
try {
|
|
|
|
_cpu->Exec();
|
|
|
|
} catch(const std::runtime_error &ex) {
|
2016-02-19 18:05:04 +00:00
|
|
|
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
2016-02-12 03:59:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-16 20:55:16 +00:00
|
|
|
uint32_t currentFrameNumber = PPU::GetFrameCount();
|
|
|
|
if(currentFrameNumber != lastFrameNumber) {
|
|
|
|
lastFrameNumber = currentFrameNumber;
|
2014-06-30 18:44:30 +00:00
|
|
|
|
2015-08-31 01:04:21 +00:00
|
|
|
//Sleep until we're ready to start the next frame
|
|
|
|
clockTimer.WaitUntil(targetTime);
|
2016-06-26 00:46:54 +00:00
|
|
|
|
|
|
|
if(_resetRequested) {
|
|
|
|
//Used by NSF player to reset console after changing track
|
|
|
|
ResetComponents(true);
|
|
|
|
_resetRequested = false;
|
|
|
|
}
|
2015-08-31 01:04:21 +00:00
|
|
|
|
2015-07-05 23:05:33 +00:00
|
|
|
if(!_pauseLock.IsFree()) {
|
2014-07-06 23:54:47 +00:00
|
|
|
//Need to temporarely pause the emu (to save/load a state, etc.)
|
2015-07-05 23:05:33 +00:00
|
|
|
_runLock.Release();
|
2014-07-06 23:54:47 +00:00
|
|
|
|
|
|
|
//Spin wait until we are allowed to start again
|
2015-07-05 23:05:33 +00:00
|
|
|
_pauseLock.WaitForRelease();
|
2014-07-01 16:44:01 +00:00
|
|
|
|
2015-07-05 23:05:33 +00:00
|
|
|
_runLock.Acquire();
|
2014-07-01 16:44:01 +00:00
|
|
|
}
|
2014-07-06 23:54:47 +00:00
|
|
|
|
2016-02-06 04:14:27 +00:00
|
|
|
bool paused = EmulationSettings::IsPaused();
|
2016-01-31 18:53:17 +00:00
|
|
|
if(paused && !_stop) {
|
2015-07-02 03:17:14 +00:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
|
|
|
|
|
|
|
|
//Prevent audio from looping endlessly while game is paused
|
2016-01-15 00:33:16 +00:00
|
|
|
SoundMixer::StopAudio();
|
2016-09-04 23:04:52 +00:00
|
|
|
|
|
|
|
_runLock.Release();
|
2016-08-30 01:07:52 +00:00
|
|
|
|
|
|
|
PlatformUtilities::EnableScreensaver();
|
2016-09-04 11:17:00 +00:00
|
|
|
while(paused && !_stop) {
|
2014-07-10 01:48:54 +00:00
|
|
|
//Sleep until emulation is resumed
|
|
|
|
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
2016-02-06 04:14:27 +00:00
|
|
|
paused = EmulationSettings::IsPaused();
|
2014-07-10 01:48:54 +00:00
|
|
|
}
|
2016-08-30 01:07:52 +00:00
|
|
|
PlatformUtilities::DisableScreensaver();
|
|
|
|
_runLock.Acquire();
|
2015-07-02 03:17:14 +00:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
|
2014-07-10 01:48:54 +00:00
|
|
|
}
|
2015-07-22 03:05:27 +00:00
|
|
|
|
2015-08-31 01:04:21 +00:00
|
|
|
//Get next target time, and adjust based on whether we are ahead or behind
|
|
|
|
double timeLag = EmulationSettings::GetEmulationSpeed() == 0 ? 0 : clockTimer.GetElapsedMS() - targetTime;
|
2016-07-10 23:15:00 +00:00
|
|
|
UpdateNesModel(true);
|
|
|
|
targetTime = GetFrameDelay();
|
|
|
|
|
2014-07-06 23:54:47 +00:00
|
|
|
clockTimer.Reset();
|
2015-08-31 01:04:21 +00:00
|
|
|
targetTime -= timeLag;
|
|
|
|
if(targetTime < 0) {
|
|
|
|
targetTime = 0;
|
|
|
|
}
|
2016-07-10 22:22:37 +00:00
|
|
|
|
|
|
|
if(_controlManager->GetLagFlag()) {
|
|
|
|
_lagCounter++;
|
|
|
|
}
|
2014-07-06 23:54:47 +00:00
|
|
|
|
|
|
|
if(_stop) {
|
|
|
|
_stop = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-14 22:20:56 +00:00
|
|
|
}
|
2016-01-15 00:33:16 +00:00
|
|
|
SoundMixer::StopAudio();
|
2015-12-26 22:11:00 +00:00
|
|
|
Movie::Stop();
|
2016-06-05 18:36:20 +00:00
|
|
|
SoundMixer::StopRecording();
|
2016-08-30 01:07:52 +00:00
|
|
|
PlatformUtilities::EnableScreensaver();
|
2015-08-31 01:04:21 +00:00
|
|
|
|
2016-09-01 00:54:38 +00:00
|
|
|
_autoSaveManager.reset();
|
|
|
|
|
2015-08-31 01:04:21 +00:00
|
|
|
VideoDecoder::GetInstance()->StopThread();
|
|
|
|
|
2016-01-31 05:41:33 +00:00
|
|
|
_initialized = false;
|
2016-01-29 03:34:23 +00:00
|
|
|
_romFilepath = "";
|
|
|
|
|
2015-07-05 23:05:33 +00:00
|
|
|
_stopLock.Release();
|
|
|
|
_runLock.Release();
|
2014-06-26 01:52:37 +00:00
|
|
|
}
|
|
|
|
|
2016-02-14 17:58:35 +00:00
|
|
|
bool Console::IsRunning()
|
|
|
|
{
|
|
|
|
return !Instance->_stopLock.IsFree();
|
|
|
|
}
|
|
|
|
|
2016-07-10 23:15:00 +00:00
|
|
|
void Console::UpdateNesModel(bool sendNotification)
|
2015-07-22 03:05:27 +00:00
|
|
|
{
|
2016-02-06 04:14:27 +00:00
|
|
|
bool configChanged = false;
|
|
|
|
if(EmulationSettings::NeedControllerUpdate()) {
|
|
|
|
_controlManager->UpdateControlDevices();
|
|
|
|
configChanged = true;
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:05:27 +00:00
|
|
|
NesModel model = EmulationSettings::GetNesModel();
|
|
|
|
if(model == NesModel::Auto) {
|
2016-06-16 01:59:34 +00:00
|
|
|
switch(_mapper->GetGameSystem()) {
|
|
|
|
case GameSystem::NesPal: model = NesModel::PAL; break;
|
|
|
|
case GameSystem::Dendy: model = NesModel::Dendy; break;
|
|
|
|
default: model = NesModel::NTSC; break;
|
|
|
|
}
|
2015-07-22 03:05:27 +00:00
|
|
|
}
|
2016-02-06 04:14:27 +00:00
|
|
|
if(_model != model) {
|
|
|
|
_model = model;
|
|
|
|
configChanged = true;
|
2016-07-10 23:15:00 +00:00
|
|
|
|
|
|
|
if(sendNotification) {
|
|
|
|
MessageManager::DisplayMessage("Region", model == NesModel::PAL ? "PAL" : (model == NesModel::Dendy ? "Dendy" : "NTSC"));
|
|
|
|
}
|
2016-02-06 04:14:27 +00:00
|
|
|
}
|
2016-07-10 23:15:00 +00:00
|
|
|
|
|
|
|
_mapper->SetNesModel(model);
|
|
|
|
_ppu->SetNesModel(model);
|
|
|
|
_apu->SetNesModel(model);
|
|
|
|
|
|
|
|
if(configChanged && sendNotification) {
|
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double Console::GetFrameDelay()
|
|
|
|
{
|
|
|
|
uint32_t emulationSpeed = EmulationSettings::GetEmulationSpeed();
|
2016-01-23 05:52:06 +00:00
|
|
|
double frameDelay;
|
2015-08-25 00:27:07 +00:00
|
|
|
if(emulationSpeed == 0) {
|
2015-08-24 00:24:24 +00:00
|
|
|
frameDelay = 0;
|
|
|
|
} else {
|
2016-01-31 00:33:32 +00:00
|
|
|
//60.1fps (NTSC), 50.01fps (PAL/Dendy)
|
2016-07-10 23:15:00 +00:00
|
|
|
switch(_model) {
|
2016-06-03 03:56:11 +00:00
|
|
|
default:
|
2016-01-31 00:33:32 +00:00
|
|
|
case NesModel::NTSC: frameDelay = 16.63926405550947; break;
|
|
|
|
case NesModel::PAL:
|
|
|
|
case NesModel::Dendy: frameDelay = 19.99720920217466; break;
|
|
|
|
}
|
2015-08-25 00:27:07 +00:00
|
|
|
frameDelay /= (double)emulationSpeed / 100.0;
|
2015-08-24 00:24:24 +00:00
|
|
|
}
|
2015-08-25 00:27:07 +00:00
|
|
|
|
2016-01-23 05:52:06 +00:00
|
|
|
return frameDelay;
|
2015-07-22 03:05:27 +00:00
|
|
|
}
|
|
|
|
|
2014-07-01 16:44:01 +00:00
|
|
|
void Console::SaveState(ostream &saveStream)
|
2014-06-26 01:52:37 +00:00
|
|
|
{
|
2015-07-06 02:23:44 +00:00
|
|
|
if(Instance->_initialized) {
|
2014-07-06 23:54:47 +00:00
|
|
|
Instance->_cpu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_ppu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_memoryManager->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_apu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_controlManager->SaveSnapshot(&saveStream);
|
2016-06-11 20:08:16 +00:00
|
|
|
Instance->_mapper->SaveSnapshot(&saveStream);
|
2014-07-06 23:54:47 +00:00
|
|
|
}
|
2014-07-01 16:44:01 +00:00
|
|
|
}
|
2014-06-26 01:52:37 +00:00
|
|
|
|
2014-07-01 16:44:01 +00:00
|
|
|
void Console::LoadState(istream &loadStream)
|
|
|
|
{
|
2015-07-06 02:23:44 +00:00
|
|
|
if(Instance->_initialized) {
|
2016-07-19 20:36:07 +00:00
|
|
|
//Stop any movie that might have been playing/recording if a state is loaded
|
|
|
|
//(Note: Loading a state is disabled in the UI while a movie is playing/recording)
|
|
|
|
Movie::Stop();
|
|
|
|
|
2014-07-06 23:54:47 +00:00
|
|
|
Instance->_cpu->LoadSnapshot(&loadStream);
|
|
|
|
Instance->_ppu->LoadSnapshot(&loadStream);
|
|
|
|
Instance->_memoryManager->LoadSnapshot(&loadStream);
|
|
|
|
Instance->_apu->LoadSnapshot(&loadStream);
|
|
|
|
Instance->_controlManager->LoadSnapshot(&loadStream);
|
2016-06-11 20:08:16 +00:00
|
|
|
Instance->_mapper->LoadSnapshot(&loadStream);
|
2014-07-10 01:11:02 +00:00
|
|
|
|
2015-07-02 03:17:14 +00:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::StateLoaded);
|
2014-07-06 23:54:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::LoadState(uint8_t *buffer, uint32_t bufferSize)
|
|
|
|
{
|
|
|
|
stringstream stream;
|
|
|
|
stream.write((char*)buffer, bufferSize);
|
|
|
|
stream.seekg(0, ios::beg);
|
|
|
|
LoadState(stream);
|
2014-06-26 01:52:37 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 23:02:33 +00:00
|
|
|
std::shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
2015-06-24 23:26:19 +00:00
|
|
|
{
|
2016-07-31 18:31:44 +00:00
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
2016-08-25 23:02:33 +00:00
|
|
|
if(!_debugger && autoStart) {
|
2015-08-22 02:42:44 +00:00
|
|
|
_debugger.reset(new Debugger(Console::Instance, _cpu, _ppu, _memoryManager, _mapper));
|
|
|
|
}
|
|
|
|
return _debugger;
|
2015-06-24 23:26:19 +00:00
|
|
|
}
|
2015-08-22 02:42:44 +00:00
|
|
|
|
|
|
|
void Console::StopDebugger()
|
|
|
|
{
|
2016-10-27 02:09:15 +00:00
|
|
|
auto lock = _debuggerLock.AcquireSafe();
|
2015-08-22 02:42:44 +00:00
|
|
|
_debugger.reset();
|
2016-02-06 04:14:27 +00:00
|
|
|
}
|
|
|
|
|
2016-06-26 00:46:54 +00:00
|
|
|
void Console::RequestReset()
|
|
|
|
{
|
|
|
|
Instance->_resetRequested = true;
|
|
|
|
}
|
|
|
|
|
2016-02-06 04:14:27 +00:00
|
|
|
NesModel Console::GetNesModel()
|
|
|
|
{
|
|
|
|
return Instance->_model;
|
2016-07-10 22:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Console::GetLagCounter()
|
|
|
|
{
|
|
|
|
return Instance->_lagCounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::ResetLagCounter()
|
|
|
|
{
|
|
|
|
Instance->_lagCounter = 0;
|
2016-11-26 23:04:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::IsDebuggerAttached()
|
|
|
|
{
|
|
|
|
return (bool)Instance->_debugger;
|
2015-08-22 02:42:44 +00:00
|
|
|
}
|