mirror of https://github.com/mgba-emu/mgba.git
GBA: Savedata is now synced shortly after data finishes being written
This commit is contained in:
parent
250d3b940d
commit
4b3df31e49
1
CHANGES
1
CHANGES
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue