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 "serialize.h"
7
8mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate");
9
10#ifdef _MSC_VER
11#include <time.h>
12#else
13#include <sys/time.h>
14#endif
15
16const uint32_t GB_SAVESTATE_MAGIC = 0x00400000;
17const uint32_t GB_SAVESTATE_VERSION = 0x00000000;
18
19void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
20 STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
21 STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
22
23 if (gb->memory.rom) {
24 memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title));
25 } else {
26 memset(state->title, 0, sizeof(state->title));
27 }
28
29 state->model = gb->model;
30
31 state->cpu.a = gb->cpu->a;
32 state->cpu.f = gb->cpu->f.packed;
33 state->cpu.b = gb->cpu->b;
34 state->cpu.c = gb->cpu->c;
35 state->cpu.d = gb->cpu->d;
36 state->cpu.e = gb->cpu->e;
37 state->cpu.h = gb->cpu->h;
38 state->cpu.l = gb->cpu->l;
39 STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp);
40 STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc);
41
42 STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
43 STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
44
45 STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
46 state->cpu.bus = gb->cpu->bus;
47 state->cpu.executionState = gb->cpu->executionState;
48 STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
49
50 state->cpu.condition = gb->cpu->condition;
51 state->cpu.irqPending = gb->cpu->irqPending;
52
53 state->cpu.doubleSpeed = gb->doubleSpeed;
54
55 GBMemorySerialize(&gb->memory, state);
56 GBIOSerialize(gb, state);
57 GBVideoSerialize(&gb->video, state);
58 GBTimerSerialize(&gb->timer, state);
59 GBAudioSerialize(&gb->audio, state);
60
61#ifndef _MSC_VER
62 struct timeval tv;
63 if (!gettimeofday(&tv, 0)) {
64 uint64_t usec = tv.tv_usec;
65 usec += tv.tv_sec * 1000000LL;
66 STORE_64LE(usec, 0, &state->creationUsec);
67 }
68#else
69 struct timespec ts;
70 if (timespec_get(&ts, TIME_UTC)) {
71 uint64_t usec = ts.tv_nsec / 1000;
72 usec += ts.tv_sec * 1000000LL;
73 STORE_64LE(usec, 0, &state->creationUsec);
74 }
75#endif
76 else {
77 state->creationUsec = 0;
78 }
79}
80
81bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
82 bool error = false;
83 int32_t check;
84 uint32_t ucheck;
85 LOAD_32LE(ucheck, 0, &state->versionMagic);
86 if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
87 mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
88 error = true;
89 } else if (ucheck < GB_SAVESTATE_MAGIC) {
90 mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
91 error = true;
92 } else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
93 mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
94 }
95
96 if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
97 mLOG(GB_STATE, WARN, "Savestate is for a different game");
98 error = true;
99 }
100 LOAD_32LE(ucheck, 0, &state->romCrc32);
101 if (ucheck != gb->romCrc32) {
102 mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
103 }
104 LOAD_32LE(check, 0, &state->cpu.cycles);
105 if (check < 0) {
106 mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
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_32LE(check, 0, &state->video.eventDiff);
114 if (check < 0) {
115 mLOG(GB_STATE, WARN, "Savestate is corrupted: video eventDiff is negative");
116 error = true;
117 }
118 if (error) {
119 return false;
120 }
121
122 gb->cpu->a = state->cpu.a;
123 gb->cpu->f.packed = state->cpu.f;
124 gb->cpu->b = state->cpu.b;
125 gb->cpu->c = state->cpu.c;
126 gb->cpu->d = state->cpu.d;
127 gb->cpu->e = state->cpu.e;
128 gb->cpu->h = state->cpu.h;
129 gb->cpu->l = state->cpu.l;
130 LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
131 LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);
132
133 LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
134 gb->cpu->bus = state->cpu.bus;
135 gb->cpu->executionState = state->cpu.executionState;
136 LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
137
138 gb->cpu->condition = state->cpu.condition;
139 gb->cpu->irqPending = state->cpu.irqPending;
140
141 gb->doubleSpeed = state->cpu.doubleSpeed;
142
143 LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
144 LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
145
146 gb->model = state->model;
147
148 if (gb->model < GB_MODEL_CGB) {
149 gb->audio.style = GB_AUDIO_DMG;
150 } else {
151 gb->audio.style = GB_AUDIO_CGB;
152 }
153
154 GBMemoryDeserialize(&gb->memory, state);
155 GBIODeserialize(gb, state);
156 GBVideoDeserialize(&gb->video, state);
157 GBTimerDeserialize(&gb->timer, state);
158 GBAudioDeserialize(&gb->audio, state);
159
160 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
161
162 return true;
163}