all repos — mgba @ 549787227a488a4f52e30ee0b14cb9bf331b327c

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/sm83/sm83.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	STORE_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
 27
 28	if (gb->memory.rom) {
 29		memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->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
 54	GBSerializedCpuFlags flags = 0;
 55	flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
 56	flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
 57	flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
 58	flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
 59	flags = GBSerializedCpuFlagsSetHalted(flags, gb->cpu->halted);
 60	flags = GBSerializedCpuFlagsSetBlocked(flags, gb->cpuBlocked);
 61	STORE_32LE(flags, 0, &state->cpu.flags);
 62	STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
 63
 64	GBMemorySerialize(gb, state);
 65	GBIOSerialize(gb, state);
 66	GBVideoSerialize(&gb->video, state);
 67	GBTimerSerialize(&gb->timer, state);
 68	GBAudioSerialize(&gb->audio, state);
 69
 70	if (gb->model & GB_MODEL_SGB) {
 71		GBSGBSerialize(gb, state);
 72	}
 73}
 74
 75bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
 76	bool error = false;
 77	int32_t check;
 78	uint32_t ucheck;
 79	int16_t check16;
 80	uint16_t ucheck16;
 81	LOAD_32LE(ucheck, 0, &state->versionMagic);
 82	if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
 83		mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 84		error = true;
 85	} else if (ucheck < GB_SAVESTATE_MAGIC) {
 86		mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 87		error = true;
 88	} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
 89		mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
 90	}
 91	bool canSgb = ucheck >= GB_SAVESTATE_MAGIC + 2;
 92
 93	if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title))) {
 94		LOAD_32LE(ucheck, 0, &state->versionMagic);
 95		if (ucheck > GB_SAVESTATE_MAGIC + 2 || memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
 96			// There was a bug in previous versions where the memory address being compared was wrong
 97			mLOG(GB_STATE, WARN, "Savestate is for a different game");
 98			error = true;
 99		}
100	}
101	LOAD_32LE(ucheck, 0, &state->romCrc32);
102	if (ucheck != gb->romCrc32) {
103		mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
104	}
105	LOAD_32LE(check, 0, &state->cpu.cycles);
106	if (check < 0) {
107		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
108		error = true;
109	}
110	if (state->cpu.executionState != SM83_CORE_FETCH) {
111		mLOG(GB_STATE, WARN, "Savestate is corrupted: Execution state is not FETCH");
112		error = true;
113	}
114	if (check >= (int32_t) DMG_SM83_FREQUENCY) {
115		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
116		error = true;
117	}
118	LOAD_16LE(check16, 0, &state->video.x);
119	if (check16 < -7 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
120		mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
121		error = true;
122	}
123	LOAD_16LE(check16, 0, &state->video.ly);
124	if (check16 < 0 || check16 > GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
125		mLOG(GB_STATE, WARN, "Savestate is corrupted: video y is out of range");
126		error = true;
127	}
128	LOAD_16LE(ucheck16, 0, &state->memory.dmaDest);
129	if (ucheck16 + state->memory.dmaRemaining > GB_SIZE_OAM) {
130		mLOG(GB_STATE, WARN, "Savestate is corrupted: DMA destination is out of range");
131		error = true;
132	}
133	LOAD_16LE(ucheck16, 0, &state->video.bcpIndex);
134	if (ucheck16 >= 0x40) {
135		mLOG(GB_STATE, WARN, "Savestate is corrupted: BCPS is out of range");
136	}
137	LOAD_16LE(ucheck16, 0, &state->video.ocpIndex);
138	if (ucheck16 >= 0x40) {
139		mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
140	}
141	bool differentBios = !gb->biosVf || gb->model != state->model;
142	if (state->io[0x50] == 0xFF) {
143		if (differentBios) {
144			mLOG(GB_STATE, WARN, "Incompatible savestate, please restart with correct BIOS in %s mode", GBModelToName(state->model));
145			error = true;
146		} else {
147			// TODO: Make it work correctly
148			mLOG(GB_STATE, WARN, "Loading savestate in BIOS. This may not work correctly");
149		}
150	}
151	if (error) {
152		return false;
153	}
154	mTimingClear(&gb->timing);
155	LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
156	LOAD_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
157
158	gb->cpu->a = state->cpu.a;
159	gb->cpu->f.packed = state->cpu.f;
160	gb->cpu->b = state->cpu.b;
161	gb->cpu->c = state->cpu.c;
162	gb->cpu->d = state->cpu.d;
163	gb->cpu->e = state->cpu.e;
164	gb->cpu->h = state->cpu.h;
165	gb->cpu->l = state->cpu.l;
166	LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
167	LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
168
169	LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
170	gb->cpu->bus = state->cpu.bus;
171	gb->cpu->executionState = state->cpu.executionState;
172
173	GBSerializedCpuFlags flags;
174	LOAD_32LE(flags, 0, &state->cpu.flags);
175	gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
176	gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
177	gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
178	gb->cpu->halted = GBSerializedCpuFlagsGetHalted(flags);
179	gb->cpuBlocked = GBSerializedCpuFlagsGetBlocked(flags);
180
181	gb->audio.timingFactor = gb->doubleSpeed + 1;
182
183	LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
184	LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
185	gb->timing.root = NULL;
186
187	uint32_t when;
188	LOAD_32LE(when, 0, &state->cpu.eiPending);
189	if (GBSerializedCpuFlagsIsEiPending(flags)) {
190		mTimingSchedule(&gb->timing, &gb->eiPending, when);
191	}
192
193	gb->model = state->model;
194
195	if (gb->model < GB_MODEL_CGB) {
196		gb->audio.style = GB_AUDIO_DMG;
197	} else {
198		gb->audio.style = GB_AUDIO_CGB;
199	}
200
201	GBMemoryDeserialize(gb, state);
202	GBVideoDeserialize(&gb->video, state);
203	GBIODeserialize(gb, state);
204	GBTimerDeserialize(&gb->timer, state);
205	GBAudioDeserialize(&gb->audio, state);
206
207	if (gb->memory.io[0x50] == 0xFF) {
208		GBMapBIOS(gb);
209	} else {
210		GBUnmapBIOS(gb);
211	}
212
213	if (gb->model & GB_MODEL_SGB && canSgb) {
214		GBSGBDeserialize(gb, state);
215	}
216
217	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
218
219	gb->timing.reroot = gb->timing.root;
220	gb->timing.root = NULL;
221
222	return true;
223}
224
225// TODO: Reorganize SGB into its own file
226void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) {
227	state->sgb.command = gb->video.sgbCommandHeader;
228	state->sgb.bits = gb->sgbBit;
229
230	GBSerializedSGBFlags flags = 0;
231	flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits);
232	flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode);
233	flags = GBSerializedSGBFlagsSetBufferIndex(flags, gb->video.sgbBufferIndex);
234	flags = GBSerializedSGBFlagsSetReqControllers(flags, gb->sgbControllers);
235	flags = GBSerializedSGBFlagsSetIncrement(flags, gb->sgbIncrement);
236	flags = GBSerializedSGBFlagsSetCurrentController(flags, gb->sgbCurrentController);
237	STORE_32LE(flags, 0, &state->sgb.flags);
238
239	memcpy(state->sgb.packet, gb->video.sgbPacketBuffer, sizeof(state->sgb.packet));
240	memcpy(state->sgb.inProgressPacket, gb->sgbPacket, sizeof(state->sgb.inProgressPacket));
241
242	if (gb->video.renderer->sgbCharRam) {
243		memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam));
244	}
245	if (gb->video.renderer->sgbMapRam) {
246		memcpy(state->sgb.mapRam, gb->video.renderer->sgbMapRam, sizeof(state->sgb.mapRam));
247	}
248	if (gb->video.renderer->sgbPalRam) {
249		memcpy(state->sgb.palRam, gb->video.renderer->sgbPalRam, sizeof(state->sgb.palRam));
250	}
251	if (gb->video.renderer->sgbAttributeFiles) {
252		memcpy(state->sgb.atfRam, gb->video.renderer->sgbAttributeFiles, sizeof(state->sgb.atfRam));
253	}
254	if (gb->video.renderer->sgbAttributes) {
255		memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes));
256	}
257	gb->video.renderer->enableSGBBorder(gb->video.renderer, gb->video.sgbBorders);
258}
259
260void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
261	gb->video.sgbCommandHeader = state->sgb.command;
262	gb->sgbBit = state->sgb.bits;
263
264	GBSerializedSGBFlags flags;
265	LOAD_32LE(flags, 0, &state->sgb.flags);
266	gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags);
267	gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags);
268	gb->video.sgbBufferIndex = GBSerializedSGBFlagsGetBufferIndex(flags);
269	gb->sgbControllers = GBSerializedSGBFlagsGetReqControllers(flags);
270	gb->sgbCurrentController = GBSerializedSGBFlagsGetCurrentController(flags);
271	gb->sgbIncrement = GBSerializedSGBFlagsGetIncrement(flags);
272
273	// Old versions of mGBA stored the increment bits here
274	if (gb->sgbBit > 129 && gb->sgbBit & 2) {
275		gb->sgbIncrement = true;
276	}
277
278	memcpy(gb->video.sgbPacketBuffer, state->sgb.packet, sizeof(state->sgb.packet));
279	memcpy(gb->sgbPacket, state->sgb.inProgressPacket, sizeof(state->sgb.inProgressPacket));
280
281	if (!gb->video.renderer->sgbCharRam) {
282		gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
283	}
284	if (!gb->video.renderer->sgbMapRam) {
285		gb->video.renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
286	}
287	if (!gb->video.renderer->sgbPalRam) {
288		gb->video.renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
289	}
290	if (!gb->video.renderer->sgbAttributeFiles) {
291		gb->video.renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
292	}
293	if (!gb->video.renderer->sgbAttributes) {
294		gb->video.renderer->sgbAttributes = malloc(90 * 45);
295	}
296
297	memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
298	memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
299	memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
300	memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
301	memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
302
303	GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
304}