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
16MGBA_EXPORT const uint32_t GBSavestateMagic = 0x00400000;
17MGBA_EXPORT const uint32_t GBSavestateVersion = 0x00000002;
18
19void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
20 STORE_32LE(GBSavestateMagic + GBSavestateVersion, 0, &state->versionMagic);
21 STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
22 STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
23 STORE_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
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 flags = GBSerializedCpuFlagsSetHalted(flags, gb->cpu->halted);
57 flags = GBSerializedCpuFlagsSetBlocked(flags, gb->cpuBlocked);
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 > GBSavestateMagic + GBSavestateVersion) {
80 mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GBSavestateMagic + GBSavestateVersion, ucheck);
81 error = true;
82 } else if (ucheck < GBSavestateMagic) {
83 mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GBSavestateMagic + GBSavestateVersion, ucheck);
84 error = true;
85 } else if (ucheck < GBSavestateMagic + GBSavestateVersion) {
86 mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GBSavestateMagic + GBSavestateVersion, ucheck);
87 }
88 bool canSgb = ucheck >= GBSavestateMagic + 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 > GBSavestateMagic + 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 != SM83_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_SM83_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 < -7 || 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 bool differentBios = !gb->biosVf || gb->model != state->model;
139 if (state->io[GB_REG_BANK] == 0xFF) {
140 if (differentBios) {
141 mLOG(GB_STATE, WARN, "Incompatible savestate, please restart with correct BIOS in %s mode", GBModelToName(state->model));
142 error = true;
143 } else {
144 // TODO: Make it work correctly
145 mLOG(GB_STATE, WARN, "Loading savestate in BIOS. This may not work correctly");
146 }
147 }
148 if (error) {
149 return false;
150 }
151 mTimingClear(&gb->timing);
152 LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
153 LOAD_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
154
155 gb->cpu->a = state->cpu.a;
156 gb->cpu->f.packed = state->cpu.f;
157 gb->cpu->b = state->cpu.b;
158 gb->cpu->c = state->cpu.c;
159 gb->cpu->d = state->cpu.d;
160 gb->cpu->e = state->cpu.e;
161 gb->cpu->h = state->cpu.h;
162 gb->cpu->l = state->cpu.l;
163 LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
164 LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
165
166 LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
167 gb->cpu->bus = state->cpu.bus;
168 gb->cpu->executionState = state->cpu.executionState;
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->cpu->halted = GBSerializedCpuFlagsGetHalted(flags);
176 gb->cpuBlocked = GBSerializedCpuFlagsGetBlocked(flags);
177
178 LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
179 LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
180 gb->timing.root = NULL;
181
182 uint32_t when;
183 LOAD_32LE(when, 0, &state->cpu.eiPending);
184 if (GBSerializedCpuFlagsIsEiPending(flags)) {
185 mTimingSchedule(&gb->timing, &gb->eiPending, when);
186 } else {
187 gb->eiPending.when = when + mTimingCurrentTime(&gb->timing);
188 }
189
190 gb->model = state->model;
191
192 if (gb->model < GB_MODEL_CGB) {
193 gb->audio.style = GB_AUDIO_DMG;
194 } else {
195 gb->audio.style = GB_AUDIO_CGB;
196 }
197
198 GBUnmapBIOS(gb);
199 GBMemoryDeserialize(gb, state);
200 GBVideoDeserialize(&gb->video, state);
201 GBIODeserialize(gb, state);
202 GBTimerDeserialize(&gb->timer, state);
203 GBAudioDeserialize(&gb->audio, state);
204
205 if (gb->memory.io[GB_REG_BANK] == 0xFF) {
206 GBMapBIOS(gb);
207 }
208
209 if (gb->model & GB_MODEL_SGB && canSgb) {
210 GBSGBDeserialize(gb, state);
211 }
212
213 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
214
215 gb->timing.reroot = gb->timing.root;
216 gb->timing.root = NULL;
217
218 return true;
219}
220
221// TODO: Reorganize SGB into its own file
222void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) {
223 state->sgb.command = gb->video.sgbCommandHeader;
224 state->sgb.bits = gb->sgbBit;
225
226 GBSerializedSGBFlags flags = 0;
227 flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits);
228 flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode);
229 flags = GBSerializedSGBFlagsSetBufferIndex(flags, gb->video.sgbBufferIndex);
230 flags = GBSerializedSGBFlagsSetReqControllers(flags, gb->sgbControllers);
231 flags = GBSerializedSGBFlagsSetIncrement(flags, gb->sgbIncrement);
232 flags = GBSerializedSGBFlagsSetCurrentController(flags, gb->sgbCurrentController);
233 STORE_32LE(flags, 0, &state->sgb.flags);
234
235 memcpy(state->sgb.packet, gb->video.sgbPacketBuffer, sizeof(state->sgb.packet));
236 memcpy(state->sgb.inProgressPacket, gb->sgbPacket, sizeof(state->sgb.inProgressPacket));
237
238 if (gb->video.renderer->sgbCharRam) {
239 memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam));
240 }
241 if (gb->video.renderer->sgbMapRam) {
242 memcpy(state->sgb.mapRam, gb->video.renderer->sgbMapRam, sizeof(state->sgb.mapRam));
243 }
244 if (gb->video.renderer->sgbPalRam) {
245 memcpy(state->sgb.palRam, gb->video.renderer->sgbPalRam, sizeof(state->sgb.palRam));
246 }
247 if (gb->video.renderer->sgbAttributeFiles) {
248 memcpy(state->sgb.atfRam, gb->video.renderer->sgbAttributeFiles, sizeof(state->sgb.atfRam));
249 }
250 if (gb->video.renderer->sgbAttributes) {
251 memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes));
252 }
253}
254
255void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
256 gb->video.sgbCommandHeader = state->sgb.command;
257 gb->sgbBit = state->sgb.bits;
258
259 GBSerializedSGBFlags flags;
260 LOAD_32LE(flags, 0, &state->sgb.flags);
261 gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags);
262 gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags);
263 gb->video.sgbBufferIndex = GBSerializedSGBFlagsGetBufferIndex(flags);
264 gb->sgbControllers = GBSerializedSGBFlagsGetReqControllers(flags);
265 gb->sgbCurrentController = GBSerializedSGBFlagsGetCurrentController(flags);
266 gb->sgbIncrement = GBSerializedSGBFlagsGetIncrement(flags);
267
268 // Old versions of mGBA stored the increment bits here
269 if (gb->sgbBit > 129 && gb->sgbBit & 2) {
270 gb->sgbIncrement = true;
271 }
272
273 memcpy(gb->video.sgbPacketBuffer, state->sgb.packet, sizeof(state->sgb.packet));
274 memcpy(gb->sgbPacket, state->sgb.inProgressPacket, sizeof(state->sgb.inProgressPacket));
275
276 if (!gb->video.renderer->sgbCharRam) {
277 gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
278 }
279 if (!gb->video.renderer->sgbMapRam) {
280 gb->video.renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
281 }
282 if (!gb->video.renderer->sgbPalRam) {
283 gb->video.renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
284 }
285 if (!gb->video.renderer->sgbAttributeFiles) {
286 gb->video.renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
287 }
288 if (!gb->video.renderer->sgbAttributes) {
289 gb->video.renderer->sgbAttributes = malloc(90 * 45);
290 }
291
292 memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
293 memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
294 memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
295 memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
296 memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));
297
298 GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
299}