diff --git a/include/mgba/internal/defines.h b/include/mgba/internal/defines.h new file mode 100644 index 000000000..8af603736 --- /dev/null +++ b/include/mgba/internal/defines.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_INTERNAL_DEFINES_H +#define M_INTERNAL_DEFINES_H + +#define mSAVEDATA_CLEANUP_THRESHOLD 15 + +enum { + mSAVEDATA_DIRT_NONE = 0, + mSAVEDATA_DIRT_NEW = 1, + mSAVEDATA_DIRT_SEEN = 2, +}; + +static inline bool mSavedataClean(int* dirty, uint32_t* dirtAge, uint32_t frameCount) { + if (*dirty & mSAVEDATA_DIRT_NEW) { + *dirtAge = frameCount; + *dirty &= ~mSAVEDATA_DIRT_NEW; + if (!(*dirty & mSAVEDATA_DIRT_SEEN)) { + *dirty |= mSAVEDATA_DIRT_SEEN; + } + } else if ((*dirty & mSAVEDATA_DIRT_SEEN) && frameCount - *dirtAge > mSAVEDATA_CLEANUP_THRESHOLD) { + *dirty = 0; + return true; + } + return false; +} + +#endif diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index d0e59e07e..a0196c162 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -102,7 +102,7 @@ struct GB { struct VFile* sramRealVf; uint32_t sramSize; int sramDirty; - int32_t sramDirtAge; + uint32_t sramDirtAge; bool sramMaskWriteback; int sgbBit; diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index a9dc8b7e9..29ffb6960 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -65,11 +65,6 @@ enum { GB_SIZE_MBC6_FLASH = 0x100000, }; -enum { - GB_SRAM_DIRT_NEW = 1, - GB_SRAM_DIRT_SEEN = 2 -}; - struct GBMemory; typedef void (*GBMemoryBankControllerWrite)(struct GB*, uint16_t address, uint8_t value); typedef uint8_t (*GBMemoryBankControllerRead)(struct GBMemory*, uint16_t address); diff --git a/include/mgba/internal/gba/savedata.h b/include/mgba/internal/gba/savedata.h index 395e06b7a..7f0b84c83 100644 --- a/include/mgba/internal/gba/savedata.h +++ b/include/mgba/internal/gba/savedata.h @@ -60,11 +60,6 @@ enum FlashManufacturer { FLASH_MFG_SANYO = 0x1362 }; -enum SavedataDirty { - SAVEDATA_DIRT_NEW = 1, - SAVEDATA_DIRT_SEEN = 2 -}; - enum { SAVEDATA_FLASH_BASE = 0x0E005555, @@ -92,7 +87,7 @@ struct GBASavedata { unsigned settling; struct mTimingEvent dust; - enum SavedataDirty dirty; + int dirty; uint32_t dirtAge; enum FlashStateMachine flashState; diff --git a/src/gb/gb.c b/src/gb/gb.c index b94d7f482..79a5d60b0 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include #include #include @@ -17,8 +18,6 @@ #include #include -#define CLEANUP_THRESHOLD 15 - const uint32_t CGB_SM83_FREQUENCY = 0x800000; const uint32_t SGB_SM83_FREQUENCY = 0x418B1E; @@ -233,20 +232,13 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) { if (!gb->sramVf) { return; } - if (gb->sramDirty & GB_SRAM_DIRT_NEW) { - gb->sramDirtAge = frameCount; - gb->sramDirty &= ~GB_SRAM_DIRT_NEW; - if (!(gb->sramDirty & GB_SRAM_DIRT_SEEN)) { - gb->sramDirty |= GB_SRAM_DIRT_SEEN; - } - } else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) { + if (mSavedataClean(&gb->sramDirty, &gb->sramDirtAge, frameCount)) { if (gb->sramMaskWriteback) { GBSavedataUnmask(gb); } if (gb->memory.mbcType == GB_MBC3_RTC) { GBMBCRTCWrite(gb); } - gb->sramDirty = 0; if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) { mLOG(GB_MEM, INFO, "Savedata synced"); } else { diff --git a/src/gb/mbc.c b/src/gb/mbc.c index bd8ad46f0..de6f7802d 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -6,9 +6,10 @@ #include #include -#include +#include #include #include +#include #include #include @@ -615,6 +616,7 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) { address &= 0x1FF; memory->sramBank[(address >> 1)] &= 0xF0 >> shift; memory->sramBank[(address >> 1)] |= (value & 0xF) << shift; + gb->sramDirty |= mSAVEDATA_DIRT_NEW; break; default: // TODO @@ -776,6 +778,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) { case 0x2B: if (memory->sramAccess) { memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value; + gb->sramDirty |= mSAVEDATA_DIRT_NEW; } break; case 0x2C: @@ -841,6 +844,7 @@ void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { break; case 0x5: _GBMBC7Write(&gb->memory, address, value); + gb->sramDirty |= mSAVEDATA_DIRT_NEW; break; default: // TODO @@ -1163,6 +1167,7 @@ void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value) { address &= 0x7F; if (address == 0 && value & 1) { value &= 6; // TODO: Timing + gb->sramDirty |= mSAVEDATA_DIRT_NEW; _GBPocketCamCapture(memory); } if (address < sizeof(memory->mbcState.pocketCam.registers)) { @@ -1287,6 +1292,7 @@ void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) { switch (tama5->registers[GBTAMA5_CS] >> 1) { case 0x0: // RAM write memory->sram[address] = out; + gb->sramDirty |= mSAVEDATA_DIRT_NEW; break; case 0x1: // RAM read break; diff --git a/src/gb/memory.c b/src/gb/memory.c index 0ec280aa1..175950e82 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -356,11 +357,13 @@ void GBStore8(struct SM83Core* cpu, uint16_t address, int8_t value) { if (memory->rtcAccess) { memory->rtcRegs[memory->activeRtcReg] = value; } else if (memory->sramAccess && memory->sram && memory->directSramAccess) { - memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; + if (memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] != value) { + memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; + gb->sramDirty |= mSAVEDATA_DIRT_NEW; + } } else { memory->mbcWrite(gb, address, value); } - gb->sramDirty |= GB_SRAM_DIRT_NEW; return; case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0 + 2: @@ -648,7 +651,7 @@ void GBPatch8(struct SM83Core* cpu, uint16_t address, int8_t value, int8_t* old, } else { memory->mbcWrite(gb, address, value); } - gb->sramDirty |= GB_SRAM_DIRT_NEW; + gb->sramDirty |= mSAVEDATA_DIRT_NEW; return; case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0 + 2: diff --git a/src/gba/memory.c b/src/gba/memory.c index 039e1f8f8..fddef9223 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -1075,12 +1076,12 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo } else { memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; } - memory->savedata.dirty |= SAVEDATA_DIRT_NEW; + memory->savedata.dirty |= mSAVEDATA_DIRT_NEW; } else if (memory->hw.devices & HW_TILT) { GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value); } else if (memory->savedata.type == SAVEDATA_SRAM512) { memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)] = value; - memory->savedata.dirty |= SAVEDATA_DIRT_NEW; + memory->savedata.dirty |= mSAVEDATA_DIRT_NEW; } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } diff --git a/src/gba/savedata.c b/src/gba/savedata.c index fbae0a554..182a6cc30 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -24,7 +25,6 @@ #define FLASH_PROGRAM_CYCLES 650 // This needs real testing, and is only an estimation currently #define EEPROM_SETTLE_CYCLES 115000 -#define CLEANUP_THRESHOLD 15 mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata", "gba.savedata"); @@ -379,7 +379,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->dirty |= mSAVEDATA_DIRT_NEW; savedata->currentBank[address] = value; savedata->command = FLASH_COMMAND_NONE; mTimingDeschedule(savedata->timing, &savedata->dust); @@ -511,7 +511,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->dirty |= mSAVEDATA_DIRT_NEW; savedata->data[savedata->writeAddress >> 3] = current; mTimingDeschedule(savedata->timing, &savedata->dust); mTimingSchedule(savedata->timing, &savedata->dust, EEPROM_SETTLE_CYCLES); @@ -565,15 +565,10 @@ void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) { if (!savedata->vf) { return; } - if (savedata->dirty & SAVEDATA_DIRT_NEW) { - savedata->dirtAge = frameCount; - savedata->dirty &= ~SAVEDATA_DIRT_NEW; - savedata->dirty |= SAVEDATA_DIRT_SEEN; - } else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) { + if (mSavedataClean(&savedata->dirty, &savedata->dirtAge, frameCount)) { if (savedata->maskWriteback) { GBASavedataUnmask(savedata); } - savedata->dirty = 0; if (savedata->mapMode & MAP_WRITE) { size_t size = GBASavedataSize(savedata); if (savedata->data && savedata->vf->sync(savedata->vf, savedata->data, size)) { @@ -650,7 +645,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) { void _flashErase(struct GBASavedata* savedata) { mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase"); - savedata->dirty |= SAVEDATA_DIRT_NEW; + savedata->dirty |= mSAVEDATA_DIRT_NEW; size_t size = SIZE_CART_FLASH512; if (savedata->type == SAVEDATA_FLASH1M) { size = SIZE_CART_FLASH1M; @@ -660,7 +655,7 @@ void _flashErase(struct GBASavedata* savedata) { void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) { mLOG(GBA_SAVE, DEBUG, "Performing flash sector erase at 0x%04x", sectorStart); - savedata->dirty |= SAVEDATA_DIRT_NEW; + savedata->dirty |= mSAVEDATA_DIRT_NEW; size_t size = 0x1000; if (savedata->type == SAVEDATA_FLASH1M) { mLOG(GBA_SAVE, DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);