From c213ee9bb6f91e65af778d818772e7d36971b824 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 31 May 2016 23:24:20 -0700 Subject: [PATCH] GB: Polish savestates a bit --- src/gb/memory.c | 28 +++++++----- src/gb/serialize.c | 21 ++++++--- src/gb/serialize.h | 110 ++++++++++++++++++++++++++++++++++++++------- src/gb/timer.h | 4 ++ src/gb/video.c | 11 +++-- 5 files changed, 135 insertions(+), 39 deletions(-) diff --git a/src/gb/memory.c b/src/gb/memory.c index df08311ec..54b4a6f72 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -952,12 +952,14 @@ void GBMemorySerialize(const struct GBMemory* memory, struct GBSerializedState* 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 @@ void GBMemoryDeserialize(struct GBMemory* memory, const struct GBSerializedState 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) { diff --git a/src/gb/serialize.c b/src/gb/serialize.c index 9a6c6bf03..e5985ad4e 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -5,6 +5,9 @@ * 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 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) { 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 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { 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); diff --git a/src/gb/serialize.h b/src/gb/serialize.h index 1284e0688..9be4997cc 100644 --- a/src/gb/serialize.h +++ b/src/gb/serialize.h @@ -42,7 +42,11 @@ mLOG_DECLARE_CATEGORY(GB_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 @@ mLOG_DECLARE_CATEGORY(GB_STATE); * | 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 @@ struct GBSerializedPSGState { } 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 @@ struct GBSerializedState { int32_t eiPending; int32_t reservedDiPending; - bool condition : 1; - bool irqPending : 1; - bool doubleSpeed : 1; + GBSerializedCpuFlags flags; } cpu; struct { @@ -198,9 +276,9 @@ struct GBSerializedState { 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 @@ struct GBSerializedState { 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]; }; diff --git a/src/gb/timer.h b/src/gb/timer.h index c650dad3a..84d5ea035 100644 --- a/src/gb/timer.h +++ b/src/gb/timer.h @@ -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 diff --git a/src/gb/video.c b/src/gb/video.c index d18bb14f9..47fa1c3c9 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -443,8 +443,10 @@ void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* sta 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 @@ void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* s 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);