all repos — mgba @ 65665324ef9124280a8a310ab9cea048d519a5a9

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
 12#include <mgba-util/memory.h>
 13
 14mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate", "gb.serialize");
 15
 16const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
 17const uint32_t GB_SAVESTATE_VERSION = 0x00000002;
 18
 19static void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state);
 20static void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state);
 21
 22void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
 23	STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
 24	STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
 25	STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
 26
 27	if (gb->memory.rom) {
 28		memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title));
 29	} else {
 30		memset(state->title, 0, sizeof(state->title));
 31	}
 32
 33	state->model = gb->model;
 34
 35	state->cpu.a = gb->cpu->a;
 36	state->cpu.f = gb->cpu->f.packed;
 37	state->cpu.b = gb->cpu->b;
 38	state->cpu.c = gb->cpu->c;
 39	state->cpu.d = gb->cpu->d;
 40	state->cpu.e = gb->cpu->e;
 41	state->cpu.h = gb->cpu->h;
 42	state->cpu.l = gb->cpu->l;
 43	STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp);
 44	STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc);
 45
 46	STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
 47	STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
 48
 49	STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
 50	state->cpu.bus = gb->cpu->bus;
 51	state->cpu.executionState = gb->cpu->executionState;
 52
 53	GBSerializedCpuFlags flags = 0;
 54	flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
 55	flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
 56	flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
 57	flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
 58	STORE_32LE(flags, 0, &state->cpu.flags);
 59	STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
 60
 61	GBMemorySerialize(gb, state);
 62	GBIOSerialize(gb, state);
 63	GBVideoSerialize(&gb->video, state);
 64	GBTimerSerialize(&gb->timer, state);
 65	GBAudioSerialize(&gb->audio, state);
 66
 67	if (gb->model == GB_MODEL_SGB) {
 68		GBSGBSerialize(gb, state);
 69	}
 70}
 71
 72bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
 73	bool error = false;
 74	int32_t check;
 75	uint32_t ucheck;
 76	int16_t check16;
 77	uint16_t ucheck16;
 78	LOAD_32LE(ucheck, 0, &state->versionMagic);
 79	if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
 80		mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 81		error = true;
 82	} else if (ucheck < GB_SAVESTATE_MAGIC) {
 83		mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 84		error = true;
 85	} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
 86		mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 87	}
 88	bool canSgb = ucheck >= GB_SAVESTATE_MAGIC + 2;
 89
 90	if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title))) {
 91		LOAD_32LE(ucheck, 0, &state->versionMagic);
 92		if (ucheck > GB_SAVESTATE_MAGIC + 2 || memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
 93			// There was a bug in previous versions where the memory address being compared was wrong
 94			mLOG(GB_STATE, WARN, "Savestate is for a different game");
 95			error = true;
 96		}
 97	}
 98	LOAD_32LE(ucheck, 0, &state->romCrc32);
 99	if (ucheck != gb->romCrc32) {
100		mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
101	}
102	LOAD_32LE(check, 0, &state->cpu.cycles);
103	if (check < 0) {
104		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
105		error = true;
106	}
107	if (state->cpu.executionState != LR35902_CORE_FETCH) {
108		mLOG(GB_STATE, WARN, "Savestate is corrupted: Execution state is not FETCH");
109		error = true;
110	}
111	if (check >= (int32_t) DMG_LR35902_FREQUENCY) {
112		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
113		error = true;
114	}
115	LOAD_16LE(check16, 0, &state->video.x);
116	if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
117		mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
118		error = true;
119	}
120	LOAD_16LE(check16, 0, &state->video.ly);
121	if (check16 < 0 || check16 > GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
122		mLOG(GB_STATE, WARN, "Savestate is corrupted: video y is out of range");
123		error = true;
124	}
125	LOAD_16LE(ucheck16, 0, &state->memory.dmaDest);
126	if (ucheck16 + state->memory.dmaRemaining > GB_SIZE_OAM) {
127		mLOG(GB_STATE, WARN, "Savestate is corrupted: DMA destination is out of range");
128		error = true;
129	}
130	LOAD_16LE(ucheck16, 0, &state->video.bcpIndex);
131	if (ucheck16 >= 0x40) {
132		mLOG(GB_STATE, WARN, "Savestate is corrupted: BCPS is out of range");
133	}
134	LOAD_16LE(ucheck16, 0, &state->video.ocpIndex);
135	if (ucheck16 >= 0x40) {
136		mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
137	}
138	if (error) {
139		return false;
140	}
141	gb->timing.root = NULL;
142	LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
143
144	gb->cpu->a = state->cpu.a;
145	gb->cpu->f.packed = state->cpu.f;
146	gb->cpu->b = state->cpu.b;
147	gb->cpu->c = state->cpu.c;
148	gb->cpu->d = state->cpu.d;
149	gb->cpu->e = state->cpu.e;
150	gb->cpu->h = state->cpu.h;
151	gb->cpu->l = state->cpu.l;
152	LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
153	LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
154
155	LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
156	gb->cpu->bus = state->cpu.bus;
157	gb->cpu->executionState = state->cpu.executionState;
158
159	GBSerializedCpuFlags flags;
160	LOAD_32LE(flags, 0, &state->cpu.flags);
161	gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
162	gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
163	gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
164	gb->audio.timingFactor = gb->doubleSpeed + 1;
165
166	LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
167	LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
168	gb->timing.root = NULL;
169
170	uint32_t when;
171	LOAD_32LE(when, 0, &state->cpu.eiPending);
172	if (GBSerializedCpuFlagsIsEiPending(flags)) {
173		mTimingSchedule(&gb->timing, &gb->eiPending, when);
174	}
175
176	enum GBModel oldModel = gb->model;
177	gb->model = state->model;
178
179	if (gb->model < GB_MODEL_CGB) {
180		gb->audio.style = GB_AUDIO_DMG;
181	} else {
182		gb->audio.style = GB_AUDIO_CGB;
183	}
184
185	if (gb->model != GB_MODEL_SGB || oldModel != GB_MODEL_SGB) {
186		gb->video.sgbBorders = false;
187	}
188
189	GBMemoryDeserialize(gb, state);
190	GBVideoDeserialize(&gb->video, state);
191	GBIODeserialize(gb, state);
192	GBTimerDeserialize(&gb->timer, state);
193	GBAudioDeserialize(&gb->audio, state);
194
195	if (gb->model == GB_MODEL_SGB && canSgb) {
196		GBSGBDeserialize(gb, state);
197	}
198
199	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
200
201	gb->timing.reroot = gb->timing.root;
202	gb->timing.root = NULL;
203
204	return true;
205}
206
207// TODO: Reorganize SGB into its own file
208void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) {
209	state->sgb.command = gb->video.sgbCommandHeader;
210	state->sgb.bits = gb->sgbBit;
211
212	GBSerializedSGBFlags flags = 0;
213	flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits);
214	flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode);
215	STORE_32LE(flags, 0, &state->sgb.flags);
216
217	memcpy(state->sgb.packet, gb->sgbPacket, sizeof(state->sgb.packet));
218
219	if (gb->video.renderer->sgbCharRam) {
220		memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam));
221	}
222	if (gb->video.renderer->sgbMapRam) {
223		memcpy(state->sgb.mapRam, gb->video.renderer->sgbMapRam, sizeof(state->sgb.mapRam));
224	}
225	if (gb->video.renderer->sgbPalRam) {
226		memcpy(state->sgb.palRam, gb->video.renderer->sgbPalRam, sizeof(state->sgb.palRam));
227	}
228	if (gb->video.renderer->sgbAttributeFiles) {
229		memcpy(state->sgb.atfRam, gb->video.renderer->sgbAttributeFiles, sizeof(state->sgb.atfRam));
230	}
231	if (gb->video.renderer->sgbAttributes) {
232		memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes));
233	}
234}
235
236void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
237	gb->video.sgbCommandHeader = state->sgb.command;
238	gb->sgbBit = state->sgb.bits;
239
240	GBSerializedSGBFlags flags;
241	LOAD_32LE(flags, 0, &state->sgb.flags);
242	gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags);
243	gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags);
244
245	memcpy(gb->sgbPacket, state->sgb.packet, sizeof(state->sgb.packet));
246
247	if (!gb->video.renderer->sgbCharRam) {
248		gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
249	}
250	if (!gb->video.renderer->sgbMapRam) {
251		gb->video.renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
252	}
253	if (!gb->video.renderer->sgbPalRam) {
254		gb->video.renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
255	}
256	if (!gb->video.renderer->sgbAttributeFiles) {
257		gb->video.renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
258	}
259	if (!gb->video.renderer->sgbAttributes) {
260		gb->video.renderer->sgbAttributes = malloc(90 * 45);
261	}
262
263	memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
264	memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
265	memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
266	memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
267	memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
268
269	GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
270	GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
271}