all repos — mgba @ c1d02a1369df031fc877b1800ae5f9f08df5df7b

mGBA Game Boy Advance Emulator

src/gba/savedata.c (view raw)

  1/* Copyright (c) 2013-2015 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 "savedata.h"
  7
  8#include "gba/gba.h"
  9#include "gba/serialize.h"
 10
 11#include "util/memory.h"
 12#include "util/vfs.h"
 13
 14#include <errno.h>
 15#include <fcntl.h>
 16
 17static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
 18static void _flashErase(struct GBASavedata* savedata);
 19static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);
 20
 21void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
 22	savedata->type = SAVEDATA_AUTODETECT;
 23	savedata->data = 0;
 24	savedata->command = EEPROM_COMMAND_NULL;
 25	savedata->flashState = FLASH_STATE_RAW;
 26	savedata->vf = vf;
 27	savedata->realVf = vf;
 28	savedata->mapMode = MAP_WRITE;
 29}
 30
 31void GBASavedataDeinit(struct GBASavedata* savedata) {
 32	if (savedata->vf) {
 33		switch (savedata->type) {
 34		case SAVEDATA_SRAM:
 35			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM);
 36			break;
 37		case SAVEDATA_FLASH512:
 38			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
 39			break;
 40		case SAVEDATA_FLASH1M:
 41			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M);
 42			break;
 43		case SAVEDATA_EEPROM:
 44			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM);
 45			break;
 46		case SAVEDATA_FORCE_NONE:
 47		case SAVEDATA_AUTODETECT:
 48			break;
 49		}
 50		savedata->vf = 0;
 51	} else {
 52		switch (savedata->type) {
 53		case SAVEDATA_SRAM:
 54			mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
 55			break;
 56		case SAVEDATA_FLASH512:
 57			mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
 58			break;
 59		case SAVEDATA_FLASH1M:
 60			mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M);
 61			break;
 62		case SAVEDATA_EEPROM:
 63			mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
 64			break;
 65		case SAVEDATA_FORCE_NONE:
 66		case SAVEDATA_AUTODETECT:
 67			break;
 68		}
 69	}
 70	savedata->data = 0;
 71	savedata->type = SAVEDATA_AUTODETECT;
 72}
 73
 74void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
 75	GBASavedataDeinit(savedata);
 76	savedata->vf = vf;
 77	savedata->mapMode = MAP_READ;
 78}
 79
 80void GBASavedataUnmask(struct GBASavedata* savedata) {
 81	if (savedata->mapMode != MAP_READ) {
 82		return;
 83	}
 84	GBASavedataDeinit(savedata);
 85	savedata->vf = savedata->realVf;
 86	savedata->mapMode = MAP_WRITE;
 87}
 88
 89bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
 90	if (savedata->data) {
 91		switch (savedata->type) {
 92		case SAVEDATA_SRAM:
 93			return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
 94		case SAVEDATA_FLASH512:
 95			return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
 96		case SAVEDATA_FLASH1M:
 97			return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
 98		case SAVEDATA_EEPROM:
 99			return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
100		case SAVEDATA_AUTODETECT:
101		case SAVEDATA_FORCE_NONE:
102			return true;
103		}
104	} else if (savedata->vf) {
105		off_t read = 0;
106		uint8_t buffer[2048];
107		do {
108			read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
109			out->write(out, buffer, read);
110		} while (read == sizeof(buffer));
111		return read >= 0;
112	}
113	return true;
114}
115
116void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) {
117	if (savedata->type != SAVEDATA_AUTODETECT) {
118		struct VFile* vf = savedata->vf;
119		GBASavedataDeinit(savedata);
120		GBASavedataInit(savedata, vf);
121	}
122	switch (type) {
123	case SAVEDATA_FLASH512:
124	case SAVEDATA_FLASH1M:
125		savedata->type = type;
126		GBASavedataInitFlash(savedata);
127		break;
128	case SAVEDATA_EEPROM:
129		GBASavedataInitEEPROM(savedata);
130		break;
131	case SAVEDATA_SRAM:
132		GBASavedataInitSRAM(savedata);
133		break;
134	case SAVEDATA_FORCE_NONE:
135		savedata->type = SAVEDATA_FORCE_NONE;
136		break;
137	case SAVEDATA_AUTODETECT:
138		break;
139	}
140}
141
142void GBASavedataInitFlash(struct GBASavedata* savedata) {
143	if (savedata->type == SAVEDATA_AUTODETECT) {
144		savedata->type = SAVEDATA_FLASH512;
145	}
146	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
147		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
148		return;
149	}
150	size_t flashSize = SIZE_CART_FLASH512;
151	off_t end;
152	if (!savedata->vf) {
153		end = 0;
154		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
155	} else {
156		end = savedata->vf->size(savedata->vf);
157		if (end < SIZE_CART_FLASH512) {
158			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
159			flashSize = SIZE_CART_FLASH1M;
160		}
161		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
162	}
163
164	savedata->currentBank = savedata->data;
165	if (end < SIZE_CART_FLASH512) {
166		memset(&savedata->data[end], 0xFF, flashSize - end);
167	}
168}
169
170void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
171	if (savedata->type == SAVEDATA_AUTODETECT) {
172		savedata->type = SAVEDATA_EEPROM;
173	} else {
174		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
175		return;
176	}
177	off_t end;
178	if (!savedata->vf) {
179		end = 0;
180		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
181	} else {
182		end = savedata->vf->size(savedata->vf);
183		if (end < SIZE_CART_EEPROM) {
184			savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
185		}
186		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
187	}
188	if (end < SIZE_CART_EEPROM) {
189		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
190	}
191}
192
193void GBASavedataInitSRAM(struct GBASavedata* savedata) {
194	if (savedata->type == SAVEDATA_AUTODETECT) {
195		savedata->type = SAVEDATA_SRAM;
196	} else {
197		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
198		return;
199	}
200	off_t end;
201	if (!savedata->vf) {
202		end = 0;
203		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
204	} else {
205		end = savedata->vf->size(savedata->vf);
206		if (end < SIZE_CART_SRAM) {
207			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
208		}
209		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
210	}
211
212	if (end < SIZE_CART_SRAM) {
213		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
214	}
215}
216
217uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
218	if (savedata->command == FLASH_COMMAND_ID) {
219		if (savedata->type == SAVEDATA_FLASH512) {
220			if (address < 2) {
221				return FLASH_MFG_PANASONIC >> (address * 8);
222			}
223		} else if (savedata->type == SAVEDATA_FLASH1M) {
224			if (address < 2) {
225				return FLASH_MFG_SANYO >> (address * 8);
226			}
227		}
228	}
229	return savedata->currentBank[address];
230}
231
232void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
233	switch (savedata->flashState) {
234	case FLASH_STATE_RAW:
235		switch (savedata->command) {
236		case FLASH_COMMAND_PROGRAM:
237			savedata->currentBank[address] = value;
238			savedata->command = FLASH_COMMAND_NONE;
239			break;
240		case FLASH_COMMAND_SWITCH_BANK:
241			if (address == 0 && value < 2) {
242				_flashSwitchBank(savedata, value);
243			} else {
244				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
245				savedata->command = FLASH_COMMAND_NONE;
246			}
247			savedata->command = FLASH_COMMAND_NONE;
248			break;
249		default:
250			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
251				savedata->flashState = FLASH_STATE_START;
252			} else {
253				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
254			}
255			break;
256		}
257		break;
258	case FLASH_STATE_START:
259		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
260			savedata->flashState = FLASH_STATE_CONTINUE;
261		} else {
262			GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
263			savedata->flashState = FLASH_STATE_RAW;
264		}
265		break;
266	case FLASH_STATE_CONTINUE:
267		savedata->flashState = FLASH_STATE_RAW;
268		if (address == FLASH_BASE_HI) {
269			switch (savedata->command) {
270			case FLASH_COMMAND_NONE:
271				switch (value) {
272				case FLASH_COMMAND_ERASE:
273				case FLASH_COMMAND_ID:
274				case FLASH_COMMAND_PROGRAM:
275				case FLASH_COMMAND_SWITCH_BANK:
276					savedata->command = value;
277					break;
278				default:
279					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
280					break;
281				}
282				break;
283			case FLASH_COMMAND_ERASE:
284				switch (value) {
285				case FLASH_COMMAND_ERASE_CHIP:
286					_flashErase(savedata);
287					break;
288				default:
289					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
290					break;
291				}
292				savedata->command = FLASH_COMMAND_NONE;
293				break;
294			case FLASH_COMMAND_ID:
295				if (value == FLASH_COMMAND_TERMINATE) {
296					savedata->command = FLASH_COMMAND_NONE;
297				}
298				break;
299			default:
300				GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
301				savedata->command = FLASH_COMMAND_NONE;
302				break;
303			}
304		} else if (savedata->command == FLASH_COMMAND_ERASE) {
305			if (value == FLASH_COMMAND_ERASE_SECTOR) {
306				_flashEraseSector(savedata, address);
307				savedata->command = FLASH_COMMAND_NONE;
308			} else {
309				GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
310			}
311		}
312		break;
313	}
314}
315
316void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
317	switch (savedata->command) {
318	// Read header
319	case EEPROM_COMMAND_NULL:
320	default:
321		savedata->command = value & 0x1;
322		break;
323	case EEPROM_COMMAND_PENDING:
324		savedata->command <<= 1;
325		savedata->command |= value & 0x1;
326		if (savedata->command == EEPROM_COMMAND_WRITE) {
327			savedata->writeAddress = 0;
328		} else {
329			savedata->readAddress = 0;
330		}
331		break;
332	// Do commands
333	case EEPROM_COMMAND_WRITE:
334		// Write
335		if (writeSize > 65) {
336			savedata->writeAddress <<= 1;
337			savedata->writeAddress |= (value & 0x1) << 6;
338		} else if (writeSize == 1) {
339			savedata->command = EEPROM_COMMAND_NULL;
340		} else {
341			uint8_t current = savedata->data[savedata->writeAddress >> 3];
342			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
343			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
344			savedata->data[savedata->writeAddress >> 3] = current;
345			++savedata->writeAddress;
346		}
347		break;
348	case EEPROM_COMMAND_READ_PENDING:
349		// Read
350		if (writeSize > 1) {
351			savedata->readAddress <<= 1;
352			if (value & 0x1) {
353				savedata->readAddress |= 0x40;
354			}
355		} else {
356			savedata->readBitsRemaining = 68;
357			savedata->command = EEPROM_COMMAND_READ;
358		}
359		break;
360	}
361}
362
363uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
364	if (savedata->command != EEPROM_COMMAND_READ) {
365		return 1;
366	}
367	--savedata->readBitsRemaining;
368	if (savedata->readBitsRemaining < 64) {
369		int step = 63 - savedata->readBitsRemaining;
370		uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
371		if (!savedata->readBitsRemaining) {
372			savedata->command = EEPROM_COMMAND_NULL;
373		}
374		return data & 0x1;
375	}
376	return 0;
377}
378
379void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
380	state->savedata.type = savedata->type;
381	state->savedata.command = savedata->command;
382	state->savedata.flashState = savedata->flashState;
383	state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000];
384	state->savedata.readBitsRemaining = savedata->readBitsRemaining;
385	state->savedata.readAddress = savedata->readAddress;
386	state->savedata.writeAddress = savedata->writeAddress;
387
388	UNUSED(includeData); // TODO
389}
390
391void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData) {
392	if (state->savedata.type == SAVEDATA_FORCE_NONE) {
393		return;
394	}
395	if (savedata->type != state->savedata.type) {
396		GBASavedataForceType(savedata, state->savedata.type);
397	}
398	savedata->command = state->savedata.command;
399	savedata->flashState = state->savedata.flashState;
400	savedata->readBitsRemaining = state->savedata.readBitsRemaining;
401	savedata->readAddress = state->savedata.readAddress;
402	savedata->writeAddress = state->savedata.writeAddress;
403	if (savedata->type == SAVEDATA_FLASH1M) {
404		_flashSwitchBank(savedata, state->savedata.flashBank);
405	}
406
407	UNUSED(includeData); // TODO
408}
409
410void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
411	GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank);
412	savedata->currentBank = &savedata->data[bank << 16];
413	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
414		savedata->type = SAVEDATA_FLASH1M;
415		if (savedata->vf) {
416			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
417			memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
418		}
419	}
420}
421
422void _flashErase(struct GBASavedata* savedata) {
423	GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
424	size_t size = SIZE_CART_FLASH512;
425	if (savedata->type == SAVEDATA_FLASH1M) {
426		size = SIZE_CART_FLASH1M;
427	}
428	memset(savedata->data, 0xFF, size);
429}
430
431void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
432	GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
433	size_t size = 0x1000;
434	if (savedata->type == SAVEDATA_FLASH1M) {
435		GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
436	}
437	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
438}