Cocoa Port: Continue refactoring the emulation execution loop code to be less port-dependent.
This commit is contained in:
parent
3bf295f4ce
commit
abebaebdef
|
@ -15,6 +15,9 @@
|
|||
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 "ClientExecutionControl.h"
|
||||
|
@ -22,11 +25,25 @@
|
|||
|
||||
ClientExecutionControl::ClientExecutionControl()
|
||||
{
|
||||
_newSettingsPendingOnReset = true;
|
||||
_newSettingsPendingOnExecutionLoopStart = true;
|
||||
_newSettingsPendingOnNDSExec = true;
|
||||
|
||||
_needResetFramesToSkip = false;
|
||||
|
||||
_frameTime = 0.0;
|
||||
_framesToSkip = 0;
|
||||
_prevExecBehavior = ExecutionBehavior_Pause;
|
||||
|
||||
_settingsPending.cpuEngineID = CPUEmulationEngineID_Interpreter;
|
||||
_settingsPending.JITMaxBlockSize = 12;
|
||||
_settingsPending.filePathARM9BIOS = std::string();
|
||||
_settingsPending.filePathARM7BIOS = std::string();
|
||||
_settingsPending.filePathFirmware = std::string();
|
||||
|
||||
_settingsPending.enableAdvancedBusLevelTiming = true;
|
||||
_settingsPending.enableRigorous3DRenderingTiming = false;
|
||||
_settingsPending.enableGameSpecificHacks = true;
|
||||
_settingsPending.enableExternalBIOS = false;
|
||||
_settingsPending.enableBIOSInterrupts = false;
|
||||
_settingsPending.enableBIOSPatchDelayLoop = false;
|
||||
|
@ -35,31 +52,30 @@ ClientExecutionControl::ClientExecutionControl()
|
|||
_settingsPending.enableDebugConsole = false;
|
||||
_settingsPending.enableEnsataEmulation = false;
|
||||
|
||||
_settingsPending.executionSpeed = 1.0f;
|
||||
_settingsPending.enableExecutionSpeedLimiter = true;
|
||||
_settingsPending.executionSpeed = SPEED_SCALAR_NORMAL;
|
||||
|
||||
_settingsPending.enableFrameSkip = true;
|
||||
_settingsPending.framesToSkip = 0;
|
||||
_settingsPending.frameJumpTarget = 0;
|
||||
|
||||
_settingsPending.execBehavior = ExecutionBehavior_Pause;
|
||||
_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(&_mutexSettingsApplyOnReset, NULL);
|
||||
pthread_mutex_init(&_mutexSettingsPendingOnExecutionLoopStart, NULL);
|
||||
pthread_mutex_init(&_mutexSettingsApplyOnExecutionLoopStart, NULL);
|
||||
pthread_mutex_init(&_mutexSettingsPendingOnNDSExec, NULL);
|
||||
pthread_mutex_init(&_mutexSettingsApplyOnNDSExec, NULL);
|
||||
}
|
||||
|
||||
ClientExecutionControl::~ClientExecutionControl()
|
||||
{
|
||||
pthread_mutex_destroy(&this->_mutexSettingsPendingOnReset);
|
||||
pthread_mutex_destroy(&this->_mutexSettingsApplyOnReset);
|
||||
pthread_mutex_destroy(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
pthread_mutex_destroy(&this->_mutexSettingsApplyOnExecutionLoopStart);
|
||||
pthread_mutex_destroy(&this->_mutexSettingsPendingOnNDSExec);
|
||||
pthread_mutex_destroy(&this->_mutexSettingsApplyOnNDSExec);
|
||||
}
|
||||
|
||||
CPUEmulationEngineID ClientExecutionControl::GetCPUEmulationEngineID()
|
||||
|
@ -73,8 +89,14 @@ CPUEmulationEngineID ClientExecutionControl::GetCPUEmulationEngineID()
|
|||
|
||||
void ClientExecutionControl::SetCPUEmulationEngineID(CPUEmulationEngineID engineID)
|
||||
{
|
||||
#if !defined(__i386__) && !defined(__x86_64__)
|
||||
engineID = CPUEmulationEngine_Interpreter;
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
|
||||
this->_settingsPending.cpuEngineID = engineID;
|
||||
|
||||
this->_newSettingsPendingOnReset = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
|
||||
}
|
||||
|
||||
|
@ -100,6 +122,86 @@ void ClientExecutionControl::SetJITMaxBlockSize(uint8_t blockSize)
|
|||
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -116,6 +218,8 @@ void ClientExecutionControl::SetEnableAdvancedBusLevelTiming(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableAdvancedBusLevelTiming = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -132,6 +236,26 @@ void ClientExecutionControl::SetEnableRigorous3DRenderingTiming(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -148,6 +272,8 @@ void ClientExecutionControl::SetEnableExternalBIOS(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableExternalBIOS = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -164,6 +290,8 @@ void ClientExecutionControl::SetEnableBIOSInterrupts(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableBIOSInterrupts = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -180,6 +308,8 @@ void ClientExecutionControl::SetEnableBIOSPatchDelayLoop(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableBIOSPatchDelayLoop = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -196,6 +326,8 @@ void ClientExecutionControl::SetEnableExternalFirmware(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableExternalFirmware = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -212,6 +344,8 @@ void ClientExecutionControl::SetEnableFirmwareBoot(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableFirmwareBoot = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -228,6 +362,8 @@ void ClientExecutionControl::SetEnableDebugConsole(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
this->_settingsPending.enableDebugConsole = enable;
|
||||
|
||||
this->_newSettingsPendingOnNDSExec = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
}
|
||||
|
||||
|
@ -244,13 +380,33 @@ void ClientExecutionControl::SetEnableEnsataEmulation(bool enable)
|
|||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
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);
|
||||
}
|
||||
|
||||
bool ClientExecutionControl::GetEnableSpeedLimiter()
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
const bool enable = this->_settingsPending.enableSpeedLimiter;
|
||||
const bool enable = this->_settingsPending.enableExecutionSpeedLimiter;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
|
||||
return enable;
|
||||
|
@ -259,23 +415,27 @@ bool ClientExecutionControl::GetEnableSpeedLimiter()
|
|||
void ClientExecutionControl::SetEnableSpeedLimiter(bool enable)
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
this->_settingsPending.enableSpeedLimiter = enable;
|
||||
this->_settingsPending.enableExecutionSpeedLimiter = enable;
|
||||
|
||||
this->_newSettingsPendingOnExecutionLoopStart = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
}
|
||||
|
||||
float ClientExecutionControl::GetExecutionSpeed()
|
||||
double ClientExecutionControl::GetExecutionSpeed()
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
const float speedScalar = this->_settingsPending.executionSpeed;
|
||||
const double speedScalar = this->_settingsPending.executionSpeed;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
|
||||
return speedScalar;
|
||||
}
|
||||
|
||||
void ClientExecutionControl::SetExecutionSpeed(float speedScalar)
|
||||
void ClientExecutionControl::SetExecutionSpeed(double speedScalar)
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
this->_settingsPending.executionSpeed = speedScalar;
|
||||
|
||||
this->_newSettingsPendingOnExecutionLoopStart = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
}
|
||||
|
||||
|
@ -288,46 +448,98 @@ bool ClientExecutionControl::GetEnableFrameSkip()
|
|||
return enable;
|
||||
}
|
||||
|
||||
bool ClientExecutionControl::GetEnableFrameSkipApplied()
|
||||
{
|
||||
return this->_settingsApplied.enableFrameSkip;
|
||||
}
|
||||
|
||||
void ClientExecutionControl::SetEnableFrameSkip(bool enable)
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
|
||||
if (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()
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
const uint8_t numFramesToSkip = this->_settingsPending.framesToSkip;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
return this->_framesToSkip;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
this->_settingsPending.execBehavior = newBehavior;
|
||||
|
||||
this->_newSettingsPendingOnExecutionLoopStart = true;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
}
|
||||
|
||||
FrameJumpBehavior ClientExecutionControl::GetFrameJumpBehavior()
|
||||
|
@ -340,67 +552,113 @@ void ClientExecutionControl::SetFrameJumpBehavior(FrameJumpBehavior newBehavior)
|
|||
this->_settingsPending.jumpBehavior = newBehavior;
|
||||
}
|
||||
|
||||
void ClientExecutionControl::FlushSettingsOnReset()
|
||||
void ClientExecutionControl::ApplySettingsOnReset()
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnReset);
|
||||
|
||||
CommonSettings.use_jit = (this->_settingsPending.cpuEngineID == CPUEmulationEngineID_DynamicRecompiler);
|
||||
CommonSettings.jit_max_block_size = this->_settingsPending.JITMaxBlockSize;
|
||||
if (this->_newSettingsPendingOnReset)
|
||||
{
|
||||
this->_settingsApplied.cpuEngineID = this->_settingsPending.cpuEngineID;
|
||||
this->_settingsApplied.JITMaxBlockSize = this->_settingsPending.JITMaxBlockSize;
|
||||
|
||||
this->_settingsApplied.filePathARM9BIOS = this->_settingsPending.filePathARM9BIOS;
|
||||
this->_settingsApplied.filePathARM7BIOS = this->_settingsPending.filePathARM7BIOS;
|
||||
this->_settingsApplied.filePathFirmware = this->_settingsPending.filePathFirmware;
|
||||
|
||||
this->_newSettingsPendingOnReset = false;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
|
||||
}
|
||||
|
||||
void ClientExecutionControl::FlushSettingsOnExecutionLoopStart()
|
||||
{
|
||||
pthread_mutex_lock(&this->_mutexSettingsApplyOnExecutionLoopStart);
|
||||
CommonSettings.use_jit = (this->_settingsApplied.cpuEngineID == CPUEmulationEngineID_DynamicRecompiler);
|
||||
CommonSettings.jit_max_block_size = this->_settingsApplied.JITMaxBlockSize;
|
||||
|
||||
pthread_mutex_lock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
|
||||
const bool didFrameSkipSettingChange = (this->_settingsPending.enableFrameSkip != this->_settingsApplied.enableFrameSkip);
|
||||
if (didFrameSkipSettingChange)
|
||||
if (this->_settingsApplied.filePathARM9BIOS.length() == 0)
|
||||
{
|
||||
this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip;
|
||||
this->_settingsApplied.framesToSkip = this->_settingsPending.framesToSkip;
|
||||
}
|
||||
|
||||
const float speedScalar = (this->_settingsPending.executionSpeed > SPEED_SCALAR_MIN) ? this->_settingsPending.executionSpeed : SPEED_SCALAR_MIN;
|
||||
const bool didExecutionSpeedChange = (speedScalar != this->_settingsApplied.executionSpeed) || (this->_settingsPending.enableSpeedLimiter != this->_settingsApplied.enableSpeedLimiter);
|
||||
if (didExecutionSpeedChange)
|
||||
{
|
||||
this->_settingsApplied.enableSpeedLimiter = this->_settingsPending.enableSpeedLimiter;
|
||||
this->_settingsApplied.executionSpeed = speedScalar;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
|
||||
|
||||
if (didFrameSkipSettingChange)
|
||||
{
|
||||
NDS_OmitFrameSkip(2);
|
||||
}
|
||||
|
||||
if (didExecutionSpeedChange)
|
||||
{
|
||||
if (this->_settingsApplied.enableSpeedLimiter)
|
||||
{
|
||||
this->_settingsApplied.timeBudget = this->GetFrameAbsoluteTime(1.0f/speedScalar);
|
||||
memset(CommonSettings.ARM9BIOS, 0, sizeof(CommonSettings.ARM9BIOS));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_settingsApplied.timeBudget = 0;
|
||||
}
|
||||
strlcpy(CommonSettings.ARM9BIOS, this->_settingsApplied.filePathARM9BIOS.c_str(), sizeof(CommonSettings.ARM9BIOS));
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&this->_mutexSettingsApplyOnExecutionLoopStart);
|
||||
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->_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);
|
||||
|
||||
if (this->_newSettingsPendingOnNDSExec)
|
||||
{
|
||||
this->_settingsApplied.enableAdvancedBusLevelTiming = this->_settingsPending.enableAdvancedBusLevelTiming;
|
||||
this->_settingsApplied.enableRigorous3DRenderingTiming = this->_settingsPending.enableRigorous3DRenderingTiming;
|
||||
this->_settingsApplied.enableGameSpecificHacks = this->_settingsPending.enableGameSpecificHacks;
|
||||
this->_settingsApplied.enableExternalBIOS = this->_settingsPending.enableExternalBIOS;
|
||||
this->_settingsApplied.enableBIOSInterrupts = this->_settingsPending.enableBIOSInterrupts;
|
||||
this->_settingsApplied.enableBIOSPatchDelayLoop = this->_settingsPending.enableBIOSPatchDelayLoop;
|
||||
|
@ -409,6 +667,14 @@ void ClientExecutionControl::FlushSettingsOnNDSExec()
|
|||
this->_settingsApplied.enableDebugConsole = this->_settingsPending.enableDebugConsole;
|
||||
this->_settingsApplied.enableEnsataEmulation = this->_settingsPending.enableEnsataEmulation;
|
||||
|
||||
this->_settingsApplied.enableCheats = this->_settingsPending.enableCheats;
|
||||
|
||||
this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip;
|
||||
|
||||
const bool needResetFramesToSkip = this->_needResetFramesToSkip;
|
||||
|
||||
this->_needResetFramesToSkip = false;
|
||||
this->_newSettingsPendingOnNDSExec = false;
|
||||
pthread_mutex_unlock(&this->_mutexSettingsPendingOnNDSExec);
|
||||
|
||||
CommonSettings.advanced_timing = this->_settingsApplied.enableAdvancedBusLevelTiming;
|
||||
|
@ -422,11 +688,110 @@ void ClientExecutionControl::FlushSettingsOnNDSExec()
|
|||
CommonSettings.DebugConsole = this->_settingsApplied.enableDebugConsole;
|
||||
CommonSettings.EnsataEmulation = this->_settingsApplied.enableEnsataEmulation;
|
||||
|
||||
pthread_mutex_unlock(&this->_mutexSettingsApplyOnNDSExec);
|
||||
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 1.0;
|
||||
return this->_frameTime;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define _CLIENT_EXECUTION_CONTROL_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
|
||||
#define SPEED_SCALAR_QUARTER 0.25 // Speed scalar for quarter execution speed.
|
||||
#define SPEED_SCALAR_HALF 0.5 // Speed scalar for half execution speed.
|
||||
|
@ -60,9 +61,13 @@ typedef struct ClientExecutionControlSettings
|
|||
{
|
||||
CPUEmulationEngineID cpuEngineID;
|
||||
uint8_t JITMaxBlockSize;
|
||||
std::string filePathARM9BIOS;
|
||||
std::string filePathARM7BIOS;
|
||||
std::string filePathFirmware;
|
||||
|
||||
bool enableAdvancedBusLevelTiming;
|
||||
bool enableRigorous3DRenderingTiming;
|
||||
bool enableGameSpecificHacks;
|
||||
bool enableExternalBIOS;
|
||||
bool enableBIOSInterrupts;
|
||||
bool enableBIOSPatchDelayLoop;
|
||||
|
@ -71,12 +76,12 @@ typedef struct ClientExecutionControlSettings
|
|||
bool enableDebugConsole;
|
||||
bool enableEnsataEmulation;
|
||||
|
||||
bool enableSpeedLimiter;
|
||||
float executionSpeed;
|
||||
uint64_t timeBudget;
|
||||
bool enableCheats;
|
||||
|
||||
bool enableExecutionSpeedLimiter;
|
||||
double executionSpeed;
|
||||
|
||||
bool enableFrameSkip;
|
||||
uint8_t framesToSkip;
|
||||
uint64_t frameJumpTarget;
|
||||
|
||||
ExecutionBehavior execBehavior;
|
||||
|
@ -90,14 +95,19 @@ private:
|
|||
ClientExecutionControlSettings _settingsPending;
|
||||
ClientExecutionControlSettings _settingsApplied;
|
||||
|
||||
bool _newSettingsPendingOnReset;
|
||||
bool _newSettingsPendingOnExecutionLoopStart;
|
||||
bool _newSettingsPendingOnNDSExec;
|
||||
|
||||
bool _needResetFramesToSkip;
|
||||
|
||||
double _frameTime;
|
||||
uint8_t _framesToSkip;
|
||||
ExecutionBehavior _prevExecBehavior;
|
||||
|
||||
pthread_mutex_t _mutexSettingsPendingOnReset;
|
||||
pthread_mutex_t _mutexSettingsApplyOnReset;
|
||||
|
||||
pthread_mutex_t _mutexSettingsPendingOnExecutionLoopStart;
|
||||
pthread_mutex_t _mutexSettingsApplyOnExecutionLoopStart;
|
||||
|
||||
pthread_mutex_t _mutexSettingsPendingOnNDSExec;
|
||||
pthread_mutex_t _mutexSettingsApplyOnNDSExec;
|
||||
|
||||
public:
|
||||
ClientExecutionControl();
|
||||
|
@ -109,12 +119,24 @@ public:
|
|||
uint8_t GetJITMaxBlockSize();
|
||||
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();
|
||||
void SetEnableAdvancedBusLevelTiming(bool enable);
|
||||
|
||||
bool GetEnableRigorous3DRenderingTiming();
|
||||
void SetEnableRigorous3DRenderingTiming(bool enable);
|
||||
|
||||
bool GetEnableGameSpecificHacks();
|
||||
void SetEnableGameSpecificHacks(bool enable);
|
||||
|
||||
bool GetEnableExternalBIOS();
|
||||
void SetEnableExternalBIOS(bool enable);
|
||||
|
||||
|
@ -136,31 +158,45 @@ public:
|
|||
bool GetEnableEnsataEmulation();
|
||||
void SetEnableEnsataEmulation(bool enable);
|
||||
|
||||
bool GetEnableCheats();
|
||||
void SetEnableCheats(bool enable);
|
||||
|
||||
bool GetEnableSpeedLimiter();
|
||||
void SetEnableSpeedLimiter(bool enable);
|
||||
|
||||
float GetExecutionSpeed();
|
||||
void SetExecutionSpeed(float speedScalar);
|
||||
double GetExecutionSpeed();
|
||||
void SetExecutionSpeed(double speedScalar);
|
||||
|
||||
bool GetEnableFrameSkip();
|
||||
bool GetEnableFrameSkipApplied();
|
||||
void SetEnableFrameSkip(bool enable);
|
||||
|
||||
uint8_t GetFramesToSkip();
|
||||
void SetFramesToSkip(uint8_t numFrames);
|
||||
void ResetFramesToSkip();
|
||||
|
||||
uint64_t GetFrameJumpTarget();
|
||||
uint64_t GetFrameJumpTargetApplied();
|
||||
void SetFrameJumpTarget(uint64_t newJumpTarget);
|
||||
|
||||
ExecutionBehavior GetPreviousExecutionBehavior();
|
||||
ExecutionBehavior GetExecutionBehavior();
|
||||
ExecutionBehavior GetExecutionBehaviorApplied();
|
||||
void SetExecutionBehavior(ExecutionBehavior newBehavior);
|
||||
|
||||
FrameJumpBehavior GetFrameJumpBehavior();
|
||||
void SetFrameJumpBehavior(FrameJumpBehavior newBehavior);
|
||||
|
||||
void FlushSettingsOnReset();
|
||||
void FlushSettingsOnExecutionLoopStart();
|
||||
void FlushSettingsOnNDSExec();
|
||||
void ApplySettingsOnReset();
|
||||
void ApplySettingsOnExecutionLoopStart();
|
||||
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_
|
||||
|
|
|
@ -35,11 +35,6 @@ typedef void *gdbstub_handle_t;
|
|||
typedef struct
|
||||
{
|
||||
CocoaDSCore *cdsCore;
|
||||
ExecutionBehavior behavior;
|
||||
bool isFrameSkipEnabled;
|
||||
uint64_t frameJumpTarget;
|
||||
uint8_t framesToSkip;
|
||||
uint64_t timeBudgetMachAbsTime;
|
||||
pthread_mutex_t mutexOutputList;
|
||||
pthread_mutex_t mutexThreadExecute;
|
||||
pthread_cond_t condThreadExecute;
|
||||
|
@ -48,6 +43,8 @@ typedef struct
|
|||
|
||||
@interface CocoaDSCore : NSObject
|
||||
{
|
||||
ClientExecutionControl *execControl;
|
||||
|
||||
CocoaDSController *cdsController;
|
||||
CocoaDSFirmware *cdsFirmware;
|
||||
CocoaDSGPU *cdsGPU;
|
||||
|
@ -56,9 +53,6 @@ typedef struct
|
|||
pthread_t coreThread;
|
||||
CoreThreadParam threadParam;
|
||||
|
||||
NSInteger prevCoreState;
|
||||
BOOL isSpeedLimitEnabled;
|
||||
CGFloat speedScalar;
|
||||
std::string _slot1R4Path;
|
||||
|
||||
NSTimer *_fpsTimer;
|
||||
|
@ -73,16 +67,6 @@ typedef struct
|
|||
volatile gdbstub_handle_t gdbStubHandleARM9;
|
||||
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;
|
||||
NSString *slot1StatusText;
|
||||
NSString *frameStatus;
|
||||
|
@ -92,12 +76,10 @@ typedef struct
|
|||
|
||||
OSSpinLock spinlockCdsController;
|
||||
OSSpinLock spinlockMasterExecute;
|
||||
OSSpinLock spinlockExecutionChange;
|
||||
OSSpinLock spinlockCheatEnableFlag;
|
||||
OSSpinLock spinlockEmulationFlags;
|
||||
OSSpinLock spinlockCPUEmulationEngine;
|
||||
}
|
||||
|
||||
@property (readonly, nonatomic) ClientExecutionControl *execControl;
|
||||
|
||||
@property (retain) CocoaDSController *cdsController;
|
||||
@property (retain) CocoaDSFirmware *cdsFirmware;
|
||||
@property (retain) CocoaDSGPU *cdsGPU;
|
||||
|
@ -142,12 +124,11 @@ typedef struct
|
|||
|
||||
@property (readonly) pthread_rwlock_t *rwlockCoreExecute;
|
||||
|
||||
- (BOOL) ejectCardFlag;
|
||||
- (BOOL) isSlot1Ejected;
|
||||
- (void) slot1Eject;
|
||||
|
||||
- (void) changeRomSaveType:(NSInteger)saveTypeID;
|
||||
- (void) changeExecutionSpeed;
|
||||
- (void) applyDynaRec;
|
||||
- (void) updateExecutionSpeedStatus;
|
||||
- (BOOL) applySlot1Device;
|
||||
|
||||
- (void) restoreCoreState;
|
||||
|
@ -171,5 +152,3 @@ typedef struct
|
|||
@end
|
||||
|
||||
static void* RunCoreThread(void *arg);
|
||||
static uint8_t CalculateFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime);
|
||||
uint64_t GetFrameAbsoluteTime(const double frameTimeScalar);
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
#include "ClientExecutionControl.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#include "../../movie.h"
|
||||
#include "../../NDSSystem.h"
|
||||
#include "../../armcpu.h"
|
||||
|
@ -78,6 +75,8 @@ volatile bool execute = true;
|
|||
|
||||
@implementation CocoaDSCore
|
||||
|
||||
@synthesize execControl;
|
||||
|
||||
@dynamic cdsController;
|
||||
@synthesize cdsFirmware;
|
||||
@synthesize cdsGPU;
|
||||
|
@ -146,6 +145,8 @@ volatile bool execute = true;
|
|||
return self;
|
||||
}
|
||||
|
||||
execControl = new ClientExecutionControl;
|
||||
|
||||
_fpsTimer = nil;
|
||||
_isTimerAtSecond = NO;
|
||||
|
||||
|
@ -154,42 +155,16 @@ volatile bool execute = true;
|
|||
cdsGPU = [[[[CocoaDSGPU alloc] init] 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;
|
||||
slot1StatusText = NSSTRING_STATUS_EMULATION_NOT_RUNNING;
|
||||
|
||||
spinlockMasterExecute = 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;
|
||||
_slot1R4Path = "";
|
||||
|
||||
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.mutexThreadExecute, NULL);
|
||||
|
@ -252,6 +227,7 @@ volatile bool execute = true;
|
|||
|
||||
[self setIsGdbStubStarted:NO];
|
||||
|
||||
delete execControl;
|
||||
NDS_DeInit();
|
||||
|
||||
[super dealloc];
|
||||
|
@ -305,81 +281,50 @@ volatile bool execute = true;
|
|||
return theController;
|
||||
}
|
||||
|
||||
- (void) setIsFrameSkipEnabled:(BOOL)theState
|
||||
- (void) setIsFrameSkipEnabled:(BOOL)enable
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
|
||||
if (theState)
|
||||
{
|
||||
threadParam.isFrameSkipEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
threadParam.isFrameSkipEnabled = false;
|
||||
threadParam.framesToSkip = 0;
|
||||
NDS_OmitFrameSkip(2);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
execControl->SetEnableFrameSkip((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) isFrameSkipEnabled
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
const BOOL theState = threadParam.isFrameSkipEnabled ? YES : NO;
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
return theState;
|
||||
const bool enable = execControl->GetEnableFrameSkip();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setSpeedScalar:(CGFloat)scalar
|
||||
{
|
||||
OSSpinLockLock(&spinlockExecutionChange);
|
||||
speedScalar = scalar;
|
||||
OSSpinLockUnlock(&spinlockExecutionChange);
|
||||
[self changeExecutionSpeed];
|
||||
execControl->SetExecutionSpeed((float)scalar);
|
||||
[self updateExecutionSpeedStatus];
|
||||
}
|
||||
|
||||
- (CGFloat) speedScalar
|
||||
{
|
||||
OSSpinLockLock(&spinlockExecutionChange);
|
||||
const CGFloat scalar = speedScalar;
|
||||
OSSpinLockUnlock(&spinlockExecutionChange);
|
||||
|
||||
const CGFloat scalar = (CGFloat)execControl->GetExecutionSpeed();
|
||||
return scalar;
|
||||
}
|
||||
|
||||
- (void) setIsSpeedLimitEnabled:(BOOL)theState
|
||||
- (void) setIsSpeedLimitEnabled:(BOOL)enable
|
||||
{
|
||||
OSSpinLockLock(&spinlockExecutionChange);
|
||||
isSpeedLimitEnabled = theState;
|
||||
OSSpinLockUnlock(&spinlockExecutionChange);
|
||||
[self changeExecutionSpeed];
|
||||
execControl->SetEnableSpeedLimiter((enable) ? true : false);
|
||||
[self updateExecutionSpeedStatus];
|
||||
}
|
||||
|
||||
- (BOOL) isSpeedLimitEnabled
|
||||
{
|
||||
OSSpinLockLock(&spinlockExecutionChange);
|
||||
const BOOL enabled = isSpeedLimitEnabled;
|
||||
OSSpinLockUnlock(&spinlockExecutionChange);
|
||||
|
||||
return enabled;
|
||||
const bool enable = execControl->GetEnableSpeedLimiter();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setIsCheatingEnabled:(BOOL)theState
|
||||
- (void) setIsCheatingEnabled:(BOOL)enable
|
||||
{
|
||||
OSSpinLockLock(&spinlockCheatEnableFlag);
|
||||
CommonSettings.cheatsDisable = theState ? false : true;
|
||||
OSSpinLockUnlock(&spinlockCheatEnableFlag);
|
||||
execControl->SetEnableCheats((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) isCheatingEnabled
|
||||
{
|
||||
OSSpinLockLock(&spinlockCheatEnableFlag);
|
||||
BOOL theState = CommonSettings.cheatsDisable ? NO : YES;
|
||||
OSSpinLockUnlock(&spinlockCheatEnableFlag);
|
||||
|
||||
return theState;
|
||||
const bool enable = execControl->GetEnableCheats();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setIsGdbStubStarted:(BOOL)theState
|
||||
|
@ -463,8 +408,7 @@ volatile bool execute = true;
|
|||
// frame skipping this time.
|
||||
if (isInDebugTrap && !theState)
|
||||
{
|
||||
threadParam.framesToSkip = 0;
|
||||
NDS_OmitFrameSkip(2);
|
||||
execControl->ResetFramesToSkip();
|
||||
}
|
||||
|
||||
isInDebugTrap = theState;
|
||||
|
@ -477,214 +421,141 @@ volatile bool execute = true;
|
|||
|
||||
- (void) setEmuFlagAdvancedBusLevelTiming:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.advanced_timing = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableAdvancedBusLevelTiming((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagAdvancedBusLevelTiming
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.advanced_timing) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableAdvancedBusLevelTiming();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagRigorousTiming:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.rigorous_timing = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableRigorous3DRenderingTiming((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagRigorousTiming
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.rigorous_timing) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableRigorous3DRenderingTiming();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagUseGameSpecificHacks:(BOOL)useTiming
|
||||
- (void) setEmuFlagUseGameSpecificHacks:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.gamehacks.en = (useTiming) ? true : false;
|
||||
CommonSettings.gamehacks.apply();
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableGameSpecificHacks((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagUseGameSpecificHacks
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL useTiming = (CommonSettings.gamehacks.en) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return useTiming;
|
||||
const bool enable = execControl->GetEnableGameSpecificHacks();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagUseExternalBios:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.UseExtBIOS = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableExternalBIOS((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagUseExternalBios
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.UseExtBIOS) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableExternalBIOS();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagEmulateBiosInterrupts:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.SWIFromBIOS = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableBIOSInterrupts((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagEmulateBiosInterrupts
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.SWIFromBIOS) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableBIOSInterrupts();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagPatchDelayLoop:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.PatchSWI3 = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableBIOSPatchDelayLoop((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagPatchDelayLoop
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.PatchSWI3) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableBIOSPatchDelayLoop();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagUseExternalFirmware:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.UseExtFirmware = (enable) ? true : false;
|
||||
CommonSettings.UseExtFirmwareSettings = CommonSettings.UseExtFirmware;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableExternalFirmware((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagUseExternalFirmware
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.UseExtFirmware) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableExternalFirmware();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagFirmwareBoot:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.BootFromFirmware = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableFirmwareBoot((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagFirmwareBoot
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.BootFromFirmware) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableFirmwareBoot();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagDebugConsole:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.DebugConsole = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableDebugConsole((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagDebugConsole
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.DebugConsole) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableDebugConsole();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setEmuFlagEmulateEnsata:(BOOL)enable
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.EnsataEmulation = (enable) ? true : false;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetEnableEnsataEmulation((enable) ? true : false);
|
||||
}
|
||||
|
||||
- (BOOL) emuFlagEmulateEnsata
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const BOOL enable = (CommonSettings.EnsataEmulation) ? YES : NO;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return enable;
|
||||
const bool enable = execControl->GetEnableEnsataEmulation();
|
||||
return (enable) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void) setCpuEmulationEngine:(NSInteger)engineID
|
||||
{
|
||||
OSSpinLockLock(&spinlockCPUEmulationEngine);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
cpuEmulationEngine = engineID;
|
||||
#else
|
||||
cpuEmulationEngine = CPUEmulationEngine_Interpreter;
|
||||
#endif
|
||||
OSSpinLockUnlock(&spinlockCPUEmulationEngine);
|
||||
execControl->SetCPUEmulationEngineID((CPUEmulationEngineID)engineID);
|
||||
}
|
||||
|
||||
- (NSInteger) cpuEmulationEngine
|
||||
{
|
||||
OSSpinLockLock(&spinlockCPUEmulationEngine);
|
||||
const NSInteger engineID = cpuEmulationEngine;
|
||||
OSSpinLockUnlock(&spinlockCPUEmulationEngine);
|
||||
|
||||
return engineID;
|
||||
return (NSInteger)execControl->GetCPUEmulationEngineID();
|
||||
}
|
||||
|
||||
- (void) setMaxJITBlockSize:(NSInteger)blockSize
|
||||
{
|
||||
pthread_rwlock_wrlock(&threadParam.rwlockCoreExecute);
|
||||
CommonSettings.jit_max_block_size = (blockSize > 0) ? blockSize : 1;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
execControl->SetJITMaxBlockSize((uint8_t)blockSize);
|
||||
}
|
||||
|
||||
- (NSInteger) maxJITBlockSize
|
||||
{
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockCoreExecute);
|
||||
const NSInteger blockSize = CommonSettings.jit_max_block_size;
|
||||
pthread_rwlock_unlock(&threadParam.rwlockCoreExecute);
|
||||
|
||||
return blockSize;
|
||||
return (NSInteger)execControl->GetJITMaxBlockSize();
|
||||
}
|
||||
|
||||
- (void) setCoreState:(NSInteger)coreState
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
|
||||
if (threadParam.behavior == ExecutionBehavior_Run || threadParam.behavior == ExecutionBehavior_Pause)
|
||||
{
|
||||
prevCoreState = threadParam.behavior;
|
||||
}
|
||||
execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
|
||||
|
||||
threadParam.behavior = (ExecutionBehavior)coreState;
|
||||
threadParam.framesToSkip = 0;
|
||||
NDS_OmitFrameSkip(2);
|
||||
pthread_mutex_lock(&threadParam.mutexOutputList);
|
||||
|
||||
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 = nil;
|
||||
break;
|
||||
|
@ -758,6 +629,8 @@ volatile bool execute = true;
|
|||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&threadParam.mutexOutputList);
|
||||
|
||||
pthread_cond_signal(&threadParam.condThreadExecute);
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
|
@ -767,62 +640,44 @@ volatile bool execute = true;
|
|||
|
||||
- (NSInteger) coreState
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
const NSInteger theState = threadParam.behavior;
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
return theState;
|
||||
const NSInteger behavior = (NSInteger)execControl->GetExecutionBehavior();
|
||||
return behavior;
|
||||
}
|
||||
|
||||
- (void) setArm9ImageURL:(NSURL *)fileURL
|
||||
{
|
||||
if (fileURL != nil)
|
||||
{
|
||||
strlcpy(CommonSettings.ARM9BIOS, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.ARM9BIOS));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(CommonSettings.ARM9BIOS, 0, sizeof(CommonSettings.ARM9BIOS));
|
||||
}
|
||||
const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
|
||||
execControl->SetARM9ImagePath(filePath);
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
if (fileURL != nil)
|
||||
{
|
||||
strlcpy(CommonSettings.ARM7BIOS, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.ARM7BIOS));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(CommonSettings.ARM7BIOS, 0, sizeof(CommonSettings.ARM7BIOS));
|
||||
}
|
||||
const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
|
||||
execControl->SetARM7ImagePath(filePath);
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
if (fileURL != nil)
|
||||
{
|
||||
strlcpy(CommonSettings.Firmware, [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding], sizeof(CommonSettings.Firmware));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(CommonSettings.Firmware, 0, sizeof(CommonSettings.Firmware));
|
||||
}
|
||||
const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
|
||||
execControl->SetFirmwareImagePath(filePath);
|
||||
}
|
||||
|
||||
- (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
|
||||
|
@ -830,7 +685,7 @@ volatile bool execute = true;
|
|||
return &threadParam.rwlockCoreExecute;
|
||||
}
|
||||
|
||||
- (BOOL) ejectCardFlag
|
||||
- (BOOL) isSlot1Ejected
|
||||
{
|
||||
const BOOL isEjected = (nds.cardEjected) ? YES : NO;
|
||||
return isEjected;
|
||||
|
@ -852,54 +707,18 @@ volatile bool execute = true;
|
|||
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;
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
threadParam.timeBudgetMachAbsTime = GetFrameAbsoluteTime(1.0/theSpeed);
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
[self setExecutionSpeedStatus:[NSString stringWithFormat:@"%1.2fx", theSpeed]];
|
||||
[self setExecutionSpeedStatus:[NSString stringWithFormat:@"%1.2fx", [self speedScalar]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
threadParam.timeBudgetMachAbsTime = 0;
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
[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
|
||||
{
|
||||
const NSInteger deviceTypeID = [self slot1DeviceType];
|
||||
|
@ -946,16 +765,16 @@ volatile bool execute = true;
|
|||
|
||||
- (void) restoreCoreState
|
||||
{
|
||||
[self setCoreState:prevCoreState];
|
||||
[self setCoreState:(NSInteger)execControl->GetPreviousExecutionBehavior()];
|
||||
}
|
||||
|
||||
- (void) reset
|
||||
{
|
||||
[self setCoreState:ExecutionBehavior_Pause];
|
||||
[self applyDynaRec];
|
||||
[self applySlot1Device];
|
||||
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
execControl->ApplySettingsOnReset();
|
||||
NDS_Reset();
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
|
@ -1003,18 +822,12 @@ volatile bool execute = true;
|
|||
|
||||
- (void) frameJumpTo:(NSUInteger)targetFrameNum
|
||||
{
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
execControl->SetFrameJumpTarget(targetFrameNum);
|
||||
|
||||
threadParam.frameJumpTarget = targetFrameNum;
|
||||
if (targetFrameNum <= (NSUInteger)currFrameCounter)
|
||||
if (targetFrameNum > [self frameNumber])
|
||||
{
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
[self setCoreState:ExecutionBehavior_FrameJump];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) frameJump:(NSUInteger)relativeFrameNum
|
||||
|
@ -1163,26 +976,37 @@ static void* RunCoreThread(void *arg)
|
|||
{
|
||||
CoreThreadParam *param = (CoreThreadParam *)arg;
|
||||
CocoaDSCore *cdsCore = (CocoaDSCore *)param->cdsCore;
|
||||
ClientExecutionControl *execControl = [cdsCore execControl];
|
||||
NSMutableArray *cdsOutputList = [cdsCore cdsOutputList];
|
||||
NSUInteger frameNum = 0;
|
||||
uint64_t startTime = 0;
|
||||
uint64_t timeBudget = 0; // Need local variable to ensure that param->timeBudgetMachAbsTime is thread-safe.
|
||||
uint64_t frameNum = 0;
|
||||
double startTime = 0;
|
||||
double frameTime = 0; // The amount of time that is expected for the frame to run.
|
||||
|
||||
ExecutionBehavior behavior = ExecutionBehavior_Pause;
|
||||
uint64_t frameJumpTarget = 0;
|
||||
|
||||
do
|
||||
{
|
||||
startTime = mach_absolute_time();
|
||||
pthread_mutex_lock(¶m->mutexThreadExecute);
|
||||
timeBudget = param->timeBudgetMachAbsTime;
|
||||
startTime = execControl->GetCurrentAbsoluteTime();
|
||||
|
||||
while (!(param->behavior != ExecutionBehavior_Pause && execute))
|
||||
pthread_mutex_lock(¶m->mutexThreadExecute);
|
||||
execControl->ApplySettingsOnExecutionLoopStart();
|
||||
behavior = execControl->GetExecutionBehaviorApplied();
|
||||
|
||||
while (!(behavior != ExecutionBehavior_Pause && execute))
|
||||
{
|
||||
pthread_cond_wait(¶m->condThreadExecute, ¶m->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];
|
||||
if (param->behavior != ExecutionBehavior_FrameJump)
|
||||
if (behavior != ExecutionBehavior_FrameJump)
|
||||
{
|
||||
[cdsController flush];
|
||||
}
|
||||
|
@ -1196,10 +1020,12 @@ static void* RunCoreThread(void *arg)
|
|||
NDS_endProcessingInput();
|
||||
FCEUMOV_HandleRecording();
|
||||
|
||||
execControl->ApplySettingsOnNDSExec();
|
||||
|
||||
// Execute the frame and increment the frame counter.
|
||||
pthread_rwlock_wrlock(¶m->rwlockCoreExecute);
|
||||
NDS_exec<false>();
|
||||
frameNum = currFrameCounter;
|
||||
frameNum = (uint64_t)currFrameCounter;
|
||||
pthread_rwlock_unlock(¶m->rwlockCoreExecute);
|
||||
|
||||
// Check if an internal execution error occurred that halted the emulation.
|
||||
|
@ -1216,9 +1042,11 @@ static void* RunCoreThread(void *arg)
|
|||
[cdsController updateMicLevel];
|
||||
[cdsController clearMicLevelMeasure];
|
||||
|
||||
const uint8_t framesToSkip = execControl->GetFramesToSkip();
|
||||
|
||||
pthread_mutex_lock(¶m->mutexOutputList);
|
||||
|
||||
switch (param->behavior)
|
||||
switch (behavior)
|
||||
{
|
||||
case ExecutionBehavior_Run:
|
||||
case ExecutionBehavior_FrameAdvance:
|
||||
|
@ -1226,7 +1054,7 @@ static void* RunCoreThread(void *arg)
|
|||
{
|
||||
for (CocoaDSOutput *cdsOutput in cdsOutputList)
|
||||
{
|
||||
if (![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || param->framesToSkip == 0)
|
||||
if ( ![cdsOutput isKindOfClass:[CocoaDSDisplay class]] || (framesToSkip == 0) )
|
||||
{
|
||||
[cdsOutput doCoreEmuFrame];
|
||||
}
|
||||
|
@ -1240,22 +1068,22 @@ static void* RunCoreThread(void *arg)
|
|||
|
||||
pthread_mutex_unlock(¶m->mutexOutputList);
|
||||
|
||||
switch (param->behavior)
|
||||
switch (behavior)
|
||||
{
|
||||
case ExecutionBehavior_Run:
|
||||
{
|
||||
// Determine the number of frames to skip based on how much time "debt"
|
||||
// we owe on timeBudget.
|
||||
if (param->isFrameSkipEnabled)
|
||||
if (execControl->GetEnableFrameSkipApplied())
|
||||
{
|
||||
if (param->framesToSkip > 0)
|
||||
if (framesToSkip > 0)
|
||||
{
|
||||
NDS_SkipNextFrame();
|
||||
param->framesToSkip--;
|
||||
execControl->SetFramesToSkip(framesToSkip - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
param->framesToSkip = CalculateFrameSkip(timeBudget, startTime);
|
||||
execControl->SetFramesToSkip( execControl->CalculateFrameSkip(startTime, frameTime) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1263,14 +1091,14 @@ static void* RunCoreThread(void *arg)
|
|||
|
||||
case ExecutionBehavior_FrameJump:
|
||||
{
|
||||
if (param->framesToSkip > 0)
|
||||
if (framesToSkip > 0)
|
||||
{
|
||||
NDS_SkipNextFrame();
|
||||
param->framesToSkip--;
|
||||
execControl->SetFramesToSkip(framesToSkip - 1);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1283,18 +1111,17 @@ static void* RunCoreThread(void *arg)
|
|||
|
||||
// If we're doing a frame advance, switch back to pause state immediately
|
||||
// after we're done with the frame.
|
||||
if (param->behavior == ExecutionBehavior_FrameAdvance)
|
||||
if (behavior == ExecutionBehavior_FrameAdvance)
|
||||
{
|
||||
[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;
|
||||
NDS_OmitFrameSkip(2);
|
||||
execControl->ResetFramesToSkip();
|
||||
}
|
||||
else if (frameNum >= param->frameJumpTarget)
|
||||
else if (frameNum >= frameJumpTarget)
|
||||
{
|
||||
[cdsCore restoreCoreState];
|
||||
}
|
||||
|
@ -1302,7 +1129,7 @@ static void* RunCoreThread(void *arg)
|
|||
else
|
||||
{
|
||||
// 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);
|
||||
|
@ -1310,80 +1137,6 @@ static void* RunCoreThread(void *arg)
|
|||
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
|
||||
|
||||
pthread_mutex_t* OSXDriver::GetCoreThreadMutexLock()
|
||||
|
@ -1432,7 +1185,7 @@ void OSXDriver::EMU_DebugIdleWakeUp()
|
|||
|
||||
#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.
|
||||
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)
|
||||
{
|
||||
pthread_join(*((pthread_t*)thread_handle), NULL);
|
||||
pthread_join(*(pthread_t *)thread_handle, NULL);
|
||||
free(thread_handle);
|
||||
}
|
||||
|
|
|
@ -1682,7 +1682,7 @@
|
|||
[self pauseCore];
|
||||
|
||||
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
|
||||
[cdsCore applyDynaRec];
|
||||
[cdsCore execControl]->ApplySettingsOnReset();
|
||||
[cdsCore applySlot1Device];
|
||||
[self writeDefaultsSlot1Settings:nil];
|
||||
|
||||
|
|
Loading…
Reference in New Issue