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