diff --git a/src/gba/gba.c b/src/gba/gba.c index 568fb629e..2bef0c6a0 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -96,14 +96,22 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { gba->performingDMA = false; } -void GBADestroy(struct GBA* gba) { +void GBAUnloadROM(struct GBA* gba) { if (gba->pristineRom == gba->memory.rom) { gba->memory.rom = 0; + } else { + mappedMemoryFree(gba->pristineRom, gba->pristineRomSize); } if (gba->romVf) { gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); + gba->pristineRom = 0; + gba->romVf = 0; } +} + +void GBADestroy(struct GBA* gba) { + GBAUnloadROM(gba); if (gba->biosVf) { gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS); @@ -370,6 +378,7 @@ void GBADetachDebugger(struct GBA* gba) { } void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) { + GBAUnloadROM(gba); gba->romVf = vf; gba->pristineRomSize = vf->size(vf); vf->seek(vf, 0, SEEK_SET); diff --git a/src/gba/gba.h b/src/gba/gba.h index 636c2ae14..25212d19e 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -208,6 +208,7 @@ void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mo void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname); void GBAYankROM(struct GBA* gba); +void GBAUnloadROM(struct GBA* gba); void GBALoadBIOS(struct GBA* gba, struct VFile* vf); void GBAApplyPatch(struct GBA* gba, struct Patch* patch); diff --git a/src/gba/supervisor/thread.c b/src/gba/supervisor/thread.c index b5a1fad42..8a39da3bb 100644 --- a/src/gba/supervisor/thread.c +++ b/src/gba/supervisor/thread.c @@ -23,6 +23,8 @@ #include +static void _loadGameDir(struct GBAThread* threadContext); + static const float _defaultFPSTarget = 60.f; #ifndef DISABLE_THREADING @@ -352,18 +354,7 @@ void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext->gameDir = VDirOpen(args->fname); threadContext->stateDir = threadContext->gameDir; } else { - threadContext->rom = VFileOpen(args->fname, O_RDONLY); - threadContext->gameDir = 0; -#if USE_LIBZIP - if (!threadContext->gameDir) { - threadContext->gameDir = VDirOpenZip(args->fname, 0); - } -#endif -#if USE_LZMA - if (!threadContext->gameDir) { - threadContext->gameDir = VDirOpen7z(args->fname, 0); - } -#endif + GBAThreadLoadROM(threadContext, args->fname); } threadContext->fname = args->fname; threadContext->patch = VFileOpen(args->patch, O_RDONLY); @@ -398,25 +389,7 @@ bool GBAThreadStart(struct GBAThread* threadContext) { } if (threadContext->gameDir) { - threadContext->gameDir->rewind(threadContext->gameDir); - struct VDirEntry* dirent = threadContext->gameDir->listNext(threadContext->gameDir); - while (dirent) { - struct Patch patchTemp; - struct VFile* vf = threadContext->gameDir->openFile(threadContext->gameDir, dirent->name(dirent), O_RDONLY); - if (!vf) { - dirent = threadContext->gameDir->listNext(threadContext->gameDir); - continue; - } - if (!threadContext->rom && GBAIsROM(vf)) { - threadContext->rom = vf; - } else if (!threadContext->patch && loadPatch(vf, &patchTemp)) { - threadContext->patch = vf; - } else { - vf->close(vf); - } - dirent = threadContext->gameDir->listNext(threadContext->gameDir); - } - + _loadGameDir(threadContext); } if (!threadContext->rom && !bootBios) { @@ -678,6 +651,67 @@ void GBAThreadPauseFromThread(struct GBAThread* threadContext) { GBASyncSetVideoSync(&threadContext->sync, frameOn); } +void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname) { + threadContext->rom = VFileOpen(fname, O_RDONLY); + threadContext->gameDir = 0; +#if USE_LIBZIP + if (!threadContext->gameDir) { + threadContext->gameDir = VDirOpenZip(fname, 0); + } +#endif +#if USE_LZMA + if (!threadContext->gameDir) { + threadContext->gameDir = VDirOpen7z(fname, 0); + } +#endif +} + +static void _loadGameDir(struct GBAThread* threadContext) { + threadContext->gameDir->rewind(threadContext->gameDir); + struct VDirEntry* dirent = threadContext->gameDir->listNext(threadContext->gameDir); + while (dirent) { + struct Patch patchTemp; + struct VFile* vf = threadContext->gameDir->openFile(threadContext->gameDir, dirent->name(dirent), O_RDONLY); + if (!vf) { + dirent = threadContext->gameDir->listNext(threadContext->gameDir); + continue; + } + if (!threadContext->rom && GBAIsROM(vf)) { + threadContext->rom = vf; + } else if (!threadContext->patch && loadPatch(vf, &patchTemp)) { + threadContext->patch = vf; + } else { + vf->close(vf); + } + dirent = threadContext->gameDir->listNext(threadContext->gameDir); + } +} + +void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname) { + GBAUnloadROM(threadContext->gba); + + if (threadContext->rom) { + threadContext->rom->close(threadContext->rom); + threadContext->rom = 0; + } + + if (threadContext->save) { + threadContext->save->close(threadContext->save); + threadContext->save = 0; + } + + GBAThreadLoadROM(threadContext, fname); + if(threadContext->gameDir) { + _loadGameDir(threadContext); + } + + threadContext->fname = fname; + threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR); + + GBARaiseIRQ(threadContext->gba, IRQ_GAMEPAK); + GBALoadROM(threadContext->gba, threadContext->rom, threadContext->save, threadContext->fname); +} + #ifdef USE_PTHREADS struct GBAThread* GBAThreadGetContext(void) { pthread_once(&_contextOnce, _createTLS); diff --git a/src/gba/supervisor/thread.h b/src/gba/supervisor/thread.h index 8fc99b867..aa86940f2 100644 --- a/src/gba/supervisor/thread.h +++ b/src/gba/supervisor/thread.h @@ -126,6 +126,9 @@ void GBAThreadTogglePause(struct GBAThread* threadContext); void GBAThreadPauseFromThread(struct GBAThread* threadContext); struct GBAThread* GBAThreadGetContext(void); +void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname); +void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname); + #ifdef USE_PNG void GBAThreadTakeScreenshot(struct GBAThread* threadContext); #endif