GB: More selective savegame dirt, unify logic

This commit is contained in:
Vicki Pfau 2022-01-20 21:34:23 -08:00
parent 8564f5fef4
commit b127178377
9 changed files with 57 additions and 39 deletions

View File

@ -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

View File

@ -102,7 +102,7 @@ struct GB {
struct VFile* sramRealVf;
uint32_t sramSize;
int sramDirty;
int32_t sramDirtAge;
uint32_t sramDirtAge;
bool sramMaskWriteback;
int sgbBit;

View File

@ -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);

View File

@ -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;

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gb/gb.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/io.h>
#include <mgba/internal/gb/mbc.h>
#include <mgba/internal/sm83/sm83.h>
@ -17,8 +18,6 @@
#include <mgba-util/patch.h>
#include <mgba-util/vfs.h>
#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 {

View File

@ -6,9 +6,10 @@
#include <mgba/internal/gb/mbc.h>
#include <mgba/core/interface.h>
#include <mgba/internal/sm83/sm83.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/memory.h>
#include <mgba/internal/sm83/sm83.h>
#include <mgba-util/crc32.h>
#include <mgba-util/vfs.h>
@ -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;

View File

@ -6,6 +6,7 @@
#include <mgba/internal/gb/memory.h>
#include <mgba/core/interface.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/io.h>
#include <mgba/internal/gb/mbc.h>
@ -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) {
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:

View File

@ -7,6 +7,7 @@
#include <mgba/internal/arm/decoder.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/dma.h>
#include <mgba/internal/gba/io.h>
@ -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);
}

View File

@ -6,6 +6,7 @@
#include <mgba/internal/gba/savedata.h>
#include <mgba/internal/arm/macros.h>
#include <mgba/internal/defines.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/serialize.h>
@ -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);