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}