GBA: Savedata is now synced shortly after data finishes being written

This commit is contained in:
Jeffrey Pfau 2015-07-07 00:30:10 -07:00
parent 250d3b940d
commit 4b3df31e49
5 changed files with 53 additions and 0 deletions

View File

@ -99,6 +99,7 @@ Misc:
- All: Proper handling of Unicode file paths
- GBA Video: Slightly optimize mode 0 mosaic rendering
- VFS: Add sync method to force syncing with backing
- GBA: Savedata is now synced shortly after data finishes being written
0.2.1: (2015-05-13)
Bugfixes:

View File

@ -756,6 +756,8 @@ void GBAFrameStarted(struct GBA* gba) {
}
void GBAFrameEnded(struct GBA* gba) {
GBASavedataClean(&gba->memory.savedata, gba->video.frameCounter);
if (gba->rr) {
gba->rr->nextFrame(gba->rr);
}

View File

@ -818,6 +818,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
GBASavedataWriteFlash(&memory->savedata, address, value);
} else if (memory->savedata.type == SAVEDATA_SRAM) {
memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
memory->savedata.dirty |= SAVEDATA_DIRT_NEW;
} else if (memory->hw.devices & HW_TILT) {
GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value);
} else {

View File

@ -20,6 +20,7 @@
// 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
#define CLEANUP_THRESHOLD 15
static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
static void _flashErase(struct GBASavedata* savedata);
@ -33,6 +34,8 @@ void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
savedata->vf = vf;
savedata->realVf = vf;
savedata->mapMode = MAP_WRITE;
savedata->dirty = 0;
savedata->dirtAge = 0;
}
void GBASavedataDeinit(struct GBASavedata* savedata) {
@ -252,6 +255,7 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
case FLASH_STATE_RAW:
switch (savedata->command) {
case FLASH_COMMAND_PROGRAM:
savedata->dirty |= SAVEDATA_DIRT_NEW;
savedata->currentBank[address] = value;
savedata->command = FLASH_COMMAND_NONE;
break;
@ -359,6 +363,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
uint8_t current = savedata->data[savedata->writeAddress >> 3];
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
savedata->dirty |= SAVEDATA_DIRT_NEW;
savedata->data[savedata->writeAddress >> 3] = current;
++savedata->writeAddress;
} else {
@ -401,6 +406,38 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
return 0;
}
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
if (savedata->dirty & SAVEDATA_DIRT_NEW) {
savedata->dirty &= ~SAVEDATA_DIRT_NEW;
if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
savedata->dirtAge = frameCount;
savedata->dirty |= SAVEDATA_DIRT_SEEN;
}
} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
size_t size;
switch (savedata->type) {
case SAVEDATA_EEPROM:
size = SIZE_CART_EEPROM;
break;
case SAVEDATA_SRAM:
size = SIZE_CART_SRAM;
break;
case SAVEDATA_FLASH512:
size = SIZE_CART_FLASH512;
break;
case SAVEDATA_FLASH1M:
size = SIZE_CART_FLASH1M;
break;
default:
size = 0;
break;
}
savedata->vf->sync(savedata->vf, savedata->data, size);
savedata->dirty = 0;
GBALog(0, GBA_LOG_INFO, "Savedata synced");
}
}
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
state->savedata.type = savedata->type;
state->savedata.command = savedata->command;
@ -451,6 +488,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
void _flashErase(struct GBASavedata* savedata) {
GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
savedata->dirty |= SAVEDATA_DIRT_NEW;
size_t size = SIZE_CART_FLASH512;
if (savedata->type == SAVEDATA_FLASH1M) {
size = SIZE_CART_FLASH1M;
@ -460,6 +498,7 @@ void _flashErase(struct GBASavedata* savedata) {
void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
savedata->dirty |= SAVEDATA_DIRT_NEW;
size_t size = 0x1000;
if (savedata->type == SAVEDATA_FLASH1M) {
GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);

View File

@ -51,6 +51,11 @@ enum FlashManufacturer {
FLASH_MFG_SANYO = 0x1362
};
enum SavedataDirty {
SAVEDATA_DIRT_NEW = 1,
SAVEDATA_DIRT_SEEN = 2
};
enum {
SAVEDATA_FLASH_BASE = 0x0E005555,
@ -77,6 +82,9 @@ struct GBASavedata {
unsigned settling;
int dust;
enum SavedataDirty dirty;
uint32_t dirtAge;
enum FlashStateMachine flashState;
};
@ -98,6 +106,8 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata);
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize);
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount);
struct GBASerializedState;
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData);
void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData);