all repos — mgba @ c3f69e7b693ae568e33d83cee264040c2db3d516

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