+++ /dev/null
-/*******************************************************************\r
- *\r
- * File: Engine.cpp\r
- *\r
- * Author: Peter van Sebille (peter@yipton.net)\r
- *\r
- * Modified/adapted for picodriveN by notaz, 2006\r
- *\r
- * (c) Copyright 2006, notaz\r
- * (c) Copyright 2002, Peter van Sebille\r
- * All Rights Reserved\r
- *\r
- *******************************************************************/\r
-\r
-\r
-#include "Engine.h"\r
-#include <w32std.h>\r
-#include <eikenv.h>\r
-#include <e32svr.h>\r
-#include <e32math.h>\r
-#include <e32uid.h>\r
-\r
-#include <string.h>\r
-\r
-#include "version.h"\r
-#include <pico/pico_int.h>\r
-#include "../common/emu.h"\r
-#include "engine/debug.h"\r
-#include "App.h"\r
-\r
-// this is where we start to break a bunch of symbian rules\r
-extern TInt machineUid;\r
-extern int gamestate, gamestate_next;\r
-extern char *loadrom_fname;\r
-extern int loadrom_result;\r
-extern const char *actionNames[];\r
-RSemaphore initSemaphore;\r
-RSemaphore pauseSemaphore;\r
-RSemaphore loadWaitSemaphore;\r
-static CPicolAppView *appView = 0;\r
-\r
-\r
-TInt CPicoGameSession::Do(const TPicoServRqst what, TAny *param)\r
-{\r
- switch (what)\r
- {\r
- case PicoMsgLoadState: \r
- if(!rom_loaded) return -1; // no ROM\r
- return emu_save_load_game(1, 0);\r
-\r
- case PicoMsgSaveState:\r
- if(!rom_loaded) return -1;\r
- return emu_save_load_game(0, 0);\r
-\r
- case PicoMsgLoadROM:\r
- return loadROM((TPtrC16 *)param);\r
- \r
- case PicoMsgResume:\r
- DEBUGPRINT(_L("resume"));\r
- if(rom_loaded) {\r
- return ChangeRunState(PGS_Running);\r
- }\r
- return 1;\r
-\r
- case PicoMsgReset: \r
- if(rom_loaded) {\r
- return ChangeRunState(PGS_Reset);\r
- }\r
- return 1;\r
-\r
- case PicoMsgKeys:\r
- return ChangeRunState(PGS_KeyConfig);\r
-\r
- case PicoMsgPause:\r
- return ChangeRunState(PGS_Paused);\r
-\r
- case PicoMsgQuit:\r
- DEBUGPRINT(_L("got quit msg."));\r
- return ChangeRunState(PGS_Quit);\r
-\r
- // config change\r
- case PicoMsgConfigChange:\r
- return changeConfig((TPicoConfig *)param);\r
-\r
- case PicoMsgSetAppView:\r
- appView = (CPicolAppView *)param;\r
- return 1;\r
-\r
- default:\r
- return 1;\r
- }\r
-}\r
-\r
-TInt EmuThreadFunction(TAny* anArg);\r
-\r
-TInt CPicoGameSession::StartEmuThread()\r
-{\r
- TInt res=KErrNone;\r
- iEmuRunning = EFalse;\r
-\r
- if (initSemaphore.Handle() > 0)\r
- initSemaphore.Close();\r
- initSemaphore.CreateLocal(0);\r
- if (pauseSemaphore.Handle() <= 0)\r
- pauseSemaphore.CreateLocal(0);\r
- if (loadWaitSemaphore.Handle() <= 0)\r
- loadWaitSemaphore.CreateLocal(0);\r
-\r
- RThread thread;\r
- if(iThreadWatcher && (res = thread.Open(iThreadWatcher->iTid)) == KErrNone) {\r
- // should be a dead thread in some strange state.\r
- DEBUGPRINT(_L("found thread with the same id (id=%i, RequestCount=%i), killing.."),\r
- (TInt32)thread.Id(), thread.RequestCount());\r
- // what can we do in this situation? Nothing seems to help, it just stays in this state.\r
- delete iThreadWatcher;\r
- iThreadWatcher = 0;\r
- thread.Kill(1);\r
- thread.Terminate(1);\r
- thread.Close();\r
- }\r
-\r
- res=thread.Create(_L("PicoEmuThread"), // create new server thread\r
- EmuThreadFunction, // thread's main function\r
- KDefaultStackSize,\r
- KMinHeapSize,\r
- KPicoMaxHeapSize,\r
- 0 // &semaphore // passed as TAny* argument to thread function\r
- );\r
-\r
- if(res == KErrNone) { // thread created ok - now start it going\r
- thread.SetPriority(EPriorityMore);\r
- iEmuRunning = ETrue;\r
- if (iThreadWatcher) delete iThreadWatcher;\r
- iThreadWatcher = CThreadWatcher::NewL(thread.Id());\r
- thread.Resume(); // start it going\r
- DEBUGPRINT(_L("initSemaphore.Wait()"));\r
- res = initSemaphore.Wait(3*1000*1000); // wait until it's initialized\r
- DEBUGPRINT(_L("initSemaphore resume, ExitReason() == %i"), thread.ExitReason());\r
- res |= thread.ExitReason();\r
- thread.Close(); // we're no longer interested in the other thread\r
- if(res != KErrNone) iEmuRunning = EFalse;\r
- return res;\r
- }\r
-\r
- return res;\r
-}\r
-\r
-TInt CPicoGameSession::ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next)\r
-{\r
- if (!iEmuRunning) {\r
- gamestate = PGS_Paused;\r
- TInt res = StartEmuThread();\r
- if(res != KErrNone) DEBUGPRINT(_L("StartEmuThread() returned %i"), res);\r
- if (!iEmuRunning) return PicoErrEmuThread;\r
- }\r
-\r
- int oldstate = gamestate;\r
- gamestate = newstate;\r
- gamestate_next = newstate_next ? newstate_next : PGS_Paused;\r
- if (oldstate == PGS_Paused) pauseSemaphore.Signal();\r
- return 0;\r
-}\r
-\r
-\r
-TInt CPicoGameSession::loadROM(TPtrC16 *pptr)\r
-{\r
- TInt ret;\r
- char buff[150];\r
-\r
- // make sure emu thread is ok\r
- ret = ChangeRunState(PGS_Paused);\r
- if(ret) return ret;\r
-\r
- // read the contents of the client pointer into a TPtr.\r
- static TBuf8<KMaxFileName> writeBuf;\r
- writeBuf.Copy(*pptr);\r
-\r
- // push the emu thead to a load state. This is done so that it owns all file handles.\r
- // If successful, in will enter PGS_Running state by itself.\r
- loadrom_fname = (char *)writeBuf.PtrZ();\r
- loadrom_result = 0;\r
- loadWaitSemaphore.Wait(1); // make sure sem is not set\r
- ret = ChangeRunState(PGS_ReloadRom);\r
- if(ret) return ret;\r
-\r
- loadWaitSemaphore.Wait(60*1000*1000);\r
-\r
- if (loadrom_result == 0)\r
- return PicoErrRomOpenFailed;\r
-\r
- emu_get_game_name(buff);\r
- TPtrC8 buff8((TUint8*) buff);\r
- iRomInternalName.Copy(buff8);\r
-\r
- DEBUGPRINT(_L("done waiting for ROM load"));\r
-\r
- // debug\r
- #ifdef __DEBUG_PRINT\r
- TInt mem, cells = User::CountAllocCells();\r
- User::AllocSize(mem);\r
- DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);\r
- #endif\r
-\r
- return 0;\r
-}\r
-\r
-\r
-TInt CPicoGameSession::changeConfig(TPicoConfig *aConfig)\r
-{\r
- // 6 button pad, enable XYZM config if needed\r
- if (PicoOpt & POPT_6BTN_PAD)\r
- {\r
- actionNames[8] = "Z";\r
- actionNames[9] = "Y";\r
- actionNames[10] = "X";\r
- actionNames[11] = "MODE";\r
- } else {\r
- actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;\r
- }\r
-\r
- // if we are in center 90||270 modes, we can bind renderer switcher\r
- if (currentConfig.scaling == TPicoConfig::PMFit &&\r
- (currentConfig.rotation == TPicoConfig::PRot0 || currentConfig.rotation == TPicoConfig::PRot180))\r
- actionNames[25] = 0;\r
- else actionNames[25] = "RENDERER";\r
-\r
- return 0;\r
-}\r
-\r
-\r
-#ifdef __DEBUG_PRINT_FILE\r
-extern RMutex logMutex;\r
-#endif\r
-\r
-void CPicoGameSession::freeResources()\r
-{\r
- RThread thread;\r
- TInt i;\r
-\r
- DEBUGPRINT(_L("CPicoGameSession::freeResources()"));\r
-\r
- if(iThreadWatcher && thread.Open(iThreadWatcher->iTid) == KErrNone)\r
- {\r
- // try to stop our emu thread\r
- gamestate = PGS_Quit;\r
- if(pauseSemaphore.Handle() > 0)\r
- pauseSemaphore.Signal();\r
-\r
- if(thread.Handle() > 0)\r
- {\r
- // tried reopening thread handle here over time intervals to detect if thread is alive,\r
- // but would run into handle panics.\r
-\r
- for(i = 0; i < 8; i++) {\r
- User::After(100 * 1000);\r
- if(thread.ExitReason() != 0) break;\r
- }\r
-\r
- if(thread.ExitReason() == 0) {\r
- // too late, time to die\r
- DEBUGPRINT(_L("thread %i not responding, killing.."), (TInt32) thread.Id());\r
- thread.Terminate(1);\r
- }\r
- thread.Close();\r
- }\r
-\r
- }\r
-\r
- if (iThreadWatcher != NULL)\r
- {\r
- DEBUGPRINT(_L("delete iThreadWatcher"));\r
- delete iThreadWatcher;\r
- DEBUGPRINT(_L("after delete iThreadWatcher"));\r
- iThreadWatcher = NULL;\r
- }\r
-\r
- if (initSemaphore.Handle() > 0)\r
- initSemaphore.Close();\r
- if (pauseSemaphore.Handle() > 0)\r
- pauseSemaphore.Close();\r
- if (loadWaitSemaphore.Handle() > 0)\r
- loadWaitSemaphore.Close();\r
- DEBUGPRINT(_L("freeResources() returning"));\r
-#ifdef __DEBUG_PRINT_FILE\r
- if (logMutex.Handle() > 0)\r
- logMutex.Close();\r
-#endif\r
-}\r
-\r
-TBool CPicoGameSession::iEmuRunning = EFalse;\r
-CThreadWatcher *CPicoGameSession::iThreadWatcher = 0;\r
-TBuf<150> CPicoGameSession::iRomInternalName;\r
-\r
-\r
-// CThreadWatcher\r
-CThreadWatcher::~CThreadWatcher()\r
-{\r
- Cancel();\r
- DEBUGPRINT(_L("after CThreadWatcher::Cancel();"));\r
-}\r
-\r
-CThreadWatcher::CThreadWatcher(const TThreadId& aTid)\r
-: CActive(CActive::EPriorityStandard), iTid(aTid)\r
-{\r
-}\r
-\r
-\r
-CThreadWatcher* CThreadWatcher::NewL(const TThreadId& aTid)\r
-{\r
- CThreadWatcher* self = new(ELeave) CThreadWatcher(aTid);\r
- CleanupStack::PushL(self);\r
- self->ConstructL();\r
- CleanupStack::Pop(); // self\r
- return self;\r
-}\r
-\r
-void CThreadWatcher::ConstructL()\r
-{\r
- CActiveScheduler::Add(this);\r
- RThread thread;\r
- if(thread.Open(iTid) == KErrNone) {\r
- thread.Logon(iStatus);\r
- thread.Close();\r
- SetActive();\r
- }\r
-}\r
-\r
-void CThreadWatcher::RunL()\r
-{\r
- DEBUGPRINT(_L("CThreadWatcher::RunL()"));\r
- CPicoGameSession::iEmuRunning = EFalse;\r
- if(appView) appView->UpdateCommandList();\r
- //initSemaphore.Signal(); // no point to do that here, AS can't get here if it is waiting\r
-}\r
-\r
-void CThreadWatcher::DoCancel()\r
-{\r
- RThread thread;\r
- DEBUGPRINT(_L("CThreadWatcher::DoCancel()"));\r
- if(thread.Open(iTid) == KErrNone) {\r
- DEBUGPRINT(_L("thread.LogonCancel(iStatus);"));\r
- thread.LogonCancel(iStatus);\r
- thread.Close();\r
- }\r
-}\r
-\r
-extern "C" void cache_flush_d_inval_i(const void *start_addr, const void *end_addr)\r
-{\r
- // TODO\r
- User::IMB_Range((TAny *)start_addr, (TAny *)end_addr);\r
-}\r
-\r