all repos — mgba @ 3d113112c48006681f7df1d107517533c29fb97e

mGBA Game Boy Advance Emulator

src/gb/serialize.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba/internal/gb/serialize.h>
  7
  8#include <mgba/internal/gb/io.h>
  9#include <mgba/internal/gb/timer.h>
 10#include <mgba/internal/lr35902/lr35902.h>
 11
 12mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate");
 13
 14#ifdef _MSC_VER
 15#include <time.h>
 16#else
 17#include <sys/time.h>
 18#endif
 19
 20const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
 21const uint32_t GB_SAVESTATE_VERSION = 0x00000001;
 22
 23void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
 24	STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
 25	STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
 26	STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
 27
 28	if (gb->memory.rom) {
 29		memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title));
 30	} else {
 31		memset(state->title, 0, sizeof(state->title));
 32	}
 33
 34	state->model = gb->model;
 35
 36	state->cpu.a = gb->cpu->a;
 37	state->cpu.f = gb->cpu->f.packed;
 38	state->cpu.b = gb->cpu->b;
 39	state->cpu.c = gb->cpu->c;
 40	state->cpu.d = gb->cpu->d;
 41	state->cpu.e = gb->cpu->e;
 42	state->cpu.h = gb->cpu->h;
 43	state->cpu.l = gb->cpu->l;
 44	STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp);
 45	STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc);
 46
 47	STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
 48	STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
 49
 50	STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
 51	state->cpu.bus = gb->cpu->bus;
 52	state->cpu.executionState = gb->cpu->executionState;
 53	STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
 54
 55	GBSerializedCpuFlags flags = 0;
 56	flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
 57	flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
 58	flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
 59	flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
 60	STORE_32LE(flags, 0, &state->cpu.flags);
 61	STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
 62
 63	GBMemorySerialize(gb, state);
 64	GBIOSerialize(gb, state);
 65	GBVideoSerialize(&gb->video, state);
 66	GBTimerSerialize(&gb->timer, state);
 67	GBAudioSerialize(&gb->audio, state);
 68
 69#ifndef _MSC_VER
 70	struct timeval tv;
 71	if (!gettimeofday(&tv, 0)) {
 72		uint64_t usec = tv.tv_usec;
 73		usec += tv.tv_sec * 1000000LL;
 74		STORE_64LE(usec, 0, &state->creationUsec);
 75	}
 76#else
 77	struct timespec ts;
 78	if (timespec_get(&ts, TIME_UTC)) {
 79		uint64_t usec = ts.tv_nsec / 1000;
 80		usec += ts.tv_sec * 1000000LL;
 81		STORE_64LE(usec, 0, &state->creationUsec);
 82	}
 83#endif
 84	else {
 85		state->creationUsec = 0;
 86	}
 87}
 88
 89bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
 90	bool error = false;
 91	int32_t check;
 92	uint32_t ucheck;
 93	int16_t check16;
 94	uint16_t ucheck16;
 95	LOAD_32LE(ucheck, 0, &state->versionMagic);
 96	if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
 97		mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 98		error = true;
 99	} else if (ucheck < GB_SAVESTATE_MAGIC) {
100		mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
101		error = true;
102	} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
103		mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
104	}
105
106	if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
107		mLOG(GB_STATE, WARN, "Savestate is for a different game");
108		error = true;
109	}
110	LOAD_32LE(ucheck, 0, &state->romCrc32);
111	if (ucheck != gb->romCrc32) {
112		mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
113	}
114	LOAD_32LE(check, 0, &state->cpu.cycles);
115	if (check < 0) {
116		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
117		error = true;
118	}
119	if (state->cpu.executionState != LR35902_CORE_FETCH) {
120		mLOG(GB_STATE, WARN, "Savestate is corrupted: Execution state is not FETCH");
121		error = true;
122	}
123	if (check >= (int32_t) DMG_LR35902_FREQUENCY) {
124		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
125		error = true;
126	}
127	LOAD_16LE(check16, 0, &state->video.x);
128	if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
129		mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
130		error = true;
131	}
132	LOAD_16LE(check16, 0, &state->video.ly);
133	if (check16 < 0 || check16 > GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
134		mLOG(GB_STATE, WARN, "Savestate is corrupted: video y is out of range");
135		error = true;
136	}
137	LOAD_16LE(ucheck16, 0, &state->memory.dmaDest);
138	if (ucheck16 + state->memory.dmaRemaining > GB_SIZE_OAM) {
139		mLOG(GB_STATE, WARN, "Savestate is corrupted: DMA destination is out of range");
140		error = true;
141	}
142	LOAD_16LE(ucheck16, 0, &state->video.bcpIndex);
143	if (ucheck16 >= 0x40) {
144		mLOG(GB_STATE, WARN, "Savestate is corrupted: BCPS is out of range");
145	}
146	LOAD_16LE(ucheck16, 0, &state->video.ocpIndex);
147	if (ucheck16 >= 0x40) {
148		mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
149	}
150	if (error) {
151		return false;
152	}
153
154	gb->cpu->a = state->cpu.a;
155	gb->cpu->f.packed = state->cpu.f;
156	gb->cpu->b = state->cpu.b;
157	gb->cpu->c = state->cpu.c;
158	gb->cpu->d = state->cpu.d;
159	gb->cpu->e = state->cpu.e;
160	gb->cpu->h = state->cpu.h;
161	gb->cpu->l = state->cpu.l;
162	LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
163	LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
164
165	LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
166	gb->cpu->bus = state->cpu.bus;
167	gb->cpu->executionState = state->cpu.executionState;
168	LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
169
170	GBSerializedCpuFlags flags;
171	LOAD_32LE(flags, 0, &state->cpu.flags);
172	gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
173	gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
174	gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
175	gb->audio.timingFactor = gb->doubleSpeed + 1;
176
177	uint32_t when;
178	LOAD_32LE(when, 0, &state->cpu.eiPending);
179	mTimingDeschedule(&gb->timing, &gb->eiPending);
180	if (GBSerializedCpuFlagsIsEiPending(flags)) {
181		mTimingSchedule(&gb->timing, &gb->eiPending, when);
182	}
183
184	LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
185	LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
186	LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
187
188	gb->model = state->model;
189
190	if (gb->model < GB_MODEL_CGB) {
191		gb->audio.style = GB_AUDIO_DMG;
192	} else {
193		gb->audio.style = GB_AUDIO_CGB;
194	}
195
196	GBMemoryDeserialize(gb, state);
197	GBIODeserialize(gb, state);
198	GBVideoDeserialize(&gb->video, state);
199	GBTimerDeserialize(&gb->timer, state);
200	GBAudioDeserialize(&gb->audio, state);
201
202	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
203
204	return true;
205}