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/>.
*/
#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,93 +552,246 @@ 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;
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)
if (this->_newSettingsPendingOnReset)
{
this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip;
this->_settingsApplied.framesToSkip = this->_settingsPending.framesToSkip;
}
this->_settingsApplied.cpuEngineID = this->_settingsPending.cpuEngineID;
this->_settingsApplied.JITMaxBlockSize = this->_settingsPending.JITMaxBlockSize;
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;
}
this->_settingsApplied.filePathARM9BIOS = this->_settingsPending.filePathARM9BIOS;
this->_settingsApplied.filePathARM7BIOS = this->_settingsPending.filePathARM7BIOS;
this->_settingsApplied.filePathFirmware = this->_settingsPending.filePathFirmware;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnExecutionLoopStart);
this->_newSettingsPendingOnReset = false;
pthread_mutex_unlock(&this->_mutexSettingsPendingOnReset);
if (didFrameSkipSettingChange)
{
NDS_OmitFrameSkip(2);
}
CommonSettings.use_jit = (this->_settingsApplied.cpuEngineID == CPUEmulationEngineID_DynamicRecompiler);
CommonSettings.jit_max_block_size = this->_settingsApplied.JITMaxBlockSize;
if (didExecutionSpeedChange)
{
if (this->_settingsApplied.enableSpeedLimiter)
if (this->_settingsApplied.filePathARM9BIOS.length() == 0)
{
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));
}
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));
}
}
pthread_mutex_unlock(&this->_mutexSettingsApplyOnExecutionLoopStart);
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);
this->_settingsApplied.enableAdvancedBusLevelTiming = this->_settingsPending.enableAdvancedBusLevelTiming;
this->_settingsApplied.enableRigorous3DRenderingTiming = this->_settingsPending.enableRigorous3DRenderingTiming;
this->_settingsApplied.enableExternalBIOS = this->_settingsPending.enableExternalBIOS;
this->_settingsApplied.enableBIOSInterrupts = this->_settingsPending.enableBIOSInterrupts;
this->_settingsApplied.enableBIOSPatchDelayLoop = this->_settingsPending.enableBIOSPatchDelayLoop;
this->_settingsApplied.enableExternalFirmware = this->_settingsPending.enableExternalFirmware;
this->_settingsApplied.enableFirmwareBoot = this->_settingsPending.enableFirmwareBoot;
this->_settingsApplied.enableDebugConsole = this->_settingsPending.enableDebugConsole;
this->_settingsApplied.enableEnsataEmulation = this->_settingsPending.enableEnsataEmulation;
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;
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;
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;
this->_settingsApplied.enableFrameSkip = this->_settingsPending.enableFrameSkip;
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 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);
}

View File

@ -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_

View File

@ -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);

View File

@ -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;
[self setCoreState:ExecutionBehavior_FrameJump];
}
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(&param->mutexThreadExecute);
timeBudget = param->timeBudgetMachAbsTime;
startTime = execControl->GetCurrentAbsoluteTime();
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);
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(&param->rwlockCoreExecute);
NDS_exec<false>();
frameNum = currFrameCounter;
frameNum = (uint64_t)currFrameCounter;
pthread_rwlock_unlock(&param->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(&param->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(&param->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);
}

View File

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