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)
+
+
-