Merge pull request #246 from unknownbrackets/emu-reset

Fix emu reset
This commit is contained in:
Henrik Rydgård 2012-12-24 02:04:44 -08:00
commit 3b730eb96a
29 changed files with 221 additions and 177 deletions

View file

@ -62,7 +62,6 @@ struct CtrlLatch {
//////////////////////////////////////////////////////////////////////////
// STATE BEGIN
static bool ctrlInited = false;
static bool analogEnabled = false;
static int ctrlLatchBufs = 0;
static u32 ctrlOldButtons = 0;
@ -259,13 +258,14 @@ void __CtrlTimerUpdate(u64 userdata, int cyclesLate)
void __CtrlInit()
{
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
ctrlTimer = CoreTiming::RegisterEvent("CtrlSampleTimer", __CtrlTimerUpdate);
__DisplayListenVblank(__CtrlVblank);
if (!ctrlInited)
{
__DisplayListenVblank(__CtrlVblank);
ctrlInited = true;
}
ctrlIdleReset = -1;
ctrlIdleBack = -1;
ctrlCycle = 0;
std::lock_guard<std::recursive_mutex> guard(ctrlMutex);
ctrlBuf = 1;
ctrlBufRead = 0;
@ -282,14 +282,11 @@ void __CtrlInit()
for (int i = 0; i < NUM_CTRL_BUFFERS; i++)
memcpy(&ctrlBufs[i], &ctrlCurrent, sizeof(_ctrl_data));
}
ctrlIdleReset = -1;
ctrlIdleBack = -1;
ctrlCycle = 0;
void __CtrlShutdown()
{
waitingThreads.clear();
ctrlTimer = CoreTiming::RegisterEvent("CtrlSampleTimer", __CtrlTimerUpdate);
}
u32 sceCtrlSetSamplingCycle(u32 cycle)

View file

@ -33,6 +33,7 @@ void Register_sceCtrl();
#define CTRL_RTRIGGER 0x0200
void __CtrlInit();
void __CtrlShutdown();
void __CtrlButtonDown(u32 buttonBit);
void __CtrlButtonUp(u32 buttonBit);

View file

@ -36,6 +36,11 @@ const int PSP_LANGUAGE_SIMPLIFIED_CHINESE = 11;
static u32 iLanguage = PSP_LANGUAGE_ENGLISH;
static u32 iButtonValue = 0;
void __ImposeInit()
{
iLanguage = PSP_LANGUAGE_ENGLISH;
iButtonValue = 0;
}
u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr)
{

View file

@ -18,3 +18,4 @@
#pragma once
void Register_sceImpose();
void __ImposeInit();

View file

@ -84,7 +84,7 @@ const std::string &EmuDebugOutput() {
typedef u32 (*DeferredAction)(SceUID id, int param);
DeferredAction defAction = 0;
u32 defParam;
u32 defParam = 0;
#define SCE_STM_FDIR 0x1000
#define SCE_STM_FREG 0x2000
@ -154,6 +154,8 @@ public:
void __IoInit() {
INFO_LOG(HLE, "Starting up I/O...");
MemoryStick_SetFatState(PSP_FAT_MEMORYSTICK_STATE_ASSIGNED);
#ifdef _WIN32
char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT];
@ -192,6 +194,8 @@ void __IoInit() {
}
void __IoShutdown() {
defAction = 0;
defParam = 0;
}
u32 sceIoAssign(const char *aliasname, const char *physname, const char *devname, u32 flag) {

View file

@ -53,6 +53,8 @@
#include "sceUmd.h"
#include "sceSsl.h"
#include "sceSas.h"
#include "sceImpose.h"
#include "sceUsb.h"
#include "../Util/PPGeDraw.h"
@ -78,6 +80,10 @@ void __KernelInit()
__KernelMemoryInit();
__KernelThreadingInit();
__KernelMutexInit();
__KernelSemaInit();
__KernelAlarmInit();
__KernelEventFlagInit();
__KernelMbxInit();
__IoInit();
__AudioInit();
__SasInit();
@ -89,6 +95,8 @@ void __KernelInit()
__UmdInit();
__CtrlInit();
__SslInit();
__ImposeInit();
__UsbInit();
// "Internal" PSP libraries
__PPGeInit();
@ -110,13 +118,15 @@ void __KernelShutdown()
__PPGeShutdown();
__CtrlShutdown();
__UtilityShutdown();
__GeShutdown();
__SasShutdown();
__AudioShutdown();
__IoShutdown();
__InterruptsShutdown();
__KernelThreadingShutdown();
__KernelMutexShutdown();
__KernelThreadingShutdown();
__KernelMemoryShutdown();
CoreTiming::ClearPendingEvents();

View file

@ -78,17 +78,7 @@ public:
Alarm *alarm;
};
bool alarmInitComplete = false;
int alarmTimer = 0;
void __KernelTriggerAlarm(u64 userdata, int cyclesLate);
void __KernelAlarmInit()
{
alarmTimer = CoreTiming::RegisterEvent("Alarm", __KernelTriggerAlarm);
alarmInitComplete = true;
}
static int alarmTimer = 0;
void __KernelTriggerAlarm(u64 userdata, int cyclesLate)
{
@ -100,6 +90,11 @@ void __KernelTriggerAlarm(u64 userdata, int cyclesLate)
__TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR, uid);
}
void __KernelAlarmInit()
{
alarmTimer = CoreTiming::RegisterEvent("Alarm", __KernelTriggerAlarm);
}
void __KernelScheduleAlarm(Alarm *alarm, u64 ticks)
{
alarm->alm.schedule = (CoreTiming::GetTicks() + ticks) / (u64) CoreTiming::GetClockFrequencyMHz();
@ -108,9 +103,6 @@ void __KernelScheduleAlarm(Alarm *alarm, u64 ticks)
SceUID __KernelSetAlarm(u64 ticks, u32 handlerPtr, u32 commonPtr)
{
if (!alarmInitComplete)
__KernelAlarmInit();
if (!Memory::IsValidAddress(handlerPtr))
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;

View file

@ -20,4 +20,6 @@
SceUID sceKernelSetAlarm(SceUInt clock, u32 handlerPtr, u32 commonPtr);
SceUID sceKernelSetSysClockAlarm(u32 sysClockPtr, u32 handlerPtr, u32 commonPtr);
int sceKernelCancelAlarm(SceUID uid);
int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr);
int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr);
void __KernelAlarmInit();

View file

@ -90,13 +90,11 @@ enum PspEventFlagWaitTypes
PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR,
};
bool eventFlagInitComplete = false;
int eventFlagWaitTimer = 0;
void __KernelEventFlagInit()
{
eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", &__KernelEventFlagTimeout);
eventFlagInitComplete = true;
}
bool __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
@ -168,9 +166,6 @@ bool __KernelClearEventFlagThreads(EventFlag *e, int reason)
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr)
{
if (!eventFlagInitComplete)
__KernelEventFlagInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateEventFlag(): invalid name", SCE_KERNEL_ERROR_ERROR);

View file

@ -26,3 +26,5 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr);
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr);
void __KernelEventFlagInit();

