all repos — mgba @ 1d021a72c7a1245adeceecd706dbebfb739f6247

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
  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}