all repos — mgba @ 264f238ec31b3c29e3bcd84fe561d1d32d5f57e2

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