2014-06-14 11:27:55 -04:00
|
|
|
#include "stdafx.h"
|
2015-07-01 23:17:14 -04:00
|
|
|
#include <thread>
|
2014-06-14 11:27:55 -04:00
|
|
|
#include "Console.h"
|
2017-04-29 08:29:56 -04:00
|
|
|
#include "CPU.h"
|
|
|
|
#include "PPU.h"
|
|
|
|
#include "APU.h"
|
|
|
|
#include "MemoryManager.h"
|
|
|
|
#include "AutoSaveManager.h"
|
2015-07-01 23:17:14 -04:00
|
|
|
#include "BaseMapper.h"
|
2016-04-30 20:08:53 -04:00
|
|
|
#include "ControlManager.h"
|
|
|
|
#include "VsControlManager.h"
|
2014-06-24 02:47:32 -04:00
|
|
|
#include "MapperFactory.h"
|
2015-07-01 23:17:14 -04:00
|
|
|
#include "Debugger.h"
|
2015-07-17 20:58:57 -04:00
|
|
|
#include "MessageManager.h"
|
2016-01-28 20:47:16 -05:00
|
|
|
#include "RomLoader.h"
|
2015-07-17 20:58:57 -04:00
|
|
|
#include "EmulationSettings.h"
|
2017-06-28 19:00:08 -04:00
|
|
|
#include "../Utilities/sha1.h"
|
2014-06-23 19:02:09 -04:00
|
|
|
#include "../Utilities/Timer.h"
|
2014-07-09 18:29:07 -04:00
|
|
|
#include "../Utilities/FolderUtilities.h"
|
2016-08-29 21:07:52 -04:00
|
|
|
#include "../Utilities/PlatformUtilities.h"
|
2017-09-30 14:07:07 -04:00
|
|
|
#include "VirtualFile.h"
|
2017-06-28 19:00:08 -04:00
|
|
|
#include "HdBuilderPpu.h"
|
2015-08-14 21:50:14 -04:00
|
|
|
#include "HdPpu.h"
|
2016-06-25 20:46:54 -04:00
|
|
|
#include "NsfPpu.h"
|
2016-01-14 19:33:16 -05:00
|
|
|
#include "SoundMixer.h"
|
2016-06-25 20:46:54 -04:00
|
|
|
#include "NsfMapper.h"
|
2017-04-18 22:39:45 -04:00
|
|
|
#include "MovieManager.h"
|
2017-04-28 19:54:58 -04:00
|
|
|
#include "RewindManager.h"
|
2017-05-06 15:27:48 -04:00
|
|
|
#include "SaveStateManager.h"
|
2017-06-28 19:00:08 -04:00
|
|
|
#include "HdPackBuilder.h"
|
2017-08-19 16:46:57 -04:00
|
|
|
#include "HdAudioDevice.h"
|
2017-11-19 23:08:23 -05:00
|
|
|
#include "FDS.h"
|
|
|
|
#include "SystemActionManager.h"
|
|
|
|
#include "FdsSystemActionManager.h"
|
|
|
|
#include "VsSystemActionManager.h"
|
2017-11-24 21:38:12 -05:00
|
|
|
#include "FamilyBasicDataRecorder.h"
|
2017-11-19 23:08:23 -05:00
|
|
|
#include "IBarcodeReader.h"
|
|
|
|
#include "IBattery.h"
|
|
|
|
#include "KeyManager.h"
|
|
|
|
#include "BatteryManager.h"
|
2014-06-14 11:27:55 -04:00
|
|
|
|
2015-07-05 22:23:44 -04:00
|
|
|
shared_ptr<Console> Console::Instance(new Console());
|
2014-06-21 19:03:13 -04:00
|
|
|
|
2015-07-05 22:23:44 -04:00
|
|
|
Console::Console()
|
2014-06-14 11:27:55 -04:00
|
|
|
{
|
2016-12-11 10:56:23 -05:00
|
|
|
_resetRequested = false;
|
2014-07-09 18:29:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Console::~Console()
|
|
|
|
{
|
2017-04-18 22:39:45 -04:00
|
|
|
MovieManager::Stop();
|
2016-06-05 14:36:20 -04:00
|
|
|
SoundMixer::StopRecording();
|
2014-07-09 18:29:07 -04:00
|
|
|
}
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
shared_ptr<Console> Console::GetInstance()
|
2014-07-09 18:29:07 -04:00
|
|
|
{
|
|
|
|
return Console::Instance;
|
|
|
|
}
|
|
|
|
|
2015-07-20 23:20:41 -04:00
|
|
|
void Console::Release()
|
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
Console::Instance.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::SaveBatteries()
|
|
|
|
{
|
|
|
|
_mapper->SaveBattery();
|
|
|
|
|
|
|
|
shared_ptr<IBattery> device = std::dynamic_pointer_cast<IBattery>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort));
|
|
|
|
if(device) {
|
|
|
|
device->SaveBattery();
|
|
|
|
}
|
2015-07-20 23:20:41 -04:00
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
2014-07-09 18:29:07 -04:00
|
|
|
{
|
2016-06-19 16:55:26 -04:00
|
|
|
SoundMixer::StopAudio();
|
|
|
|
|
2017-05-06 15:27:48 -04:00
|
|
|
if(!_romFilepath.empty() && _mapper) {
|
2016-07-26 19:19:28 -04:00
|
|
|
//Ensure we save any battery file before loading a new game
|
2017-11-19 23:08:23 -05:00
|
|
|
SaveBatteries();
|
2017-05-06 15:27:48 -04:00
|
|
|
|
|
|
|
//Save current game state before loading another one
|
2017-07-30 09:03:54 -04:00
|
|
|
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
|
2016-07-26 19:19:28 -04:00
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
if(romFile.IsValid()) {
|
|
|
|
LoadHdPack(romFile, patchFile);
|
|
|
|
if(patchFile.IsValid()) {
|
|
|
|
if(romFile.ApplyPatch(patchFile)) {
|
2017-11-19 23:08:23 -05:00
|
|
|
MessageManager::DisplayMessage("Patch", "ApplyingPatch", patchFile.GetFileName());
|
2017-07-30 09:03:54 -04:00
|
|
|
} else {
|
|
|
|
//Patch failed
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-30 09:03:54 -04:00
|
|
|
vector<uint8_t> fileData;
|
|
|
|
romFile.ReadFile(fileData);
|
2016-07-26 19:19:28 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
BatteryManager::Initialize(FolderUtilities::GetFilename(romFile.GetFileName(), false));
|
2017-07-30 09:03:54 -04:00
|
|
|
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFile.GetFileName(), fileData);
|
2017-06-28 19:00:08 -04:00
|
|
|
if(mapper) {
|
|
|
|
if(_mapper) {
|
|
|
|
//Send notification only if a game was already running and we successfully loaded the new one
|
2017-11-29 23:24:26 -05:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2015-12-26 17:11:00 -05:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
if(_romFilepath != (string)romFile || _patchFilename != (string)patchFile) {
|
|
|
|
_romFilepath = romFile;
|
|
|
|
_patchFilename = patchFile;
|
|
|
|
|
|
|
|
//Changed game, stop all recordings
|
|
|
|
MovieManager::Stop();
|
|
|
|
SoundMixer::StopRecording();
|
|
|
|
StopRecordingHdPack();
|
|
|
|
}
|
2017-05-25 20:04:49 -04:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_autoSaveManager.reset(new AutoSaveManager());
|
|
|
|
VideoDecoder::GetInstance()->StopThread();
|
2017-07-15 22:52:37 -04:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_mapper = mapper;
|
|
|
|
_memoryManager.reset(new MemoryManager(_mapper));
|
|
|
|
_cpu.reset(new CPU(_memoryManager.get()));
|
2017-11-19 23:08:23 -05:00
|
|
|
_apu.reset(new APU(_memoryManager.get()));
|
|
|
|
|
|
|
|
switch(_mapper->GetGameSystem()) {
|
|
|
|
case GameSystem::FDS: _systemActionManager.reset(new FdsSystemActionManager(Console::GetInstance(), _mapper)); break;
|
|
|
|
case GameSystem::VsUniSystem: _systemActionManager.reset(new VsSystemActionManager(Console::GetInstance())); break;
|
|
|
|
default: _systemActionManager.reset(new SystemActionManager(Console::GetInstance())); break;
|
|
|
|
}
|
2014-06-21 15:43:41 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
if(_mapper->GetGameSystem() == GameSystem::VsUniSystem) {
|
|
|
|
_controlManager.reset(new VsControlManager(_systemActionManager, _mapper->GetMapperControlDevice()));
|
|
|
|
} else {
|
|
|
|
_controlManager.reset(new ControlManager(_systemActionManager, _mapper->GetMapperControlDevice()));
|
|
|
|
}
|
|
|
|
_controlManager->UpdateControlDevices();
|
|
|
|
|
2017-08-19 17:51:36 -04:00
|
|
|
if(_hdData && (!_hdData->Tiles.empty() || !_hdData->Backgrounds.empty())) {
|
2017-11-19 23:08:23 -05:00
|
|
|
_ppu.reset(new HdPpu(_mapper.get(), _controlManager.get(), _hdData->Version));
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(NsfMapper::GetInstance()) {
|
|
|
|
//Disable most of the PPU for NSFs
|
2017-11-19 23:08:23 -05:00
|
|
|
_ppu.reset(new NsfPpu(_mapper.get(), _controlManager.get()));
|
2017-06-28 19:00:08 -04:00
|
|
|
} else {
|
2017-11-19 23:08:23 -05:00
|
|
|
_ppu.reset(new PPU(_mapper.get(), _controlManager.get()));
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2016-01-23 00:52:06 -05:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_memoryManager->RegisterIODevice(_ppu.get());
|
|
|
|
_memoryManager->RegisterIODevice(_apu.get());
|
|
|
|
_memoryManager->RegisterIODevice(_controlManager.get());
|
|
|
|
_memoryManager->RegisterIODevice(_mapper.get());
|
2017-08-19 16:46:57 -04:00
|
|
|
if(_hdData && (!_hdData->BgmFilesById.empty() || !_hdData->SfxFilesById.empty())) {
|
|
|
|
_hdAudioDevice.reset(new HdAudioDevice(_hdData.get()));
|
|
|
|
_memoryManager->RegisterIODevice(_hdAudioDevice.get());
|
|
|
|
}
|
2016-01-28 22:34:23 -05:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_model = NesModel::Auto;
|
|
|
|
UpdateNesModel(false);
|
2016-06-04 08:55:52 -04:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_initialized = true;
|
2017-04-28 19:54:58 -04:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
if(_debugger) {
|
|
|
|
StopDebugger();
|
|
|
|
GetDebugger();
|
|
|
|
}
|
|
|
|
|
|
|
|
ResetComponents(false);
|
2016-07-10 19:15:00 -04:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_rewindManager.reset(new RewindManager());
|
2017-11-19 23:08:23 -05:00
|
|
|
_controlManager->UpdateInputState();
|
2017-06-28 19:00:08 -04:00
|
|
|
|
|
|
|
VideoDecoder::GetInstance()->StartThread();
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
FolderUtilities::AddKnownGameFolder(romFile.GetFolderPath());
|
2017-06-28 19:00:08 -04: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));
|
|
|
|
if(EmulationSettings::GetOverclockRate() != 100) {
|
|
|
|
MessageManager::DisplayMessage("ClockRate", std::to_string(EmulationSettings::GetOverclockRate()) + "%");
|
|
|
|
}
|
|
|
|
return true;
|
2016-06-12 18:11:31 -04:00
|
|
|
}
|
2014-07-10 19:25:35 -04:00
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
//Reset battery source to current game if new game failed to load
|
|
|
|
BatteryManager::Initialize(FolderUtilities::GetFilename(GetRomName(), false));
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
MessageManager::DisplayMessage("Error", "CouldNotLoadFile", romFile.GetFileName());
|
2017-06-28 19:00:08 -04:00
|
|
|
return false;
|
2015-07-05 22:23:44 -04:00
|
|
|
}
|
2014-07-01 12:44:01 -04:00
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
bool Console::LoadROM(VirtualFile romFile, VirtualFile patchFile)
|
2015-12-27 18:41:38 -05:00
|
|
|
{
|
|
|
|
Console::Pause();
|
2017-07-30 09:03:54 -04:00
|
|
|
bool result = Instance->Initialize(romFile, patchFile);
|
2015-07-05 22:23:44 -04:00
|
|
|
Console::Resume();
|
2017-04-23 18:47:28 -04:00
|
|
|
return result;
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
|
|
|
|
2017-04-22 13:19:21 -04:00
|
|
|
bool Console::LoadROM(string romName, HashInfo hashInfo)
|
2014-06-14 11:27:55 -04:00
|
|
|
{
|
2017-08-19 19:40:02 -04:00
|
|
|
string currentRomFilepath = Console::GetRomPath().GetFilePath();
|
2015-07-05 22:23:44 -04:00
|
|
|
if(!currentRomFilepath.empty()) {
|
2017-04-22 13:19:21 -04:00
|
|
|
HashInfo gameHashInfo = Instance->_mapper->GetHashInfo();
|
2017-04-24 18:28:50 -04:00
|
|
|
if(gameHashInfo.Crc32Hash == hashInfo.Crc32Hash || gameHashInfo.Sha1Hash.compare(hashInfo.Sha1Hash) == 0 || gameHashInfo.PrgChrMd5Hash.compare(hashInfo.PrgChrMd5Hash) == 0) {
|
2017-11-19 23:08:23 -05:00
|
|
|
//Current game matches, power cycle game and return
|
|
|
|
Instance->PowerCycle();
|
2015-07-05 22:23:44 -04:00
|
|
|
return true;
|
|
|
|
}
|
2016-02-08 23:34:48 -05:00
|
|
|
}
|
2015-07-05 22:23:44 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
string match = FindMatchingRom(romName, hashInfo);
|
|
|
|
if(!match.empty()) {
|
|
|
|
return Console::LoadROM(match);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
string Console::FindMatchingRom(string romName, HashInfo hashInfo)
|
|
|
|
{
|
|
|
|
VirtualFile currentRom = Console::GetRomPath();
|
|
|
|
if(currentRom.IsValid() && !Console::GetPatchFile().IsValid()) {
|
|
|
|
HashInfo gameHashInfo = Instance->_mapper->GetHashInfo();
|
|
|
|
if(gameHashInfo.Crc32Hash == hashInfo.Crc32Hash || gameHashInfo.Sha1Hash.compare(hashInfo.Sha1Hash) == 0 || gameHashInfo.PrgChrMd5Hash.compare(hashInfo.PrgChrMd5Hash) == 0) {
|
|
|
|
//Current game matches
|
|
|
|
return currentRom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-01 18:45:53 -04:00
|
|
|
string lcRomname = romName;
|
|
|
|
std::transform(lcRomname.begin(), lcRomname.end(), lcRomname.begin(), ::tolower);
|
|
|
|
std::unordered_set<string> validExtensions = { { ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe", "*.7z", "*.zip" } };
|
|
|
|
vector<string> romFiles;
|
2016-12-09 12:49:17 -05:00
|
|
|
for(string folder : FolderUtilities::GetKnownGameFolders()) {
|
2017-09-01 18:45:53 -04:00
|
|
|
vector<string> files = FolderUtilities::GetFilesInFolder(folder, validExtensions, true);
|
|
|
|
romFiles.insert(romFiles.end(), files.begin(), files.end());
|
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
|
2017-09-01 18:45:53 -04:00
|
|
|
string match = RomLoader::FindMatchingRom(romFiles, romName, hashInfo, true);
|
|
|
|
if(!match.empty()) {
|
2017-11-19 23:08:23 -05:00
|
|
|
return match;
|
2015-07-05 22:23:44 -04:00
|
|
|
}
|
|
|
|
|
2016-02-08 23:34:48 -05:00
|
|
|
//Perform slow CRC32 search for ROM
|
2017-09-01 18:45:53 -04:00
|
|
|
match = RomLoader::FindMatchingRom(romFiles, romName, hashInfo, false);
|
|
|
|
if(!match.empty()) {
|
2017-11-19 23:08:23 -05:00
|
|
|
return match;
|
2014-07-09 18:29:07 -04:00
|
|
|
}
|
2016-02-08 23:34:48 -05:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
return "";
|
2014-07-09 18:29:07 -04:00
|
|
|
}
|
|
|
|
|
2017-08-19 19:40:02 -04:00
|
|
|
VirtualFile Console::GetRomPath()
|
2014-07-09 18:29:07 -04:00
|
|
|
{
|
2017-08-19 19:40:02 -04:00
|
|
|
return static_cast<VirtualFile>(Instance->_romFilepath);
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
|
|
|
|
2016-06-17 20:53:05 -04:00
|
|
|
string Console::GetRomName()
|
|
|
|
{
|
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->GetRomName();
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
VirtualFile Console::GetPatchFile()
|
|
|
|
{
|
2017-11-20 19:15:17 -05:00
|
|
|
return Instance ? (VirtualFile)Instance->_patchFilename : VirtualFile();
|
2017-11-19 23:08:23 -05:00
|
|
|
}
|
|
|
|
|
2017-03-04 22:24:41 -05:00
|
|
|
RomFormat Console::GetRomFormat()
|
|
|
|
{
|
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->GetRomFormat();
|
|
|
|
} else {
|
|
|
|
return RomFormat::Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
bool Console::IsChrRam()
|
|
|
|
{
|
|
|
|
if(Instance->_mapper) {
|
|
|
|
return Instance->_mapper->HasChrRam();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
HashInfo Console::GetHashInfo()
|
2016-01-28 20:47:16 -05:00
|
|
|
{
|
2016-06-17 20:53:05 -04:00
|
|
|
if(Instance->_mapper) {
|
2017-07-30 09:03:54 -04:00
|
|
|
return Instance->_mapper->GetHashInfo();
|
2016-06-17 20:53:05 -04:00
|
|
|
} else {
|
2017-07-30 09:03:54 -04:00
|
|
|
return {};
|
2016-06-17 20:53:05 -04:00
|
|
|
}
|
2016-01-28 20:47:16 -05:00
|
|
|
}
|
2016-07-01 23:54:31 -04:00
|
|
|
NesModel Console::GetModel()
|
|
|
|
{
|
|
|
|
return Instance->_model;
|
|
|
|
}
|
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
shared_ptr<SystemActionManager> Console::GetSystemActionManager()
|
|
|
|
{
|
|
|
|
return _systemActionManager;
|
|
|
|
}
|
|
|
|
|
2017-05-02 23:31:06 -04:00
|
|
|
void Console::PowerCycle()
|
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
if(_initialized && !_romFilepath.empty()) {
|
|
|
|
LoadROM(_romFilepath, _patchFilename);
|
2017-05-02 23:31:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-05 19:35:38 -04:00
|
|
|
void Console::Reset(bool softReset)
|
2014-06-14 11:27:55 -04:00
|
|
|
{
|
2015-07-05 22:23:44 -04:00
|
|
|
if(Instance->_initialized) {
|
2017-11-19 23:08:23 -05:00
|
|
|
if(softReset) {
|
|
|
|
if(EmulationSettings::CheckFlag(EmulationFlags::DisablePpuReset)) {
|
|
|
|
//Allow mid-frame resets to allow the PPU to get out-of-sync
|
|
|
|
RequestReset();
|
|
|
|
} else {
|
|
|
|
Instance->_systemActionManager->Reset();
|
2017-02-24 23:06:13 -05:00
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
} else {
|
|
|
|
Instance->_systemActionManager->PowerCycle();
|
2015-12-26 17:11:00 -05:00
|
|
|
}
|
2014-07-01 12:44:01 -04:00
|
|
|
}
|
2014-06-14 11:27:55 -04:00
|
|
|
}
|
|
|
|
|
2014-06-25 13:30:02 -04:00
|
|
|
void Console::ResetComponents(bool softReset)
|
2014-06-24 02:47:32 -04:00
|
|
|
{
|
2016-07-17 14:07:22 -04:00
|
|
|
_memoryManager->Reset(softReset);
|
2017-02-24 23:06:13 -05:00
|
|
|
if(!EmulationSettings::CheckFlag(EmulationFlags::DisablePpuReset) || !softReset) {
|
|
|
|
_ppu->Reset();
|
|
|
|
}
|
2015-07-19 01:30:13 -04:00
|
|
|
_apu->Reset(softReset);
|
2017-04-20 21:58:35 -04:00
|
|
|
_cpu->Reset(softReset, _model);
|
2016-06-21 22:13:26 -04:00
|
|
|
_controlManager->Reset(softReset);
|
2016-07-10 18:22:37 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
KeyManager::UpdateDevices();
|
2015-08-24 20:27:07 -04:00
|
|
|
|
2017-08-30 18:31:27 -04:00
|
|
|
MessageManager::SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
|
2017-10-03 18:40:26 -04:00
|
|
|
|
|
|
|
if(softReset) {
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
if(debugger) {
|
2017-10-05 20:48:18 -04:00
|
|
|
debugger->ResetCounters();
|
2017-10-03 18:40:26 -04:00
|
|
|
debugger->ProcessEvent(EventType::Reset);
|
|
|
|
}
|
|
|
|
}
|
2014-06-24 02:47:32 -04:00
|
|
|
}
|
|
|
|
|
2014-06-20 21:48:55 -04:00
|
|
|
void Console::Stop()
|
|
|
|
{
|
|
|
|
_stop = true;
|
2016-07-31 14:31:44 -04:00
|
|
|
|
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
if(debugger) {
|
2017-08-21 23:11:14 -04:00
|
|
|
debugger->Suspend();
|
2015-08-21 22:42:44 -04:00
|
|
|
}
|
2015-07-05 19:12:41 -04:00
|
|
|
_stopLock.Acquire();
|
|
|
|
_stopLock.Release();
|
2014-06-21 19:03:13 -04:00
|
|
|
}
|
|
|
|
|
2014-07-01 12:44:01 -04:00
|
|
|
void Console::Pause()
|
|
|
|
{
|
2016-07-31 14:31:44 -04:00
|
|
|
shared_ptr<Debugger> debugger = Console::Instance->_debugger;
|
|
|
|
if(debugger) {
|
2015-08-21 22:42:44 -04:00
|
|
|
//Make sure debugger resumes if we try to pause the emu, otherwise we will get deadlocked.
|
2016-07-31 14:31:44 -04:00
|
|
|
debugger->Suspend();
|
2015-08-21 22:42:44 -04:00
|
|
|
}
|
2015-07-05 22:23:44 -04:00
|
|
|
Console::Instance->_pauseLock.Acquire();
|
|
|
|
//Spin wait until emu pauses
|
|
|
|
Console::Instance->_runLock.Acquire();
|
2014-07-01 12:44:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::Resume()
|
|
|
|
{
|
2015-07-05 22:23:44 -04:00
|
|
|
Console::Instance->_runLock.Release();
|
|
|
|
Console::Instance->_pauseLock.Release();
|
2016-06-04 08:55:52 -04:00
|
|
|
|
2016-07-31 14:31:44 -04:00
|
|
|
shared_ptr<Debugger> debugger = Console::Instance->_debugger;
|
|
|
|
if(debugger) {
|
2016-06-04 08:55:52 -04:00
|
|
|
//Make sure debugger resumes if we try to pause the emu, otherwise we will get deadlocked.
|
2016-07-31 14:31:44 -04:00
|
|
|
debugger->Resume();
|
2016-06-04 08:55:52 -04:00
|
|
|
}
|
2014-07-01 12:44:01 -04:00
|
|
|
}
|
|
|
|
|
2014-06-14 11:27:55 -04:00
|
|
|
void Console::Run()
|
|
|
|
{
|
2014-06-21 15:43:41 -04:00
|
|
|
Timer clockTimer;
|
2015-07-21 23:05:27 -04:00
|
|
|
double targetTime;
|
|
|
|
uint32_t lastFrameNumber = -1;
|
2016-08-31 20:54:38 -04:00
|
|
|
|
|
|
|
_autoSaveManager.reset(new AutoSaveManager());
|
2015-07-14 21:51:39 -04:00
|
|
|
|
2015-07-05 19:05:33 -04:00
|
|
|
_runLock.Acquire();
|
|
|
|
_stopLock.Acquire();
|
2014-07-06 19:54:47 -04:00
|
|
|
|
2017-10-07 13:01:42 -04:00
|
|
|
_emulationThreadId = std::this_thread::get_id();
|
|
|
|
|
2016-07-10 19:15:00 -04:00
|
|
|
targetTime = GetFrameDelay();
|
2015-07-21 23:05:27 -04:00
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
VideoDecoder::GetInstance()->StartThread();
|
2016-08-29 21:07:52 -04:00
|
|
|
|
|
|
|
PlatformUtilities::DisableScreensaver();
|
2017-05-06 15:27:48 -04:00
|
|
|
|
2017-05-22 11:50:21 -04:00
|
|
|
UpdateNesModel(true);
|
|
|
|
|
2017-05-06 15:27:48 -04:00
|
|
|
bool crashed = false;
|
2017-12-04 00:09:11 -05:00
|
|
|
try {
|
|
|
|
while(true) {
|
2016-02-11 22:59:31 -05:00
|
|
|
_cpu->Exec();
|
2017-02-24 23:06:13 -05:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
if(_resetRequested) {
|
|
|
|
//Used by NSF player to reset console after changing track
|
|
|
|
//Also used with DisablePpuReset option to reset mid-frame
|
|
|
|
MovieManager::Stop();
|
|
|
|
ResetComponents(true);
|
|
|
|
_resetRequested = false;
|
|
|
|
}
|
2016-12-23 13:56:45 -05:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
uint32_t currentFrameNumber = PPU::GetFrameCount();
|
|
|
|
if(currentFrameNumber != lastFrameNumber) {
|
|
|
|
_rewindManager->ProcessEndOfFrame();
|
|
|
|
EmulationSettings::DisableOverclocking(_disableOcNextFrame || NsfMapper::GetInstance());
|
|
|
|
_disableOcNextFrame = false;
|
2014-07-06 19:54:47 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
//Sleep until we're ready to start the next frame
|
|
|
|
clockTimer.WaitUntil(targetTime);
|
2014-07-01 12:44:01 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
if(!_pauseLock.IsFree()) {
|
|
|
|
//Need to temporarely pause the emu (to save/load a state, etc.)
|
|
|
|
_runLock.Release();
|
2014-07-06 19:54:47 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
//Spin wait until we are allowed to start again
|
|
|
|
_pauseLock.WaitForRelease();
|
2016-09-04 19:04:52 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
_runLock.Acquire();
|
2014-07-09 21:48:54 -04:00
|
|
|
}
|
2016-12-14 20:48:47 -05:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
bool paused = EmulationSettings::IsPaused();
|
|
|
|
if(paused && !_stop) {
|
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
|
|
|
|
|
|
|
|
//Prevent audio from looping endlessly while game is paused
|
|
|
|
SoundMixer::StopAudio();
|
|
|
|
|
|
|
|
_runLock.Release();
|
|
|
|
|
|
|
|
PlatformUtilities::EnableScreensaver();
|
|
|
|
while(paused && !_stop) {
|
|
|
|
//Sleep until emulation is resumed
|
|
|
|
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
|
|
|
|
paused = EmulationSettings::IsPaused();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(EmulationSettings::CheckFlag(EmulationFlags::DebuggerWindowEnabled)) {
|
|
|
|
//Prevent pausing when debugger is active
|
|
|
|
EmulationSettings::ClearFlags(EmulationFlags::Paused);
|
|
|
|
}
|
|
|
|
|
|
|
|
PlatformUtilities::DisableScreensaver();
|
|
|
|
_runLock.Acquire();
|
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
|
2016-12-14 20:48:47 -05:00
|
|
|
}
|
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
_systemActionManager->ProcessSystemActions();
|
2015-07-21 23:05:27 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
if(debugger) {
|
|
|
|
debugger->ProcessEvent(EventType::StartFrame);
|
|
|
|
}
|
2017-09-01 14:57:02 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
//Get next target time, and adjust based on whether we are ahead or behind
|
|
|
|
double timeLag = EmulationSettings::GetEmulationSpeed() == 0 ? 0 : clockTimer.GetElapsedMS() - targetTime;
|
|
|
|
UpdateNesModel(true);
|
|
|
|
targetTime = GetFrameDelay();
|
2016-07-10 19:15:00 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
clockTimer.Reset();
|
|
|
|
targetTime -= timeLag;
|
|
|
|
if(targetTime < 0) {
|
|
|
|
targetTime = 0;
|
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
lastFrameNumber = PPU::GetFrameCount();
|
|
|
|
|
|
|
|
if(_stop) {
|
|
|
|
_stop = false;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-06 19:54:47 -04:00
|
|
|
}
|
|
|
|
}
|
2017-12-04 00:09:11 -05:00
|
|
|
} catch(const std::runtime_error &ex) {
|
|
|
|
crashed = true;
|
|
|
|
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
2014-06-14 18:20:56 -04:00
|
|
|
}
|
2017-05-06 15:27:48 -04:00
|
|
|
|
|
|
|
if(!crashed) {
|
2017-07-30 09:03:54 -04:00
|
|
|
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
|
2017-05-06 15:27:48 -04:00
|
|
|
}
|
|
|
|
|
2017-04-28 19:54:58 -04:00
|
|
|
_rewindManager.reset();
|
2017-08-09 17:44:52 -04:00
|
|
|
StopRecordingHdPack();
|
2016-01-14 19:33:16 -05:00
|
|
|
SoundMixer::StopAudio();
|
2017-04-18 22:39:45 -04:00
|
|
|
MovieManager::Stop();
|
2016-06-05 14:36:20 -04:00
|
|
|
SoundMixer::StopRecording();
|
2016-08-29 21:07:52 -04:00
|
|
|
PlatformUtilities::EnableScreensaver();
|
2015-08-30 21:04:21 -04:00
|
|
|
|
2016-08-31 20:54:38 -04:00
|
|
|
_autoSaveManager.reset();
|
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
VideoDecoder::GetInstance()->StopThread();
|
|
|
|
|
2017-05-30 07:36:55 -04:00
|
|
|
EmulationSettings::ClearFlags(EmulationFlags::Paused);
|
|
|
|
|
2016-01-31 00:41:33 -05:00
|
|
|
_initialized = false;
|
2017-07-15 22:52:37 -04:00
|
|
|
|
|
|
|
if(!_romFilepath.empty() && _mapper) {
|
|
|
|
//Ensure we save any battery file before unloading anything
|
2017-11-19 23:08:23 -05:00
|
|
|
SaveBatteries();
|
2017-07-15 22:52:37 -04:00
|
|
|
}
|
|
|
|
|
2016-01-28 22:34:23 -05:00
|
|
|
_romFilepath = "";
|
2017-05-06 15:27:48 -04:00
|
|
|
_mapper.reset();
|
|
|
|
_ppu.reset();
|
|
|
|
_cpu.reset();
|
|
|
|
_memoryManager.reset();
|
|
|
|
_controlManager.reset();
|
2016-01-28 22:34:23 -05:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
_hdPackBuilder.reset();
|
|
|
|
_hdData.reset();
|
|
|
|
|
2015-07-05 19:05:33 -04:00
|
|
|
_stopLock.Release();
|
|
|
|
_runLock.Release();
|
2017-08-05 14:24:44 -04:00
|
|
|
|
2017-10-07 13:01:42 -04:00
|
|
|
_emulationThreadId = std::thread::id();
|
|
|
|
|
2017-08-05 14:24:44 -04:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
|
2017-10-05 21:40:25 -04:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::EmulationStopped);
|
2014-06-25 21:52:37 -04:00
|
|
|
}
|
|
|
|
|
2016-02-14 12:58:35 -05:00
|
|
|
bool Console::IsRunning()
|
|
|
|
{
|
2017-10-03 18:18:29 -04:00
|
|
|
return !Instance->_stopLock.IsFree();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::IsPaused()
|
|
|
|
{
|
2017-10-05 20:48:18 -04:00
|
|
|
return _runLock.IsFree() || !_pauseLock.IsFree();
|
2016-02-14 12:58:35 -05:00
|
|
|
}
|
|
|
|
|
2016-07-10 19:15:00 -04:00
|
|
|
void Console::UpdateNesModel(bool sendNotification)
|
2015-07-21 23:05:27 -04:00
|
|
|
{
|
2016-02-05 23:14:27 -05:00
|
|
|
bool configChanged = false;
|
|
|
|
if(EmulationSettings::NeedControllerUpdate()) {
|
|
|
|
_controlManager->UpdateControlDevices();
|
|
|
|
configChanged = true;
|
|
|
|
}
|
|
|
|
|
2015-07-21 23:05:27 -04:00
|
|
|
NesModel model = EmulationSettings::GetNesModel();
|
|
|
|
if(model == NesModel::Auto) {
|
2016-06-15 21:59:34 -04: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-21 23:05:27 -04:00
|
|
|
}
|
2016-02-05 23:14:27 -05:00
|
|
|
if(_model != model) {
|
|
|
|
_model = model;
|
|
|
|
configChanged = true;
|
2016-07-10 19:15:00 -04:00
|
|
|
|
|
|
|
if(sendNotification) {
|
|
|
|
MessageManager::DisplayMessage("Region", model == NesModel::PAL ? "PAL" : (model == NesModel::Dendy ? "Dendy" : "NTSC"));
|
|
|
|
}
|
2016-02-05 23:14:27 -05:00
|
|
|
}
|
2016-07-10 19:15:00 -04: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 00:52:06 -05:00
|
|
|
double frameDelay;
|
2015-08-24 20:27:07 -04:00
|
|
|
if(emulationSpeed == 0) {
|
2015-08-23 20:24:24 -04:00
|
|
|
frameDelay = 0;
|
|
|
|
} else {
|
2016-01-30 19:33:32 -05:00
|
|
|
//60.1fps (NTSC), 50.01fps (PAL/Dendy)
|
2016-07-10 19:15:00 -04:00
|
|
|
switch(_model) {
|
2016-06-02 23:56:11 -04:00
|
|
|
default:
|
2017-09-29 22:09:00 -04:00
|
|
|
case NesModel::NTSC: frameDelay = EmulationSettings::CheckFlag(EmulationFlags::IntegerFpsMode) ? 16.6666666666666666667 : 16.63926405550947; break;
|
2016-01-30 19:33:32 -05:00
|
|
|
case NesModel::PAL:
|
2017-09-29 22:09:00 -04:00
|
|
|
case NesModel::Dendy: frameDelay = EmulationSettings::CheckFlag(EmulationFlags::IntegerFpsMode) ? 20 : 19.99720920217466; break;
|
2016-01-30 19:33:32 -05:00
|
|
|
}
|
2015-08-24 20:27:07 -04:00
|
|
|
frameDelay /= (double)emulationSpeed / 100.0;
|
2015-08-23 20:24:24 -04:00
|
|
|
}
|
2015-08-24 20:27:07 -04:00
|
|
|
|
2016-01-23 00:52:06 -05:00
|
|
|
return frameDelay;
|
2015-07-21 23:05:27 -04:00
|
|
|
}
|
|
|
|
|
2014-07-01 12:44:01 -04:00
|
|
|
void Console::SaveState(ostream &saveStream)
|
2014-06-25 21:52:37 -04:00
|
|
|
{
|
2015-07-05 22:23:44 -04:00
|
|
|
if(Instance->_initialized) {
|
2014-07-06 19:54:47 -04:00
|
|
|
Instance->_cpu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_ppu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_memoryManager->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_apu->SaveSnapshot(&saveStream);
|
|
|
|
Instance->_controlManager->SaveSnapshot(&saveStream);
|
2016-06-11 16:08:16 -04:00
|
|
|
Instance->_mapper->SaveSnapshot(&saveStream);
|
2017-08-20 19:03:16 -04:00
|
|
|
if(Instance->_hdAudioDevice) {
|
|
|
|
Instance->_hdAudioDevice->SaveSnapshot(&saveStream);
|
|
|
|
} else {
|
|
|
|
Snapshotable::WriteEmptyBlock(&saveStream);
|
|
|
|
}
|
2014-07-06 19:54:47 -04:00
|
|
|
}
|
2014-07-01 12:44:01 -04:00
|
|
|
}
|
2014-06-25 21:52:37 -04:00
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
void Console::LoadState(istream &loadStream, uint32_t stateVersion)
|
2014-07-01 12:44:01 -04:00
|
|
|
{
|
2015-07-05 22:23:44 -04:00
|
|
|
if(Instance->_initialized) {
|
2017-11-19 23:08:23 -05:00
|
|
|
Instance->_cpu->LoadSnapshot(&loadStream, stateVersion);
|
|
|
|
Instance->_ppu->LoadSnapshot(&loadStream, stateVersion);
|
|
|
|
Instance->_memoryManager->LoadSnapshot(&loadStream, stateVersion);
|
|
|
|
Instance->_apu->LoadSnapshot(&loadStream, stateVersion);
|
|
|
|
Instance->_controlManager->LoadSnapshot(&loadStream, stateVersion);
|
|
|
|
Instance->_mapper->LoadSnapshot(&loadStream, stateVersion);
|
2017-08-20 19:03:16 -04:00
|
|
|
if(Instance->_hdAudioDevice) {
|
2017-11-19 23:08:23 -05:00
|
|
|
Instance->_hdAudioDevice->LoadSnapshot(&loadStream, stateVersion);
|
2017-08-20 19:03:16 -04:00
|
|
|
} else {
|
|
|
|
Snapshotable::SkipBlock(&loadStream);
|
|
|
|
}
|
2014-07-09 21:11:02 -04:00
|
|
|
|
2017-10-05 20:48:18 -04:00
|
|
|
shared_ptr<Debugger> debugger = Instance->_debugger;
|
|
|
|
if(debugger) {
|
|
|
|
debugger->ResetCounters();
|
|
|
|
}
|
|
|
|
|
2015-07-01 23:17:14 -04:00
|
|
|
MessageManager::SendNotification(ConsoleNotificationType::StateLoaded);
|
2014-07-06 19:54:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::LoadState(uint8_t *buffer, uint32_t bufferSize)
|
|
|
|
{
|
2017-04-28 19:54:58 -04:00
|
|
|
//Send any unprocessed sound to the SoundMixer - needed for rewind
|
|
|
|
Instance->_apu->EndFrame();
|
|
|
|
|
2014-07-06 19:54:47 -04:00
|
|
|
stringstream stream;
|
|
|
|
stream.write((char*)buffer, bufferSize);
|
|
|
|
stream.seekg(0, ios::beg);
|
|
|
|
LoadState(stream);
|
2014-06-25 21:52:37 -04:00
|
|
|
}
|
|
|
|
|
2016-08-25 19:02:33 -04:00
|
|
|
std::shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
2015-06-24 19:26:19 -04:00
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
shared_ptr<Debugger> debugger = _debugger;
|
|
|
|
if(!debugger && autoStart) {
|
|
|
|
debugger.reset(new Debugger(Console::Instance, _cpu, _ppu, _apu, _memoryManager, _mapper));
|
|
|
|
_debugger = debugger;
|
2015-08-21 22:42:44 -04:00
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
return debugger;
|
2015-06-24 19:26:19 -04:00
|
|
|
}
|
2015-08-21 22:42:44 -04:00
|
|
|
|
|
|
|
void Console::StopDebugger()
|
|
|
|
{
|
|
|
|
_debugger.reset();
|
2016-02-05 23:14:27 -05:00
|
|
|
}
|
|
|
|
|
2016-06-25 20:46:54 -04:00
|
|
|
void Console::RequestReset()
|
|
|
|
{
|
|
|
|
Instance->_resetRequested = true;
|
|
|
|
}
|
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
std::thread::id Console::GetEmulationThreadId()
|
2016-07-10 18:22:37 -04:00
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
return Instance->_emulationThreadId;
|
2016-07-10 18:22:37 -04:00
|
|
|
}
|
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
uint32_t Console::GetLagCounter()
|
2017-10-07 13:01:42 -04:00
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
return Instance->_controlManager->GetLagCounter();
|
2017-10-07 13:01:42 -04:00
|
|
|
}
|
|
|
|
|
2016-07-10 18:22:37 -04:00
|
|
|
void Console::ResetLagCounter()
|
|
|
|
{
|
2017-11-19 23:08:23 -05:00
|
|
|
Console::Pause();
|
|
|
|
Instance->_controlManager->ResetLagCounter();
|
|
|
|
Console::Reset();
|
2016-11-26 18:04:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::IsDebuggerAttached()
|
|
|
|
{
|
|
|
|
return (bool)Instance->_debugger;
|
2016-12-23 13:56:45 -05:00
|
|
|
}
|
|
|
|
|
2017-04-29 16:11:22 -04:00
|
|
|
void Console::SetNextFrameOverclockStatus(bool disabled)
|
2016-12-23 13:56:45 -05:00
|
|
|
{
|
2017-04-29 16:11:22 -04:00
|
|
|
Instance->_disableOcNextFrame = disabled;
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
|
|
|
HdPackData* Console::GetHdData()
|
|
|
|
{
|
|
|
|
return Instance->_hdData.get();
|
|
|
|
}
|
|
|
|
|
2017-08-19 17:51:36 -04:00
|
|
|
bool Console::IsHdPpu()
|
|
|
|
{
|
|
|
|
return Instance->_hdData && std::dynamic_pointer_cast<HdPpu>(Instance->_ppu) != nullptr;
|
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
void Console::LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
|
|
|
_hdData.reset();
|
2017-08-20 19:03:16 -04:00
|
|
|
_hdAudioDevice.reset();
|
2017-06-28 19:00:08 -04:00
|
|
|
if(EmulationSettings::CheckFlag(EmulationFlags::UseHdPacks)) {
|
|
|
|
_hdData.reset(new HdPackData());
|
2017-07-30 09:03:54 -04:00
|
|
|
if(!HdPackLoader::LoadHdNesPack(romFile, *_hdData.get())) {
|
2017-06-28 19:00:08 -04:00
|
|
|
_hdData.reset();
|
|
|
|
} else {
|
2017-07-30 09:03:54 -04:00
|
|
|
auto result = _hdData->PatchesByHash.find(romFile.GetSha1Hash());
|
2017-06-28 19:00:08 -04:00
|
|
|
if(result != _hdData->PatchesByHash.end()) {
|
2017-07-30 09:03:54 -04:00
|
|
|
patchFile = result->second;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::StartRecordingHdPack(string saveFolder, ScaleFilterType filterType, uint32_t scale, uint32_t flags, uint32_t chrRamBankSize)
|
|
|
|
{
|
|
|
|
Console::Pause();
|
|
|
|
std::stringstream saveState;
|
|
|
|
Instance->SaveState(saveState);
|
|
|
|
|
|
|
|
Instance->_hdPackBuilder.reset();
|
|
|
|
Instance->_hdPackBuilder.reset(new HdPackBuilder(saveFolder, filterType, scale, flags, chrRamBankSize, !Instance->_mapper->HasChrRom()));
|
|
|
|
|
|
|
|
Instance->_memoryManager->UnregisterIODevice(Instance->_ppu.get());
|
|
|
|
Instance->_ppu.reset();
|
2017-11-19 23:08:23 -05:00
|
|
|
Instance->_ppu.reset(new HdBuilderPpu(Instance->_mapper.get(), Instance->_controlManager.get(), Instance->_hdPackBuilder.get(), chrRamBankSize));
|
2017-06-28 19:00:08 -04:00
|
|
|
Instance->_memoryManager->RegisterIODevice(Instance->_ppu.get());
|
|
|
|
|
|
|
|
Instance->LoadState(saveState);
|
|
|
|
Console::Resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::StopRecordingHdPack()
|
|
|
|
{
|
2017-08-09 17:44:52 -04:00
|
|
|
if(Instance->_hdPackBuilder) {
|
|
|
|
Console::Pause();
|
|
|
|
std::stringstream saveState;
|
|
|
|
Instance->SaveState(saveState);
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-08-09 17:44:52 -04:00
|
|
|
Instance->_memoryManager->UnregisterIODevice(Instance->_ppu.get());
|
|
|
|
Instance->_ppu.reset();
|
2017-11-19 23:08:23 -05:00
|
|
|
Instance->_ppu.reset(new PPU(Instance->_mapper.get(), Instance->_controlManager.get()));
|
2017-08-09 17:44:52 -04:00
|
|
|
Instance->_memoryManager->RegisterIODevice(Instance->_ppu.get());
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-08-09 17:44:52 -04:00
|
|
|
Instance->_hdPackBuilder.reset();
|
|
|
|
|
|
|
|
Instance->LoadState(saveState);
|
|
|
|
Console::Resume();
|
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ConsoleFeatures Console::GetAvailableFeatures()
|
|
|
|
{
|
|
|
|
ConsoleFeatures features = ConsoleFeatures::None;
|
|
|
|
if(_mapper) {
|
|
|
|
features = (ConsoleFeatures)((int)features | (int)_mapper->GetAvailableFeatures());
|
|
|
|
|
|
|
|
if(dynamic_cast<VsControlManager*>(_controlManager.get())) {
|
|
|
|
features = (ConsoleFeatures)((int)features | (int)ConsoleFeatures::VsSystem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(std::dynamic_pointer_cast<IBarcodeReader>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort))) {
|
|
|
|
features = (ConsoleFeatures)((int)features | (int)ConsoleFeatures::BarcodeReader);
|
|
|
|
}
|
2017-11-24 21:38:12 -05:00
|
|
|
|
|
|
|
if(std::dynamic_pointer_cast<FamilyBasicDataRecorder>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort2))) {
|
|
|
|
features = (ConsoleFeatures)((int)features | (int)ConsoleFeatures::TapeRecorder);
|
|
|
|
}
|
2017-11-19 23:08:23 -05:00
|
|
|
}
|
|
|
|
return features;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::InputBarcode(uint64_t barcode, uint32_t digitCount)
|
|
|
|
{
|
|
|
|
shared_ptr<IBarcodeReader> barcodeReader = std::dynamic_pointer_cast<IBarcodeReader>(_mapper->GetMapperControlDevice());
|
|
|
|
if(barcodeReader) {
|
|
|
|
barcodeReader->InputBarcode(barcode, digitCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
barcodeReader = std::dynamic_pointer_cast<IBarcodeReader>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort));
|
|
|
|
if(barcodeReader) {
|
|
|
|
barcodeReader->InputBarcode(barcode, digitCount);
|
|
|
|
}
|
2017-11-24 21:38:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::LoadTapeFile(string filepath)
|
|
|
|
{
|
|
|
|
shared_ptr<FamilyBasicDataRecorder> dataRecorder = std::dynamic_pointer_cast<FamilyBasicDataRecorder>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort2));
|
|
|
|
if(dataRecorder) {
|
|
|
|
Console::Pause();
|
|
|
|
dataRecorder->LoadFromFile(filepath);
|
|
|
|
Console::Resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::StartRecordingTapeFile(string filepath)
|
|
|
|
{
|
|
|
|
shared_ptr<FamilyBasicDataRecorder> dataRecorder = std::dynamic_pointer_cast<FamilyBasicDataRecorder>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort2));
|
|
|
|
if(dataRecorder) {
|
|
|
|
Console::Pause();
|
|
|
|
dataRecorder->StartRecording(filepath);
|
|
|
|
Console::Resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::StopRecordingTapeFile()
|
|
|
|
{
|
|
|
|
shared_ptr<FamilyBasicDataRecorder> dataRecorder = std::dynamic_pointer_cast<FamilyBasicDataRecorder>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort2));
|
|
|
|
if(dataRecorder) {
|
|
|
|
Console::Pause();
|
|
|
|
dataRecorder->StopRecording();
|
|
|
|
Console::Resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Console::IsRecordingTapeFile()
|
|
|
|
{
|
|
|
|
shared_ptr<FamilyBasicDataRecorder> dataRecorder = std::dynamic_pointer_cast<FamilyBasicDataRecorder>(_controlManager->GetControlDevice(BaseControlDevice::ExpDevicePort2));
|
|
|
|
if(dataRecorder) {
|
|
|
|
return dataRecorder->IsRecording();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|