View file

@ -33,35 +33,9 @@ struct Interrupt
PSPInterrupt intno;
};
// Yeah, this bit is a bit silly.
static int interruptsEnabled = 1;
static bool inInterrupt;
void __InterruptsInit()
{
interruptsEnabled = 1;
}
void __InterruptsShutdown()
{
}
void __DisableInterrupts()
{
interruptsEnabled = 0;
}
void __EnableInterrupts()
{
interruptsEnabled = 1;
}
bool __InterruptsEnabled()
{
return interruptsEnabled != 0;
}
void __DisableInterrupts();
void __EnableInterrupts();
bool __InterruptsEnabled();
// InterruptsManager
//////////////////////////////////////////////////////////////////////////
@ -116,18 +90,6 @@ void sceKernelCpuResumeIntrWithSync(u32 enable)
sceKernelCpuResumeIntr(enable);
}
bool __IsInInterrupt()
{
return inInterrupt;
}
bool __CanExecuteInterrupt()
{
return !inInterrupt;
}
class IntrHandler {
public:
void add(int subIntrNum, SubIntrHandler *handler)
@ -154,6 +116,13 @@ public:
return 0;
// what to do, what to do...
}
void clear()
{
std::map<int, SubIntrHandler *>::iterator it, end;
for (it = subIntrHandlers.begin(), end = subIntrHandlers.end(); it != end; ++it)
delete it->second;
subIntrHandlers.clear();
}
void queueUp(int subintr)
{
@ -184,17 +153,9 @@ private:
class InterruptState
{
public:
void save()
{
insideInterrupt = __IsInInterrupt();
__KernelSaveContext(&savedCpu);
}
void restore()
{
::inInterrupt = insideInterrupt;
__KernelLoadContext(&savedCpu);
}
void save();
void restore();
void clear();
bool insideInterrupt;
ThreadContext savedCpu;
@ -208,6 +169,66 @@ InterruptState intState;
IntrHandler intrHandlers[PSP_NUMBER_INTERRUPTS];
std::list<PendingInterrupt> pendingInterrupts;
// Yeah, this bit is a bit silly.
static int interruptsEnabled = 1;
static bool inInterrupt;
void __InterruptsInit()
{
interruptsEnabled = 1;
inInterrupt = false;
intState.clear();
}
void __InterruptsShutdown()
{
for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
intrHandlers[i].clear();
pendingInterrupts.clear();
}
void __DisableInterrupts()
{
interruptsEnabled = 0;
}
void __EnableInterrupts()
{
interruptsEnabled = 1;
}
bool __InterruptsEnabled()
{
return interruptsEnabled != 0;
}
bool __IsInInterrupt()
{
return inInterrupt;
}
bool __CanExecuteInterrupt()
{
return !inInterrupt;
}
void InterruptState::save()
{
insideInterrupt = __IsInInterrupt();
__KernelSaveContext(&savedCpu);
}
void InterruptState::restore()
{
::inInterrupt = insideInterrupt;
__KernelLoadContext(&savedCpu);
}
void InterruptState::clear()
{
insideInterrupt = false;
}
// http://forums.ps2dev.org/viewtopic.php?t=5687

View file

@ -30,8 +30,7 @@ const int PSP_MBX_ERROR_DUPLICATE_MSG = 0x800201C9;
typedef std::pair<SceUID, u32> MbxWaitingThread;
void __KernelMbxTimeout(u64 userdata, int cyclesLate);
bool mbxInitComplete = false;
int mbxWaitTimer = 0;
static int mbxWaitTimer = 0;
struct NativeMbx
{
@ -162,8 +161,6 @@ struct Mbx : public KernelObject
void __KernelMbxInit()
{
mbxWaitTimer = CoreTiming::RegisterEvent("MbxTimeout", &__KernelMbxTimeout);
mbxInitComplete = true;
}
bool __KernelUnlockMbxForThread(Mbx *m, MbxWaitingThread &th, u32 &error, int result, bool &wokeThreads)
@ -263,9 +260,6 @@ std::vector<MbxWaitingThread>::iterator __KernelMbxFindPriority(std::vector<MbxW
SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr)
{
if (!mbxInitComplete)
__KernelMbxInit();
if (!name)
{
WARN_LOG(HLE, "%08x=%s(): invalid name", SCE_KERNEL_ERROR_ERROR, __FUNCTION__);

View file

@ -32,3 +32,5 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr);
int sceKernelPollMbx(SceUID id, u32 packetAddrPtr);
int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr);
int sceKernelReferMbxStatus(SceUID id, u32 infoAddr);
void __KernelMbxInit();

View file

@ -107,24 +107,18 @@ struct LwMutex : public KernelObject
std::vector<SceUID> waitingThreads;
};
bool mutexInitComplete = false;
int mutexWaitTimer = 0;
int lwMutexWaitTimer = 0;
static int mutexWaitTimer = 0;
static int lwMutexWaitTimer = 0;
// Thread -> Mutex locks for thread end.
typedef std::multimap<SceUID, SceUID> MutexMap;
MutexMap mutexHeldLocks;
static MutexMap mutexHeldLocks;
void __KernelMutexInit()
{
mutexWaitTimer = CoreTiming::RegisterEvent("MutexTimeout", &__KernelMutexTimeout);
lwMutexWaitTimer = CoreTiming::RegisterEvent("LwMutexTimeout", &__KernelLwMutexTimeout);
// TODO: Install on first mutex (if it's slow?)
__KernelListenThreadEnd(&__KernelMutexThreadEnd);
mutexInitComplete = true;
mutexWaitTimer = 0;
lwMutexWaitTimer = 0;
}
void __KernelMutexShutdown()
@ -191,9 +185,6 @@ std::vector<SceUID>::iterator __KernelMutexFindPriority(std::vector<SceUID> &wai
int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optionsPtr)
{
if (!mutexInitComplete)
__KernelMutexInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);
@ -507,9 +498,6 @@ int sceKernelUnlockMutex(SceUID id, int count)
int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr)
{
if (!mutexInitComplete)
__KernelMutexInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateLwMutex(): invalid name", SCE_KERNEL_ERROR_ERROR);

View file

@ -61,13 +61,11 @@ struct Semaphore : public KernelObject
std::vector<SceUID> waitingThreads;
};
bool semaInitComplete = false;
int semaWaitTimer = 0;
static int semaWaitTimer = 0;
void __KernelSemaInit()
{
semaWaitTimer = CoreTiming::RegisterEvent("SemaphoreTimeout", &__KernelSemaTimeout);
semaInitComplete = true;
}
// Returns whether the thread should be removed.
@ -173,9 +171,6 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
//SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option);
int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 optionPtr)
{
if (!semaInitComplete)
__KernelSemaInit();
if (!name)
{
WARN_LOG(HLE, "%08x=sceKernelCreateSema(): invalid name", SCE_KERNEL_ERROR_ERROR);

View file

@ -27,3 +27,5 @@ int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr);
int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);
void __KernelSemaTimeout(u64 userdata, int cycleslate);
void __KernelSemaInit();

