diff --git a/CHANGES b/CHANGES index 84b39ecfb..1df07b350 100644 --- a/CHANGES +++ b/CHANGES @@ -50,6 +50,7 @@ Bugfixes: - GBA Hardware: RTC accuracy improvements - GB Timer: Minor accuracy improvements - GB Audio: Clock frame events on DIV + - GBA: Fix SharkPort saves for EEPROM games Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/include/mgba/internal/gba/savedata.h b/include/mgba/internal/gba/savedata.h index a807c6c91..af4c897d0 100644 --- a/include/mgba/internal/gba/savedata.h +++ b/include/mgba/internal/gba/savedata.h @@ -102,7 +102,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata); void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback); void GBASavedataUnmask(struct GBASavedata* savedata); -size_t GBASavedataSize(struct GBASavedata* savedata); +size_t GBASavedataSize(const struct GBASavedata* savedata); bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in); void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming); diff --git a/src/gba/savedata.c b/src/gba/savedata.c index c8c6c8be7..ec41c4eb9 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -138,7 +138,7 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { return true; } -size_t GBASavedataSize(struct GBASavedata* savedata) { +size_t GBASavedataSize(const struct GBASavedata* savedata) { switch (savedata->type) { case SAVEDATA_SRAM: return SIZE_CART_SRAM; diff --git a/src/gba/sharkport.c b/src/gba/sharkport.c index d9ca483c9..88c79eec6 100644 --- a/src/gba/sharkport.c +++ b/src/gba/sharkport.c @@ -130,8 +130,21 @@ bool GBASavedataImportSharkPort(struct GBA* gba, struct VFile* vf, bool testChec goto cleanup; } - memcpy(gba->memory.savedata.data, &payload[0x1C], copySize); - gba->memory.savedata.vf && gba->memory.savedata.vf->sync(gba->memory.savedata.vf, gba->memory.savedata.data, size); + if (gba->memory.savedata.type == SAVEDATA_EEPROM) { + size_t i; + for (i = 0; i < copySize; i += 8) { + uint32_t lo, hi; + LOAD_32BE(lo, i + 0x1C, payload); + LOAD_32BE(hi, i + 0x20, payload); + STORE_32LE(hi, i, gba->memory.savedata.data); + STORE_32LE(lo, i + 4, gba->memory.savedata.data); + } + } else { + memcpy(gba->memory.savedata.data, &payload[0x1C], copySize); + } + if (gba->memory.savedata.vf) { + gba->memory.savedata.vf->sync(gba->memory.savedata.vf, gba->memory.savedata.data, size); + } free(payload); return true; @@ -146,7 +159,7 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) { char c[0x1C]; int32_t i; } buffer; - int32_t size = strlen(SHARKPORT_HEADER); + uint32_t size = strlen(SHARKPORT_HEADER); STORE_32(size, 0, &buffer.i); if (vf->write(vf, &buffer.i, 4) < 4) { return false; @@ -187,22 +200,8 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) { } // Write payload - size = 0x1C; - switch (gba->memory.savedata.type) { - case SAVEDATA_SRAM: - size += SIZE_CART_SRAM; - break; - case SAVEDATA_FLASH512: - size += SIZE_CART_FLASH512; - break; - case SAVEDATA_FLASH1M: - size += SIZE_CART_FLASH1M; - break; - case SAVEDATA_EEPROM: - size += SIZE_CART_EEPROM; - break; - case SAVEDATA_FORCE_NONE: - case SAVEDATA_AUTODETECT: + size = 0x1C + GBASavedataSize(&gba->memory.savedata); + if (size == 0x1C) { return false; } STORE_32(size, 0, &buffer.i); @@ -229,17 +228,24 @@ bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) { } uint32_t checksum = 0; - int i; + size_t i; for (i = 0; i < 0x1C; ++i) { checksum += buffer.c[i] << (checksum % 24); } - if (vf->write(vf, gba->memory.savedata.data, size) < size) { - return false; - } - for (i = 0; i < size; ++i) { - checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24); + if (gba->memory.savedata.type == SAVEDATA_EEPROM) { + for (i = 0; i < size; ++i) { + char byte = gba->memory.savedata.data[i ^ 7]; + checksum += byte << (checksum % 24); + vf->write(vf, &byte, 1); + } + } else if (vf->write(vf, gba->memory.savedata.data, size) < size) { + return false; + } else { + for (i = 0; i < size; ++i) { + checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24); + } } STORE_32(checksum, 0, &buffer.i);