diff --git a/CHANGES b/CHANGES index 2fa2dae34..c6fd570bd 100644 --- a/CHANGES +++ b/CHANGES @@ -75,6 +75,7 @@ Misc: - All: Enable link-time optimization - GBA Thread: Make GBASyncWaitFrameStart time out - GBA: Move A/V stream interface into core + - GBA: Savestates now take into account savedata state machines (fixes #109) 0.1.1: (2015-01-24) Bugfixes: diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 00acf2648..bc9a34851 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -6,6 +6,7 @@ #include "savedata.h" #include "gba/gba.h" +#include "gba/serialize.h" #include "util/memory.h" #include "util/vfs.h" @@ -375,6 +376,37 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) { return 0; } +void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) { + state->savedata.type = savedata->type; + state->savedata.command = savedata->command; + state->savedata.flashState = savedata->flashState; + state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000]; + state->savedata.readBitsRemaining = savedata->readBitsRemaining; + state->savedata.readAddress = savedata->readAddress; + state->savedata.writeAddress = savedata->writeAddress; + + UNUSED(includeData); // TODO +} + +void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData) { + if (state->savedata.type == SAVEDATA_FORCE_NONE) { + return; + } + if (savedata->type != state->savedata.type) { + GBASavedataForceType(savedata, state->savedata.type); + } + savedata->command = state->savedata.command; + savedata->flashState = state->savedata.flashState; + savedata->readBitsRemaining = state->savedata.readBitsRemaining; + savedata->readAddress = state->savedata.readAddress; + savedata->writeAddress = state->savedata.writeAddress; + if (savedata->type == SAVEDATA_FLASH1M) { + _flashSwitchBank(savedata, state->savedata.flashBank); + } + + UNUSED(includeData); // TODO +} + void _flashSwitchBank(struct GBASavedata* savedata, int bank) { GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank); savedata->currentBank = &savedata->data[bank << 16]; diff --git a/src/gba/savedata.h b/src/gba/savedata.h index 42aad655a..d1614283a 100644 --- a/src/gba/savedata.h +++ b/src/gba/savedata.h @@ -13,10 +13,10 @@ struct VFile; enum SavedataType { SAVEDATA_AUTODETECT = -1, SAVEDATA_FORCE_NONE = 0, - SAVEDATA_SRAM, - SAVEDATA_FLASH512, - SAVEDATA_FLASH1M, - SAVEDATA_EEPROM + SAVEDATA_SRAM = 1, + SAVEDATA_FLASH512 = 2, + SAVEDATA_FLASH1M = 3, + SAVEDATA_EEPROM = 4 }; enum SavedataCommand { @@ -42,8 +42,8 @@ enum SavedataCommand { enum FlashStateMachine { FLASH_STATE_RAW = 0, - FLASH_STATE_START, - FLASH_STATE_CONTINUE + FLASH_STATE_START = 1, + FLASH_STATE_CONTINUE = 2, }; enum FlashManufacturer { @@ -67,9 +67,9 @@ struct GBASavedata { int mapMode; struct VFile* realVf; - int readBitsRemaining; - int readAddress; - int writeAddress; + int32_t readBitsRemaining; + uint32_t readAddress; + uint32_t writeAddress; uint8_t* currentBank; @@ -94,4 +94,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); +struct GBASerializedState; +void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData); +void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData); + #endif diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 5b0d8e868..2395ee635 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -48,6 +48,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { GBAIOSerialize(gba, state); GBAVideoSerialize(&gba->video, state); GBAAudioSerialize(&gba->audio, state); + GBASavedataSerialize(&gba->memory.savedata, state, false); state->associatedStreamId = 0; if (gba->rr) { @@ -111,6 +112,7 @@ void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { GBAIODeserialize(gba, state); GBAVideoDeserialize(&gba->video, state); GBAAudioDeserialize(&gba->audio, state); + GBASavedataDeserialize(&gba->memory.savedata, state, false); if (gba->rr) { gba->rr->stateLoaded(gba->rr, state); diff --git a/src/gba/serialize.h b/src/gba/serialize.h index 50c0f717c..5a2d9a34b 100644 --- a/src/gba/serialize.h +++ b/src/gba/serialize.h @@ -129,7 +129,7 @@ extern const uint32_t GBA_SAVESTATE_MAGIC; * 0x00290 - 0x002C3: GPIO state * | 0x00290 - 0x00291: Pin state * | 0x00292 - 0x00293: Direction state - * | 0x00294 - 0x002B6: RTC state (see gba-hardware.h for format) + * | 0x00294 - 0x002B6: RTC state (see hardware.h for format) * | 0x002B7 - 0x002B7: GPIO devices * | bit 0: Has RTC values * | bit 1: Has rumble value (reserved) @@ -150,7 +150,20 @@ extern const uint32_t GBA_SAVESTATE_MAGIC; * | 0x002C1 - 0x002C3: Flags * | bits 0 - 1: Tilt state machine * | bits 2 - 31: Reserved - * 0x002C4 - 0x002F3: Reserved (leave zero) + * 0x002C4 - 0x002DF: Reserved (leave zero) + * 0x002E0 - 0x002EF: Savedata state + * | 0x002E0 - 0x002E0: Savedata type + * | 0x002E1 - 0x002E1: Savedata command (see savedata.h) + * | 0x002E2 - 0x002E2: Flags + * | bits 0 - 1: Flash state machine + * | bits 2 - 3: Reserved + * | bit 4: Flash bank + * | bits 5 - 7: Reserved + * | 0x002E3 - 0x002E3: Reserved + * | 0x002E4 - 0x002E7: EEPROM read bits remaining + * | 0x002E8 - 0x002EB: EEPROM read address + * | 0x002EC - 0x002EBF EEPROM write address + * 0x002F0 - 0x002F3: Reserved (leave zero) * 0x002F4 - 0x002FF: Prefetch * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch * | 0x002F8 - 0x002FB: CPU prefecth (decode slot) @@ -271,7 +284,22 @@ struct GBASerializedState { unsigned : 22; } hw; - uint32_t reservedHardware[12]; + uint32_t reservedHardware[7]; + + struct { + unsigned type : 8; + unsigned command : 8; + unsigned flashState : 2; + unsigned : 2; + unsigned flashBank : 1; + unsigned : 3; + unsigned : 8; + int32_t readBitsRemaining; + uint32_t readAddress; + uint32_t writeAddress; + } savedata; + + uint32_t reservedPadding; uint32_t biosPrefetch; uint32_t cpuPrefetch[2];