GB: Restore savestates

This commit is contained in:
Jeffrey Pfau 2016-12-19 19:40:16 -08:00
parent 9aa6d8fe3c
commit 0bf0975a5d
8 changed files with 122 additions and 31 deletions

View File

@ -54,6 +54,19 @@ void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent* event) {
} }
} }
bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent* event) {
struct mTimingEvent* const* previous = &timing->root;
const struct mTimingEvent* next = timing->root;
while (next) {
if (next == event) {
return true;
}
previous = &next->next;
next = next->next;
}
return false;
}
int32_t mTimingTick(struct mTiming* timing, int32_t cycles) { int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
timing->masterCycles += cycles; timing->masterCycles += cycles;
uint32_t masterCycles = timing->masterCycles; uint32_t masterCycles = timing->masterCycles;
@ -69,7 +82,7 @@ int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
return *timing->nextEvent; return *timing->nextEvent;
} }
int32_t mTimingCurrentTime(struct mTiming* timing) { int32_t mTimingCurrentTime(const struct mTiming* timing) {
return timing->masterCycles + *timing->relativeCycles; return timing->masterCycles + *timing->relativeCycles;
} }

View File

@ -32,8 +32,9 @@ void mTimingDeinit(struct mTiming* timing);
void mTimingClear(struct mTiming* timing); void mTimingClear(struct mTiming* timing);
void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when); void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when);
void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*); void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*);
bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*);
int32_t mTimingTick(struct mTiming* timing, int32_t cycles); int32_t mTimingTick(struct mTiming* timing, int32_t cycles);
int32_t mTimingCurrentTime(struct mTiming* timing); int32_t mTimingCurrentTime(const struct mTiming* timing);
int32_t mTimingNextEvent(struct mTiming* timing); int32_t mTimingNextEvent(struct mTiming* timing);
#endif #endif

View File

@ -592,6 +592,9 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
state->memory.dmaRemaining = memory->dmaRemaining; state->memory.dmaRemaining = memory->dmaRemaining;
memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs)); memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs));
STORE_32LE(memory->dmaEvent.when - mTimingCurrentTime(&gb->timing), 0, &state->memory.dmaNext);
STORE_32LE(memory->hdmaEvent.when - mTimingCurrentTime(&gb->timing), 0, &state->memory.hdmaNext);
GBSerializedMemoryFlags flags = 0; GBSerializedMemoryFlags flags = 0;
flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess); flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess);
flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess); flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess);
@ -624,6 +627,18 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
memory->dmaRemaining = state->memory.dmaRemaining; memory->dmaRemaining = state->memory.dmaRemaining;
memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs)); memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs));
uint32_t when;
LOAD_32LE(when, 0, &state->memory.dmaNext);
mTimingDeschedule(&gb->timing, &memory->dmaEvent);
if (memory->dmaRemaining) {
mTimingSchedule(&gb->timing, &memory->dmaEvent, when);
}
LOAD_32LE(when, 0, &state->memory.hdmaNext);
mTimingDeschedule(&gb->timing, &memory->hdmaEvent);
if (memory->hdmaRemaining) {
mTimingSchedule(&gb->timing, &memory->hdmaEvent, when);
}
GBSerializedMemoryFlags flags; GBSerializedMemoryFlags flags;
LOAD_16LE(flags, 0, &state->memory.flags); LOAD_16LE(flags, 0, &state->memory.flags);
memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags); memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags);

View File

@ -17,11 +17,12 @@ mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate");
#endif #endif
const uint32_t GB_SAVESTATE_MAGIC = 0x00400000; const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
const uint32_t GB_SAVESTATE_VERSION = 0x00000000; const uint32_t GB_SAVESTATE_VERSION = 0x00000001;
void GBSerialize(struct GB* gb, struct GBSerializedState* state) { void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
STORE_32LE(gb->romCrc32, 0, &state->romCrc32); STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
if (gb->memory.rom) { if (gb->memory.rom) {
memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title)); memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title));
@ -54,7 +55,9 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending); flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed); flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
STORE_32LE(flags, 0, &state->cpu.flags); STORE_32LE(flags, 0, &state->cpu.flags);
STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
GBMemorySerialize(gb, state); GBMemorySerialize(gb, state);
GBIOSerialize(gb, state); GBIOSerialize(gb, state);
@ -120,11 +123,6 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high"); mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
error = true; error = true;
} }
LOAD_32LE(check, 0, &state->video.eventDiff);
if (check < 0) {
mLOG(GB_STATE, WARN, "Savestate is corrupted: video eventDiff is negative");
error = true;
}
LOAD_16LE(check16, 0, &state->video.x); LOAD_16LE(check16, 0, &state->video.x);
if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) { if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range"); mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
@ -175,8 +173,16 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags); gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
gb->audio.timingFactor = gb->doubleSpeed + 1; gb->audio.timingFactor = gb->doubleSpeed + 1;
uint32_t when;
LOAD_32LE(when, 0, &state->cpu.eiPending);
mTimingDeschedule(&gb->timing, &gb->eiPending);
if (GBSerializedCpuFlagsIsEiPending(flags)) {
mTimingSchedule(&gb->timing, &gb->eiPending, when);
}
LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
gb->model = state->model; gb->model = state->model;

View File

