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}