#include "debug.h"\r
#include "../Engine.h"\r
\r
-#include "../../../pico/picoInt.h"\r
+#include <pico/pico_int.h>\r
+#include "../../common/emu.h"\r
+#include "../emu.h"\r
#include "vid.h"\r
-#include "polledAS.h"\r
+#include "PolledAS.h"\r
//#include "audio.h"\r
#include "audio_mediaserver.h"\r
\r
-#include <EZlib.h>\r
-#include "../../../zlib/gzio_symb.h"\r
+//#include <ezlib.h>\r
+#include <zlib/zlib.h>\r
\r
\r
//#define BENCHMARK\r
// globals are allowed, so why not to (ab)use them?\r
//TInt machineUid = 0;\r
int gamestate = PGS_Paused, gamestate_next = PGS_Paused;\r
-TPicoConfig *currentConfig = 0;\r
-static char noticeMsg[64]; // notice msg to draw\r
+char *loadrom_fname = NULL;\r
+int loadrom_result = 0;\r
static timeval noticeMsgTime = { 0, 0 }; // when started showing\r
static CGameAudioMS *gameAudio = 0; // the audio object itself\r
-static int reset_timing, pico_was_reset;\r
-static int state_slot = 0;\r
-extern const char *RomFileName;\r
+static int reset_timing = 0;\r
+static int pico_was_reset = 0;\r
extern RSemaphore initSemaphore;\r
extern RSemaphore pauseSemaphore;\r
+extern RSemaphore loadWaitSemaphore;\r
\r
// some forward declarations\r
static void MainInit();\r
static void MainExit();\r
static void DumpMemInfo();\r
-void MainOldCleanup();\r
\r
\r
class TPicoDirectScreenAccess : public MDirectScreenAccess\r
};\r
\r
\r
-static int snd_excess_add = 0, snd_excess_cnt = 0; // hack\r
-\r
-static void updateSound(void)\r
+static void updateSound(int len)\r
{\r
- int len = PsndLen;\r
-\r
- snd_excess_cnt += snd_excess_add;\r
- if (snd_excess_cnt >= 0x10000) {\r
- snd_excess_cnt -= 0x10000;\r
- if (PicoOpt&8) {\r
- PsndOut[len*2] = PsndOut[len*2-2];\r
- PsndOut[len*2+1] = PsndOut[len*2-1];\r
- } else {\r
- PsndOut[len] = PsndOut[len-1];\r
- }\r
- len++;\r
- }\r
-\r
PsndOut = gameAudio->NextFrameL(len);\r
if(!PsndOut) { // sound output problems?\r
strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r
int thissec = 0, frames_done = 0, frames_shown = 0;\r
int target_fps, target_frametime;\r
int i, lim_time;\r
- //TRawEvent blevent;\r
\r
MainInit();\r
buff[0] = 0;\r
\r
- // just to keep the backlight on (works only on UIQ2)\r
- //blevent.Set(TRawEvent::EActive);\r
+ // try to start pico\r
+ DEBUGPRINT(_L("PicoInit()"));\r
+ PicoInit();\r
+ PicoDrawSetColorFormat(2);\r
+ PicoWriteSound = updateSound;\r
\r
// loop?\r
- for(;;) {\r
- if(gamestate == PGS_Running) {\r
+ for(;;)\r
+ {\r
+ if (gamestate == PGS_Running)\r
+ {\r
+ #ifdef __DEBUG_PRINT\r
+ TInt mem, cells = User::CountAllocCells();\r
+ User::AllocSize(mem);\r
+ DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024);\r
+ #endif\r
+\r
// switch context to other thread\r
User::After(50000);\r
// prepare window and stuff\r
if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS");\r
}\r
target_frametime = 1000000/target_fps;\r
- if(!noticeMsgTime.tv_sec && pico_was_reset)\r
+ if (!noticeMsgTime.tv_sec && pico_was_reset)\r
gettimeofday(¬iceMsgTime, 0);\r
\r
- if (PsndOut) {\r
- snd_excess_cnt = 0;\r
- snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;\r
- }\r
+ // prepare CD buffer\r
+ if (PicoAHW & PAHW_MCD) PicoCDBufferInit();\r
\r
pico_was_reset = 0;\r
reset_timing = 1;\r
\r
- while(gamestate == PGS_Running) {\r
+ while (gamestate == PGS_Running)\r
+ {\r
gettimeofday(&tval, 0);\r
if(reset_timing) {\r
reset_timing = 0;\r
}\r
\r
// second changed?\r
- if(thissec != tval.tv_sec) {\r
+ if (thissec != tval.tv_sec)\r
+ {\r
#ifdef BENCHMARK\r
static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];\r
if(++bench == 10) {\r
bench_fps += frames_shown;\r
sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);\r
#else\r
- if(currentConfig->iFlags & 2) \r
+ if (currentConfig.EmuOpt & EOPT_SHOW_FPS) \r
sprintf(buff, "%02i/%02i", frames_shown, frames_done);\r
#endif\r
\r
\r
thissec = tval.tv_sec;\r
\r
- if(PsndOut == 0 && currentConfig->iFrameskip >= 0) {\r
+ if(PsndOut == 0 && currentConfig.Frameskip >= 0) {\r
frames_done = frames_shown = 0;\r
} else {\r
// it is quite common for this implementation to leave 1 fame unfinished\r
frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0;\r
if (frames_shown > frames_done) frames_shown = frames_done;\r
}\r
+ User::ResetInactivityTime();\r
}\r
\r
\r
lim_time = (frames_done+1) * target_frametime;\r
- if(currentConfig->iFrameskip >= 0) { // frameskip enabled\r
- for(i = 0; i < currentConfig->iFrameskip; i++) {\r
+ if (currentConfig.Frameskip >= 0) // frameskip enabled\r
+ {\r
+ for (i = 0; i < currentConfig.Frameskip && gamestate == PGS_Running; i++)\r
+ {\r
CGameWindow::DoKeys();\r
SkipFrame(); frames_done++;\r
if (PsndOut) { // do framelimitting if sound is enabled\r
}\r
lim_time += target_frametime;\r
}\r
- } else if(tval.tv_usec > lim_time) { // auto frameskip\r
+ }\r
+ else if(tval.tv_usec > lim_time) { // auto frameskip\r
// no time left for this frame - skip\r
CGameWindow::DoKeys();\r
SkipFrame(); frames_done++;\r
continue;\r
}\r
\r
+ // we might have lost focus already\r
+ if (gamestate != PGS_Running) break;\r
+\r
CGameWindow::DoKeys();\r
PicoFrame();\r
\r
if(thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
\r
// sleep if we are still too fast\r
- if(PsndOut != 0 || currentConfig->iFrameskip < 0)\r
+ if(PsndOut != 0 || currentConfig.Frameskip < 0)\r
{\r
// TODO: check if User::After() is accurate\r
gettimeofday(&tval, 0);\r
vidDrawFrame(notice, buff, frames_shown);\r
\r
frames_done++; frames_shown++;\r
- }\r
+ } // while\r
+\r
+ if (PicoAHW & PAHW_MCD) PicoCDBufferFree();\r
\r
// save SRAM\r
- if((currentConfig->iFlags & 1) && SRam.changed) {\r
- saveLoadGame(0, 1);\r
+ if ((currentConfig.EmuOpt & EOPT_USE_SRAM) && SRam.changed) {\r
+ emu_SaveLoadGame(0, 1);\r
SRam.changed = 0;\r
}\r
+ CPolledActiveScheduler::Instance()->Schedule();\r
CGameWindow::FreeResources();\r
- } else if(gamestate == PGS_Paused) {\r
+ }\r
+ else if(gamestate == PGS_Reset)\r
+ {\r
+ PicoReset();\r
+ pico_was_reset = 1;\r
+ gamestate = PGS_Running;\r
+ }\r
+ else if(gamestate == PGS_ReloadRom)\r
+ {\r
+ loadrom_result = emu_ReloadRom(loadrom_fname);\r
+ pico_was_reset = 1;\r
+ if (loadrom_result)\r
+ gamestate = PGS_Running;\r
+ else {\r
+ extern char menuErrorMsg[];\r
+ gamestate = PGS_Paused;\r
+ lprintf("%s\n", menuErrorMsg);\r
+ }\r
+ DEBUGPRINT(_L("done loading ROM, retval=%i"), loadrom_result);\r
+ loadWaitSemaphore.Signal();\r
+ User::After(50000);\r
+ }\r
+ else if(gamestate == PGS_Paused) {\r
DEBUGPRINT(_L("pausing.."));\r
pauseSemaphore.Wait();\r
- } else if(gamestate == PGS_KeyConfig) {\r
+ }\r
+ else if(gamestate == PGS_KeyConfig)\r
+ {\r
// switch context to other thread\r
User::After(50000);\r
// prepare window and stuff\r
User::After(150000);\r
}\r
\r
+ emu_WriteConfig(0);\r
CGameWindow::FreeResources();\r
- } else if(gamestate == PGS_DebugHeap) {\r
- #ifdef __DEBUG_PRINT\r
- TInt cells = User::CountAllocCells();\r
- TInt mem;\r
- User::AllocSize(mem);\r
- DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024);\r
- gamestate = gamestate_next;\r
- #endif\r
} else if(gamestate == PGS_Quit) {\r
break;\r
}\r
}\r
\r
+ // this thread has to close it's own handles,\r
+ // other one will crash trying to do that\r
+ PicoExit();\r
+\r
MainExit();\r
}\r
\r
{\r
DEBUGPRINT(_L("\r\n\r\nstarting.."));\r
\r
- // our thread might have been crashed previously, so many other objects may be still floating around\r
- MainOldCleanup();\r
-\r
DEBUGPRINT(_L("CPolledActiveScheduler::NewL()"));\r
CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine\r
\r
\r
DumpMemInfo();\r
\r
- // try to start pico\r
- DEBUGPRINT(_L("PicoInit();"));\r
- PicoInit();\r
- PicoDrawSetColorFormat(2);\r
- PicoWriteSound = updateSound;\r
-\r
// if (pauseSemaphore.Handle() <= 0)\r
// pauseSemaphore.CreateLocal(0);\r
DEBUGPRINT(_L("initSemaphore.Signal()"));\r
\r
DEBUGPRINT(_L("%i: cleaning up.."), (TInt32) thisThread.Id());\r
\r
- // save SRAM\r
- if((currentConfig->iFlags & 1) && SRam.changed) {\r
- saveLoadGame(0, 1);\r
- SRam.changed = 0;\r
- }\r
-\r
- PicoExit();\r
// pauseSemaphore.Close();\r
\r
if(gameAudio) delete gameAudio;\r
delete CPolledActiveScheduler::Instance();\r
}\r
\r
-void MainOldCleanup()\r
-{\r
- DEBUGPRINT(_L("MainOldCleanup.."));\r
-\r
- // There was previously a handle leak here, so thread stuff was not cleaned\r
- // and I thought I would have to do it mself.\r
-\r
- // clean any resources which might be left after a thread crash\r
- //CGameWindow::FreeResources(ETrue);\r
-\r
- //if(CPolledActiveScheduler::Instance())\r
- // delete CPolledActiveScheduler::Instance();\r
-}\r
-\r
static void DumpMemInfo()\r
{\r
TInt ramSize, ramSizeFree, romSize;\r
}\r
\r
\r
+extern "C" TInt my_SetExceptionHandler(TInt, TExceptionHandler, TUint32);\r
+\r
TInt EmuThreadFunction(TAny*)\r
{\r
+ TInt ret;\r
const TUint32 exs = KExceptionAbort|KExceptionKill|KExceptionUserInterrupt|KExceptionFpe|KExceptionFault|KExceptionInteger|KExceptionDebug;\r
\r
- DEBUGPRINT(_L("EmuThreadFunction()"));\r
- User::SetExceptionHandler(ExceptionHandler, exs/*(TUint32) -1*/); // does not work?\r
+ DEBUGPRINT(_L("EmuThreadFunction(), def ExceptionHandler %08x, my %08x"),\r
+ User::ExceptionHandler(), ExceptionHandler);\r
+ User::SetJustInTime(1);\r
+ ret = User::SetExceptionHandler(ExceptionHandler, exs/*(TUint32) -1*/); // does not work :(\r
+ // my_SetExceptionHandler(KCurrentThreadHandle, ExceptionHandler, 0xffffffff);\r
+ DEBUGPRINT(_L("SetExceptionHandler %i, %08x"), ret, User::ExceptionHandler());\r
+ User::ModifyExceptionMask(0, exs);\r
\r
//TInt pc, sp;\r
//asm volatile ("str pc, %0" : "=m" (pc) );\r
\r
TRAPD(error, TargetEpocGameL());\r
\r
- __ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error));\r
+ __ASSERT_ALWAYS(!error, User::Panic(_L("PicoDrive"), error));\r
delete cleanup;\r
\r
DEBUGPRINT(_L("exitting..")); \r
// try to start the audio engine\r
static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;\r
\r
- if(gamestate == PGS_Running && (currentConfig->iFlags & 4)) {\r
+ if (gamestate == PGS_Running && (currentConfig.EmuOpt & EOPT_EN_SOUND))\r
+ {\r
TInt err = 0;\r
if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) {\r
// if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled\r
//sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old)));\r
- sound_rerate();\r
+ PsndRerate(1);\r
}\r
if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed\r
if(gameAudio) delete gameAudio; gameAudio = 0;\r
DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal);\r
- TRAP(err, gameAudio = CGameAudioMS::NewL(PsndRate, (PicoOpt&8) ? 1 : 0, Pico.m.pal ? 50 : 60));\r
+ TRAP(err, gameAudio = CGameAudioMS::NewL(PsndRate, (PicoOpt&8) ? 1 : 0,\r
+ Pico.m.pal ? 50 : 60, currentConfig.volume));\r
}\r
if( gameAudio) {\r
TRAP(err, PsndOut = gameAudio->ResumeL());\r
}\r
\r
vidFree();\r
-\r
- // emu might change renderer by itself, so we may need to sync config\r
- if(currentConfig && currentConfig->iPicoOpt != PicoOpt) {\r
- currentConfig->iFlags |= 0x80;\r
- }\r
}\r
\r
\r
const TPicoAreaConfigEntry *e = areaConfig + 1;\r
for(i = 0; !e->rect.IsEmpty(); e++, i++)\r
if(e->rect.Contains(p)) {\r
- areaActions = currentConfig->iAreaBinds[i];\r
+ areaActions = currentConfig.KeyBinds[i+256];\r
break;\r
}\r
//DEBUGPRINT(_L("pointer event: %i %i"), p.iX, p.iY);\r
for(i = 9; i >= 0; i--) {\r
int scan = pressedKeys[i];\r
if(scan) {\r
- if(keyFlags[scan] & 1) allActions |= currentConfig->iKeyBinds[scan];\r
+ if(keyFlags[scan] & 1) allActions |= currentConfig.KeyBinds[scan];\r
if((keyFlags[scan]& 3)==3) forceUpdate = 1;\r
if(keyFlags[scan] & 2) keyFlags[scan] &= ~1;\r
}\r
areaActions = 0;\r
}\r
}\r
+\r
+ if (movie_data) emu_updateMovie();\r
}\r
\r
\r
const TPicoAreaConfigEntry *e = areaConfig + 1;\r
for(i = 0; e->rect != TRect(0,0,0,0); e++, i++)\r
if(e->rect.Contains(p)) {\r
- currentConfig->iAreaBinds[i] ^= currentActCode;\r
+ currentConfig.KeyBinds[i+256] ^= currentActCode;\r
break;\r
}\r
}\r
if(which == 31) {\r
gamestate = PGS_Paused;\r
} else if (scan < 256) {\r
- if(!(keyFlags[scan]&0x40)) currentConfig->iKeyBinds[scan] ^= currentActCode;\r
+ if(!(keyFlags[scan]&0x40)) currentConfig.KeyBinds[scan] ^= currentActCode;\r
}\r
}\r
\r
\r
void CGameWindow::RunEvents(TUint32 which)\r
{\r
- if(which & 0x4000) currentConfig->iFrameskip = -1;\r
- if(which & 0x2000) currentConfig->iFrameskip = 8;\r
- if(which & 0x1800) { // save or load (but not both)\r
+ if (which & 0x4000) currentConfig.Frameskip = -1;\r
+ if (which & 0x2000) currentConfig.Frameskip = 8;\r
+ if (which & 0x1800) { // save or load (but not both)\r
if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output\r
\r
vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME");\r
- saveLoadGame(which & 0x1000);\r
+ emu_SaveLoadGame(which & 0x1000, 0);\r
\r
if(PsndOut) PsndOut = gameAudio->ResumeL();\r
reset_timing = 1;\r
}\r
- if(which & 0x0400) gamestate = PGS_Paused;\r
- if(which & 0x0200) { // switch renderer\r
- if(!(currentConfig->iScreenMode == TPicoConfig::PMFit &&\r
- (currentConfig->iScreenRotation == TPicoConfig::PRot0 || currentConfig->iScreenRotation == TPicoConfig::PRot180))) {\r
-\r
+ if (which & 0x0400) gamestate = PGS_Paused;\r
+ if (which & 0x0200) { // switch renderer\r
+ if (!(currentConfig.scaling == TPicoConfig::PMFit &&\r
+ (currentConfig.rotation == TPicoConfig::PRot0 || currentConfig.rotation == TPicoConfig::PRot180)))\r
+ {\r
PicoOpt^=0x10;\r
vidInit(0, 1);\r
\r
sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot);\r
gettimeofday(¬iceMsgTime, 0);\r
}\r
- if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0);\r
- if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1);\r
-}\r
-\r
-\r
-// must use wrappers, or else will run into some weird loader error (see pico/area.c)\r
-static size_t fRead2(void *p, size_t _s, size_t _n, void *file)\r
-{\r
- return fread(p, _s, _n, (FILE *) file);\r
-}\r
-\r
-static size_t fWrite2(void *p, size_t _s, size_t _n, void *file)\r
-{\r
- return fwrite(p, _s, _n, (FILE *) file);\r
-}\r
-\r
-static size_t gzRead2(void *p, size_t, size_t _n, void *file)\r
-{\r
- return gzread(file, p, _n);\r
-}\r
-\r
-static size_t gzWrite2(void *p, size_t, size_t _n, void *file)\r
-{\r
- return gzwrite(file, p, _n);\r
+ if ((which & 0x0030) && gameAudio != NULL) {\r
+ currentConfig.volume = gameAudio->ChangeVolume((which & 0x0010) ? 1 : 0);\r
+ sprintf(noticeMsg, "VOL@%02i@", currentConfig.volume);\r
+ gettimeofday(¬iceMsgTime, 0);\r
+ }\r
}\r
\r
\r
-// this function is shared between both threads\r
-int saveLoadGame(int load, int sram)\r
+extern "C" void emu_noticeMsgUpdated(void)\r
{\r
- int res = 0;\r
-\r
- if(!RomFileName) return -1;\r
-\r
- // make save filename\r
- char saveFname[KMaxFileName];\r
- strcpy(saveFname, RomFileName);\r
- saveFname[KMaxFileName-8] = 0;\r
- if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0;\r
- if(sram) strcat(saveFname, ".srm");\r
- else {\r
- if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot);\r
- strcat(saveFname, ".mds");\r
- }\r
-\r
- DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname));\r
-\r
- if(sram) {\r
- FILE *sramFile;\r
- int sram_size = SRam.end-SRam.start+1;\r
- if(SRam.reg_back & 4) sram_size=0x2000;\r
- if(!SRam.data) return 0; // SRam forcefully disabled for this game\r
- if(load) {\r
- sramFile = fopen(saveFname, "rb");\r
- if(!sramFile) return -1;\r
- fread(SRam.data, 1, sram_size, sramFile);\r
- fclose(sramFile);\r
- } else {\r
- // sram save needs some special processing\r
- // see if we have anything to save\r
- for(; sram_size > 0; sram_size--)\r
- if(SRam.data[sram_size-1]) break;\r
- \r
- if(sram_size) {\r
- sramFile = fopen(saveFname, "wb");\r
- res = fwrite(SRam.data, 1, sram_size, sramFile);\r
- res = (res != sram_size) ? -1 : 0;\r
- fclose(sramFile);\r
- }\r
- }\r
- return res;\r
- } else {\r
- void *PmovFile = NULL;\r
- // try gzip first\r
- if(currentConfig->iFlags & 0x80) {\r
- strcat(saveFname, ".gz");\r
- if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {\r
- areaRead = gzRead2;\r
- areaWrite = gzWrite2;\r
- if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);\r
- } else\r
- saveFname[strlen(saveFname)-3] = 0;\r
- }\r
- if(!PmovFile) { // gzip failed or was disabled\r
- if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {\r
- areaRead = fRead2;\r
- areaWrite = fWrite2;\r
- }\r
- }\r
- if(PmovFile) {\r
- PmovState(load ? 6 : 5, PmovFile); // load/save\r
- strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED");\r
- if(areaRead == gzRead2)\r
- gzclose(PmovFile);\r
- else fclose ((FILE *) PmovFile);\r
- PmovFile = 0;\r
- if (load) Pico.m.dirtyPal=1;\r
- } else {\r
- strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED");\r
- res = -1;\r
- }\r
-\r
- gettimeofday(¬iceMsgTime, 0);\r
- return res;\r
+ char *p = noticeMsg;\r
+ while (*p) {\r
+ if (*p == ' ') *p = '@';\r
+ if (*p < '0' || *p > 'Z') { *p = 0; break; }\r
+ p++;\r
}\r
+ gettimeofday(¬iceMsgTime, 0);\r
}\r
\r
// static class members\r