all repos — mgba @ ce0adb6c001719a6e22e5f42af1107dad310be21

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