all repos — mgba @ bd085ad3726cce0a406641ed280a06e302dfc686

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