@ -20,7 +20,8 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* 0x00000 - 0x00003: Version Magic (0x01000001) * 0x00000 - 0x00003: Version Magic (0x01000001)
* 0x00004 - 0x00007: ROM CRC32 * 0x00004 - 0x00007: ROM CRC32
* 0x00008: Game Boy model * 0x00008: Game Boy model
* 0x00009 - 0x0000F: Reserved (leave zero) * 0x00009 - 0x0000B: Reserved (leave zero)
* 0x0000C - 0x0000F: Master cycles
* 0x00010 - 0x0001F: Game title/code (e.g. PM_CRYSTALBYTE) * 0x00010 - 0x0001F: Game title/code (e.g. PM_CRYSTALBYTE)
* 0x00020 - 0x00047: CPU state: * 0x00020 - 0x00047: CPU state:
* | 0x00020: A register * | 0x00020: A register
@ -46,7 +47,8 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | bit 0: Is condition met? * | bit 0: Is condition met?
* | bit 1: Is condition IRQ pending? * | bit 1: Is condition IRQ pending?
* | bit 2: Double speed * | bit 2: Double speed
* | bits 3 - 31: Reserved * | bit 3: Is EI pending?
* | bits 4 - 31: Reserved
* 0x00048 - 0x0005B: Audio channel 1/framer state * 0x00048 - 0x0005B: Audio channel 1/framer state
* | 0x00048 - 0x0004B: Envelepe timing * | 0x00048 - 0x0004B: Envelepe timing
* | bits 0 - 6: Remaining length * | bits 0 - 6: Remaining length
@ -99,14 +101,13 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | bit 5: Has channel 1 sweep occurred? * | bit 5: Has channel 1 sweep occurred?
* | bit 6: Is channel 3's memory readable? * | bit 6: Is channel 3's memory readable?
* | bit 7: Reserved * | bit 7: Reserved
* | 0x000A8 - 0x000AB: Next event * | 0x000A8 - 0x000AF: Rserved
* | 0x000AC - 0x000AF: Event diff
* | 0x000B0 - 0x000B3: Next sample * | 0x000B0 - 0x000B3: Next sample
* 0x000B4 - 0x000153: Video state * 0x000B4 - 0x000153: Video state
* | 0x000B4 - 0x000B5: Current x * | 0x000B4 - 0x000B5: Current x
* | 0x000B6 - 0x000B7: Current y (ly) * | 0x000B6 - 0x000B7: Current y (ly)
* | 0x000B8 - 0x000BB: Next event * | 0x000B8 - 0x000BB: Next frame
* | 0x000BC - 0x000BF: Event diff * | 0x000BC - 0x000BF: Reserved
* | 0x000C0 - 0x000C3: Next mode * | 0x000C0 - 0x000C3: Next mode
* | 0x000C4 - 0x000C7: Dot cycle counter * | 0x000C4 - 0x000C7: Dot cycle counter
* | 0x000C8 - 0x000CB: Frame counter * | 0x000C8 - 0x000CB: Frame counter
@ -122,7 +123,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | 0x000D4 - 0x00153: Palette entries * | 0x000D4 - 0x00153: Palette entries
* 0x00154 - 0x000167: Timer state * 0x00154 - 0x000167: Timer state
* | 0x00154 - 0x00157: Next event * | 0x00154 - 0x00157: Next event
* | 0x00158 - 0x0015B: Event diff * | 0x00158 - 0x0015B: Next IRQ
* | 0x0015C - 0x0015F: Next DIV * | 0x0015C - 0x0015F: Next DIV
* | 0x00160 - 0x00163: Inernal DIV * | 0x00160 - 0x00163: Inernal DIV
* | 0x00164: TIMA period * | 0x00164: TIMA period
@ -187,7 +188,7 @@ struct GBSerializedPSGState {
int32_t nextFrame; int32_t nextFrame;
int32_t nextCh3Fade; int32_t nextCh3Fade;
int32_t reserved; int32_t reserved;
int32_t nextEvent; uint32_t nextEvent;
} ch1; } ch1;
struct { struct {
GBSerializedAudioEnvelope envelope; GBSerializedAudioEnvelope envelope;
@ -198,13 +199,13 @@ struct GBSerializedPSGState {
uint32_t wavebanks[8]; uint32_t wavebanks[8];
int16_t length; int16_t length;
int16_t reserved; int16_t reserved;
int32_t nextEvent; uint32_t nextEvent;
} ch3; } ch3;
struct { struct {
int32_t lfsr; int32_t lfsr;
GBSerializedAudioEnvelope envelope; GBSerializedAudioEnvelope envelope;
int32_t reserved; int32_t reserved;
int32_t nextEvent; uint32_t nextEvent;
} ch4; } ch4;
}; };
@ -212,6 +213,7 @@ DECL_BITFIELD(GBSerializedCpuFlags, uint32_t);
DECL_BIT(GBSerializedCpuFlags, Condition, 0); DECL_BIT(GBSerializedCpuFlags, Condition, 0);
DECL_BIT(GBSerializedCpuFlags, IrqPending, 1); DECL_BIT(GBSerializedCpuFlags, IrqPending, 1);
DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2); DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2);
DECL_BIT(GBSerializedCpuFlags, EiPending, 1);
DECL_BITFIELD(GBSerializedTimerFlags, uint8_t); DECL_BITFIELD(GBSerializedTimerFlags, uint8_t);
DECL_BIT(GBSerializedTimerFlags, IrqPending, 0); DECL_BIT(GBSerializedTimerFlags, IrqPending, 0);
@ -220,6 +222,8 @@ DECL_BITFIELD(GBSerializedVideoFlags, uint8_t);
DECL_BIT(GBSerializedVideoFlags, BcpIncrement, 0); DECL_BIT(GBSerializedVideoFlags, BcpIncrement, 0);
DECL_BIT(GBSerializedVideoFlags, OcpIncrement, 1); DECL_BIT(GBSerializedVideoFlags, OcpIncrement, 1);
DECL_BITS(GBSerializedVideoFlags, Mode, 2, 2); DECL_BITS(GBSerializedVideoFlags, Mode, 2, 2);
DECL_BIT(GBSerializedVideoFlags, NotModeEventScheduled, 4);
DECL_BIT(GBSerializedVideoFlags, NotFrameEventScheduled, 5);
DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t); DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t);
DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2); DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2);
@ -238,7 +242,8 @@ struct GBSerializedState {
uint32_t versionMagic; uint32_t versionMagic;
uint32_t romCrc32; uint32_t romCrc32;
uint8_t model; uint8_t model;
uint8_t reservedHeader[7]; uint8_t reservedHeader[3];
uint32_t masterCycles;
char title[16]; char title[16];
@ -264,7 +269,7 @@ struct GBSerializedState {
uint16_t irqVector; uint16_t irqVector;
int32_t eiPending; uint32_t eiPending;
int32_t reservedDiPending; int32_t reservedDiPending;
GBSerializedCpuFlags flags; GBSerializedCpuFlags flags;
} cpu; } cpu;
@ -273,21 +278,21 @@ struct GBSerializedState {
struct GBSerializedPSGState psg; struct GBSerializedPSGState psg;
GBSerializedAudioFlags flags; GBSerializedAudioFlags flags;
int32_t reserved[2]; int32_t reserved[2];
int32_t nextSample; uint32_t nextSample;
} audio; } audio;
struct { struct {
int16_t x; int16_t x;
int16_t ly; int16_t ly;
int32_t nextEvent; uint32_t nextFrame;
int32_t eventDiff; uint32_t reserved;
int32_t nextMode; uint32_t nextMode;
int32_t dotCounter; int32_t dotCounter;
int32_t frameCounter; int32_t frameCounter;
uint8_t vramCurrentBank; uint8_t vramCurrentBank;
GBSerializedVideoFlags flags; GBSerializedVideoFlags flags;
uint16_t reserved; uint16_t reserved2;
uint16_t bcpIndex; uint16_t bcpIndex;
uint16_t ocpIndex; uint16_t ocpIndex;
@ -296,10 +301,10 @@ struct GBSerializedState {
} video; } video;
struct { struct {
int32_t nextEvent; uint32_t nextEvent;
int32_t eventDiff; uint32_t nextIRQ;
int32_t nextDiv; uint32_t nextDiv;
uint32_t internalDiv; uint32_t internalDiv;
uint8_t timaPeriod; uint8_t timaPeriod;
GBSerializedTimerFlags flags; GBSerializedTimerFlags flags;
@ -311,11 +316,11 @@ struct GBSerializedState {
uint8_t wramCurrentBank; uint8_t wramCurrentBank;
uint8_t sramCurrentBank; uint8_t sramCurrentBank;
int32_t dmaNext; uint32_t dmaNext;
uint16_t dmaSource; uint16_t dmaSource;
uint16_t dmaDest; uint16_t dmaDest;
int32_t hdmaNext; uint32_t hdmaNext;
uint16_t hdmaSource; uint16_t hdmaSource;
uint16_t hdmaDest; uint16_t hdmaDest;

View File

@ -96,10 +96,28 @@ void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* sta
STORE_32LE(timer->nextDiv, 0, &state->timer.nextDiv); STORE_32LE(timer->nextDiv, 0, &state->timer.nextDiv);
STORE_32LE(timer->internalDiv, 0, &state->timer.internalDiv); STORE_32LE(timer->internalDiv, 0, &state->timer.internalDiv);
STORE_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod); STORE_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod);
STORE_32LE(timer->event.when - mTimingCurrentTime(&timer->p->timing), 0, &state->timer.nextEvent);
STORE_32LE(timer->irq.when - mTimingCurrentTime(&timer->p->timing), 0, &state->timer.nextIRQ);
GBSerializedTimerFlags flags = GBSerializedTimerFlagsSetIrqPending(0, mTimingIsScheduled(&timer->p->timing, &timer->irq));
STORE_32LE(flags, 0, &state->timer.flags);
} }
void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state) { void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state) {
LOAD_32LE(timer->nextDiv, 0, &state->timer.nextDiv); LOAD_32LE(timer->nextDiv, 0, &state->timer.nextDiv);
LOAD_32LE(timer->internalDiv, 0, &state->timer.internalDiv); LOAD_32LE(timer->internalDiv, 0, &state->timer.internalDiv);
LOAD_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod); LOAD_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod);
uint32_t when;
LOAD_32LE(when, 0, &state->timer.nextEvent);
mTimingDeschedule(&timer->p->timing, &timer->event);
mTimingSchedule(&timer->p->timing, &timer->event, when);
GBSerializedTimerFlags flags;
LOAD_32LE(flags, 0, &state->timer.flags);
mTimingDeschedule(&timer->p->timing, &timer->irq);
if (GBSerializedTimerFlagsIsIrqPending(flags)) {
LOAD_32LE(when, 0, &state->timer.nextIRQ);
mTimingSchedule(&timer->p->timing, &timer->irq, when);
}
} }

View File

@ -315,6 +315,7 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
mTimingDeschedule(&video->p->timing, &video->frameEvent); mTimingDeschedule(&video->p->timing, &video->frameEvent);
} }
if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) { if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) {
// TODO: Fix serialization; this gets internal and visible modes out of sync
video->stat = GBRegisterSTATSetMode(video->stat, 0); video->stat = GBRegisterSTATSetMode(video->stat, 0);
video->p->memory.io[REG_STAT] = video->stat; video->p->memory.io[REG_STAT] = video->stat;
video->ly = 0; video->ly = 0;
@ -498,6 +499,8 @@ void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* sta
flags = GBSerializedVideoFlagsSetBcpIncrement(flags, video->bcpIncrement); flags = GBSerializedVideoFlagsSetBcpIncrement(flags, video->bcpIncrement);
flags = GBSerializedVideoFlagsSetOcpIncrement(flags, video->ocpIncrement); flags = GBSerializedVideoFlagsSetOcpIncrement(flags, video->ocpIncrement);
flags = GBSerializedVideoFlagsSetMode(flags, video->mode); flags = GBSerializedVideoFlagsSetMode(flags, video->mode);
flags = GBSerializedVideoFlagsSetNotModeEventScheduled(flags, !mTimingIsScheduled(&video->p->timing, &video->modeEvent));
flags = GBSerializedVideoFlagsSetNotFrameEventScheduled(flags, !mTimingIsScheduled(&video->p->timing, &video->frameEvent));
state->video.flags = flags; state->video.flags = flags;
STORE_16LE(video->bcpIndex, 0, &state->video.bcpIndex); STORE_16LE(video->bcpIndex, 0, &state->video.bcpIndex);
STORE_16LE(video->ocpIndex, 0, &state->video.ocpIndex); STORE_16LE(video->ocpIndex, 0, &state->video.ocpIndex);
@ -507,6 +510,9 @@ void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* sta
STORE_16LE(video->palette[i], i * 2, state->video.palette); STORE_16LE(video->palette[i], i * 2, state->video.palette);
} }
STORE_32LE(video->modeEvent.when - mTimingCurrentTime(&video->p->timing), 0, &state->video.nextMode);
STORE_32LE(video->frameEvent.when - mTimingCurrentTime(&video->p->timing), 0, &state->video.nextFrame);
memcpy(state->vram, video->vram, GB_SIZE_VRAM); memcpy(state->vram, video->vram, GB_SIZE_VRAM);
memcpy(state->oam, &video->oam.raw, GB_SIZE_OAM); memcpy(state->oam, &video->oam.raw, GB_SIZE_OAM);
} }
@ -526,6 +532,33 @@ void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* s
LOAD_16LE(video->ocpIndex, 0, &state->video.ocpIndex); LOAD_16LE(video->ocpIndex, 0, &state->video.ocpIndex);
video->ocpIndex &= 0x3F; video->ocpIndex &= 0x3F;
switch (video->mode) {
case 0:
video->modeEvent.callback = _endMode0;
break;
case 1:
video->modeEvent.callback = _endMode1;
break;
case 2:
video->modeEvent.callback = _endMode2;
break;
case 3:
video->modeEvent.callback = _endMode3;
break;
}
uint32_t when;
mTimingDeschedule(&video->p->timing, &video->modeEvent);
if (!GBSerializedVideoFlagsIsNotModeEventScheduled(flags)) {
LOAD_32LE(when, 0, &state->video.nextMode);
mTimingSchedule(&video->p->timing, &video->modeEvent, when);
}
mTimingDeschedule(&video->p->timing, &video->frameEvent);
if (!GBSerializedVideoFlagsIsNotFrameEventScheduled(flags)) {
LOAD_32LE(when, 0, &state->video.nextFrame);
mTimingSchedule(&video->p->timing, &video->frameEvent, when);
}
size_t i; size_t i;
for (i = 0; i < 64; ++i) { for (i = 0; i < 64; ++i) {
LOAD_16LE(video->palette[i], i * 2, state->video.palette); LOAD_16LE(video->palette[i], i * 2, state->video.palette);

View File

@ -21,7 +21,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* 0x00000 - 0x00003: Version Magic (0x01000001) * 0x00000 - 0x00003: Version Magic (0x01000001)
* 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS) * 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS)
* 0x00008 - 0x0000B: ROM CRC32 * 0x00008 - 0x0000B: ROM CRC32
* 0x0000C - 0x0000F: Reserved (leave zero) * 0x0000C - 0x0000F: Master cycles
* 0x00010 - 0x0001B: Game title (e.g. METROID4USA) * 0x00010 - 0x0001B: Game title (e.g. METROID4USA)
* 0x0001C - 0x0001F: Game code (e.g. AMTE) * 0x0001C - 0x0001F: Game code (e.g. AMTE)
* 0x00020 - 0x0012F: CPU state: * 0x00020 - 0x0012F: CPU state: