From 3e1793d3f892c8cba92a2eea663ce5f2af5d5584 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 7 Jun 2021 18:47:22 -0700 Subject: [PATCH] GBA Savedata: Support for 64 kiB SRAM saves --- CHANGES | 1 + include/mgba/internal/gba/memory.h | 1 + include/mgba/internal/gba/savedata.h | 4 +++- src/gba/memory.c | 5 ++++ src/gba/overrides.c | 6 +++++ src/gba/savedata.c | 34 ++++++++++++++++++++++++++++ src/platform/qt/OverrideView.ui | 5 ++++ 7 files changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 1559694e4..5408b8755 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ Features: - Tool for converting scanned pictures of e-Reader cards to raw dotcode data - Cheat code support in homebrew ports - Support for combo "Super Game Boy Color" SGB + GBC ROM hacks + - Support for 64 kiB SRAM saves used in some bootlegs Emulation fixes: - GB Video: Clear VRAM on reset (fixes mgba.io/i/2152) - GBA SIO: Add missing NORMAL8 implementation bits (fixes mgba.io/i/2172) diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index f7d4e1eb9..59b22b457 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -68,6 +68,7 @@ enum { SIZE_CART1 = 0x02000000, SIZE_CART2 = 0x02000000, SIZE_CART_SRAM = 0x00008000, + SIZE_CART_SRAM512 = 0x00010000, SIZE_CART_FLASH512 = 0x00010000, SIZE_CART_FLASH1M = 0x00020000, SIZE_CART_EEPROM = 0x00002000, diff --git a/include/mgba/internal/gba/savedata.h b/include/mgba/internal/gba/savedata.h index 05cd65963..395e06b7a 100644 --- a/include/mgba/internal/gba/savedata.h +++ b/include/mgba/internal/gba/savedata.h @@ -24,7 +24,8 @@ enum SavedataType { SAVEDATA_FLASH512 = 2, SAVEDATA_FLASH1M = 3, SAVEDATA_EEPROM = 4, - SAVEDATA_EEPROM512 = 5 + SAVEDATA_EEPROM512 = 5, + SAVEDATA_SRAM512 = 6, }; enum SavedataCommand { @@ -110,6 +111,7 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type); void GBASavedataInitFlash(struct GBASavedata* savedata); void GBASavedataInitEEPROM(struct GBASavedata* savedata); void GBASavedataInitSRAM(struct GBASavedata* savedata); +void GBASavedataInitSRAM512(struct GBASavedata* savedata); uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address); void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value); diff --git a/src/gba/memory.c b/src/gba/memory.c index f650881b1..a7e3ac7c9 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -717,6 +717,8 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = GBASavedataReadFlash(&memory->savedata, address); } else if (memory->hw.devices & HW_TILT) { value = GBAHardwareTiltRead(&memory->hw, address & OFFSET_MASK); + } else if (memory->savedata.type == SAVEDATA_SRAM512) { + value = memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)]; } else { mLOG(GBA_MEM, GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address); value = 0xFF; @@ -1070,6 +1072,9 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo memory->savedata.dirty |= SAVEDATA_DIRT_NEW; } else if (memory->hw.devices & HW_TILT) { GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value); + } else if (memory->savedata.type == SAVEDATA_SRAM512) { + memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)] = value; + memory->savedata.dirty |= SAVEDATA_DIRT_NEW; } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } diff --git a/src/gba/overrides.c b/src/gba/overrides.c index 2c95ada25..2e0ce10de 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -241,6 +241,9 @@ bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOver if (strcasecmp(savetype, "SRAM") == 0) { found = true; override->savetype = SAVEDATA_SRAM; + } else if (strcasecmp(savetype, "SRAM512") == 0) { + found = true; + override->savetype = SAVEDATA_SRAM512; } else if (strcasecmp(savetype, "EEPROM") == 0) { found = true; override->savetype = SAVEDATA_EEPROM; @@ -288,6 +291,9 @@ void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOver case SAVEDATA_SRAM: savetype = "SRAM"; break; + case SAVEDATA_SRAM512: + savetype = "SRAM512"; + break; case SAVEDATA_EEPROM: savetype = "EEPROM"; break; diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 1ae924a9f..fbae0a554 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -68,6 +68,9 @@ void GBASavedataDeinit(struct GBASavedata* savedata) { case SAVEDATA_SRAM: mappedMemoryFree(savedata->data, SIZE_CART_SRAM); break; + case SAVEDATA_SRAM512: + mappedMemoryFree(savedata->data, SIZE_CART_SRAM512); + break; case SAVEDATA_FLASH512: mappedMemoryFree(savedata->data, SIZE_CART_FLASH512); break; @@ -124,6 +127,8 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { switch (savedata->type) { case SAVEDATA_SRAM: return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM; + case SAVEDATA_SRAM512: + return out->write(out, savedata->data, SIZE_CART_SRAM512) == SIZE_CART_SRAM512; case SAVEDATA_FLASH512: return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512; case SAVEDATA_FLASH1M: @@ -153,6 +158,8 @@ size_t GBASavedataSize(const struct GBASavedata* savedata) { switch (savedata->type) { case SAVEDATA_SRAM: return SIZE_CART_SRAM; + case SAVEDATA_SRAM512: + return SIZE_CART_SRAM512; case SAVEDATA_FLASH512: return SIZE_CART_FLASH512; case SAVEDATA_FLASH1M: @@ -233,6 +240,9 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) case SAVEDATA_SRAM: GBASavedataInitSRAM(savedata); break; + case SAVEDATA_SRAM512: + GBASavedataInitSRAM512(savedata); + break; case SAVEDATA_FORCE_NONE: savedata->type = SAVEDATA_FORCE_NONE; break; @@ -322,6 +332,30 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) { } } +void GBASavedataInitSRAM512(struct GBASavedata* savedata) { + if (savedata->type == SAVEDATA_AUTODETECT) { + savedata->type = SAVEDATA_SRAM512; + } else { + mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); + return; + } + off_t end; + if (!savedata->vf) { + end = 0; + savedata->data = anonymousMemoryMap(SIZE_CART_SRAM512); + } else { + end = savedata->vf->size(savedata->vf); + if (end < SIZE_CART_SRAM512) { + savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM512); + } + savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM512, savedata->mapMode); + } + + if (end < SIZE_CART_SRAM512) { + memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM512 - end); + } +} + uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) { if (savedata->command == FLASH_COMMAND_ID) { if (savedata->type == SAVEDATA_FLASH512) { diff --git a/src/platform/qt/OverrideView.ui b/src/platform/qt/OverrideView.ui index 99e851ff9..e1e84927c 100644 --- a/src/platform/qt/OverrideView.ui +++ b/src/platform/qt/OverrideView.ui @@ -151,6 +151,11 @@ EEPROM 512 bytes + + + SRAM 64kB (bootlegs only) + +