From 9aa6d8fe3c299c0e6690b61439dff6c235df8846 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 19 Dec 2016 18:24:24 -0800 Subject: [PATCH] GBA: Restore savestates --- src/gb/audio.c | 37 +++++++++++++++++++++++++++++++++++++ src/gb/serialize.h | 3 +-- src/gba/audio.c | 6 ++++++ src/gba/io.c | 17 +++++++++++++---- src/gba/serialize.c | 9 +++------ src/gba/serialize.h | 33 ++++++++++++++------------------- src/gba/timer.c | 1 + src/gba/video.c | 13 +++++++++++++ 8 files changed, 88 insertions(+), 31 deletions(-) diff --git a/src/gb/audio.c b/src/gb/audio.c index 3fe0a73e5..547ae49da 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -891,6 +891,7 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat uint32_t ch4Flags = 0; flags = GBSerializedAudioFlagsSetFrame(flags, audio->frame); + STORE_32LE(audio->frameEvent.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextFrame); flags = GBSerializedAudioFlagsSetCh1Volume(flags, audio->ch1.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh1Dead(flags, audio->ch1.envelope.dead); @@ -901,6 +902,7 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat ch1Flags = GBSerializedAudioEnvelopeSetNextStep(ch1Flags, audio->ch1.envelope.nextStep); ch1Flags = GBSerializedAudioEnvelopeSetFrequency(ch1Flags, audio->ch1.sweep.realFrequency); STORE_32LE(ch1Flags, 0, &state->ch1.envelope); + STORE_32LE(audio->ch1Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextEvent); flags = GBSerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh2Dead(flags, audio->ch2.envelope.dead); @@ -908,9 +910,13 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat ch2Flags = GBSerializedAudioEnvelopeSetLength(ch2Flags, audio->ch2.control.length); ch2Flags = GBSerializedAudioEnvelopeSetNextStep(ch2Flags, audio->ch2.envelope.nextStep); STORE_32LE(ch2Flags, 0, &state->ch2.envelope); + STORE_32LE(audio->ch2Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch2.nextEvent); + flags = GBSerializedAudioFlagsSetCh3Readable(flags, audio->ch3.readable); memcpy(state->ch3.wavebanks, audio->ch3.wavedata32, sizeof(state->ch3.wavebanks)); STORE_16LE(audio->ch3.length, 0, &state->ch3.length); + STORE_32LE(audio->ch3Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch3.nextEvent); + STORE_32LE(audio->ch3Fade.when - mTimingCurrentTime(audio->timing), 0, &state->ch1.nextCh3Fade); flags = GBSerializedAudioFlagsSetCh4Volume(flags, audio->ch4.envelope.currentVolume); flags = GBSerializedAudioFlagsSetCh4Dead(flags, audio->ch4.envelope.dead); @@ -918,6 +924,7 @@ void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGStat ch4Flags = GBSerializedAudioEnvelopeSetLength(ch4Flags, audio->ch4.length); ch4Flags = GBSerializedAudioEnvelopeSetNextStep(ch4Flags, audio->ch4.envelope.nextStep); STORE_32LE(ch4Flags, 0, &state->ch4.envelope); + STORE_32LE(audio->ch4Event.when - mTimingCurrentTime(audio->timing), 0, &state->ch4.nextEvent); STORE_32LE(flags, 0, flagsOut); } @@ -927,6 +934,7 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt uint32_t ch1Flags = 0; uint32_t ch2Flags = 0; uint32_t ch4Flags = 0; + uint32_t when; audio->playingCh1 = !!(*audio->nr52 & 0x0001); audio->playingCh2 = !!(*audio->nr52 & 0x0002); @@ -944,6 +952,11 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch1.control.length = GBSerializedAudioEnvelopeGetLength(ch1Flags); audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags); audio->ch1.sweep.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags); + LOAD_32LE(when, 0, &state->ch1.nextEvent); + mTimingDeschedule(audio->timing, &audio->ch1Event); + if (audio->ch1.envelope.dead < 2 && audio->playingCh1) { + mTimingSchedule(audio->timing, &audio->ch1Event, when); + } LOAD_32LE(ch2Flags, 0, &state->ch2.envelope); audio->ch2.envelope.currentVolume = GBSerializedAudioFlagsGetCh2Volume(flags); @@ -951,11 +964,25 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch2.control.hi = GBSerializedAudioFlagsGetCh2Hi(flags); audio->ch2.control.length = GBSerializedAudioEnvelopeGetLength(ch2Flags); audio->ch2.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch2Flags); + LOAD_32LE(when, 0, &state->ch2.nextEvent); + mTimingDeschedule(audio->timing, &audio->ch2Event); + if (audio->ch2.envelope.dead < 2 && audio->playingCh2) { + mTimingSchedule(audio->timing, &audio->ch2Event, when); + } audio->ch3.readable = GBSerializedAudioFlagsGetCh3Readable(flags); // TODO: Big endian? memcpy(audio->ch3.wavedata32, state->ch3.wavebanks, sizeof(audio->ch3.wavedata32)); LOAD_16LE(audio->ch3.length, 0, &state->ch3.length); + LOAD_32LE(when, 0, &state->ch3.nextEvent); + mTimingDeschedule(audio->timing, &audio->ch3Event); + if (audio->playingCh3) { + mTimingSchedule(audio->timing, &audio->ch3Event, when); + } + LOAD_32LE(when, 0, &state->ch1.nextCh3Fade); + if (audio->ch3.readable && audio->style == GB_AUDIO_DMG) { + mTimingSchedule(audio->timing, &audio->ch3Fade, when); + } LOAD_32LE(ch4Flags, 0, &state->ch4.envelope); audio->ch4.envelope.currentVolume = GBSerializedAudioFlagsGetCh4Volume(flags); @@ -963,12 +990,22 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch4.length = GBSerializedAudioEnvelopeGetLength(ch4Flags); audio->ch4.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch4Flags); LOAD_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr); + LOAD_32LE(when, 0, &state->ch4.nextEvent); + mTimingDeschedule(audio->timing, &audio->ch4Event); + if (audio->ch4.envelope.dead < 2 && audio->playingCh4) { + mTimingSchedule(audio->timing, &audio->ch4Event, when); + } } void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state) { GBAudioPSGSerialize(audio, &state->audio.psg, &state->audio.flags); + STORE_32LE(audio->sampleEvent.when - mTimingCurrentTime(audio->timing), 0, &state->audio.nextSample); } void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* state) { GBAudioPSGDeserialize(audio, &state->audio.psg, &state->audio.flags); + uint32_t when; + LOAD_32LE(when, 0, &state->audio.nextSample); + mTimingDeschedule(audio->timing, &audio->sampleEvent); + mTimingSchedule(audio->timing, &audio->sampleEvent, when); } diff --git a/src/gb/serialize.h b/src/gb/serialize.h index d8db7e101..24d45f534 100644 --- a/src/gb/serialize.h +++ b/src/gb/serialize.h @@ -272,8 +272,7 @@ struct GBSerializedState { struct { struct GBSerializedPSGState psg; GBSerializedAudioFlags flags; - int32_t nextEvent; - int32_t eventDiff; + int32_t reserved[2]; int32_t nextSample; } audio; diff --git a/src/gba/audio.c b/src/gba/audio.c index baf87d3fe..4194f3a78 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -320,6 +320,7 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB)); uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo); STORE_32(fifoSize, 0, &state->audio.fifoSize); + STORE_32(audio->sampleEvent.when - mTimingCurrentTime(&audio->p->timing), 0, &state->audio.nextSample); } void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) { @@ -337,6 +338,11 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]); CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]); } + + uint32_t when; + LOAD_32(when, 0, &state->audio.nextSample); + mTimingDeschedule(&audio->p->timing, &audio->sampleEvent); + mTimingSchedule(&audio->p->timing, &audio->sampleEvent, when); } float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) { diff --git a/src/gba/io.c b/src/gba/io.c index e85101a30..0168b31ab 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -912,13 +912,14 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io); STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload); STORE_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); - STORE_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + STORE_32(gba->timers[i].lastEvent - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].lastEvent); + STORE_32(gba->timers[i].event.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextEvent); STORE_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval); STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags); STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); STORE_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); - STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].nextEvent); + STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when); } GBAHardwareSerialize(&gba->memory.hw, state); @@ -936,6 +937,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { } } + uint32_t when; for (i = 0; i < 4; ++i) { LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload); LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); @@ -945,13 +947,20 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { // Overwrite invalid values in savestate gba->timers[i].lastEvent = 0; } else { - LOAD_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + LOAD_32(when, 0, &state->timers[i].lastEvent); + gba->timers[i].lastEvent = when + mTimingCurrentTime(&gba->timing); } + LOAD_32(when, 0, &state->timers[i].nextEvent); + mTimingDeschedule(&gba->timing, &gba->timers[i].event); + if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { + mTimingSchedule(&gba->timing, &gba->timers[i].event, when); + } + LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io); LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); - LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].nextEvent); + LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when); if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) { GBADMASchedule(gba, i, &gba->memory.dma[i]); } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 8130fd00c..efa931212 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -23,7 +23,7 @@ #endif const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000; -const uint32_t GBA_SAVESTATE_VERSION = 0x00000001; +const uint32_t GBA_SAVESTATE_VERSION = 0x00000002; mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate"); @@ -36,6 +36,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { STORE_32(GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32(gba->biosChecksum, 0, &state->biosChecksum); STORE_32(gba->romCrc32, 0, &state->romCrc32); + STORE_32(gba->timing.masterCycles, 0, &state->masterCycles); if (gba->memory.rom) { state->id = ((struct GBACartridge*) gba->memory.rom)->id; @@ -144,11 +145,6 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { mLOG(GBA_STATE, WARN, "Savestate is corrupted: CPU cycles are too high"); error = true; } - LOAD_32(check, 0, &state->video.eventDiff); - if (check < 0) { - mLOG(GBA_STATE, WARN, "Savestate is corrupted: video eventDiff is negative"); - error = true; - } LOAD_32(check, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); int region = (check >> BASE_OFFSET); if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((check - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { @@ -158,6 +154,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { if (error) { return false; } + LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles); size_t i; for (i = 0; i < 16; ++i) { LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs); diff --git a/src/gba/serialize.h b/src/gba/serialize.h index 1ba5c3814..a062b2018 100644 --- a/src/gba/serialize.h +++ b/src/gba/serialize.h @@ -64,8 +64,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * 0x0018C - 0x001AB: Audio FIFO 1 * 0x001AC - 0x001CB: Audio FIFO 2 * 0x001CC - 0x001DF: Audio miscellaneous state - * | 0x001CC - 0x001CF: Next event - * | 0x001D0 - 0x001D3: Event diff + * | 0x001CC - 0x001D3: Reserved * | 0x001D4 - 0x001D7: Next sample * | 0x001D8 - 0x001DB: FIFO size * | TODO: Fix this, they're in big-endian order, but field is little-endian @@ -90,12 +89,7 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | bits 6 - 7: Reserved * 0x001E0 - 0x001FF: Video miscellaneous state * | 0x001E0 - 0x001E3: Next event - * | 0x001E4 - 0x001E7: Event diff - * | 0x001E8 - 0x001EB: Last hblank - * | 0x001EC - 0x001EF: Next hblank - * | 0x001F0 - 0x001F3: Next hblank IRQ - * | 0x001F4 - 0x001F7: Next vblank IRQ - * | 0x001F8 - 0x001FB: Next vcounter IRQ + * | 0x001E4 - 0x001FB: Reserved * | 0x001FC - 0x001FF: Frame counter * 0x00200 - 0x00213: Timer 0 * | 0x00200 - 0x00201: Reload value @@ -232,7 +226,7 @@ struct GBASerializedState { uint32_t versionMagic; uint32_t biosChecksum; uint32_t romCrc32; - uint32_t reservedHeader; + uint32_t masterCycles; char title[12]; uint32_t id; @@ -253,8 +247,7 @@ struct GBASerializedState { struct GBSerializedPSGState psg; uint8_t fifoA[32]; uint8_t fifoB[32]; - int32_t nextEvent; - int32_t eventDiff; + int32_t reserved[2]; int32_t nextSample; uint32_t fifoSize; GBSerializedAudioFlags flags; @@ -262,22 +255,24 @@ struct GBASerializedState { struct { int32_t nextEvent; - int32_t eventDiff; - int32_t lastHblank; - int32_t nextHblank; - int32_t nextHblankIRQ; - int32_t nextVblankIRQ; - int32_t nextVcounterIRQ; + int32_t reserved[6]; int32_t frameCounter; } video; - struct GBATimer timers[4]; + struct { + uint16_t reload; + uint16_t oldReload; + uint32_t lastEvent; + uint32_t nextEvent; + int32_t overflowInterval; + GBATimerFlags flags; + } timers[4]; struct { uint32_t nextSource; uint32_t nextDest; int32_t nextCount; - int32_t nextEvent; + int32_t when; } dma[4]; struct { diff --git a/src/gba/timer.c b/src/gba/timer.c index 84c3b4aa4..3ae17f50c 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -131,6 +131,7 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { currentTimer->oldReload = currentTimer->reload; currentTimer->lastEvent = gba->timing.masterCycles + gba->cpu->cycles; } else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) { + mTimingDeschedule(&gba->timing, ¤tTimer->event); if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale); } diff --git a/src/gba/video.c b/src/gba/video.c index 5a9b4c88b..d05151486 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -299,6 +299,7 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* memcpy(state->vram, video->renderer->vram, SIZE_VRAM); memcpy(state->oam, video->oam.raw, SIZE_OAM); memcpy(state->pram, video->palette, SIZE_PALETTE_RAM); + STORE_32(video->event.when - mTimingCurrentTime(&video->p->timing), 0, &state->video.nextEvent); STORE_32(video->frameCounter, 0, &state->video.frameCounter); } @@ -315,6 +316,18 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0); } LOAD_32(video->frameCounter, 0, &state->video.frameCounter); + + uint32_t when; + LOAD_32(when, 0, &state->video.nextEvent); + GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; + if (GBARegisterDISPSTATIsInHblank(dispstat)) { + video->event.callback = _startHdraw; + } else { + video->event.callback = _startHblank; + } + mTimingDeschedule(&video->p->timing, &video->event); + mTimingSchedule(&video->p->timing, &video->event, when); + LOAD_16(video->vcount, REG_VCOUNT, state->io); video->renderer->reset(video->renderer); }