Cocoa Port: Continue refactoring the emulation execution loop code to be less port-dependent.

This commit is contained in:
rogerman 2017-08-29 15:14:24 -07:00
parent 3bf295f4ce
commit abebaebdef
5 changed files with 644 additions and 511 deletions

View File

@ -15,6 +15,9 @@
along with the this software. If not, see <http://www.gnu.org/licenses/>. along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <mach/mach.h>
#include <mach/mach_time.h>
#include "NDSSystem.h" #include "NDSSystem.h"
#include "ClientExecutionControl.h" #include "ClientExecutionControl.h"
@ -22,11 +25,25 @@
ClientExecutionControl::ClientExecutionControl() ClientExecutionControl::ClientExecutionControl()
{ {
_newSettingsPendingOnReset = true;
_newSettingsPendingOnExecutionLoopStart = true;
_newSettingsPendingOnNDSExec = true;
_needResetFramesToSkip = false;
_frameTime = 0.0;
_framesToSkip = 0;
_prevExecBehavior = ExecutionBehavior_Pause;
_settingsPending.cpuEngineID = CPUEmulationEngineID_Interpreter; _settingsPending.cpuEngineID = CPUEmulationEngineID_Interpreter;
_settingsPending.JITMaxBlockSize = 12; _settingsPending.JITMaxBlockSize = 12;
_settingsPending.filePathARM9BIOS = std::string();
_settingsPending.filePathARM7BIOS = std::string();
_settingsPending.filePathFirmware = std::string();
_settingsPending.enableAdvancedBusLevelTiming = true; _settingsPending.enableAdvancedBusLevelTiming = true;
_settingsPending.enableRigorous3DRenderingTiming = false; _settingsPending.enableRigorous3DRenderingTiming = false;
_settingsPending.enableGameSpecificHacks = true;
_settingsPending.enableExternalBIOS = false; _settingsPending.enableExternalBIOS = false;
_settingsPending.enableBIOSInterrupts = false; _settingsPending.enableBIOSInterrupts = false;
_settingsPending.enableBIOSPatchDelayLoop = false; _settingsPending.enableBIOSPatchDelayLoop = false;
@ -35,31 +52,30 @@ ClientExecutionControl::ClientExecutionControl()
_settingsPending.enableDebugConsole = false; _settingsPending.enableDebugConsole = false;
_settingsPending.enableEnsataEmulation = false; _settingsPending.enableEnsataEmulation = false;
_settingsPending.executionSpeed = 1.0f; _settingsPending.enableExecutionSpeedLimiter = true;
_settingsPending.executionSpeed = SPEED_SCALAR_NORMAL;
_settingsPending.enableFrameSkip = true; _settingsPending.enableFrameSkip = true;
_settingsPending.framesToSkip = 0;
_settingsPending.frameJumpTarget = 0; _settingsPending.frameJumpTarget = 0;
_settingsPending.execBehavior = ExecutionBehavior_Pause; _settingsPending.execBehavior = ExecutionBehavior_Pause;
_settingsPending.jumpBehavior = FrameJumpBehavior_Forward; _settingsPending.jumpBehavior = FrameJumpBehavior_Forward;
_settingsApplied = _settingsPending;
_settingsApplied.filePathARM9BIOS = std::string();
_settingsApplied.filePathARM7BIOS = std::string();
_settingsApplied.filePathFirmware = std::string();
pthread_mutex_init(&_mutexSettingsPendingOnReset, NULL); pthread_mutex_init(&_mutexSettingsPendingOnReset, NULL);
pthread_mutex_init(&_mutexSettingsApplyOnReset, NULL);
pthread_mutex_init(&_mutexSettingsPendingOnExecutionLoopStart, NULL); pthread_mutex_init(&_mutexSettingsPendingOnExecutionLoopStart, NULL);
pthread_mutex_init(&_mutexSettingsApplyOnExecutionLoopStart, NULL);
pthread_mutex_init(&_mutexSettingsPendingOnNDSExec, NULL); pthread_mutex_init(&_mutexSettingsPendingOnNDSExec, NULL);
pthread_mutex_init(&_mutexSettingsApplyOnNDSExec, NULL);
} }
ClientExecutionControl::~ClientExecutionControl() ClientExecutionControl::~ClientExecutionControl()
{ {
pthread_mutex_destroy(&this->_mutexSettingsPendingOnReset); pthread_mutex_destroy(&this->_mutexSettingsPendingOnReset);
pthread_mutex_destroy(&this->_mutexSettingsApplyOnReset);
pthread_mutex_destroy(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_destroy(&this->_mutexSettingsPendingOnExecutionLoopStart);
pthread_mutex_destroy(&this->_mutexSettingsApplyOnExecutionLoopStart);
pthread_mutex_destroy(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_destroy(&this->_mutexSettingsPendingOnNDSExec);
pthread_mutex_destroy(&this->_mutexSettingsApplyOnNDSExec);
} }
CPUEmulationEngineID ClientExecutionControl::GetCPUEmulationEngineID() CPUEmulationEngineID ClientExecutionControl::GetCPUEmulationEngineID()
@ -73,8 +89,14 @@ CPUEmulationEngineID ClientExecutionControl::GetCPUEmulationEngineID()
void ClientExecutionControl::SetCPUEmulationEngineID(CPUEmulationEngineID engineID) void ClientExecutionControl::SetCPUEmulationEngineID(CPUEmulationEngineID engineID)
{ {
#if !defined(__i386__) && !defined(__x86_64__)
engineID = CPUEmulationEngine_Interpreter;
#endif
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset); pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
this->_settingsPending.cpuEngineID = engineID; this->_settingsPending.cpuEngineID = engineID;
this->_newSettingsPendingOnReset = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset); pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
} }
@ -100,6 +122,86 @@ void ClientExecutionControl::SetJITMaxBlockSize(uint8_t blockSize)
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset); pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
this->_settingsPending.JITMaxBlockSize = blockSize; this->_settingsPending.JITMaxBlockSize = blockSize;
this->_newSettingsPendingOnReset = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
}
const char* ClientExecutionControl::GetARM9ImagePath()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
const char *filePath = this->_settingsPending.filePathARM9BIOS.c_str();
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
return filePath;
}
void ClientExecutionControl::SetARM9ImagePath(const char *filePath)
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
if (filePath == NULL)
{
this->_settingsPending.filePathARM9BIOS.clear();
}
else
{
this->_settingsPending.filePathARM9BIOS = std::string(filePath, sizeof(CommonSettings.ARM9BIOS));
}
this->_newSettingsPendingOnReset = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
}
const char* ClientExecutionControl::GetARM7ImagePath()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
const char *filePath = this->_settingsPending.filePathARM7BIOS.c_str();
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
return filePath;
}
void ClientExecutionControl::SetARM7ImagePath(const char *filePath)
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
if (filePath == NULL)
{
this->_settingsPending.filePathARM7BIOS.clear();
}
else
{
this->_settingsPending.filePathARM7BIOS = std::string(filePath, sizeof(CommonSettings.ARM7BIOS));
}
this->_newSettingsPendingOnReset = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
}
const char* ClientExecutionControl::GetFirmwareImagePath()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
const char *filePath = this->_settingsPending.filePathFirmware.c_str();
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
return filePath;
}
void ClientExecutionControl::SetFirmwareImagePath(const char *filePath)
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
if (filePath == NULL)
{
this->_settingsPending.filePathFirmware.clear();
}
else
{
this->_settingsPending.filePathFirmware = std::string(filePath, sizeof(CommonSettings.Firmware));
}
this->_newSettingsPendingOnReset = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset); pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
} }
@ -116,6 +218,8 @@ void ClientExecutionControl::SetEnableAdvancedBusLevelTiming(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableAdvancedBusLevelTiming = enable; this->_settingsPending.enableAdvancedBusLevelTiming = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -132,6 +236,26 @@ void ClientExecutionControl::SetEnableRigorous3DRenderingTiming(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableRigorous3DRenderingTiming = enable; this->_settingsPending.enableRigorous3DRenderingTiming = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
}
bool ClientExecutionControl::GetEnableGameSpecificHacks()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
const bool enable = this->_settingsPending.enableGameSpecificHacks;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
return enable;
}
void ClientExecutionControl::SetEnableGameSpecificHacks(bool enable)
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableGameSpecificHacks = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -148,6 +272,8 @@ void ClientExecutionControl::SetEnableExternalBIOS(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableExternalBIOS = enable; this->_settingsPending.enableExternalBIOS = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -164,6 +290,8 @@ void ClientExecutionControl::SetEnableBIOSInterrupts(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableBIOSInterrupts = enable; this->_settingsPending.enableBIOSInterrupts = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -180,6 +308,8 @@ void ClientExecutionControl::SetEnableBIOSPatchDelayLoop(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableBIOSPatchDelayLoop = enable; this->_settingsPending.enableBIOSPatchDelayLoop = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -196,6 +326,8 @@ void ClientExecutionControl::SetEnableExternalFirmware(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableExternalFirmware = enable; this->_settingsPending.enableExternalFirmware = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -212,6 +344,8 @@ void ClientExecutionControl::SetEnableFirmwareBoot(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableFirmwareBoot = enable; this->_settingsPending.enableFirmwareBoot = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -228,6 +362,8 @@ void ClientExecutionControl::SetEnableDebugConsole(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableDebugConsole = enable; this->_settingsPending.enableDebugConsole = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
@ -244,13 +380,33 @@ void ClientExecutionControl::SetEnableEnsataEmulation(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableEnsataEmulation = enable; this->_settingsPending.enableEnsataEmulation = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
}
bool ClientExecutionControl::GetEnableCheats()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
const bool enable = this->_settingsPending.enableCheats;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
return enable;
}
void ClientExecutionControl::SetEnableCheats(bool enable)
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsPending.enableCheats = enable;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
bool ClientExecutionControl::GetEnableSpeedLimiter() bool ClientExecutionControl::GetEnableSpeedLimiter()
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const bool enable = this->_settingsPending.enableSpeedLimiter; const bool enable = this->_settingsPending.enableExecutionSpeedLimiter;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return enable; return enable;
@ -259,23 +415,27 @@ bool ClientExecutionControl::GetEnableSpeedLimiter()
void ClientExecutionControl::SetEnableSpeedLimiter(bool enable) void ClientExecutionControl::SetEnableSpeedLimiter(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
this->_settingsPending.enableSpeedLimiter = enable; this->_settingsPending.enableExecutionSpeedLimiter = enable;
this->_newSettingsPendingOnExecutionLoopStart = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
} }
float ClientExecutionControl::GetExecutionSpeed() double ClientExecutionControl::GetExecutionSpeed()
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const float speedScalar = this->_settingsPending.executionSpeed; const double speedScalar = this->_settingsPending.executionSpeed;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return speedScalar; return speedScalar;
} }
void ClientExecutionControl::SetExecutionSpeed(float speedScalar) void ClientExecutionControl::SetExecutionSpeed(double speedScalar)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
this->_settingsPending.executionSpeed = speedScalar; this->_settingsPending.executionSpeed = speedScalar;
this->_newSettingsPendingOnExecutionLoopStart = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
} }
@ -288,46 +448,98 @@ bool ClientExecutionControl::GetEnableFrameSkip()
return enable; return enable;
} }
bool ClientExecutionControl::GetEnableFrameSkipApplied()
{
return this->_settingsApplied.enableFrameSkip;
}
void ClientExecutionControl::SetEnableFrameSkip(bool enable) void ClientExecutionControl::SetEnableFrameSkip(bool enable)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
if (this->_settingsPending.enableFrameSkip != enable) if (this->_settingsPending.enableFrameSkip != enable)
{ {
this->_settingsPending.enableFrameSkip = enable; this->_settingsPending.enableFrameSkip = enable;
this->_settingsPending.framesToSkip = 0;
this->_needResetFramesToSkip = true;
this->_newSettingsPendingOnNDSExec = true;
} }
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
uint8_t ClientExecutionControl::GetFramesToSkip() uint8_t ClientExecutionControl::GetFramesToSkip()
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart); return this->_framesToSkip;
const uint8_t numFramesToSkip = this->_settingsPending.framesToSkip; }
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return numFramesToSkip; void ClientExecutionControl::SetFramesToSkip(uint8_t numFrames)
{
this->_framesToSkip = numFrames;
}
void ClientExecutionControl::ResetFramesToSkip()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_needResetFramesToSkip = true;
this->_newSettingsPendingOnNDSExec = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
} }
uint64_t ClientExecutionControl::GetFrameJumpTarget() uint64_t ClientExecutionControl::GetFrameJumpTarget()
{ {
return this->_settingsPending.frameJumpTarget; pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const uint64_t jumpTarget = this->_settingsPending.frameJumpTarget;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return jumpTarget;
}
uint64_t ClientExecutionControl::GetFrameJumpTargetApplied()
{
return this->_settingsApplied.frameJumpTarget;
} }
void ClientExecutionControl::SetFrameJumpTarget(uint64_t newJumpTarget) void ClientExecutionControl::SetFrameJumpTarget(uint64_t newJumpTarget)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
this->_settingsPending.frameJumpTarget = newJumpTarget; this->_settingsPending.frameJumpTarget = newJumpTarget;
this->_newSettingsPendingOnExecutionLoopStart = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
}
ExecutionBehavior ClientExecutionControl::GetPreviousExecutionBehavior()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const ExecutionBehavior behavior = this->_prevExecBehavior;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return behavior;
} }
ExecutionBehavior ClientExecutionControl::GetExecutionBehavior() ExecutionBehavior ClientExecutionControl::GetExecutionBehavior()
{ {
return this->_settingsPending.execBehavior; pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const ExecutionBehavior behavior = this->_settingsPending.execBehavior;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
return behavior;
}
ExecutionBehavior ClientExecutionControl::GetExecutionBehaviorApplied()
{
return this->_settingsApplied.execBehavior;
} }
void ClientExecutionControl::SetExecutionBehavior(ExecutionBehavior newBehavior) void ClientExecutionControl::SetExecutionBehavior(ExecutionBehavior newBehavior)
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
this->_settingsPending.execBehavior = newBehavior; this->_settingsPending.execBehavior = newBehavior;
this->_newSettingsPendingOnExecutionLoopStart = true;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
} }
FrameJumpBehavior ClientExecutionControl::GetFrameJumpBehavior() FrameJumpBehavior ClientExecutionControl::GetFrameJumpBehavior()
@ -340,93 +552,246 @@ void ClientExecutionControl::SetFrameJumpBehavior(FrameJumpBehavior newBehavior)
this->_settingsPending.jumpBehavior = newBehavior; this->_settingsPending.jumpBehavior = newBehavior;
} }
void ClientExecutionControl::FlushSettingsOnReset() void ClientExecutionControl::ApplySettingsOnReset()
{ {
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset); pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
CommonSettings.use_jit = (this->_settingsPending.cpuEngineID == CPUEmulationEngineID_DynamicRecompiler); if (this->_newSettingsPendingOnReset)
CommonSettings.jit_max_block_size = this->_settingsPending.JITMaxBlockSize;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
}
void ClientExecutionControl::FlushSettingsOnExecutionLoopStart()
{
pthread_mutex_lock(&this->_mutexSettingsApplyOnExecutionLoopStart);
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
const bool didFrameSkipSettingChange = (this->_settingsPending.enableFrameSkip != this->_settingsApplied.enableFrameSkip);
if (didFrameSkipSettingChange)
{ {
this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip; this->_settingsApplied.cpuEngineID = this->_settingsPending.cpuEngineID;
this->_settingsApplied.framesToSkip = this->_settingsPending.framesToSkip; this->_settingsApplied.JITMaxBlockSize = this->_settingsPending.JITMaxBlockSize;
}
const float speedScalar = (this->_settingsPending.executionSpeed > SPEED_SCALAR_MIN) ? this->_settingsPending.executionSpeed : SPEED_SCALAR_MIN; this->_settingsApplied.filePathARM9BIOS = this->_settingsPending.filePathARM9BIOS;
const bool didExecutionSpeedChange = (speedScalar != this->_settingsApplied.executionSpeed) || (this->_settingsPending.enableSpeedLimiter != this->_settingsApplied.enableSpeedLimiter); this->_settingsApplied.filePathARM7BIOS = this->_settingsPending.filePathARM7BIOS;
if (didExecutionSpeedChange) this->_settingsApplied.filePathFirmware = this->_settingsPending.filePathFirmware;
{
this->_settingsApplied.enableSpeedLimiter = this->_settingsPending.enableSpeedLimiter;
this->_settingsApplied.executionSpeed = speedScalar;
}
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart); this->_newSettingsPendingOnReset = false;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
if (didFrameSkipSettingChange) CommonSettings.use_jit = (this->_settingsApplied.cpuEngineID == CPUEmulationEngineID_DynamicRecompiler);
{ CommonSettings.jit_max_block_size = this->_settingsApplied.JITMaxBlockSize;
NDS_OmitFrameSkip(2);
}
if (didExecutionSpeedChange) if (this->_settingsApplied.filePathARM9BIOS.length() == 0)
{
if (this->_settingsApplied.enableSpeedLimiter)
{ {
this->_settingsApplied.timeBudget = this->GetFrameAbsoluteTime(1.0f/speedScalar); memset(CommonSettings.ARM9BIOS, 0, sizeof(CommonSettings.ARM9BIOS));
} }
else else
{ {
this->_settingsApplied.timeBudget = 0; strlcpy(CommonSettings.ARM9BIOS, this->_settingsApplied.filePathARM9BIOS.c_str(), sizeof(CommonSettings.ARM9BIOS));
}
if (this->_settingsApplied.filePathARM7BIOS.length() == 0)
{
memset(CommonSettings.ARM7BIOS, 0, sizeof(CommonSettings.ARM7BIOS));
}
else
{
strlcpy(CommonSettings.ARM7BIOS, this->_settingsApplied.filePathARM7BIOS.c_str(), sizeof(CommonSettings.ARM7BIOS));
}
if (this->_settingsApplied.filePathFirmware.length() == 0)
{
memset(CommonSettings.Firmware, 0, sizeof(CommonSettings.Firmware));
}
else
{
strlcpy(CommonSettings.Firmware, this->_settingsApplied.filePathFirmware.c_str(), sizeof(CommonSettings.Firmware));
} }
} }
else
pthread_mutex_unlock(&this->_mutexSettingsApplyOnExecutionLoopStart); {
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
}
} }
void ClientExecutionControl::FlushSettingsOnNDSExec() void ClientExecutionControl::ApplySettingsOnExecutionLoopStart()
{ {
pthread_mutex_lock(&this->_mutexSettingsApplyOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
if (this->_newSettingsPendingOnExecutionLoopStart)
{
const double speedScalar = (this->_settingsPending.executionSpeed > SPEED_SCALAR_MIN) ? this->_settingsPending.executionSpeed : SPEED_SCALAR_MIN;
this->_settingsApplied.enableExecutionSpeedLimiter = this->_settingsPending.enableExecutionSpeedLimiter;
this->_settingsApplied.executionSpeed = speedScalar;
this->_settingsApplied.frameJumpTarget = this->_settingsPending.frameJumpTarget;
const bool needBehaviorChange = (this->_settingsApplied.execBehavior != this->_settingsPending.execBehavior);
if (needBehaviorChange)
{
if ( (this->_settingsApplied.execBehavior == ExecutionBehavior_Run) || (this->_settingsApplied.execBehavior == ExecutionBehavior_Pause) )
{
this->_prevExecBehavior = this->_settingsApplied.execBehavior;
}
this->_settingsApplied.execBehavior = this->_settingsPending.execBehavior;
}
this->_newSettingsPendingOnExecutionLoopStart = false;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
if (this->_settingsApplied.enableExecutionSpeedLimiter)
{
this->_frameTime = this->CalculateFrameAbsoluteTime(1.0/speedScalar);
}
else
{
this->_frameTime = 0.0;
}
if (needBehaviorChange)
{
this->ResetFramesToSkip();
}
}
else
{
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
}
}
void ClientExecutionControl::ApplySettingsOnNDSExec()
{
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec); pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
this->_settingsApplied.enableAdvancedBusLevelTiming = this->_settingsPending.enableAdvancedBusLevelTiming; if (this->_newSettingsPendingOnNDSExec)
this->_settingsApplied.enableRigorous3DRenderingTiming = this->_settingsPending.enableRigorous3DRenderingTiming; {
this->_settingsApplied.enableExternalBIOS = this->_settingsPending.enableExternalBIOS; this->_settingsApplied.enableAdvancedBusLevelTiming = this->_settingsPending.enableAdvancedBusLevelTiming;
this->_settingsApplied.enableBIOSInterrupts = this->_settingsPending.enableBIOSInterrupts; this->_settingsApplied.enableRigorous3DRenderingTiming = this->_settingsPending.enableRigorous3DRenderingTiming;
this->_settingsApplied.enableBIOSPatchDelayLoop = this->_settingsPending.enableBIOSPatchDelayLoop; this->_settingsApplied.enableGameSpecificHacks = this->_settingsPending.enableGameSpecificHacks;
this->_settingsApplied.enableExternalFirmware = this->_settingsPending.enableExternalFirmware; this->_settingsApplied.enableExternalBIOS = this->_settingsPending.enableExternalBIOS;
this->_settingsApplied.enableFirmwareBoot = this->_settingsPending.enableFirmwareBoot; this->_settingsApplied.enableBIOSInterrupts = this->_settingsPending.enableBIOSInterrupts;
this->_settingsApplied.enableDebugConsole = this->_settingsPending.enableDebugConsole; this->_settingsApplied.enableBIOSPatchDelayLoop = this->_settingsPending.enableBIOSPatchDelayLoop;
this->_settingsApplied.enableEnsataEmulation = this->_settingsPending.enableEnsataEmulation; this->_settingsApplied.enableExternalFirmware = this->_settingsPending.enableExternalFirmware;
this->_settingsApplied.enableFirmwareBoot = this->_settingsPending.enableFirmwareBoot;
this->_settingsApplied.enableDebugConsole = this->_settingsPending.enableDebugConsole;
this->_settingsApplied.enableEnsataEmulation = this->_settingsPending.enableEnsataEmulation;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec); this->_settingsApplied.enableCheats = this->_settingsPending.enableCheats;
CommonSettings.advanced_timing = this->_settingsApplied.enableAdvancedBusLevelTiming; this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip;
CommonSettings.rigorous_timing = this->_settingsApplied.enableRigorous3DRenderingTiming;
CommonSettings.UseExtBIOS = this->_settingsApplied.enableExternalBIOS;
CommonSettings.SWIFromBIOS = this->_settingsApplied.enableBIOSInterrupts;
CommonSettings.PatchSWI3 = this->_settingsApplied.enableBIOSPatchDelayLoop;
CommonSettings.UseExtFirmware = this->_settingsApplied.enableExternalFirmware;
CommonSettings.UseExtFirmwareSettings = this->_settingsApplied.enableExternalFirmware;
CommonSettings.BootFromFirmware = this->_settingsApplied.enableFirmwareBoot;
CommonSettings.DebugConsole = this->_settingsApplied.enableDebugConsole;
CommonSettings.EnsataEmulation = this->_settingsApplied.enableEnsataEmulation;
pthread_mutex_unlock(&this->_mutexSettingsApplyOnNDSExec); const bool needResetFramesToSkip = this->_needResetFramesToSkip;
this->_needResetFramesToSkip = false;
this->_newSettingsPendingOnNDSExec = false;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
CommonSettings.advanced_timing = this->_settingsApplied.enableAdvancedBusLevelTiming;
CommonSettings.rigorous_timing = this->_settingsApplied.enableRigorous3DRenderingTiming;
CommonSettings.UseExtBIOS = this->_settingsApplied.enableExternalBIOS;
CommonSettings.SWIFromBIOS = this->_settingsApplied.enableBIOSInterrupts;
CommonSettings.PatchSWI3 = this->_settingsApplied.enableBIOSPatchDelayLoop;
CommonSettings.UseExtFirmware = this->_settingsApplied.enableExternalFirmware;
CommonSettings.UseExtFirmwareSettings = this->_settingsApplied.enableExternalFirmware;
CommonSettings.BootFromFirmware = this->_settingsApplied.enableFirmwareBoot;
CommonSettings.DebugConsole = this->_settingsApplied.enableDebugConsole;
CommonSettings.EnsataEmulation = this->_settingsApplied.enableEnsataEmulation;
CommonSettings.cheatsDisable = !this->_settingsApplied.enableCheats;
CommonSettings.gamehacks.en = this->_settingsApplied.enableGameSpecificHacks;
CommonSettings.gamehacks.apply();
if (needResetFramesToSkip)
{
this->_framesToSkip = 0;
NDS_OmitFrameSkip(2);
}
}
else
{
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
}
} }
uint64_t ClientExecutionControl::GetFrameAbsoluteTime(double frameTimeScalar) double ClientExecutionControl::GetFrameTime()
{ {
// Do nothing. This is implementation dependent; return this->_frameTime;
return 1.0; }
uint8_t ClientExecutionControl::CalculateFrameSkip(double startAbsoluteTime, double frameAbsoluteTime)
{
static const double skipCurve[10] = {0.60, 0.58, 0.55, 0.51, 0.46, 0.40, 0.30, 0.20, 0.10, 0.00};
static const double unskipCurve[10] = {0.75, 0.70, 0.65, 0.60, 0.50, 0.40, 0.30, 0.20, 0.10, 0.00};
static size_t skipStep = 0;
static size_t unskipStep = 0;
static uint64_t lastSetFrameSkip = 0;
// Calculate the time remaining.
const double elapsed = this->GetCurrentAbsoluteTime() - startAbsoluteTime;
uint64_t framesToSkip = 0;
if (elapsed > frameAbsoluteTime)
{
if (frameAbsoluteTime > 0)
{
framesToSkip = (uint64_t)( (((elapsed - frameAbsoluteTime) * FRAME_SKIP_AGGRESSIVENESS) / frameAbsoluteTime) + FRAME_SKIP_BIAS );
if (framesToSkip > lastSetFrameSkip)
{
framesToSkip -= (uint64_t)((double)(framesToSkip - lastSetFrameSkip) * skipCurve[skipStep]);
if (skipStep < 9)
{
skipStep++;
}
}
else
{
framesToSkip += (uint64_t)((double)(lastSetFrameSkip - framesToSkip) * skipCurve[skipStep]);
if (skipStep > 0)
{
skipStep--;
}
}
}
else
{
static const double frameRate100x = (double)FRAME_SKIP_AGGRESSIVENESS / CalculateFrameAbsoluteTime(1.0/100.0);
framesToSkip = (uint64_t)(elapsed * frameRate100x);
}
unskipStep = 0;
}
else
{
framesToSkip = (uint64_t)((double)lastSetFrameSkip * unskipCurve[unskipStep]);
if (unskipStep < 9)
{
unskipStep++;
}
skipStep = 0;
}
// Bound the frame skip.
static const uint64_t kMaxFrameSkip = (uint64_t)MAX_FRAME_SKIP;
if (framesToSkip > kMaxFrameSkip)
{
framesToSkip = kMaxFrameSkip;
}
lastSetFrameSkip = framesToSkip;
return (uint8_t)framesToSkip;
}
double ClientExecutionControl::GetCurrentAbsoluteTime()
{
return (double)mach_absolute_time();
}
double ClientExecutionControl::CalculateFrameAbsoluteTime(double frameTimeScalar)
{
mach_timebase_info_data_t timeBase;
mach_timebase_info(&timeBase);
const double frameTimeNanoseconds = DS_SECONDS_PER_FRAME * 1000000000.0 * frameTimeScalar;
return (frameTimeNanoseconds * (double)timeBase.denom) / (double)timeBase.numer;
}
void ClientExecutionControl::WaitUntilAbsoluteTime(double deadlineAbsoluteTime)
{
mach_wait_until((uint64_t)deadlineAbsoluteTime);
} }

View File

@ -19,6 +19,7 @@
#define _CLIENT_EXECUTION_CONTROL_H_ #define _CLIENT_EXECUTION_CONTROL_H_
#include <pthread.h> #include <pthread.h>
#include <string>
#define SPEED_SCALAR_QUARTER 0.25 // Speed scalar for quarter execution speed. #define SPEED_SCALAR_QUARTER 0.25 // Speed scalar for quarter execution speed.
#define SPEED_SCALAR_HALF 0.5 // Speed scalar for half execution speed. #define SPEED_SCALAR_HALF 0.5 // Speed scalar for half execution speed.
@ -60,9 +61,13 @@ typedef struct ClientExecutionControlSettings
{ {
CPUEmulationEngineID cpuEngineID; CPUEmulationEngineID cpuEngineID;
uint8_t JITMaxBlockSize; uint8_t JITMaxBlockSize;
std::string filePathARM9BIOS;
std::string filePathARM7BIOS;
std::string filePathFirmware;
bool enableAdvancedBusLevelTiming; bool enableAdvancedBusLevelTiming;
bool enableRigorous3DRenderingTiming; bool enableRigorous3DRenderingTiming;
bool enableGameSpecificHacks;
bool enableExternalBIOS; bool enableExternalBIOS;
bool enableBIOSInterrupts; bool enableBIOSInterrupts;
bool enableBIOSPatchDelayLoop; bool enableBIOSPatchDelayLoop;
@ -71,12 +76,12 @@ typedef struct ClientExecutionControlSettings
bool enableDebugConsole; bool enableDebugConsole;
bool enableEnsataEmulation; bool enableEnsataEmulation;
bool enableSpeedLimiter; bool enableCheats;
float executionSpeed;
uint64_t timeBudget; bool enableExecutionSpeedLimiter;
double executionSpeed;
bool enableFrameSkip; bool enableFrameSkip;
uint8_t framesToSkip;
uint64_t frameJumpTarget; uint64_t frameJumpTarget;
ExecutionBehavior execBehavior; ExecutionBehavior execBehavior;
@ -90,14 +95,19 @@ private:
ClientExecutionControlSettings _settingsPending; ClientExecutionControlSettings _settingsPending;
ClientExecutionControlSettings _settingsApplied; ClientExecutionControlSettings _settingsApplied;
bool _newSettingsPendingOnReset;
bool _newSettingsPendingOnExecutionLoopStart;
bool _newSettingsPendingOnNDSExec;
bool _needResetFramesToSkip;
double _frameTime;
uint8_t _framesToSkip;
ExecutionBehavior _prevExecBehavior;
pthread_mutex_t _mutexSettingsPendingOnReset; pthread_mutex_t _mutexSettingsPendingOnReset;
pthread_mutex_t _mutexSettingsApplyOnReset;
pthread_mutex_t _mutexSettingsPendingOnExecutionLoopStart; pthread_mutex_t _mutexSettingsPendingOnExecutionLoopStart;
pthread_mutex_t _mutexSettingsApplyOnExecutionLoopStart;
pthread_mutex_t _mutexSettingsPendingOnNDSExec; pthread_mutex_t _mutexSettingsPendingOnNDSExec;
pthread_mutex_t _mutexSettingsApplyOnNDSExec;
public: public:
ClientExecutionControl(); ClientExecutionControl();
@ -109,12 +119,24 @@ public:
uint8_t GetJITMaxBlockSize(); uint8_t GetJITMaxBlockSize();
void SetJITMaxBlockSize(uint8_t blockSize); void SetJITMaxBlockSize(uint8_t blockSize);
const char* GetARM9ImagePath();
void SetARM9ImagePath(const char *filePath);
const char* GetARM7ImagePath();
void SetARM7ImagePath(const char *filePath);
const char* GetFirmwareImagePath();
void SetFirmwareImagePath(const char *filePath);
bool GetEnableAdvancedBusLevelTiming(); bool GetEnableAdvancedBusLevelTiming();
void SetEnableAdvancedBusLevelTiming(bool enable); void SetEnableAdvancedBusLevelTiming(bool enable);
bool GetEnableRigorous3DRenderingTiming(); bool GetEnableRigorous3DRenderingTiming();
void SetEnableRigorous3DRenderingTiming(bool enable); void SetEnableRigorous3DRenderingTiming(bool enable);
bool GetEnableGameSpecificHacks();
void SetEnableGameSpecificHacks(bool enable);
bool GetEnableExternalBIOS(); bool GetEnableExternalBIOS();
void SetEnableExternalBIOS(bool enable); void SetEnableExternalBIOS(bool enable);
@ -136,31 +158,45 @@ public:
bool GetEnableEnsataEmulation(); bool GetEnableEnsataEmulation();
void SetEnableEnsataEmulation(bool enable); void SetEnableEnsataEmulation(bool enable);
bool GetEnableCheats();
void SetEnableCheats(bool enable);
bool GetEnableSpeedLimiter(); bool GetEnableSpeedLimiter();
void SetEnableSpeedLimiter(bool enable); void SetEnableSpeedLimiter(bool enable);
float GetExecutionSpeed(); double GetExecutionSpeed();
void SetExecutionSpeed(float speedScalar); void SetExecutionSpeed(double speedScalar);
bool GetEnableFrameSkip(); bool GetEnableFrameSkip();
bool GetEnableFrameSkipApplied();
void SetEnableFrameSkip(bool enable); void SetEnableFrameSkip(bool enable);
uint8_t GetFramesToSkip(); uint8_t GetFramesToSkip();
void SetFramesToSkip(uint8_t numFrames);
void ResetFramesToSkip();
uint64_t GetFrameJumpTarget(); uint64_t GetFrameJumpTarget();
uint64_t GetFrameJumpTargetApplied();
void SetFrameJumpTarget(uint64_t newJumpTarget); void SetFrameJumpTarget(uint64_t newJumpTarget);
ExecutionBehavior GetPreviousExecutionBehavior();
ExecutionBehavior GetExecutionBehavior(); ExecutionBehavior GetExecutionBehavior();
ExecutionBehavior GetExecutionBehaviorApplied();
void SetExecutionBehavior(ExecutionBehavior newBehavior); void SetExecutionBehavior(ExecutionBehavior newBehavior);
FrameJumpBehavior GetFrameJumpBehavior(); FrameJumpBehavior GetFrameJumpBehavior();
void SetFrameJumpBehavior(FrameJumpBehavior newBehavior); void SetFrameJumpBehavior(FrameJumpBehavior newBehavior);
void FlushSettingsOnReset(); void ApplySettingsOnReset();
void FlushSettingsOnExecutionLoopStart(); void ApplySettingsOnExecutionLoopStart();
void FlushSettingsOnNDSExec(); void ApplySettingsOnNDSExec();
virtual uint64_t GetFrameAbsoluteTime(double frameTimeScalar); double GetFrameTime();
uint8_t CalculateFrameSkip(double startAbsoluteTime, double frameAbsoluteTime);
virtual double GetCurrentAbsoluteTime();
virtual double CalculateFrameAbsoluteTime(double frameTimeScalar);
virtual void WaitUntilAbsoluteTime(double deadlineAbsoluteTime);
}; };
#endif // _CLIENT_EXECUTION_CONTROL_H_ #endif // _CLIENT_EXECUTION_CONTROL_H_

View File

@ -35,11 +35,6 @@ typedef void *gdbstub_handle_t;
typedef struct typedef struct
{ {
CocoaDSCore *cdsCore; CocoaDSCore *cdsCore;
ExecutionBehavior behavior;
bool isFrameSkipEnabled;
uint64_t frameJumpTarget;
uint8_t framesToSkip;
uint64_t timeBudgetMachAbsTime;
pthread_mutex_t mutexOutputList; pthread_mutex_t mutexOutputList;
pthread_mutex_t mutexThreadExecute; pthread_mutex_t mutexThreadExecute;
pthread_cond_t condThreadExecute; pthread_cond_t condThreadExecute;
@ -48,6 +43,8 @@ typedef struct
@interface CocoaDSCore : NSObject @interface CocoaDSCore : NSObject
{ {
ClientExecutionControl *execControl;
CocoaDSController *cdsController; CocoaDSController *cdsController;
CocoaDSFirmware *cdsFirmware; CocoaDSFirmware *cdsFirmware;
CocoaDSGPU *cdsGPU; CocoaDSGPU *cdsGPU;
@ -56,9 +53,6 @@ typedef struct
pthread_t coreThread; pthread_t coreThread;
CoreThreadParam threadParam; CoreThreadParam threadParam;
NSInteger prevCoreState;
BOOL isSpeedLimitEnabled;
CGFloat speedScalar;
std::string _slot1R4Path; std::string _slot1R4Path;
NSTimer *_fpsTimer; NSTimer *_fpsTimer;
@ -73,16 +67,6 @@ typedef struct
volatile gdbstub_handle_t gdbStubHandleARM9; volatile gdbstub_handle_t gdbStubHandleARM9;
volatile gdbstub_handle_t gdbStubHandleARM7; volatile gdbstub_handle_t gdbStubHandleARM7;
BOOL emuFlagAdvancedBusLevelTiming;
BOOL emuFlagRigorousTiming;
BOOL emuFlagUseExternalBios;
BOOL emuFlagEmulateBiosInterrupts;
BOOL emuFlagPatchDelayLoop;
BOOL emuFlagUseExternalFirmware;
BOOL emuFlagFirmwareBoot;
BOOL emuFlagDebugConsole;
BOOL emuFlagEmulateEnsata;
NSInteger cpuEmulationEngine;
NSInteger slot1DeviceType; NSInteger slot1DeviceType;
NSString *slot1StatusText; NSString *slot1StatusText;
NSString *frameStatus; NSString *frameStatus;
@ -92,12 +76,10 @@ typedef struct
OSSpinLock spinlockCdsController; OSSpinLock spinlockCdsController;
OSSpinLock spinlockMasterExecute; OSSpinLock spinlockMasterExecute;
OSSpinLock spinlockExecutionChange;
OSSpinLock spinlockCheatEnableFlag;
OSSpinLock spinlockEmulationFlags;
OSSpinLock spinlockCPUEmulationEngine;
} }
@property (readonly, nonatomic) ClientExecutionControl *execControl;
@property (retain) CocoaDSController *cdsController; @property (retain) CocoaDSController *cdsController;
@property (retain) CocoaDSFirmware *cdsFirmware; @property (retain) CocoaDSFirmware *cdsFirmware;
@property (retain) CocoaDSGPU *cdsGPU; @property (retain) CocoaDSGPU *cdsGPU;
@ -142,12 +124,11 @@ typedef struct
@property (readonly) pthread_rwlock_t *rwlockCoreExecute; @property (readonly) pthread_rwlock_t *rwlockCoreExecute;
- (BOOL) ejectCardFlag; - (BOOL) isSlot1Ejected;
- (void) slot1Eject; - (void) slot1Eject;
- (void) changeRomSaveType:(NSInteger)saveTypeID; - (void) changeRomSaveType:(NSInteger)saveTypeID;
- (void) changeExecutionSpeed; - (void) updateExecutionSpeedStatus;
- (void) applyDynaRec;
- (BOOL) applySlot1Device; - (BOOL) applySlot1Device;
- (void) restoreCoreState; - (void) restoreCoreState;
@ -171,5 +152,3 @@ typedef struct
@end @end
static void* RunCoreThread(void *arg); static void* RunCoreThread(void *arg);
static uint8_t CalculateFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime);
uint64_t GetFrameAbsoluteTime(const double frameTimeScalar);

View File

@ -27,9 +27,6 @@
#include "ClientExecutionControl.h" #include "ClientExecutionControl.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
#include "../../movie.h" #include "../../movie.h"
#include "../../NDSSystem.h" #include "../../NDSSystem.h"
#include "../../armcpu.h" #include "../../armcpu.h"
@ -78,6 +75,8 @@ volatile bool execute = true;
@implementation CocoaDSCore @implementation CocoaDSCore
@synthesize execControl;
@dynamic cdsController; @dynamic cdsController;
@synthesize cdsFirmware; @synthesize cdsFirmware;
@synthesize cdsGPU; @synthesize cdsGPU;
@ -146,6 +145,8 @@ volatile bool execute = true;
return self; return self;
} }
execControl = new ClientExecutionControl;
_fpsTimer = nil; _fpsTimer = nil;
_isTimerAtSecond = NO; _isTimerAtSecond = NO;
@ -154,42 +155,16 @@ volatile bool execute = true;
cdsGPU = [[[[CocoaDSGPU alloc] init] autorelease] retain]; cdsGPU = [[[[CocoaDSGPU alloc] init] autorelease] retain];
cdsOutputList = [[[[NSMutableArray alloc] initWithCapacity:32] autorelease] retain]; cdsOutputList = [[[[NSMutableArray alloc] initWithCapacity:32] autorelease] retain];
emuFlagAdvancedBusLevelTiming = YES;
emuFlagRigorousTiming = NO;
emuFlagUseExternalBios = NO;
emuFlagEmulateBiosInterrupts = NO;
emuFlagPatchDelayLoop = NO;
emuFlagUseExternalFirmware = NO;
emuFlagFirmwareBoot = NO;
emuFlagDebugConsole = NO;
emuFlagEmulateEnsata = NO;
slot1DeviceType = NDS_SLOT1_RETAIL_AUTO; slot1DeviceType = NDS_SLOT1_RETAIL_AUTO;
slot1StatusText = NSSTRING_STATUS_EMULATION_NOT_RUNNING; slot1StatusText = NSSTRING_STATUS_EMULATION_NOT_RUNNING;
spinlockMasterExecute = OS_SPINLOCK_INIT; spinlockMasterExecute = OS_SPINLOCK_INIT;
spinlockCdsController = OS_SPINLOCK_INIT; spinlockCdsController = OS_SPINLOCK_INIT;
spinlockExecutionChange = OS_SPINLOCK_INIT;
spinlockCheatEnableFlag = OS_SPINLOCK_INIT;
spinlockEmulationFlags = OS_SPINLOCK_INIT;
spinlockCPUEmulationEngine = OS_SPINLOCK_INIT;
isSpeedLimitEnabled = YES;
speedScalar = SPEED_SCALAR_NORMAL;
prevCoreState = ExecutionBehavior_Pause;
slot1R4URL = nil; slot1R4URL = nil;
_slot1R4Path = ""; _slot1R4Path = "";
threadParam.cdsCore = self; threadParam.cdsCore = self;
threadParam.behavior = ExecutionBehavior_Pause;
threadParam.isFrameSkipEnabled = true;
threadParam.framesToSkip = 0;
threadParam.frameJumpTarget = 0;
uint64_t timeBudgetNanoseconds = (uint64_t)(DS_SECONDS_PER_FRAME * 1000000000.0 / speedScalar);
AbsoluteTime timeBudgetAbsTime = NanosecondsToAbsolute(*(Nanoseconds *)&timeBudgetNanoseconds);
threadParam.timeBudgetMachAbsTime = *(uint64_t *)&timeBudgetAbsTime;
pthread_mutex_init(&threadParam.mutexOutputList, NULL); pthread_mutex_init(&threadParam.mutexOutputList, NULL);
pthread_mutex_init(&threadParam.mutexThreadExecute, NULL); pthread_mutex_init(&threadParam.mutexThreadExecute, NULL);
@ -252,6 +227,7 @@ volatile bool execute = true;
[self setIsGdbStubStarted:NO]; [self setIsGdbStubStarted:NO];
delete execControl;
NDS_DeInit(); NDS_DeInit();
[super dealloc]; [super dealloc];
@ -305,81 +281,50 @@ volatile bool execute = true;
return theController; return theController;
} }
- (void) setIsFrameSkipEnabled:(BOOL)theState - (void) setIsFrameSkipEnabled:(BOOL)enable
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute); execControl->SetEnableFrameSkip((enable) ? true : false);
if (theState)
{
threadParam.isFrameSkipEnabled = true;
}
else
{
threadParam.isFrameSkipEnabled = false;
threadParam.framesToSkip = 0;
NDS_OmitFrameSkip(2);
}
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
} }
- (BOOL) isFrameSkipEnabled - (BOOL) isFrameSkipEnabled
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute); const bool enable = execControl->GetEnableFrameSkip();
const BOOL theState = threadParam.isFrameSkipEnabled ? YES : NO; return (enable) ? YES : NO;
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
return theState;
} }
- (void) setSpeedScalar:(CGFloat)scalar - (void) setSpeedScalar:(CGFloat)scalar
{ {
OSSpinLockLock(&spinlockExecutionChange); execControl->SetExecutionSpeed((float)scalar);
speedScalar = scalar; [self updateExecutionSpeedStatus];
OSSpinLockUnlock(&spinlockExecutionChange);
[self changeExecutionSpeed];
} }
- (CGFloat) speedScalar - (CGFloat) speedScalar
{ {
OSSpinLockLock(&spinlockExecutionChange); const CGFloat scalar = (CGFloat)execControl->GetExecutionSpeed();
const CGFloat scalar = speedScalar;
OSSpinLockUnlock(&spinlockExecutionChange);
return scalar; return scalar;
} }
- (void) setIsSpeedLimitEnabled:(BOOL)theState - (void) setIsSpeedLimitEnabled:(BOOL)enable
{ {
OSSpinLockLock(&spinlockExecutionChange); execControl->SetEnableSpeedLimiter((enable) ? true : false);
isSpeedLimitEnabled = theState; [self updateExecutionSpeedStatus];
OSSpinLockUnlock(&spinlockExecutionChange);
[self changeExecutionSpeed];
} }
- (BOOL) isSpeedLimitEnabled - (BOOL) isSpeedLimitEnabled
{ {
OSSpinLockLock(&spinlockExecutionChange); const bool enable = execControl->GetEnableSpeedLimiter();
const BOOL enabled = isSpeedLimitEnabled; return (enable) ? YES : NO;
OSSpinLockUnlock(&spinlockExecutionChange);
return enabled;
} }
- (void) setIsCheatingEnabled:(BOOL)theState - (void) setIsCheatingEnabled:(BOOL)enable
{ {
OSSpinLockLock(&spinlockCheatEnableFlag); execControl->SetEnableCheats((enable) ? true : false);
CommonSettings.cheatsDisable = theState ? false : true;
OSSpinLockUnlock(&spinlockCheatEnableFlag);
} }
- (BOOL) isCheatingEnabled - (BOOL) isCheatingEnabled
{ {
OSSpinLockLock(&spinlockCheatEnableFlag); const bool enable = execControl->GetEnableCheats();
BOOL theState = CommonSettings.cheatsDisable ? NO : YES; return (enable) ? YES : NO;
OSSpinLockUnlock(&spinlockCheatEnableFlag);
return theState;
} }
- (void) setIsGdbStubStarted:(BOOL)theState - (void) setIsGdbStubStarted:(BOOL)theState
@ -463,8 +408,7 @@ volatile bool execute = true;
// frame skipping this time. // frame skipping this time.
if (isInDebugTrap && !theState) if (isInDebugTrap && !theState)
{ {
threadParam.framesToSkip = 0; execControl->ResetFramesToSkip();
NDS_OmitFrameSkip(2);
} }
isInDebugTrap = theState; isInDebugTrap = theState;
@ -477,214 +421,141 @@ volatile bool execute = true;
- (void) setEmuFlagAdvancedBusLevelTiming:(BOOL)enable - (void) setEmuFlagAdvancedBusLevelTiming:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableAdvancedBusLevelTiming((enable) ? true : false);
CommonSettings.advanced_timing = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagAdvancedBusLevelTiming - (BOOL) emuFlagAdvancedBusLevelTiming
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableAdvancedBusLevelTiming();
const BOOL enable = (CommonSettings.advanced_timing) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagRigorousTiming:(BOOL)enable - (void) setEmuFlagRigorousTiming:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableRigorous3DRenderingTiming((enable) ? true : false);
CommonSettings.rigorous_timing = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagRigorousTiming - (BOOL) emuFlagRigorousTiming
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableRigorous3DRenderingTiming();
const BOOL enable = (CommonSettings.rigorous_timing) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagUseGameSpecificHacks:(BOOL)useTiming - (void) setEmuFlagUseGameSpecificHacks:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableGameSpecificHacks((enable) ? true : false);
CommonSettings.gamehacks.en = (useTiming) ? true : false;
CommonSettings.gamehacks.apply();
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagUseGameSpecificHacks - (BOOL) emuFlagUseGameSpecificHacks
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableGameSpecificHacks();
const BOOL useTiming = (CommonSettings.gamehacks.en) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return useTiming;
} }
- (void) setEmuFlagUseExternalBios:(BOOL)enable - (void) setEmuFlagUseExternalBios:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableExternalBIOS((enable) ? true : false);
CommonSettings.UseExtBIOS = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagUseExternalBios - (BOOL) emuFlagUseExternalBios
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableExternalBIOS();
const BOOL enable = (CommonSettings.UseExtBIOS) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagEmulateBiosInterrupts:(BOOL)enable - (void) setEmuFlagEmulateBiosInterrupts:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableBIOSInterrupts((enable) ? true : false);
CommonSettings.SWIFromBIOS = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagEmulateBiosInterrupts - (BOOL) emuFlagEmulateBiosInterrupts
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableBIOSInterrupts();
const BOOL enable = (CommonSettings.SWIFromBIOS) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagPatchDelayLoop:(BOOL)enable - (void) setEmuFlagPatchDelayLoop:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableBIOSPatchDelayLoop((enable) ? true : false);
CommonSettings.PatchSWI3 = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagPatchDelayLoop - (BOOL) emuFlagPatchDelayLoop
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableBIOSPatchDelayLoop();
const BOOL enable = (CommonSettings.PatchSWI3) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagUseExternalFirmware:(BOOL)enable - (void) setEmuFlagUseExternalFirmware:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableExternalFirmware((enable) ? true : false);
CommonSettings.UseExtFirmware = (enable) ? true : false;
CommonSettings.UseExtFirmwareSettings = CommonSettings.UseExtFirmware;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagUseExternalFirmware - (BOOL) emuFlagUseExternalFirmware
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableExternalFirmware();
const BOOL enable = (CommonSettings.UseExtFirmware) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagFirmwareBoot:(BOOL)enable - (void) setEmuFlagFirmwareBoot:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableFirmwareBoot((enable) ? true : false);
CommonSettings.BootFromFirmware = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagFirmwareBoot - (BOOL) emuFlagFirmwareBoot
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableFirmwareBoot();
const BOOL enable = (CommonSettings.BootFromFirmware) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagDebugConsole:(BOOL)enable - (void) setEmuFlagDebugConsole:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableDebugConsole((enable) ? true : false);
CommonSettings.DebugConsole = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagDebugConsole - (BOOL) emuFlagDebugConsole
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableDebugConsole();
const BOOL enable = (CommonSettings.DebugConsole) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setEmuFlagEmulateEnsata:(BOOL)enable - (void) setEmuFlagEmulateEnsata:(BOOL)enable
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetEnableEnsataEmulation((enable) ? true : false);
CommonSettings.EnsataEmulation = (enable) ? true : false;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (BOOL) emuFlagEmulateEnsata - (BOOL) emuFlagEmulateEnsata
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); const bool enable = execControl->GetEnableEnsataEmulation();
const BOOL enable = (CommonSettings.EnsataEmulation) ? YES : NO; return (enable) ? YES : NO;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return enable;
} }
- (void) setCpuEmulationEngine:(NSInteger)engineID - (void) setCpuEmulationEngine:(NSInteger)engineID
{ {
OSSpinLockLock(&spinlockCPUEmulationEngine); execControl->SetCPUEmulationEngineID((CPUEmulationEngineID)engineID);
#if defined(__i386__) || defined(__x86_64__)
cpuEmulationEngine = engineID;
#else
cpuEmulationEngine = CPUEmulationEngine_Interpreter;
#endif
OSSpinLockUnlock(&spinlockCPUEmulationEngine);
} }
- (NSInteger) cpuEmulationEngine - (NSInteger) cpuEmulationEngine
{ {
OSSpinLockLock(&spinlockCPUEmulationEngine); return (NSInteger)execControl->GetCPUEmulationEngineID();
const NSInteger engineID = cpuEmulationEngine;
OSSpinLockUnlock(&spinlockCPUEmulationEngine);
return engineID;
} }
- (void) setMaxJITBlockSize:(NSInteger)blockSize - (void) setMaxJITBlockSize:(NSInteger)blockSize
{ {
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute); execControl->SetJITMaxBlockSize((uint8_t)blockSize);
CommonSettings.jit_max_block_size = (blockSize > 0) ? blockSize : 1;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (NSInteger) maxJITBlockSize - (NSInteger) maxJITBlockSize
{ {
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute); return (NSInteger)execControl->GetJITMaxBlockSize();
const NSInteger blockSize = CommonSettings.jit_max_block_size;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
return blockSize;
} }
- (void) setCoreState:(NSInteger)coreState - (void) setCoreState:(NSInteger)coreState
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute); pthread_mutex_lock(&threadParam.mutexThreadExecute);
if (threadParam.behavior == ExecutionBehavior_Run || threadParam.behavior == ExecutionBehavior_Pause) execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
{
prevCoreState = threadParam.behavior;
}
threadParam.behavior = (ExecutionBehavior)coreState; pthread_mutex_lock(&threadParam.mutexOutputList);
threadParam.framesToSkip = 0;
NDS_OmitFrameSkip(2);
switch ((ExecutionBehavior)coreState) switch ((ExecutionBehavior)coreState)
{ {
@ -748,7 +619,7 @@ volatile bool execute = true;
} }
} }
[self setFrameStatus:[NSString stringWithFormat:@"Jumping to frame %lu.", (unsigned long)threadParam.frameJumpTarget]]; [self setFrameStatus:[NSString stringWithFormat:@"Jumping to frame %lu.", (unsigned long)execControl->GetFrameJumpTarget()]];
[_fpsTimer invalidate]; [_fpsTimer invalidate];
_fpsTimer = nil; _fpsTimer = nil;
break; break;
@ -758,6 +629,8 @@ volatile bool execute = true;
break; break;
} }
pthread_mutex_unlock(&threadParam.mutexOutputList);
pthread_cond_signal(&threadParam.condThreadExecute); pthread_cond_signal(&threadParam.condThreadExecute);
pthread_mutex_unlock(&threadParam.mutexThreadExecute); pthread_mutex_unlock(&threadParam.mutexThreadExecute);
@ -767,62 +640,44 @@ volatile bool execute = true;
- (NSInteger) coreState - (NSInteger) coreState
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute); const NSInteger behavior = (NSInteger)execControl->GetExecutionBehavior();
const NSInteger theState = threadParam.behavior; return behavior;
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
return theState;
} }
- (void) setArm9ImageURL:(NSURL *)fileURL - (void) setArm9ImageURL:(NSURL *)fileURL
{ {
if (fileURL != nil) const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
{ execControl->SetARM9ImagePath(filePath);
strlcpy(CommonSettings.ARM9BIOS, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.ARM9BIOS));
}
else
{
memset(CommonSettings.ARM9BIOS, 0, sizeof(CommonSettings.ARM9BIOS));
}
} }
- (NSURL *) arm9ImageURL - (NSURL *) arm9ImageURL
{ {
return [NSURL fileURLWithPath:[NSString stringWithCString:CommonSettings.ARM9BIOS encoding:NSUTF8StringEncoding]]; const char *filePath = execControl->GetARM9ImagePath();
return [NSURL fileURLWithPath:[NSString stringWithCString:filePath encoding:NSUTF8StringEncoding]];
} }
- (void) setArm7ImageURL:(NSURL *)fileURL - (void) setArm7ImageURL:(NSURL *)fileURL
{ {
if (fileURL != nil) const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
{ execControl->SetARM7ImagePath(filePath);
strlcpy(CommonSettings.ARM7BIOS, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.ARM7BIOS));
}
else
{
memset(CommonSettings.ARM7BIOS, 0, sizeof(CommonSettings.ARM7BIOS));
}
} }
- (NSURL *) arm7ImageURL - (NSURL *) arm7ImageURL
{ {
return [NSURL fileURLWithPath:[NSString stringWithCString:CommonSettings.ARM7BIOS encoding:NSUTF8StringEncoding]]; const char *filePath = execControl->GetARM7ImagePath();
return [NSURL fileURLWithPath:[NSString stringWithCString:filePath encoding:NSUTF8StringEncoding]];
} }
- (void) setFirmwareImageURL:(NSURL *)fileURL - (void) setFirmwareImageURL:(NSURL *)fileURL
{ {
if (fileURL != nil) const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
{ execControl->SetFirmwareImagePath(filePath);
strlcpy(CommonSettings.Firmware, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.Firmware));
}
else
{
memset(CommonSettings.Firmware, 0, sizeof(CommonSettings.Firmware));
}
} }
- (NSURL *) firmwareImageURL - (NSURL *) firmwareImageURL
{ {
return [NSURL fileURLWithPath:[NSString stringWithCString:CommonSettings.Firmware encoding:NSUTF8StringEncoding]]; const char *filePath = execControl->GetFirmwareImagePath();
return [NSURL fileURLWithPath:[NSString stringWithCString:filePath encoding:NSUTF8StringEncoding]];
} }
- (pthread_rwlock_t *) rwlockCoreExecute - (pthread_rwlock_t *) rwlockCoreExecute
@ -830,7 +685,7 @@ volatile bool execute = true;
return &threadParam.rwlockCoreExecute; return &threadParam.rwlockCoreExecute;
} }
- (BOOL) ejectCardFlag - (BOOL) isSlot1Ejected
{ {
const BOOL isEjected = (nds.cardEjected) ? YES : NO; const BOOL isEjected = (nds.cardEjected) ? YES : NO;
return isEjected; return isEjected;
@ -852,54 +707,18 @@ volatile bool execute = true;
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute); pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
} }
- (void) changeExecutionSpeed - (void) updateExecutionSpeedStatus
{ {
if (self.isSpeedLimitEnabled) if ([self isSpeedLimitEnabled])
{ {
const CGFloat theSpeed = ([self speedScalar] > SPEED_SCALAR_MIN) ? [self speedScalar] : SPEED_SCALAR_MIN; [self setExecutionSpeedStatus:[NSString stringWithFormat:@"%1.2fx", [self speedScalar]]];
pthread_mutex_lock(&threadParam.mutexThreadExecute);
threadParam.timeBudgetMachAbsTime = GetFrameAbsoluteTime(1.0/theSpeed);
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
[self setExecutionSpeedStatus:[NSString stringWithFormat:@"%1.2fx", theSpeed]];
} }
else else
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute);
threadParam.timeBudgetMachAbsTime = 0;
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
[self setExecutionSpeedStatus:@"Unlimited"]; [self setExecutionSpeedStatus:@"Unlimited"];
} }
} }
/********************************************************************************************
applyDynaRec
Sets the use_jit variable for CommonSettings.
Takes:
Nothing.
Returns:
Nothing.
Details:
In the UI, we call setCpuEmulationEngine to set whether we should use the
interpreter or the dynamic recompiler. However, the emulator cannot handle
changing the engine while the emulation is running. Therefore, we use this
method to set the engine at a later time, using the last cpuEmulationEngine
value from the user.
********************************************************************************************/
- (void) applyDynaRec
{
const NSInteger engineID = [self cpuEmulationEngine];
pthread_mutex_lock(&threadParam.mutexThreadExecute);
CommonSettings.use_jit = (engineID == CPUEmulationEngineID_DynamicRecompiler);
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
}
- (BOOL) applySlot1Device - (BOOL) applySlot1Device
{ {
const NSInteger deviceTypeID = [self slot1DeviceType]; const NSInteger deviceTypeID = [self slot1DeviceType];
@ -946,16 +765,16 @@ volatile bool execute = true;
- (void) restoreCoreState - (void) restoreCoreState
{ {
[self setCoreState:prevCoreState]; [self setCoreState:(NSInteger)execControl->GetPreviousExecutionBehavior()];
} }
- (void) reset - (void) reset
{ {
[self setCoreState:ExecutionBehavior_Pause]; [self setCoreState:ExecutionBehavior_Pause];
[self applyDynaRec];
[self applySlot1Device]; [self applySlot1Device];
pthread_mutex_lock(&threadParam.mutexThreadExecute); pthread_mutex_lock(&threadParam.mutexThreadExecute);
execControl->ApplySettingsOnReset();
NDS_Reset(); NDS_Reset();
pthread_mutex_unlock(&threadParam.mutexThreadExecute); pthread_mutex_unlock(&threadParam.mutexThreadExecute);
@ -1003,18 +822,12 @@ volatile bool execute = true;
- (void) frameJumpTo:(NSUInteger)targetFrameNum - (void) frameJumpTo:(NSUInteger)targetFrameNum
{ {
pthread_mutex_lock(&threadParam.mutexThreadExecute); execControl->SetFrameJumpTarget(targetFrameNum);
threadParam.frameJumpTarget = targetFrameNum; if (targetFrameNum > [self frameNumber])
if (targetFrameNum <= (NSUInteger)currFrameCounter)
{ {
pthread_mutex_unlock(&threadParam.mutexThreadExecute); [self setCoreState:ExecutionBehavior_FrameJump];
return;
} }
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
[self setCoreState:ExecutionBehavior_FrameJump];
} }
- (void) frameJump:(NSUInteger)relativeFrameNum - (void) frameJump:(NSUInteger)relativeFrameNum
@ -1163,26 +976,37 @@ static void* RunCoreThread(void *arg)
{ {
CoreThreadParam *param = (CoreThreadParam *)arg; CoreThreadParam *param = (CoreThreadParam *)arg;
CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore; CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore;
ClientExecutionControl *execControl = [cdsCore execControl];
NSMutableArray *cdsOutputList = [cdsCore cdsOutputList]; NSMutableArray *cdsOutputList = [cdsCore cdsOutputList];
NSUInteger frameNum = 0; uint64_t frameNum = 0;
uint64_t startTime = 0; double startTime = 0;
uint64_t timeBudget = 0; // Need local variable to ensure that param->timeBudgetMachAbsTime is thread-safe. double frameTime = 0; // The amount of time that is expected for the frame to run.
ExecutionBehavior behavior = ExecutionBehavior_Pause;
uint64_t frameJumpTarget = 0;
do do
{ {
startTime = mach_absolute_time(); startTime = execControl->GetCurrentAbsoluteTime();
pthread_mutex_lock(&param->mutexThreadExecute);
timeBudget = param->timeBudgetMachAbsTime;
while (!(param->behavior != ExecutionBehavior_Pause && execute)) pthread_mutex_lock(&param->mutexThreadExecute);
execControl->ApplySettingsOnExecutionLoopStart();
behavior = execControl->GetExecutionBehaviorApplied();
while (!(behavior != ExecutionBehavior_Pause && execute))
{ {
pthread_cond_wait(&param->condThreadExecute, &param->mutexThreadExecute); pthread_cond_wait(&param->condThreadExecute, &param->mutexThreadExecute);
startTime = mach_absolute_time();
timeBudget = param->timeBudgetMachAbsTime; startTime = execControl->GetCurrentAbsoluteTime();
execControl->ApplySettingsOnExecutionLoopStart();
behavior = execControl->GetExecutionBehaviorApplied();
} }
frameTime = execControl->GetFrameTime();
frameJumpTarget = execControl->GetFrameJumpTargetApplied();
CocoaDSController *cdsController = [cdsCore cdsController]; CocoaDSController *cdsController = [cdsCore cdsController];
if (param->behavior != ExecutionBehavior_FrameJump) if (behavior != ExecutionBehavior_FrameJump)
{ {
[cdsController flush]; [cdsController flush];
} }
@ -1196,10 +1020,12 @@ static void* RunCoreThread(void *arg)
NDS_endProcessingInput(); NDS_endProcessingInput();
FCEUMOV_HandleRecording(); FCEUMOV_HandleRecording();
execControl->ApplySettingsOnNDSExec();
// Execute the frame and increment the frame counter. // Execute the frame and increment the frame counter.
pthread_rwlock_wrlock(&param->rwlockCoreExecute); pthread_rwlock_wrlock(&param->rwlockCoreExecute);
NDS_exec<false>(); NDS_exec<false>();
frameNum = currFrameCounter; frameNum = (uint64_t)currFrameCounter;
pthread_rwlock_unlock(&param->rwlockCoreExecute); pthread_rwlock_unlock(&param->rwlockCoreExecute);
// Check if an internal execution error occurred that halted the emulation. // Check if an internal execution error occurred that halted the emulation.
@ -1216,9 +1042,11 @@ static void* RunCoreThread(void *arg)
[cdsController updateMicLevel]; [cdsController updateMicLevel];
[cdsController clearMicLevelMeasure]; [cdsController clearMicLevelMeasure];
const uint8_t framesToSkip = execControl->GetFramesToSkip();
pthread_mutex_lock(&param->mutexOutputList); pthread_mutex_lock(&param->mutexOutputList);
switch (param->behavior) switch (behavior)
{ {
case ExecutionBehavior_Run: case ExecutionBehavior_Run:
case ExecutionBehavior_FrameAdvance: case ExecutionBehavior_FrameAdvance:
@ -1226,7 +1054,7 @@ static void* RunCoreThread(void *arg)
{ {
for (CocoaDSOutput *cdsOutput in cdsOutputList) for (CocoaDSOutput *cdsOutput in cdsOutputList)
{ {
if (![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || param->framesToSkip == 0) if ( ![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || (framesToSkip == 0) )
{ {
[cdsOutput doCoreEmuFrame]; [cdsOutput doCoreEmuFrame];
} }
@ -1240,22 +1068,22 @@ static void* RunCoreThread(void *arg)
pthread_mutex_unlock(&param->mutexOutputList); pthread_mutex_unlock(&param->mutexOutputList);
switch (param->behavior) switch (behavior)
{ {
case ExecutionBehavior_Run: case ExecutionBehavior_Run:
{ {
// Determine the number of frames to skip based on how much time "debt" // Determine the number of frames to skip based on how much time "debt"
// we owe on timeBudget. // we owe on timeBudget.
if (param->isFrameSkipEnabled) if (execControl->GetEnableFrameSkipApplied())
{ {
if (param->framesToSkip > 0) if (framesToSkip > 0)
{ {
NDS_SkipNextFrame(); NDS_SkipNextFrame();
param->framesToSkip--; execControl->SetFramesToSkip(framesToSkip - 1);
} }
else else
{ {
param->framesToSkip = CalculateFrameSkip(timeBudget, startTime); execControl->SetFramesToSkip( execControl->CalculateFrameSkip(startTime, frameTime) );
} }
} }
break; break;
@ -1263,14 +1091,14 @@ static void* RunCoreThread(void *arg)
case ExecutionBehavior_FrameJump: case ExecutionBehavior_FrameJump:
{ {
if (param->framesToSkip > 0) if (framesToSkip > 0)
{ {
NDS_SkipNextFrame(); NDS_SkipNextFrame();
param->framesToSkip--; execControl->SetFramesToSkip(framesToSkip - 1);
} }
else else
{ {
param->framesToSkip = (uint8_t)((DS_FRAMES_PER_SECOND * 1.0) + 0.85); execControl->SetFramesToSkip( (uint8_t)((DS_FRAMES_PER_SECOND * 1.0) + 0.85) );
} }
break; break;
} }
@ -1283,18 +1111,17 @@ static void* RunCoreThread(void *arg)
// If we're doing a frame advance, switch back to pause state immediately // If we're doing a frame advance, switch back to pause state immediately
// after we're done with the frame. // after we're done with the frame.
if (param->behavior == ExecutionBehavior_FrameAdvance) if (behavior == ExecutionBehavior_FrameAdvance)
{ {
[cdsCore setCoreState:ExecutionBehavior_Pause]; [cdsCore setCoreState:ExecutionBehavior_Pause];
} }
else if (param->behavior == ExecutionBehavior_FrameJump) else if (behavior == ExecutionBehavior_FrameJump)
{ {
if (frameNum == (param->frameJumpTarget - 1)) if (frameNum == (frameJumpTarget - 1))
{ {
param->framesToSkip = 0; execControl->ResetFramesToSkip();
NDS_OmitFrameSkip(2);
} }
else if (frameNum >= param->frameJumpTarget) else if (frameNum >= frameJumpTarget)
{ {
[cdsCore restoreCoreState]; [cdsCore restoreCoreState];
} }
@ -1302,7 +1129,7 @@ static void* RunCoreThread(void *arg)
else else
{ {
// If there is any time left in the loop, go ahead and pad it. // If there is any time left in the loop, go ahead and pad it.
mach_wait_until(startTime + timeBudget); execControl->WaitUntilAbsoluteTime(startTime + frameTime);
} }
} while(true); } while(true);
@ -1310,80 +1137,6 @@ static void* RunCoreThread(void *arg)
return NULL; return NULL;
} }
static uint8_t CalculateFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime)
{
static const double skipCurve[10] = {0.60, 0.58, 0.55, 0.51, 0.46, 0.40, 0.30, 0.20, 0.10, 0.00};
static const double unskipCurve[10] = {0.75, 0.70, 0.65, 0.60, 0.50, 0.40, 0.30, 0.20, 0.10, 0.00};
static size_t skipStep = 0;
static size_t unskipStep = 0;
static uint64_t lastSetFrameSkip = 0;
// Calculate the time remaining.
const uint64_t elapsed = mach_absolute_time() - frameStartMachAbsTime;
uint64_t framesToSkip = 0;
if (elapsed > timeBudgetMachAbsTime)
{
if (timeBudgetMachAbsTime > 0)
{
framesToSkip = (uint64_t)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS) / (double)timeBudgetMachAbsTime) + FRAME_SKIP_BIAS );
if (framesToSkip > lastSetFrameSkip)
{
framesToSkip -= (uint64_t)((double)(framesToSkip - lastSetFrameSkip) * skipCurve[skipStep]);
if (skipStep < 9)
{
skipStep++;
}
}
else
{
framesToSkip += (uint64_t)((double)(lastSetFrameSkip - framesToSkip) * skipCurve[skipStep]);
if (skipStep > 0)
{
skipStep--;
}
}
}
else
{
static const double frameRate100x = (double)FRAME_SKIP_AGGRESSIVENESS / (double)GetFrameAbsoluteTime(1.0/100.0);
framesToSkip = (uint64_t)((double)elapsed * frameRate100x);
}
unskipStep = 0;
}
else
{
framesToSkip = (uint64_t)((double)lastSetFrameSkip * unskipCurve[unskipStep]);
if (unskipStep < 9)
{
unskipStep++;
}
skipStep = 0;
}
// Bound the frame skip.
static const uint64_t kMaxFrameSkip = (uint64_t)MAX_FRAME_SKIP;
if (framesToSkip > kMaxFrameSkip)
{
framesToSkip = kMaxFrameSkip;
}
lastSetFrameSkip = framesToSkip;
return (uint8_t)framesToSkip;
}
uint64_t GetFrameAbsoluteTime(const double frameTimeScalar)
{
const uint64_t frameTimeNanoseconds = (uint64_t)(DS_SECONDS_PER_FRAME * 1000000000.0 * frameTimeScalar);
const AbsoluteTime frameTimeAbsTime = NanosecondsToAbsolute(*(Nanoseconds *)&frameTimeNanoseconds);
return *(uint64_t *)&frameTimeAbsTime;
}
#pragma mark - OSXDriver #pragma mark - OSXDriver
pthread_mutex_t* OSXDriver::GetCoreThreadMutexLock() pthread_mutex_t* OSXDriver::GetCoreThreadMutexLock()
@ -1432,7 +1185,7 @@ void OSXDriver::EMU_DebugIdleWakeUp()
#pragma mark - GDB Stub implementation #pragma mark - GDB Stub implementation
void* createThread_gdb(void (*thread_function)( void *data),void *thread_data) void* createThread_gdb(void (*thread_function)(void *data), void *thread_data)
{ {
// Create the thread using POSIX routines. // Create the thread using POSIX routines.
pthread_attr_t attr; pthread_attr_t attr;
@ -1458,6 +1211,6 @@ void* createThread_gdb(void (*thread_function)( void *data),void *thread_data)
void joinThread_gdb(void *thread_handle) void joinThread_gdb(void *thread_handle)
{ {
pthread_join(*((pthread_t*)thread_handle), NULL); pthread_join(*(pthread_t *)thread_handle, NULL);
free(thread_handle); free(thread_handle);
} }

View File

@ -1682,7 +1682,7 @@
[self pauseCore]; [self pauseCore];
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content]; CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
[cdsCore applyDynaRec]; [cdsCore execControl]->ApplySettingsOnReset();
[cdsCore applySlot1Device]; [cdsCore applySlot1Device];
[self writeDefaultsSlot1Settings:nil]; [self writeDefaultsSlot1Settings:nil];