GBA Savedata: Support for 64 kiB SRAM saves

This commit is contained in:
Vicki Pfau 2021-06-07 18:47:22 -07:00
parent 02a15a72c0
commit 3e1793d3f8
7 changed files with 55 additions and 1 deletions

View File

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

View File

@ -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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -151,6 +151,11 @@
<string>EEPROM 512 bytes</string>
</property>
</item>
<item>
<property name="text">
<string>SRAM 64kB (bootlegs only)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">