all repos — mgba @ 74fc29fc68e7ae84f0c27130d1d98299434ce6f2

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
 17// Some testing was done here...
 18// Erase cycles can vary greatly.
 19// Some games may vary anywhere between about 2000 cycles to up to 30000 cycles. (Observed on a Macronix (09C2) chip).
 20// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip).
 21// An average estimation is as follows.
 22#define FLASH_SETTLE_CYCLES 18000
 23#define CLEANUP_THRESHOLD 15
 24
 25static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
 26static void _flashErase(struct GBASavedata* savedata);
 27static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);
 28
 29void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
 30	savedata->type = SAVEDATA_AUTODETECT;
 31	savedata->data = 0;
 32	savedata->command = EEPROM_COMMAND_NULL;
 33	savedata->flashState = FLASH_STATE_RAW;
 34	savedata->vf = vf;
 35	savedata->realVf = vf;
 36	savedata->mapMode = MAP_WRITE;
 37	savedata->dirty = 0;
 38	savedata->dirtAge = 0;
 39}
 40
 41void GBASavedataDeinit(struct GBASavedata* savedata) {
 42	if (savedata->vf) {
 43		switch (savedata->type) {
 44		case SAVEDATA_SRAM:
 45			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM);
 46			break;
 47		case SAVEDATA_FLASH512:
 48			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
 49			break;
 50		case SAVEDATA_FLASH1M:
 51			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M);
 52			break;
 53		case SAVEDATA_EEPROM:
 54			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM);
 55			break;
 56		case SAVEDATA_FORCE_NONE:
 57		case SAVEDATA_AUTODETECT:
 58			break;
 59		}
 60		savedata->vf = 0;
 61	} else {
 62		switch (savedata->type) {
 63		case SAVEDATA_SRAM:
 64			mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
 65			break;
 66		case SAVEDATA_FLASH512:
 67			mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
 68			break;
 69		case SAVEDATA_FLASH1M:
 70			mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M);
 71			break;
 72		case SAVEDATA_EEPROM:
 73			mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
 74			break;
 75		case SAVEDATA_FORCE_NONE:
 76		case SAVEDATA_AUTODETECT:
 77			break;
 78		}
 79	}
 80	savedata->data = 0;
 81	savedata->type = SAVEDATA_AUTODETECT;
 82}
 83
 84void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
 85	GBASavedataDeinit(savedata);
 86	savedata->vf = vf;
 87	savedata->mapMode = MAP_READ;
 88}
 89
 90void GBASavedataUnmask(struct GBASavedata* savedata) {
 91	if (savedata->mapMode != MAP_READ) {
 92		return;
 93	}
 94	GBASavedataDeinit(savedata);
 95	savedata->vf = savedata->realVf;
 96	savedata->mapMode = MAP_WRITE;
 97}
 98
 99bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