View file

@ -162,7 +162,50 @@ struct ThreadWaitInfo {
u32 timeoutPtr;
};
class ActionAfterMipsCall;
// Owns outstanding MIPS calls and provides a way to get them by ID.
// TODO: MipsCall structs are kinda big, try to cut down on the copying by owning pointers instead.
class MipsCallManager {
public:
MipsCallManager() : idGen_(0) {}
int add(MipsCall *call) {
int id = genId();
calls_.insert(std::pair<int, MipsCall *>(id, call));
return id;
}
MipsCall *get(int id) {
return calls_[id];
}
MipsCall *pop(int id) {
MipsCall *temp = calls_[id];
calls_.erase(id);
return temp;
}
void clear() {
calls_.clear();
idGen_ = 0;
}
private:
int genId() { return ++idGen_; }
std::map<int, MipsCall *> calls_;
int idGen_;
};
class ActionAfterMipsCall : public Action
{
public:
virtual void run();
Thread *thread;
// Saved thread state
int status;
WaitType waitType;
int waitID;
ThreadWaitInfo waitInfo;
bool isProcessingCallbacks;
Action *chainedAction;
};
class Thread : public KernelObject
{
@ -276,8 +319,6 @@ public:
void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter);
int g_inCbCount = 0;
Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr);
void __KernelResetThread(Thread *t);
void __KernelCancelWakeup(SceUID threadID);
@ -286,6 +327,7 @@ bool __KernelCheckThreadCallbacks(Thread *thread, bool force);
//////////////////////////////////////////////////////////////////////////
//STATE BEGIN
//////////////////////////////////////////////////////////////////////////
int g_inCbCount = 0;
Thread *currentThread;
u32 idleThreadHackAddr;
u32 threadReturnHackAddr;
@ -300,6 +342,7 @@ int eventScheduledWakeup;
bool dispatchEnabled = true;
MipsCallManager mipsCalls;
// This seems nasty
SceUID curModule;
@ -435,10 +478,13 @@ void __KernelThreadingShutdown()
{
kernelMemory.Free(threadReturnHackAddr);
threadqueue.clear();
threadEndListeners.clear();
mipsCalls.clear();
threadReturnHackAddr = 0;
cbReturnHackAddr = 0;
currentThread = 0;
intReturnHackAddr = 0;
curModule = 0;
}
const char *__KernelGetThreadName(SceUID threadID)
@ -1568,50 +1614,6 @@ void sceKernelReferCallbackStatus()
}
}
// Owns outstanding MIPS calls and provides a way to get them by ID.
// TODO: MipsCall structs are kinda big, try to cut down on the copying by owning pointers instead.
class MipsCallManager {
public:
MipsCallManager() : idGen_(0) {}
int add(MipsCall *call) {
int id = genId();
calls_.insert(std::pair<int, MipsCall *>(id, call));
return id;
}
MipsCall *get(int id) {
return calls_[id];
}
MipsCall *pop(int id) {
MipsCall *temp = calls_[id];
calls_.erase(id);
return temp;
}
private:
int genId() { return ++idGen_; }
std::map<int, MipsCall *> calls_;
int idGen_;
};
MipsCallManager mipsCalls;
class ActionAfterMipsCall : public Action
{
public:
virtual void run();
Thread *thread;
// Saved thread state
int status;
WaitType waitType;
int waitID;
ThreadWaitInfo waitInfo;
bool isProcessingCallbacks;
Action *chainedAction;
};
void ActionAfterMipsCall::run() {
thread->nt.status = status;
thread->nt.waitType = waitType;
@ -1625,7 +1627,6 @@ void ActionAfterMipsCall::run() {
}
}
ActionAfterMipsCall *Thread::getRunningCallbackAction()
{
if (this == currentThread && g_inCbCount > 0)

View file

@ -22,16 +22,15 @@
#include "scePower.h"
#include "sceKernelThread.h"
static bool volatileMemLocked;
const int POWER_CB_AUTO = -1;
const int numberOfCBPowerSlots = 16;
static int powerCbSlots[numberOfCBPowerSlots];
static bool volatileMemLocked;
static int powerCbSlots[numberOfCBPowerSlots];
void __PowerInit() {
memset(powerCbSlots, 0, sizeof(powerCbSlots));
volatileMemLocked = false;
}
int scePowerGetBatteryLifePercent() {

View file

@ -47,8 +47,11 @@ struct PspUmdInfo {
u32 type;
};
void __UmdStatTimeout(u64 userdata, int cyclesLate);
void __UmdInit() {
void __UmdInit()
{
umdStatTimer = CoreTiming::RegisterEvent("UmdTimeout", &__UmdStatTimeout);
umdActivated = 1;
umdStatus = 0;
umdErrorStat = 0;
@ -214,9 +217,6 @@ void __UmdStatTimeout(u64 userdata, int cyclesLate)
void __UmdWaitStat(u32 timeout)
{
if (umdStatTimer == 0)
umdStatTimer = CoreTiming::RegisterEvent("UmdTimeout", &__UmdStatTimeout);
// This happens to be how the hardware seems to time things.
if (timeout <= 4)
timeout = 15;

View file

@ -22,6 +22,11 @@
bool usbActivated = false;
void __UsbInit()
{
usbActivated = false;
}
u32 sceUsbActivate() {
ERROR_LOG(HLE, "UNIMPL sceUsbActivate");
usbActivated = true;

View file

@ -18,3 +18,5 @@
#pragma once
void Register_sceUsb();
void __UsbInit();

View file

@ -39,6 +39,14 @@ void __UtilityInit()
SavedataParam::Init();
}
void __UtilityShutdown()
{
saveDialog.Shutdown();
msgDialog.Shutdown();
oskDialog.Shutdown();
netDialog.Shutdown();
}
int sceUtilitySavedataInitStart(u32 paramAddr)
{
DEBUG_LOG(HLE,"sceUtilitySavedataInitStart(%08x)", paramAddr);

View file

@ -18,5 +18,6 @@
#pragma once
void __UtilityInit();
void __UtilityShutdown();
void Register_sceUtility();

View file

@ -52,7 +52,9 @@ MIPSState::~MIPSState()
void MIPSState::Reset()
{
if (!MIPSComp::jit && PSP_CoreParameter().cpuCore == CPU_JIT)
if (MIPSComp::jit)
delete MIPSComp::jit;
if (PSP_CoreParameter().cpuCore == CPU_JIT)
MIPSComp::jit = new MIPSComp::Jit(this);
memset(r, 0, sizeof(r));

View file

@ -191,6 +191,8 @@ GLES_GPU::~GLES_GPU()
delete (*iter);
}
vfbs_.clear();
delete flushBeforeCommand;
}
void GLES_GPU::InitClear()

View file

@ -46,6 +46,17 @@ static bool finished;
static int dlIdGenerator = 1;
NullGPU::NullGPU()
{
interruptsEnabled_ = true;
dlIdGenerator = 1;
}
NullGPU::~NullGPU()
{
dlQueue.clear();
}
bool NullGPU::ProcessDLQueue()
{
std::vector<DisplayList>::iterator iter = dlQueue.begin();

View file

@ -24,7 +24,8 @@ class ShaderManager;
class NullGPU : public GPUInterface
{
public:
NullGPU() : interruptsEnabled_(true) {}
NullGPU();
~NullGPU();
virtual void InitClear() {}
virtual u32 EnqueueList(u32 listpc, u32 stall);
virtual void UpdateStall(int listid, u32 newstall);

View file

@ -648,11 +648,12 @@ namespace MainWindow
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory);
BOOL enable = !Core_IsStepping();
EnableMenuItem(menu,ID_EMULATION_RUN,enable);
EnableMenuItem(menu,ID_EMULATION_PAUSE,!enable);
UINT enable = !Core_IsStepping() ? MF_GRAYED : MF_ENABLED;
EnableMenuItem(menu,ID_EMULATION_RUN, g_State.bEmuThreadStarted ? enable : MF_GRAYED);
EnableMenuItem(menu,ID_EMULATION_PAUSE, g_State.bEmuThreadStarted ? !enable : MF_GRAYED);
EnableMenuItem(menu,ID_EMULATION_RESET, g_State.bEmuThreadStarted ? MF_ENABLED : MF_GRAYED);
enable = g_State.bEmuThreadStarted;
enable = g_State.bEmuThreadStarted ? MF_GRAYED : MF_ENABLED;
EnableMenuItem(menu,ID_FILE_LOAD,enable);
EnableMenuItem(menu,ID_CPU_DYNAREC,enable);
EnableMenuItem(menu,ID_CPU_INTERPRETER,enable);

Binary file not shown.