Engine.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*******************************************************************
  2. *
  3. * File: Engine.cpp
  4. *
  5. * Author: Peter van Sebille (peter@yipton.net)
  6. *
  7. * Modified/adapted for picodriveN by notaz, 2006
  8. *
  9. * (c) Copyright 2006, notaz
  10. * (c) Copyright 2002, Peter van Sebille
  11. * All Rights Reserved
  12. *
  13. *******************************************************************/
  14. #include "Engine.h"
  15. #include <w32std.h>
  16. #include <eikenv.h>
  17. #include <e32svr.h>
  18. #include <e32math.h>
  19. #include <e32uid.h>
  20. #include <string.h>
  21. #include "version.h"
  22. #include <Pico/PicoInt.h>
  23. #include "../common/emu.h"
  24. #include "engine/debug.h"
  25. #include "App.h"
  26. // this is where we start to break a bunch of symbian rules
  27. extern TInt machineUid;
  28. extern int gamestate, gamestate_next;
  29. extern char *loadrom_fname;
  30. extern int loadrom_result;
  31. extern const char *actionNames[];
  32. RSemaphore initSemaphore;
  33. RSemaphore pauseSemaphore;
  34. RSemaphore loadWaitSemaphore;
  35. int pico_was_reset = 0;
  36. static CPicolAppView *appView = 0;
  37. TInt CPicoGameSession::Do(const TPicoServRqst what, TAny *param)
  38. {
  39. switch (what)
  40. {
  41. case PicoMsgLoadState:
  42. if(!rom_loaded) return -1; // no ROM
  43. return emu_SaveLoadGame(1, 0);
  44. case PicoMsgSaveState:
  45. if(!rom_loaded) return -1;
  46. return emu_SaveLoadGame(0, 0);
  47. case PicoMsgLoadROM:
  48. return loadROM((TPtrC16 *)param);
  49. case PicoMsgResume:
  50. DEBUGPRINT(_L("resume"));
  51. if(rom_loaded) {
  52. return ChangeRunState(PGS_Running);
  53. }
  54. return 1;
  55. case PicoMsgReset:
  56. if(rom_loaded) {
  57. PicoReset();
  58. pico_was_reset = 1;
  59. return ChangeRunState(PGS_Running);
  60. }
  61. return 1;
  62. case PicoMsgKeys:
  63. return ChangeRunState(PGS_KeyConfig);
  64. case PicoMsgPause:
  65. return ChangeRunState(PGS_Paused);
  66. case PicoMsgQuit:
  67. DEBUGPRINT(_L("got quit msg."));
  68. return ChangeRunState(PGS_Quit);
  69. // config change
  70. case PicoMsgConfigChange:
  71. return changeConfig((TPicoConfig *)param);
  72. case PicoMsgSetAppView:
  73. appView = (CPicolAppView *)param;
  74. return 1;
  75. default:
  76. return 1;
  77. }
  78. }
  79. TInt EmuThreadFunction(TAny* anArg);
  80. TInt CPicoGameSession::StartEmuThread()
  81. {
  82. TInt res=KErrNone;
  83. iEmuRunning = EFalse;
  84. if (initSemaphore.Handle() > 0)
  85. initSemaphore.Close();
  86. initSemaphore.CreateLocal(0);
  87. if (pauseSemaphore.Handle() <= 0)
  88. pauseSemaphore.CreateLocal(0);
  89. if (loadWaitSemaphore.Handle() <= 0)
  90. loadWaitSemaphore.CreateLocal(0);
  91. RThread thread;
  92. if(iThreadWatcher && (res = thread.Open(iThreadWatcher->iTid)) == KErrNone) {
  93. // should be a dead thread in some strange state.
  94. DEBUGPRINT(_L("found thread with the same id (id=%i, RequestCount=%i), killing.."),
  95. (TInt32)thread.Id(), thread.RequestCount());
  96. // what can we do in this situation? Nothing seems to help, it just stays in this state.
  97. delete iThreadWatcher;
  98. iThreadWatcher = 0;
  99. thread.Kill(1);
  100. thread.Terminate(1);
  101. thread.Close();
  102. }
  103. res=thread.Create(_L("PicoEmuThread"), // create new server thread
  104. EmuThreadFunction, // thread's main function
  105. KDefaultStackSize,
  106. KMinHeapSize,
  107. KPicoMaxHeapSize,
  108. 0 // &semaphore // passed as TAny* argument to thread function
  109. );
  110. if(res == KErrNone) { // thread created ok - now start it going
  111. thread.SetPriority(EPriorityMore);
  112. iEmuRunning = ETrue;
  113. if (iThreadWatcher) delete iThreadWatcher;
  114. iThreadWatcher = CThreadWatcher::NewL(thread.Id());
  115. thread.Resume(); // start it going
  116. DEBUGPRINT(_L("initSemaphore.Wait()"));
  117. res = initSemaphore.Wait(3*1000*1000); // wait until it's initialized
  118. DEBUGPRINT(_L("initSemaphore resume, ExitReason() == %i"), thread.ExitReason());
  119. res |= thread.ExitReason();
  120. thread.Close(); // we're no longer interested in the other thread
  121. if(res != KErrNone) iEmuRunning = EFalse;
  122. return res;
  123. }
  124. return res;
  125. }
  126. TInt CPicoGameSession::ChangeRunState(TPicoGameState newstate, TPicoGameState newstate_next)
  127. {
  128. if (!iEmuRunning) {
  129. gamestate = PGS_Paused;
  130. TInt res = StartEmuThread();
  131. if(res != KErrNone) DEBUGPRINT(_L("StartEmuThread() returned %i"), res);
  132. if (!iEmuRunning) return PicoErrEmuThread;
  133. }
  134. int oldstate = gamestate;
  135. gamestate = newstate;
  136. gamestate_next = newstate_next ? newstate_next : PGS_Paused;
  137. if (oldstate == PGS_Paused) pauseSemaphore.Signal();
  138. return 0;
  139. }
  140. TInt CPicoGameSession::loadROM(TPtrC16 *pptr)
  141. {
  142. TInt ret;
  143. char buff[150];
  144. // make sure emu thread is ok
  145. ret = ChangeRunState(PGS_Paused);
  146. if(ret) return ret;
  147. // read the contents of the client pointer into a TPtr.
  148. static TBuf8<KMaxFileName> writeBuf;
  149. writeBuf.Copy(*pptr);
  150. // push the emu thead to a load state. This is done so that it owns all file handles.
  151. // If successful, in will enter PGS_Running state by itself.
  152. loadrom_fname = (char *)writeBuf.PtrZ();
  153. loadrom_result = 0;
  154. ret = ChangeRunState(PGS_ReloadRom);
  155. if(ret) return ret;
  156. loadWaitSemaphore.Wait(20*1000*1000);
  157. if (loadrom_result == 0)
  158. return PicoErrNotRom;
  159. emu_getGameName(buff);
  160. TPtrC8 buff8((TUint8*) buff);
  161. iRomInternalName.Copy(buff8);
  162. DEBUGPRINT(_L("done waiting for ROM load"));
  163. // debug
  164. #ifdef __DEBUG_PRINT
  165. TInt cells = User::CountAllocCells();
  166. TInt mem;
  167. User::AllocSize(mem);
  168. DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);
  169. ChangeRunState(PGS_DebugHeap, PGS_Running);
  170. #endif
  171. return 0;
  172. }
  173. TInt CPicoGameSession::changeConfig(TPicoConfig *aConfig)
  174. {
  175. // 6 button pad, enable XYZM config if needed
  176. if (PicoOpt & POPT_6BTN_PAD)
  177. {
  178. actionNames[8] = "Z";
  179. actionNames[9] = "Y";
  180. actionNames[10] = "X";
  181. actionNames[11] = "MODE";
  182. } else {
  183. actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;
  184. }
  185. // if we are in center 90||270 modes, we can bind renderer switcher
  186. if (currentConfig.scaling == TPicoConfig::PMFit &&
  187. (currentConfig.rotation == TPicoConfig::PRot0 || currentConfig.rotation == TPicoConfig::PRot180))
  188. actionNames[25] = 0;
  189. else actionNames[25] = "RENDERER";
  190. return 0;
  191. }
  192. #ifdef __DEBUG_PRINT_FILE
  193. extern RMutex logMutex;
  194. #endif
  195. void CPicoGameSession::freeResources()
  196. {
  197. RThread thread;
  198. TInt i;
  199. DEBUGPRINT(_L("CPicoGameSession::freeResources()"));
  200. if(iThreadWatcher && thread.Open(iThreadWatcher->iTid) == KErrNone)
  201. {
  202. // try to stop our emu thread
  203. gamestate = PGS_Quit;
  204. if(pauseSemaphore.Handle() > 0)
  205. pauseSemaphore.Signal();
  206. if(thread.Handle() > 0)
  207. {
  208. // tried reopening thread handle here over time intervals to detect if thread is alive,
  209. // but would run into handle panics.
  210. for(i = 0; i < 8; i++) {
  211. User::After(100 * 1000);
  212. if(thread.ExitReason() != 0) break;
  213. }
  214. if(thread.ExitReason() == 0) {
  215. // too late, time to die
  216. DEBUGPRINT(_L("thread %i not responding, killing.."), (TInt32) thread.Id());
  217. thread.Terminate(1);
  218. }
  219. thread.Close();
  220. }
  221. }
  222. if (iThreadWatcher != NULL)
  223. {
  224. DEBUGPRINT(_L("delete iThreadWatcher"));
  225. delete iThreadWatcher;
  226. DEBUGPRINT(_L("after delete iThreadWatcher"));
  227. iThreadWatcher = NULL;
  228. }
  229. if (initSemaphore.Handle() > 0)
  230. initSemaphore.Close();
  231. if (pauseSemaphore.Handle() > 0)
  232. pauseSemaphore.Close();
  233. if (loadWaitSemaphore.Handle() > 0)
  234. loadWaitSemaphore.Close();
  235. DEBUGPRINT(_L("freeResources() returning"));
  236. #ifdef __DEBUG_PRINT_FILE
  237. if (logMutex.Handle() > 0)
  238. logMutex.Close();
  239. #endif
  240. }
  241. TBool CPicoGameSession::iEmuRunning = EFalse;
  242. CThreadWatcher *CPicoGameSession::iThreadWatcher = 0;
  243. TBuf<150> CPicoGameSession::iRomInternalName;
  244. // CThreadWatcher
  245. CThreadWatcher::~CThreadWatcher()
  246. {
  247. Cancel();
  248. DEBUGPRINT(_L("after CThreadWatcher::Cancel();"));
  249. }
  250. CThreadWatcher::CThreadWatcher(const TThreadId& aTid)
  251. : CActive(CActive::EPriorityStandard), iTid(aTid)
  252. {
  253. }
  254. CThreadWatcher* CThreadWatcher::NewL(const TThreadId& aTid)
  255. {
  256. CThreadWatcher* self = new(ELeave) CThreadWatcher(aTid);
  257. CleanupStack::PushL(self);
  258. self->ConstructL();
  259. CleanupStack::Pop(); // self
  260. return self;
  261. }
  262. void CThreadWatcher::ConstructL()
  263. {
  264. CActiveScheduler::Add(this);
  265. RThread thread;
  266. if(thread.Open(iTid) == KErrNone) {
  267. thread.Logon(iStatus);
  268. thread.Close();
  269. SetActive();
  270. }
  271. }
  272. void CThreadWatcher::RunL()
  273. {
  274. DEBUGPRINT(_L("CThreadWatcher::RunL()"));
  275. CPicoGameSession::iEmuRunning = EFalse;
  276. if(appView) appView->UpdateCommandList();
  277. //initSemaphore.Signal(); // no point to do that here, AS can't get here if it is waiting
  278. }
  279. void CThreadWatcher::DoCancel()
  280. {
  281. RThread thread;
  282. DEBUGPRINT(_L("CThreadWatcher::DoCancel()"));
  283. if(thread.Open(iTid) == KErrNone) {
  284. DEBUGPRINT(_L("thread.LogonCancel(iStatus);"));
  285. thread.LogonCancel(iStatus);
  286. thread.Close();
  287. }
  288. }
  289. extern "C" void cache_flush_d_inval_i(const void *start_addr, const void *end_addr)
  290. {
  291. // TODO
  292. User::IMB_Range((TAny *)start_addr, (TAny *)end_addr);
  293. }