100	if (savedata->data) {
101		switch (savedata->type) {
102		case SAVEDATA_SRAM:
103			return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
104		case SAVEDATA_FLASH512:
105			return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
106		case SAVEDATA_FLASH1M:
107			return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
108		case SAVEDATA_EEPROM:
109			return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
110		case SAVEDATA_AUTODETECT:
111		case SAVEDATA_FORCE_NONE:
112			return true;
113		}
114	} else if (savedata->vf) {
115		off_t read = 0;
116		uint8_t buffer[2048];
117		do {
118			read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
119			out->write(out, buffer, read);
120		} while (read == sizeof(buffer));
121		return read >= 0;
122	}
123	return true;
124}
125
126bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) {
127	if (savedata->data) {
128		switch (savedata->type) {
129		case SAVEDATA_SRAM:
130			return in->read(in, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
131		case SAVEDATA_FLASH512:
132			return in->read(in, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
133		case SAVEDATA_FLASH1M:
134			return in->read(in, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
135		case SAVEDATA_EEPROM:
136			return in->read(in, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
137		case SAVEDATA_AUTODETECT:
138		case SAVEDATA_FORCE_NONE:
139			return true;
140		}
141	} else if (savedata->vf) {
142		off_t read = 0;
143		uint8_t buffer[2048];
144		do {
145			in->read(in, buffer, read);
146			read = savedata->vf->write(savedata->vf, buffer, sizeof(buffer));
147		} while (read == sizeof(buffer));
148		return read >= 0;
149	}
150	return true;
151}
152
153void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming) {
154	if (savedata->type != SAVEDATA_AUTODETECT) {
155		struct VFile* vf = savedata->vf;
156		GBASavedataDeinit(savedata);
157		GBASavedataInit(savedata, vf);
158	}
159	switch (type) {
160	case SAVEDATA_FLASH512:
161	case SAVEDATA_FLASH1M:
162		savedata->type = type;
163		GBASavedataInitFlash(savedata, realisticTiming);
164		break;
165	case SAVEDATA_EEPROM:
166		GBASavedataInitEEPROM(savedata);
167		break;
168	case SAVEDATA_SRAM:
169		GBASavedataInitSRAM(savedata);
170		break;
171	case SAVEDATA_FORCE_NONE:
172		savedata->type = SAVEDATA_FORCE_NONE;
173		break;
174	case SAVEDATA_AUTODETECT:
175		break;
176	}
177}
178
179void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming) {
180	if (savedata->type == SAVEDATA_AUTODETECT) {
181		savedata->type = SAVEDATA_FLASH512;
182	}
183	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
184		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
185		return;
186	}
187	int32_t flashSize = SIZE_CART_FLASH512;
188	if (savedata->type == SAVEDATA_FLASH1M) {
189		flashSize = SIZE_CART_FLASH1M;
190	}
191	off_t end;
192	if (!savedata->vf) {
193		end = 0;
194		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
195	} else {
196		end = savedata->vf->size(savedata->vf);
197		if (end < flashSize) {
198			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
199			flashSize = SIZE_CART_FLASH1M;
200		}
201		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
202	}
203
204	savedata->currentBank = savedata->data;
205	savedata->dust = 0;
206	savedata->realisticTiming = realisticTiming;
207	if (end < SIZE_CART_FLASH512) {
208		memset(&savedata->data[end], 0xFF, flashSize - end);
209	}
210}
211
212void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
213	if (savedata->type == SAVEDATA_AUTODETECT) {
214		savedata->type = SAVEDATA_EEPROM;
215	} else {
216		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
217		return;
218	}
219	off_t end;
220	if (!savedata->vf) {
221		end = 0;
222		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
223	} else {
224		end = savedata->vf->size(savedata->vf);
225		if (end < SIZE_CART_EEPROM) {
226			savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
227		}
228		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
229	}
230	if (end < SIZE_CART_EEPROM) {
231		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
232	}
233}
234
235void GBASavedataInitSRAM(struct GBASavedata* savedata) {
236	if (savedata->type == SAVEDATA_AUTODETECT) {
237		savedata->type = SAVEDATA_SRAM;
238	} else {
239		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
240		return;
241	}
242	off_t end;
243	if (!savedata->vf) {
244		end = 0;
245		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
246	} else {
247		end = savedata->vf->size(savedata->vf);
248		if (end < SIZE_CART_SRAM) {
249			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
250		}
251		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
252	}
253
254	if (end < SIZE_CART_SRAM) {
255		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
256	}
257}
258
259uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
260	if (savedata->command == FLASH_COMMAND_ID) {
261		if (savedata->type == SAVEDATA_FLASH512) {
262			if (address < 2) {
263				return FLASH_MFG_PANASONIC >> (address * 8);
264			}
265		} else if (savedata->type == SAVEDATA_FLASH1M) {
266			if (address < 2) {
267				return FLASH_MFG_SANYO >> (address * 8);
268			}
269		}
270	}
271	if (savedata->dust > 0 && (address >> 12) == savedata->settling) {
272		// Give some overhead for waitstates and the comparison
273		// This estimation can probably be improved
274		savedata->dust -= 10;
275		return 0x5F;
276	}
277	return savedata->currentBank[address];
278}
279
280void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
281	switch (savedata->flashState) {
282	case FLASH_STATE_RAW:
283		switch (savedata->command) {
284		case FLASH_COMMAND_PROGRAM:
285			savedata->dirty |= SAVEDATA_DIRT_NEW;
286			savedata->currentBank[address] = value;
287			savedata->command = FLASH_COMMAND_NONE;
288			break;
289		case FLASH_COMMAND_SWITCH_BANK:
290			if (address == 0 && value < 2) {
291				_flashSwitchBank(savedata, value);
292			} else {
293				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
294				savedata->command = FLASH_COMMAND_NONE;
295			}
296			savedata->command = FLASH_COMMAND_NONE;
297			break;
298		default:
299			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
300				savedata->flashState = FLASH_STATE_START;
301			} else {
302				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
303			}
304			break;
305		}
306		break;
307	case FLASH_STATE_START:
308		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
309			savedata->flashState = FLASH_STATE_CONTINUE;
310		} else {
311			GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
312			savedata->flashState = FLASH_STATE_RAW;
313		}
314		break;
315	case FLASH_STATE_CONTINUE:
316		savedata->flashState = FLASH_STATE_RAW;
317		if (address == FLASH_BASE_HI) {
318			switch (savedata->command) {
319			case FLASH_COMMAND_NONE:
320				switch (value) {
321				case FLASH_COMMAND_ERASE:
322				case FLASH_COMMAND_ID:
323				case FLASH_COMMAND_PROGRAM:
324				case FLASH_COMMAND_SWITCH_BANK:
325					savedata->command = value;
326					break;
327				default:
328					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
329					break;
330				}
331				break;
332			case FLASH_COMMAND_ERASE:
333				switch (value) {
334				case FLASH_COMMAND_ERASE_CHIP:
335					_flashErase(savedata);
336					break;
337				default:
338					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
339					break;
340				}
341				savedata->command = FLASH_COMMAND_NONE;
342				break;
343			case FLASH_COMMAND_ID:
344				if (value == FLASH_COMMAND_TERMINATE) {
345					savedata->command = FLASH_COMMAND_NONE;
346				}
347				break;
348			default:
349				GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
350				savedata->command = FLASH_COMMAND_NONE;
351				break;
352			}
353		} else if (savedata->command == FLASH_COMMAND_ERASE) {
354			if (value == FLASH_COMMAND_ERASE_SECTOR) {
355				_flashEraseSector(savedata, address);
356				savedata->command = FLASH_COMMAND_NONE;
357			} else {
358				GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
359			}
360		}
361		break;
362	}
363}
364
365void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
366	switch (savedata->command) {
367	// Read header
368	case EEPROM_COMMAND_NULL:
369	default:
370		savedata->command = value & 0x1;
371		break;
372	case EEPROM_COMMAND_PENDING:
373		savedata->command <<= 1;
374		savedata->command |= value & 0x1;
375		if (savedata->command == EEPROM_COMMAND_WRITE) {
376			savedata->writeAddress = 0;
377		} else {
378			savedata->readAddress = 0;
379		}
380		break;
381	// Do commands
382	case EEPROM_COMMAND_WRITE:
383		// Write
384		if (writeSize > 65) {
385			savedata->writeAddress <<= 1;
386			savedata->writeAddress |= (value & 0x1) << 6;
387		} else if (writeSize == 1) {
388			savedata->command = EEPROM_COMMAND_NULL;
389		} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
390			uint8_t current = savedata->data[savedata->writeAddress >> 3];
391			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
392			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
393			savedata->dirty |= SAVEDATA_DIRT_NEW;
394			savedata->data[savedata->writeAddress >> 3] = current;
395			++savedata->writeAddress;
396		} else {
397			GBALog(0, GBA_LOG_GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));
398		}
399		break;
400	case EEPROM_COMMAND_READ_PENDING:
401		// Read
402		if (writeSize > 1) {
403			savedata->readAddress <<= 1;
404			if (value & 0x1) {
405				savedata->readAddress |= 0x40;
406			}
407		} else {
408			savedata->readBitsRemaining = 68;
409			savedata->command = EEPROM_COMMAND_READ;
410		}
411		break;
412	}
413}
414
415uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
416	if (savedata->command != EEPROM_COMMAND_READ) {
417		return 1;
418	}
419	--savedata->readBitsRemaining;
420	if (savedata->readBitsRemaining < 64) {
421		int step = 63 - savedata->readBitsRemaining;
422		uint32_t address = (savedata->readAddress + step) >> 3;
423		if (address >= SIZE_CART_EEPROM) {
424			GBALog(0, GBA_LOG_GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
425			return 0xFF;
426		}
427		uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));
428		if (!savedata->readBitsRemaining) {
429			savedata->command = EEPROM_COMMAND_NULL;
430		}
431		return data & 0x1;
432	}
433	return 0;
434}
435
436void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
437	if (!savedata->vf) {
438		return;
439	}
440	if (savedata->dirty & SAVEDATA_DIRT_NEW) {
441		savedata->dirty &= ~SAVEDATA_DIRT_NEW;
442		if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
443			savedata->dirtAge = frameCount;
444			savedata->dirty |= SAVEDATA_DIRT_SEEN;
445		}
446	} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
447		size_t size;
448		switch (savedata->type) {
449		case SAVEDATA_EEPROM:
450			size = SIZE_CART_EEPROM;
451			break;
452		case SAVEDATA_SRAM:
453			size = SIZE_CART_SRAM;
454			break;
455		case SAVEDATA_FLASH512:
456			size = SIZE_CART_FLASH512;
457			break;
458		case SAVEDATA_FLASH1M:
459			size = SIZE_CART_FLASH1M;
460			break;
461		default:
462			size = 0;
463			break;
464		}
465		savedata->vf->sync(savedata->vf, savedata->data, size);
466		savedata->dirty = 0;
467		GBALog(0, GBA_LOG_INFO, "Savedata synced");
468	}
469}
470
471void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state) {
472	state->savedata.type = savedata->type;
473	state->savedata.command = savedata->command;
474	GBASerializedSavedataFlags flags = 0;
475	flags = GBASerializedSavedataFlagsSetFlashState(flags, savedata->flashState);
476	flags = GBASerializedSavedataFlagsTestFillFlashBank(flags, savedata->currentBank == &savedata->data[0x10000]);
477	state->savedata.flags = flags;
478	STORE_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining);
479	STORE_32(savedata->readAddress, 0, &state->savedata.readAddress);
480	STORE_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
481	STORE_16(savedata->settling, 0, &state->savedata.settlingSector);
482	STORE_16(savedata->dust, 0, &state->savedata.settlingDust);
483}
484
485void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state) {
486	if (state->savedata.type == SAVEDATA_FORCE_NONE) {
487		return;
488	}
489	if (savedata->type != state->savedata.type) {
490		GBASavedataForceType(savedata, state->savedata.type, savedata->realisticTiming);
491	}
492	savedata->command = state->savedata.command;
493	GBASerializedSavedataFlags flags = state->savedata.flags;
494	savedata->flashState = GBASerializedSavedataFlagsGetFlashState(flags);
495	LOAD_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining);
496	LOAD_32(savedata->readAddress, 0, &state->savedata.readAddress);
497	LOAD_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
498	LOAD_16(savedata->settling, 0, &state->savedata.settlingSector);
499	LOAD_16(savedata->dust, 0, &state->savedata.settlingDust);
500
501	if (savedata->type == SAVEDATA_FLASH1M) {
502		_flashSwitchBank(savedata, GBASerializedSavedataFlagsGetFlashBank(flags));
503	}
504}
505
506void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
507	GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank);
508	savedata->currentBank = &savedata->data[bank << 16];
509	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
510		savedata->type = SAVEDATA_FLASH1M;
511		if (savedata->vf) {
512			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
513			memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
514		}
515	}
516}
517
518void _flashErase(struct GBASavedata* savedata) {
519	GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
520	savedata->dirty |= SAVEDATA_DIRT_NEW;
521	size_t size = SIZE_CART_FLASH512;
522	if (savedata->type == SAVEDATA_FLASH1M) {
523		size = SIZE_CART_FLASH1M;
524	}
525	memset(savedata->data, 0xFF, size);
526}
527
528void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
529	GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
530	savedata->dirty |= SAVEDATA_DIRT_NEW;
531	size_t size = 0x1000;
532	if (savedata->type == SAVEDATA_FLASH1M) {
533		GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
534	}
535	savedata->settling = sectorStart >> 12;
536	if (savedata->realisticTiming) {
537		savedata->dust = FLASH_SETTLE_CYCLES;
538	}
539	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
540}