diff --git a/src/core/core.h b/src/core/core.h index 88ade29df..a9146d035 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -126,7 +126,7 @@ void (*busWrite16)(struct mCore*, uint32_t address, uint16_t); struct mCheatDevice* (*cheatDevice)(struct mCore*); size_t (*savedataClone)(struct mCore*, void** sram); - bool (*savedataLoad)(struct mCore*, const void* sram, size_t size); + bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/src/core/serialize.c b/src/core/serialize.c index d51840098..14a3795ac 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -407,10 +407,10 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { mLOG(SAVESTATE, WARN, "Savestate includes invalid screenshot"); } } - if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { + if (mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { mLOG(SAVESTATE, INFO, "Loading savedata"); if (item.data) { - core->savedataLoad(core, item.data, item.size); + core->savedataRestore(core, item.data, item.size, flags & SAVESTATE_SAVEDATA); } } struct mCheatDevice* device; diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index bd5b926c3..3c89e3f77 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -424,7 +424,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { runner->core->reset(runner->core); break; case RUNNER_SAVE_STATE: - mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); + mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEGAME); break; case RUNNER_LOAD_STATE: mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); diff --git a/src/gb/core.c b/src/gb/core.c index d7766d17a..99334fa7c 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -177,7 +177,7 @@ static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) { static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) { struct GB* gb = core->board; - GBSavedataMask(gb, vf); + GBSavedataMask(gb, vf, false); return true; // TODO: Return a real value } @@ -484,8 +484,13 @@ static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) { return gb->sramSize; } -static bool _GBCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { +static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) { struct GB* gb = core->board; + if (!writeback) { + struct VFile* vf = VFileFromConstMemory(sram, size); + GBSavedataMask(gb, vf, true); + return true; + } struct VFile* vf = gb->sramVf; if (vf) { vf->seek(vf, 0, SEEK_SET); @@ -563,6 +568,6 @@ struct mCore* GBCoreCreate(void) { core->detachDebugger = _GBCoreDetachDebugger; core->cheatDevice = _GBCoreCheatDevice; core->savedataClone = _GBCoreSavedataClone; - core->savedataLoad = _GBCoreSavedataLoad; + core->savedataRestore = _GBCoreSavedataRestore; return core; } diff --git a/src/gb/gb.c b/src/gb/gb.c index 3edeee5d0..d09bdf83f 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -118,8 +118,7 @@ static void GBSramDeinit(struct GB* gb) { if (gb->memory.mbcType == GB_MBC3_RTC) { GBMBCRTCWrite(gb); } - gb->sramVf->close(gb->sramVf); - gb->sramVf = 0; + gb->sramVf = NULL; } else if (gb->memory.sram) { mappedMemoryFree(gb->memory.sram, gb->sramSize); } @@ -210,9 +209,10 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) { } } -void GBSavedataMask(struct GB* gb, struct VFile* vf) { +void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) { GBSramDeinit(gb); gb->sramVf = vf; + gb->sramMaskWriteback = writeback; gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ); } @@ -220,9 +220,14 @@ void GBSavedataUnmask(struct GB* gb) { if (gb->sramVf == gb->sramRealVf) { return; } + struct VFile* vf = gb->sramVf; GBSramDeinit(gb); gb->sramVf = gb->sramRealVf; gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE); + if (gb->sramMaskWriteback) { + vf->read(vf, gb->memory.sram, gb->sramSize); + } + vf->close(vf); } void GBUnloadROM(struct GB* gb) { @@ -247,7 +252,11 @@ void GBUnloadROM(struct GB* gb) { gb->romVf = 0; } + struct VFile* vf = gb->sramVf; GBSramDeinit(gb); + if (vf) { + vf->close(vf); + } } void GBLoadBIOS(struct GB* gb, struct VFile* vf) { diff --git a/src/gb/gb.h b/src/gb/gb.h index 7e25fe8bd..b1fce80d3 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -70,6 +70,7 @@ struct GB { uint32_t sramSize; int sramDirty; int32_t sramDirtAge; + bool sramMaskWriteback; struct mAVStream* stream; @@ -121,7 +122,7 @@ void GBLoadBIOS(struct GB* gb, struct VFile* vf); void GBSramClean(struct GB* gb, uint32_t frameCount); void GBResizeSram(struct GB* gb, size_t size); -void GBSavedataMask(struct GB* gb, struct VFile* vf); +void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback); void GBSavedataUnmask(struct GB* gb); struct Patch; diff --git a/src/gba/core.c b/src/gba/core.c index 676e62aa4..6f03440de 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -211,7 +211,7 @@ static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) { static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) { struct GBA* gba = core->board; - GBASavedataMask(&gba->memory.savedata, vf); + GBASavedataMask(&gba->memory.savedata, vf, false); return true; // TODO: Return a real value } @@ -507,14 +507,19 @@ static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) { return size; } -static bool _GBACoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { +static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) { struct VFile* vf = VFileFromConstMemory(sram, size); if (!vf) { return false; } struct GBA* gba = core->board; - bool success = GBASavedataLoad(&gba->memory.savedata, vf); - vf->close(vf); + bool success = true; + if (writeback) { + success = GBASavedataLoad(&gba->memory.savedata, vf); + vf->close(vf); + } else { + GBASavedataMask(&gba->memory.savedata, vf, true); + } return success; } @@ -582,6 +587,6 @@ struct mCore* GBACoreCreate(void) { core->detachDebugger = _GBACoreDetachDebugger; core->cheatDevice = _GBACoreCheatDevice; core->savedataClone = _GBACoreSavedataClone; - core->savedataLoad = _GBACoreSavedataLoad; + core->savedataRestore = _GBACoreSavedataRestore; return core; } diff --git a/src/gba/memory.c b/src/gba/memory.c index e54ce2699..7cc4dc6df 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -92,6 +92,7 @@ void GBAMemoryDeinit(struct GBA* gba) { if (gba->memory.rom) { mappedMemoryFree(gba->memory.rom, gba->memory.romSize); } + GBASavedataUnmask(&gba->memory.savedata); GBASavedataDeinit(&gba->memory.savedata); if (gba->memory.savedata.realVf) { gba->memory.savedata.realVf->close(gba->memory.savedata.realVf); diff --git a/src/gba/rr/rr.c b/src/gba/rr/rr.c index 24edae7c3..f2af0a0d4 100644 --- a/src/gba/rr/rr.c +++ b/src/gba/rr/rr.c @@ -23,9 +23,9 @@ void GBARRInitRecord(struct GBA* gba) { GBASavedataClone(&gba->memory.savedata, gba->rr->savedata); gba->rr->savedata->close(gba->rr->savedata); gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY); - GBASavedataMask(&gba->memory.savedata, gba->rr->savedata); + GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false); } else { - GBASavedataMask(&gba->memory.savedata, 0); + GBASavedataMask(&gba->memory.savedata, 0, false); } if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { @@ -47,9 +47,9 @@ void GBARRInitPlay(struct GBA* gba) { gba->rr->savedata->close(gba->rr->savedata); } gba->rr->savedata = gba->rr->openSavedata(gba->rr, O_RDONLY); - GBASavedataMask(&gba->memory.savedata, gba->rr->savedata); + GBASavedataMask(&gba->memory.savedata, gba->rr->savedata, false); } else { - GBASavedataMask(&gba->memory.savedata, 0); + GBASavedataMask(&gba->memory.savedata, 0, false); } if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { diff --git a/src/gba/savedata.c b/src/gba/savedata.c index d3aef4fae..cfa410ae4 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -47,10 +47,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata) { if (savedata->vf) { size_t size = GBASavedataSize(savedata); savedata->vf->unmap(savedata->vf, savedata->data, size); - if (savedata->vf != savedata->realVf) { - savedata->vf->close(savedata->vf); - } - savedata->vf = 0; + savedata->vf = NULL; } else { switch (savedata->type) { case SAVEDATA_SRAM: @@ -74,23 +71,30 @@ void GBASavedataDeinit(struct GBASavedata* savedata) { savedata->type = SAVEDATA_AUTODETECT; } -void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) { +void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) { enum SavedataType type = savedata->type; GBASavedataDeinit(savedata); savedata->vf = vf; savedata->mapMode = MAP_READ; + savedata->maskWriteback = writeback; GBASavedataForceType(savedata, type, savedata->realisticTiming); } void GBASavedataUnmask(struct GBASavedata* savedata) { - if (savedata->mapMode != MAP_READ) { + if (savedata->vf == savedata->realVf) { return; } enum SavedataType type = savedata->type; + struct VFile* vf = savedata->vf; GBASavedataDeinit(savedata); savedata->vf = savedata->realVf; savedata->mapMode = MAP_WRITE; GBASavedataForceType(savedata, type, savedata->realisticTiming); + if (savedata->maskWriteback) { + GBASavedataLoad(savedata, vf); + savedata->maskWriteback = false; + } + vf->close(vf); } bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { @@ -488,6 +492,9 @@ void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) { savedata->dirty |= SAVEDATA_DIRT_SEEN; } } else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) { + if (savedata->maskWriteback) { + GBASavedataUnmask(savedata); + } size_t size = GBASavedataSize(savedata); savedata->dirty = 0; if (savedata->data && savedata->vf->sync(savedata->vf, savedata->data, size)) { diff --git a/src/gba/savedata.h b/src/gba/savedata.h index 7af806fd5..98feb52b4 100644 --- a/src/gba/savedata.h +++ b/src/gba/savedata.h @@ -74,6 +74,7 @@ struct GBASavedata { struct VFile* vf; int mapMode; + bool maskWriteback; struct VFile* realVf; int32_t readBitsRemaining; @@ -95,7 +96,7 @@ struct GBASavedata { void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf); void GBASavedataDeinit(struct GBASavedata* savedata); -void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf); +void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback); void GBASavedataUnmask(struct GBASavedata* savedata); size_t GBASavedataSize(struct GBASavedata* savedata); bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 1487daa08..d551a377b 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -470,7 +470,7 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* case SDLK_F8: case SDLK_F9: mCoreThreadInterrupt(context); - mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT); + mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SAVEDATA | SAVESTATE_SCREENSHOT); mCoreThreadContinue(context); break; default: