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