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");
13
14#ifdef _MSC_VER
15#include <time.h>
16#else
17#include <sys/time.h>
18#endif
19
20const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
21const uint32_t GB_SAVESTATE_VERSION = 0x00000001;
22
23void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
24 STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
25 STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
26 STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
27
28 if (gb->memory.rom) {
29 memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->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 STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
54
55 GBSerializedCpuFlags flags = 0;
56 flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
57 flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending);
58 flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed);
59 flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending));
60 STORE_32LE(flags, 0, &state->cpu.flags);
61 STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending);
62
63 GBMemorySerialize(gb, state);
64 GBIOSerialize(gb, state);
65 GBVideoSerialize(&gb->video, state);
66 GBTimerSerialize(&gb->timer, state);
67 GBAudioSerialize(&gb->audio, state);
68
69#ifndef _MSC_VER
70 struct timeval tv;
71 if (!gettimeofday(&tv, 0)) {
72 uint64_t usec = tv.tv_usec;
73 usec += tv.tv_sec * 1000000LL;
74 STORE_64LE(usec, 0, &state->creationUsec);
75 }
76#else
77 struct timespec ts;
78 if (timespec_get(&ts, TIME_UTC)) {
79 uint64_t usec = ts.tv_nsec / 1000;
80 usec += ts.tv_sec * 1000000LL;
81 STORE_64LE(usec, 0, &state->creationUsec);
82 }
83#endif
84 else {
85 state->creationUsec = 0;
86 }
87}
88
89bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
90 bool error = false;
91 int32_t check;
92 uint32_t ucheck;
93 int16_t check16;
94 uint16_t ucheck16;
95 LOAD_32LE(ucheck, 0, &state->versionMagic);
96 if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
97 mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
98 error = true;
99 } else if (ucheck < GB_SAVESTATE_MAGIC) {
100 mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
101 error = true;
102 } else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
103 mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
104 }
105
106 if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
107 mLOG(GB_STATE, WARN, "Savestate is for a different game");
108 error = true;
109 }
110 LOAD_32LE(ucheck, 0, &state->romCrc32);
111 if (ucheck != gb->romCrc32) {
112 mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
113 }
114 LOAD_32LE(check, 0, &state->cpu.cycles);
115 if (check < 0) {
116 mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
117 error = true;
118 }
119 if (state->cpu.executionState != LR35902_CORE_FETCH) {
120 mLOG(GB_STATE, WARN, "Savestate is corrupted: Execution state is not FETCH");
121 error = true;
122 }
123 if (check >= (int32_t) DMG_LR35902_FREQUENCY) {
124 mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
125 error = true;
126 }
127 LOAD_16LE(check16, 0, &state->video.x);
128 if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
129 mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
130 error = true;
131 }
132 LOAD_16LE(check16, 0, &state->video.ly);
133 if (check16 < 0 || check16 > GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
134 mLOG(GB_STATE, WARN, "Savestate is corrupted: video y is out of range");
135 error = true;
136 }
137 LOAD_16LE(ucheck16, 0, &state->memory.dmaDest);
138 if (ucheck16 + state->memory.dmaRemaining > GB_SIZE_OAM) {
139 mLOG(GB_STATE, WARN, "Savestate is corrupted: DMA destination is out of range");
140 error = true;
141 }
142 LOAD_16LE(ucheck16, 0, &state->video.bcpIndex);
143 if (ucheck16 >= 0x40) {
144 mLOG(GB_STATE, WARN, "Savestate is corrupted: BCPS is out of range");
145 }
146 LOAD_16LE(ucheck16, 0, &state->video.ocpIndex);
147 if (ucheck16 >= 0x40) {
148 mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
149 }
150 if (error) {
151 return false;
152 }
153
154 gb->cpu->a = state->cpu.a;
155 gb->cpu->f.packed = state->cpu.f;
156 gb->cpu->b = state->cpu.b;
157 gb->cpu->c = state->cpu.c;
158 gb->cpu->d = state->cpu.d;
159 gb->cpu->e = state->cpu.e;
160 gb->cpu->h = state->cpu.h;
161 gb->cpu->l = state->cpu.l;
162 LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
163 LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
164
165 LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
166 gb->cpu->bus = state->cpu.bus;
167 gb->cpu->executionState = state->cpu.executionState;
168 LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
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->audio.timingFactor = gb->doubleSpeed + 1;
176
177 uint32_t when;
178 LOAD_32LE(when, 0, &state->cpu.eiPending);
179 mTimingDeschedule(&gb->timing, &gb->eiPending);
180 if (GBSerializedCpuFlagsIsEiPending(flags)) {
181 mTimingSchedule(&gb->timing, &gb->eiPending, when);
182 }
183
184 LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
185 LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
186 LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
187
188 gb->model = state->model;
189
190 if (gb->model < GB_MODEL_CGB) {
191 gb->audio.style = GB_AUDIO_DMG;
192 } else {
193 gb->audio.style = GB_AUDIO_CGB;
194 }
195
196 GBMemoryDeserialize(gb, state);
197 GBIODeserialize(gb, state);
198 GBVideoDeserialize(&gb->video, state);
199 GBTimerDeserialize(&gb->timer, state);
200 GBAudioDeserialize(&gb->audio, state);
201
202 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
203
204 return true;
205}