GB: Polish savestates a bit
@@ -952,12 +952,14 @@ STORE_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining);
state->memory.dmaRemaining = memory->dmaRemaining; memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs)); - state->memory.sramAccess = memory->sramAccess; - state->memory.rtcAccess = memory->rtcAccess; - state->memory.rtcLatched = memory->rtcLatched; - state->memory.ime = memory->ime; - state->memory.isHdma = memory->isHdma; - state->memory.activeRtcReg = memory->activeRtcReg; + GBSerializedMemoryFlags flags = 0; + flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess); + flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess); + flags = GBSerializedMemoryFlagsSetRtcLatched(flags, memory->rtcLatched); + flags = GBSerializedMemoryFlagsSetIme(flags, memory->ime); + flags = GBSerializedMemoryFlagsSetIsHdma(flags, memory->isHdma); + flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg); + STORE_16LE(flags, 0, &state->memory.flags); } void GBMemoryDeserialize(struct GBMemory* memory, const struct GBSerializedState* state) {@@ -983,12 +985,14 @@ LOAD_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining);
memory->dmaRemaining = state->memory.dmaRemaining; memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs)); - memory->sramAccess = state->memory.sramAccess; - memory->rtcAccess = state->memory.rtcAccess; - memory->rtcLatched = state->memory.rtcLatched; - memory->ime = state->memory.ime; - memory->isHdma = state->memory.isHdma; - memory->activeRtcReg = state->memory.activeRtcReg; + GBSerializedMemoryFlags flags; + LOAD_16LE(flags, 0, &state->memory.flags); + memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags); + memory->rtcAccess = GBSerializedMemoryFlagsGetRtcAccess(flags); + memory->rtcLatched = GBSerializedMemoryFlagsGetRtcLatched(flags); + memory->ime = GBSerializedMemoryFlagsGetIme(flags); + memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags); + memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags); } void _pristineCow(struct GB* gb) {
@@ -5,6 +5,9 @@ * 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/. */ #include "serialize.h" +#include "gb/io.h" +#include "gb/timer.h" + mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate"); #ifdef _MSC_VER@@ -47,10 +50,13 @@ state->cpu.bus = gb->cpu->bus;
state->cpu.executionState = gb->cpu->executionState; STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); - state->cpu.condition = gb->cpu->condition; - state->cpu.irqPending = gb->cpu->irqPending; + STORE_32LE(gb->eiPending, 0, &state->cpu.eiPending); - state->cpu.doubleSpeed = gb->doubleSpeed; + GBSerializedCpuFlags flags = 0; + flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); + flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending); + flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed); + STORE_32LE(flags, 0, &state->cpu.flags); GBMemorySerialize(&gb->memory, state); GBIOSerialize(gb, state);@@ -135,10 +141,13 @@ gb->cpu->bus = state->cpu.bus;
gb->cpu->executionState = state->cpu.executionState; LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); - gb->cpu->condition = state->cpu.condition; - gb->cpu->irqPending = state->cpu.irqPending; + LOAD_32LE(gb->eiPending, 0, &state->cpu.eiPending); - gb->doubleSpeed = state->cpu.doubleSpeed; + GBSerializedCpuFlags flags; + LOAD_32LE(flags, 0, &state->cpu.flags); + gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags); + gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags); + gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags); LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
@@ -42,7 +42,11 @@ * | 0x00039: Execution state
* | 0x0003A - 0x0003B: IRQ vector * | 0x0003C - 0x0003F: EI pending cycles * | 0x00040 - 0x00043: Reserved (DI pending cycles) - * | 0x00044 - 0x00048: Flags + * | 0x00044 - 0x00047: Flags + * | bit 0: Is condition met? + * | bit 1: Is condition IRQ pending? + * | bit 2: Double speed + * | bits 3 - 31: Reserved * 0x00048 - 0x0005B: Audio channel 1/framer state * | 0x00048 - 0x0004B: Envelepe timing * | bits 0 - 6: Remaining length@@ -96,6 +100,60 @@ * | bits 6 - 7: Reserved
* | 0x000A8 - 0x000AB: Next event * | 0x000AC - 0x000AF: Event diff * | 0x000B0 - 0x000B3: Next sample + * 0x000B4 - 0x000153: Video state + * | 0x000B4 - 0x000B5: Current x + * | 0x000B6 - 0x000B7: Current y (ly) + * | 0x000B8 - 0x000BB: Next event + * | 0x000BC - 0x000BF: Event diff + * | 0x000C0 - 0x000C3: Next mode + * | 0x000C4 - 0x000C7: Dot cycle counter + * | 0x000C8 - 0x000CB: Frame counter + * | 0x000CC: Current VRAM bank + * | 0x000CD: Palette flags + * | bit 0: BCP increment + * | bit 1: OCP increment + * | bits 2 - 7: Reserved + * | 0x000CE - 0x000CF: Reserved + * | 0x000D0 - 0x000D1: BCP index + * | 0x000D1 - 0x000D3: OCP index + * | 0x000D4 - 0x00153: Palette entries + * 0x00154 - 0x000167: Timer state + * | 0x00154 - 0x00157: Next event + * | 0x00158 - 0x0015B: Event diff + * | 0x0015C - 0x0015F: Next DIV + * | 0x00160 - 0x00163: Next TIMA + * | 0x00164 - 0x00167: TIMA period + * 0x000168 - 0x000197: Memory state + * | 0x00168 - 0x00169: Current ROM bank + * | 0x0016A: Current WRAM bank + * | 0x0016B: Current SRAM bank + * | 0x0016C - 0x0016F: Next DMA + * | 0x00170 - 0x00171: Next DMA source + * | 0x00172 - 0x00173: Next DMA destination + * | 0x00174 - 0x00177: Next HDMA + * | 0x00178 - 0x00179: Next HDMA source + * | 0x0017A - 0x0017B: Next HDMA destination + * | 0x0017C - 0x0017D: HDMA remaining + * | 0x0017E: DMA remaining + * | 0x0017F - 0x00183: RTC registers + * | 0x00184 - 0x00193: MBC state (TODO) + * | 0x00194 - 0x00195: Flags + * | bit 0: SRAM accessable + * | bit 1: RTC accessible + * | bit 2: RTC latched + * | bit 3: IME + * | bit 4: Is HDMA active? + * | bits 5 - 7: Active RTC register + * | 0x00196 - 0x00197: Reserved (leave zero) + * 0x00198 - 0x0019F: Savestate creation time (usec since 1970) + * 0x001A0 - 0x0025F: Reserved (leave zero) + * 0x00260 - 0x002FF: OAM + * 0x00300 - 0x0037F: I/O memory + * 0x00380 - 0x003FE: HRAM + * 0x003FF: Interrupts enabled + * 0x00400 - 0x043FF: VRAM + * 0x04400 - 0x0C3FF: WRAM + * Total size: 0xC400 (50,176) bytes */ DECL_BITFIELD(GBSerializedAudioFlags, uint32_t);@@ -142,6 +200,28 @@ int32_t nextEvent;
} ch4; }; +DECL_BITFIELD(GBSerializedCpuFlags, uint32_t); +DECL_BIT(GBSerializedCpuFlags, Condition, 0); +DECL_BIT(GBSerializedCpuFlags, IrqPending, 1); +DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2); + + +DECL_BITFIELD(GBSerializedVideoFlags, uint8_t); +DECL_BIT(GBSerializedVideoFlags, BcpIncrement, 0); +DECL_BIT(GBSerializedVideoFlags, OcpIncrement, 1); + +DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t); +DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2); +DECL_BIT(GBSerializedMBC7Flags, Writable, 2); + +DECL_BITFIELD(GBSerializedMemoryFlags, uint16_t); +DECL_BIT(GBSerializedMemoryFlags, SramAccess, 0); +DECL_BIT(GBSerializedMemoryFlags, RtcAccess, 1); +DECL_BIT(GBSerializedMemoryFlags, RtcLatched, 2); +DECL_BIT(GBSerializedMemoryFlags, Ime, 3); +DECL_BIT(GBSerializedMemoryFlags, IsHdma, 4); +DECL_BITS(GBSerializedMemoryFlags, ActiveRtcReg, 5, 3); + #pragma pack(push, 1) struct GBSerializedState { uint32_t versionMagic;@@ -175,9 +255,7 @@ uint16_t irqVector;
int32_t eiPending; int32_t reservedDiPending; - bool condition : 1; - bool irqPending : 1; - bool doubleSpeed : 1; + GBSerializedCpuFlags flags; } cpu; struct {@@ -198,9 +276,9 @@ int32_t dotCounter;
int32_t frameCounter; uint8_t vramCurrentBank; + GBSerializedVideoFlags flags; + uint16_t reserved; - bool bcpIncrement : 1; - bool ocpIncrement : 1; uint16_t bcpIndex; uint16_t ocpIndex;@@ -243,29 +321,27 @@ GBMBC7Field field;
int8_t address; uint8_t srBits; uint32_t sr; - uint8_t command : 2; - bool writable : 1; + GBSerializedMBC7Flags flags; } mbc7; struct { uint8_t reserved[16]; } padding; }; - bool sramAccess : 1; - bool rtcAccess : 1; - bool rtcLatched : 1; - bool ime : 1; - bool isHdma : 1; - uint8_t activeRtcReg : 5; + GBSerializedMemoryFlags flags; + uint16_t reserved; } memory; + uint64_t creationUsec; + + uint32_t reserved[48]; + + uint8_t oam[GB_SIZE_OAM]; + uint8_t io[GB_SIZE_IO]; uint8_t hram[GB_SIZE_HRAM]; uint8_t ie; - uint64_t creationUsec; - - uint8_t oam[GB_SIZE_OAM]; uint8_t vram[GB_SIZE_VRAM]; uint8_t wram[GB_SIZE_WORKING_RAM]; };
@@ -34,4 +34,8 @@ void GBTimerDivReset(struct GBTimer*);
uint8_t GBTimerUpdateTAC(struct GBTimer*, GBRegisterTAC tac); void GBTimerUpdateTIMA(struct GBTimer* timer); +struct GBSerializedState; +void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* state); +void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state); + #endif
@@ -443,8 +443,10 @@ STORE_32LE(video->dotCounter, 0, &state->video.dotCounter);
STORE_32LE(video->frameCounter, 0, &state->video.frameCounter); state->video.vramCurrentBank = video->vramCurrentBank; - state->video.bcpIncrement = video->bcpIncrement; - state->video.ocpIncrement = video->ocpIncrement; + GBSerializedVideoFlags flags = 0; + flags = GBSerializedVideoFlagsSetBcpIncrement(flags, video->bcpIncrement); + flags = GBSerializedVideoFlagsSetOcpIncrement(flags, video->ocpIncrement); + state->video.flags = flags; STORE_16LE(video->bcpIndex, 0, &state->video.bcpIndex); STORE_16LE(video->ocpIndex, 0, &state->video.ocpIndex);@@ -467,8 +469,9 @@ LOAD_32LE(video->dotCounter, 0, &state->video.dotCounter);
LOAD_32LE(video->frameCounter, 0, &state->video.frameCounter); video->vramCurrentBank = state->video.vramCurrentBank; - video->bcpIncrement = state->video.bcpIncrement; - video->ocpIncrement = state->video.ocpIncrement; + GBSerializedVideoFlags flags = state->video.flags; + video->bcpIncrement = GBSerializedVideoFlagsGetBcpIncrement(flags); + video->ocpIncrement = GBSerializedVideoFlagsGetOcpIncrement(flags); LOAD_16LE(video->bcpIndex, 0, &state->video.bcpIndex); LOAD_16LE(video->ocpIndex, 0, &state->video.ocpIndex);