From 936eb1d14c9b56f15e8a4fa5b9973224baa64515 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 17 Sep 2017 15:01:13 -0700 Subject: [PATCH] GBA Savedata: Fix 512 byte EEPROM saving as 8kB (fixes #877) --- CHANGES | 1 + include/mgba/internal/gba/memory.h | 3 ++- src/gba/savedata.c | 30 ++++++++++++++++++++++++------ src/platform/libretro/libretro.c | 11 ++--------- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 339df26ea..591a966f8 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugfixes: - GB, GBA: Fix sync to video with frameskip - GB Audio: Fix NRx2 writes while active (fixes mgba.io/i/866) - GBA BIOS: Use core's VRAM variable instead of renderer's + - GBA Savedata: Fix 512 byte EEPROM saving as 8kB (fixes mgba.io/i/877) Misc: - Qt: Don't rebuild library view if style hasn't changed - SDL: Fix 2.0.5 build on macOS under some circumstances diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index 1e5c89890..165d956d0 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -67,7 +67,8 @@ enum { SIZE_CART_SRAM = 0x00010000, SIZE_CART_FLASH512 = 0x00010000, SIZE_CART_FLASH1M = 0x00020000, - SIZE_CART_EEPROM = 0x00002000 + SIZE_CART_EEPROM = 0x00002000, + SIZE_CART_EEPROM512 = 0x00000200 }; enum { diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 08eab40aa..3008b9428 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -147,7 +147,7 @@ size_t GBASavedataSize(struct GBASavedata* savedata) { case SAVEDATA_FLASH1M: return SIZE_CART_FLASH1M; case SAVEDATA_EEPROM: - return SIZE_CART_EEPROM; + return (savedata->vf && savedata->vf->size(savedata->vf) == SIZE_CART_EEPROM512) ? SIZE_CART_EEPROM512 : SIZE_CART_EEPROM; case SAVEDATA_FORCE_NONE: return 0; case SAVEDATA_AUTODETECT: @@ -257,20 +257,23 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata, bool realisticTiming) { mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } + int32_t eepromSize = SIZE_CART_EEPROM512; off_t end; if (!savedata->vf) { end = 0; savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM); } else { end = savedata->vf->size(savedata->vf); - if (end < SIZE_CART_EEPROM) { - savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM); + if (end < SIZE_CART_EEPROM512) { + savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM512); + } else if (end > SIZE_CART_EEPROM512) { + eepromSize = SIZE_CART_EEPROM; } - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode); + savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode); } savedata->realisticTiming = realisticTiming; - if (end < SIZE_CART_EEPROM) { - memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end); + if (end < SIZE_CART_EEPROM512) { + memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end); } } @@ -405,6 +408,19 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8 } } +static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) { + if (size < SIZE_CART_EEPROM512) { + return; + } + if (!savedata->vf || savedata->vf->size(savedata->vf) > SIZE_CART_EEPROM512) { + return; + } + savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512); + savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM); + savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode); + memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512); +} + void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) { switch (savedata->command) { // Read header @@ -430,6 +446,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32 } else if (writeSize == 1) { savedata->command = EEPROM_COMMAND_NULL; } else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) { + _ensureEeprom(savedata, savedata->writeAddress >> 3); uint8_t current = savedata->data[savedata->writeAddress >> 3]; current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7))); current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7)); @@ -471,6 +488,7 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) { if (savedata->readBitsRemaining < 64) { int step = 63 - savedata->readBitsRemaining; uint32_t address = (savedata->readAddress + step) >> 3; + _ensureEeprom(savedata, address); if (address >= SIZE_CART_EEPROM) { mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address); return 0xFF; diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 8cd5f4637..b843f0873 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -528,16 +528,9 @@ size_t retro_get_memory_size(unsigned id) { if (core->platform(core) == PLATFORM_GBA) { switch (((struct GBA*) core->board)->memory.savedata.type) { case SAVEDATA_AUTODETECT: - case SAVEDATA_FLASH1M: return SIZE_CART_FLASH1M; - case SAVEDATA_FLASH512: - return SIZE_CART_FLASH512; - case SAVEDATA_EEPROM: - return SIZE_CART_EEPROM; - case SAVEDATA_SRAM: - return SIZE_CART_SRAM; - case SAVEDATA_FORCE_NONE: - return 0; + default: + return GBASavedataSize(&((struct GBA*) core->board)->memory.savedata); } } #endif