all repos — mgba @ c213ee9bb6f91e65af778d818772e7d36971b824

mGBA Game Boy Advance Emulator

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