mirror of https://github.com/mgba-emu/mgba.git
GB: More selective savegame dirt, unify logic
This commit is contained in:
parent
8564f5fef4
commit
b127178377
|
@ -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
|
|
@ -102,7 +102,7 @@ struct GB {
|
|||
struct VFile* sramRealVf;
|
||||
uint32_t sramSize;
|
||||
int sramDirty;
|
||||
int32_t sramDirtAge;
|
||||
uint32_t sramDirtAge;
|
||||
bool sramMaskWriteback;
|
||||
|
||||
int sgbBit;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
12
src/gb/gb.c
12
src/gb/gb.c
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue