GBA Savedata: Add realistic timing for EEPROM
Jeffrey Pfau jeffrey@endrift.com
Sun, 14 Aug 2016 20:56:42 -0700
4 files changed,
21 insertions(+),
6 deletions(-)
M
src/gba/memory.c
→
src/gba/memory.c
@@ -811,7 +811,7 @@ break;
case REGION_CART2_EX: if (memory->savedata.type == SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); - GBASavedataInitEEPROM(&memory->savedata); + GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming); } GBASavedataWriteEEPROM(&memory->savedata, value, 1); break;@@ -1690,7 +1690,7 @@ --wordsRemaining;
} else if (destRegion == REGION_CART2_EX) { if (memory->savedata.type == SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); - GBASavedataInitEEPROM(&memory->savedata); + GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming); } word = cpu->memory.load16(cpu, source, 0); gba->bus = word | (word << 16);
M
src/gba/savedata.c
→
src/gba/savedata.c
@@ -20,6 +20,8 @@ // Some games may vary anywhere between about 2000 cycles to up to 30000 cycles. (Observed on a Macronix (09C2) chip).
// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip). // An average estimation is as follows. #define FLASH_SETTLE_CYCLES 18000 +// This needs real testing, and is only an estimation currently +#define EEPROM_SETTLE_CYCLES 14500 #define CLEANUP_THRESHOLD 15 mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata");@@ -201,7 +203,7 @@ savedata->type = type;
GBASavedataInitFlash(savedata, realisticTiming); break; case SAVEDATA_EEPROM: - GBASavedataInitEEPROM(savedata); + GBASavedataInitEEPROM(savedata, realisticTiming); break; case SAVEDATA_SRAM: GBASavedataInitSRAM(savedata);@@ -247,7 +249,7 @@ memset(&savedata->data[end], 0xFF, flashSize - end);
} } -void GBASavedataInitEEPROM(struct GBASavedata* savedata) { +void GBASavedataInitEEPROM(struct GBASavedata* savedata, bool realisticTiming) { if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_EEPROM; } else {@@ -265,6 +267,8 @@ savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
} savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode); } + savedata->dust = 0; + savedata->realisticTiming = realisticTiming; if (end < SIZE_CART_EEPROM) { memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end); }@@ -430,6 +434,9 @@ current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7)); savedata->dirty |= SAVEDATA_DIRT_NEW; savedata->data[savedata->writeAddress >> 3] = current; + if (savedata->realisticTiming) { + savedata->dust = EEPROM_SETTLE_CYCLES; + } ++savedata->writeAddress; } else { mLOG(GBA_SAVE, GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));@@ -452,7 +459,14 @@ }
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) { if (savedata->command != EEPROM_COMMAND_READ) { - return 1; + if (!savedata->realisticTiming || savedata->dust <= 0) { + return 1; + } else { + // Give some overhead for waitstates and the comparison + // This estimation can probably be improved + savedata->dust -= 10; + return 0; + } } --savedata->readBitsRemaining; if (savedata->readBitsRemaining < 64) {
M
src/gba/savedata.h
→
src/gba/savedata.h
@@ -103,7 +103,7 @@ bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in);
void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming); void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming); -void GBASavedataInitEEPROM(struct GBASavedata* savedata); +void GBASavedataInitEEPROM(struct GBASavedata* savedata, bool realisticTiming); void GBASavedataInitSRAM(struct GBASavedata* savedata); uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address);