GBA: Add somewhat more realistic flash timings, disabled currently
@@ -89,6 +89,9 @@ gba->idleLoop = IDLE_LOOP_NONE;
gba->lastJump = 0; gba->idleDetectionStep = 0; gba->idleDetectionFailures = 0; + + gba->realisticTiming = false; + gba->performingDMA = false; }
@@ -161,6 +161,8 @@ int idleDetectionStep;
int idleDetectionFailures; int32_t cachedRegisters[16]; bool taintedRegisters[16]; + + bool realisticTiming; }; struct GBACartridge {
@@ -778,7 +778,7 @@ case REGION_CART_SRAM_MIRROR:
if (memory->savedata.type == SAVEDATA_AUTODETECT) { if (address == SAVEDATA_FLASH_BASE) { GBALog(gba, GBA_LOG_INFO, "Detected Flash savegame"); - GBASavedataInitFlash(&memory->savedata); + GBASavedataInitFlash(&memory->savedata, gba->realisticTiming); } else { GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame"); GBASavedataInitSRAM(&memory->savedata);
@@ -14,6 +14,8 @@
#include <errno.h> #include <fcntl.h> +#define FLASH_SETTLE_CYCLES 18000 + static void _flashSwitchBank(struct GBASavedata* savedata, int bank); static void _flashErase(struct GBASavedata* savedata); static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);@@ -113,7 +115,7 @@ }
return true; } -void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) { +void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming) { if (savedata->type != SAVEDATA_AUTODETECT) { struct VFile* vf = savedata->vf; GBASavedataDeinit(savedata);@@ -123,7 +125,7 @@ switch (type) {
case SAVEDATA_FLASH512: case SAVEDATA_FLASH1M: savedata->type = type; - GBASavedataInitFlash(savedata); + GBASavedataInitFlash(savedata, realisticTiming); break; case SAVEDATA_EEPROM: GBASavedataInitEEPROM(savedata);@@ -139,7 +141,7 @@ break;
} } -void GBASavedataInitFlash(struct GBASavedata* savedata) { +void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming) { if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_FLASH512; }@@ -162,6 +164,8 @@ savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
} savedata->currentBank = savedata->data; + savedata->dust = 0; + savedata->realisticTiming = realisticTiming; if (end < SIZE_CART_FLASH512) { memset(&savedata->data[end], 0xFF, flashSize - end); }@@ -226,6 +230,10 @@ return FLASH_MFG_SANYO >> (address * 8);
} } } + if (savedata->dust > 0 && (address >> 12) == savedata->settling) { + --savedata->dust; + return 0x5F; + } return savedata->currentBank[address]; }@@ -384,6 +392,8 @@ state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000];
state->savedata.readBitsRemaining = savedata->readBitsRemaining; state->savedata.readAddress = savedata->readAddress; state->savedata.writeAddress = savedata->writeAddress; + state->savedata.settlingSector = savedata->settling; + state->savedata.settlingDust = savedata->dust; UNUSED(includeData); // TODO }@@ -393,13 +403,16 @@ if (state->savedata.type == SAVEDATA_FORCE_NONE) {
return; } if (savedata->type != state->savedata.type) { - GBASavedataForceType(savedata, state->savedata.type); + GBASavedataForceType(savedata, state->savedata.type, savedata->realisticTiming); } savedata->command = state->savedata.command; savedata->flashState = state->savedata.flashState; savedata->readBitsRemaining = state->savedata.readBitsRemaining; savedata->readAddress = state->savedata.readAddress; savedata->writeAddress = state->savedata.writeAddress; + savedata->settling = state->savedata.settlingSector; + savedata->dust = state->savedata.settlingDust; + if (savedata->type == SAVEDATA_FLASH1M) { _flashSwitchBank(savedata, state->savedata.flashBank); }@@ -433,6 +446,10 @@ GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
size_t size = 0x1000; if (savedata->type == SAVEDATA_FLASH1M) { GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart); + } + savedata->settling = sectorStart >> 12; + if (savedata->realisticTiming) { + savedata->dust = FLASH_SETTLE_CYCLES; } memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size); }
@@ -73,6 +73,10 @@ uint32_t writeAddress;
uint8_t* currentBank; + bool realisticTiming; + unsigned settling; + int dust; + enum FlashStateMachine flashState; };@@ -82,9 +86,9 @@
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf); void GBASavedataUnmask(struct GBASavedata* savedata); bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); -void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type); +void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming); -void GBASavedataInitFlash(struct GBASavedata* savedata); +void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming); void GBASavedataInitEEPROM(struct GBASavedata* savedata); void GBASavedataInitSRAM(struct GBASavedata* savedata);
@@ -162,8 +162,9 @@ * | bits 5 - 7: Reserved
* | 0x002E3 - 0x002E3: Reserved * | 0x002E4 - 0x002E7: EEPROM read bits remaining * | 0x002E8 - 0x002EB: EEPROM read address - * | 0x002EC - 0x002EBF EEPROM write address - * 0x002F0 - 0x002F3: Reserved (leave zero) + * | 0x002EC - 0x002EF: EEPROM write address + * | 0x002F0 - 0x002F1: Flash settling sector + * | 0x002F2 - 0x002F3: Flash settling remaining * 0x002F4 - 0x002FF: Prefetch * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch * | 0x002F8 - 0x002FB: CPU prefecth (decode slot)@@ -297,9 +298,9 @@ unsigned : 8;
int32_t readBitsRemaining; uint32_t readAddress; uint32_t writeAddress; + uint16_t settlingSector; + uint16_t settlingDust; } savedata; - - uint32_t reservedPadding; uint32_t biosPrefetch; uint32_t cpuPrefetch[2];
@@ -249,7 +249,7 @@ }
void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) { if (override->savetype != SAVEDATA_AUTODETECT) { - GBASavedataForceType(&gba->memory.savedata, override->savetype); + GBASavedataForceType(&gba->memory.savedata, override->savetype, gba->realisticTiming); } if (override->hardware != HW_NO_OVERRIDE) {