all repos — mgba @ 65fb61d7e2f5848aac38a12d4042419bb4e537c9

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 <mgba/internal/gba/savedata.h>
  7
  8#include <mgba/internal/arm/macros.h>
  9#include <mgba/internal/gba/gba.h>
 10#include <mgba/internal/gba/serialize.h>
 11
 12#include <mgba-util/memory.h>
 13#include <mgba-util/vfs.h>
 14
 15#include <errno.h>
 16#include <fcntl.h>
 17
 18// Some testing was done here...
 19// Erase cycles can vary greatly.
 20// Some games may vary anywhere between about 2000 cycles to up to 30000 cycles. (Observed on a Macronix (09C2) chip).
 21// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip).
 22// An average estimation is as follows.
 23#define FLASH_ERASE_CYCLES 30000
 24#define FLASH_PROGRAM_CYCLES 650
 25// This needs real testing, and is only an estimation currently
 26#define EEPROM_SETTLE_CYCLES 115000
 27#define CLEANUP_THRESHOLD 15
 28
 29mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata", "gba.savedata");
 30
 31static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
 32static void _flashErase(struct GBASavedata* savedata);
 33static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);
 34
 35static void _ashesToAshes(struct mTiming* timing, void* user, uint32_t cyclesLate) {
 36	UNUSED(timing);
 37	UNUSED(user);
 38	UNUSED(cyclesLate);
 39	// Funk to funky
 40}
 41
 42void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
 43	savedata->type = SAVEDATA_AUTODETECT;
 44	savedata->data = 0;
 45	savedata->command = EEPROM_COMMAND_NULL;
 46	savedata->flashState = FLASH_STATE_RAW;
 47	savedata->vf = vf;
 48	savedata->realVf = vf;
 49	savedata->mapMode = MAP_WRITE;
 50	savedata->maskWriteback = false;
 51	savedata->dirty = 0;
 52	savedata->dirtAge = 0;
 53	savedata->dust.name = "GBA Savedata Settling";
 54	savedata->dust.priority = 0x70;
 55	savedata->dust.context = savedata;
 56	savedata->dust.callback = _ashesToAshes;
 57}
 58
 59void GBASavedataDeinit(struct GBASavedata* savedata) {
 60	if (savedata->vf) {
 61		size_t size = GBASavedataSize(savedata);
 62		if (savedata->data) {
 63			savedata->vf->unmap(savedata->vf, savedata->data, size);
 64		}
 65		savedata->vf = NULL;
 66	} else {
 67		switch (savedata->type) {
 68		case SAVEDATA_SRAM:
 69			mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
 70			break;
 71		case SAVEDATA_FLASH512:
 72			mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
 73			break;
 74		case SAVEDATA_FLASH1M:
 75			mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M);
 76			break;
 77		case SAVEDATA_EEPROM:
 78			mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
 79			break;
 80		case SAVEDATA_EEPROM512:
 81			mappedMemoryFree(savedata->data, SIZE_CART_EEPROM512);
 82			break;
 83		case SAVEDATA_FORCE_NONE:
 84		case SAVEDATA_AUTODETECT:
 85			break;
 86		}
 87	}
 88	savedata->data = 0;
 89	savedata->type = SAVEDATA_AUTODETECT;
 90}
 91
 92void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) {
 93	enum SavedataType type = savedata->type;
 94	struct VFile* oldVf = savedata->vf;
 95	GBASavedataDeinit(savedata);
 96	if (oldVf && oldVf != savedata->realVf) {
 97		oldVf->close(oldVf);
 98	}
 99	savedata->vf = vf;
100	savedata->mapMode = MAP_READ;
101	savedata->maskWriteback = writeback;
102	GBASavedataForceType(savedata, type);
103}
104
105void GBASavedataUnmask(struct GBASavedata* savedata) {
106	if (!savedata->realVf || savedata->vf == savedata->realVf) {
107		return;
108	}
109	enum SavedataType type = savedata->type;
110	struct VFile* vf = savedata->vf;
111	GBASavedataDeinit(savedata);
112	savedata->vf = savedata->realVf;
113	savedata->mapMode = MAP_WRITE;
114	GBASavedataForceType(savedata, type);
115	if (savedata->maskWriteback) {
116		GBASavedataLoad(savedata, vf);
117		savedata->maskWriteback = false;
118	}
119	vf->close(vf);
120}
121
122bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
123	if (savedata->data) {
124		switch (savedata->type) {
125		case SAVEDATA_SRAM:
126			return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
127		case SAVEDATA_FLASH512:
128			return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
129		case SAVEDATA_FLASH1M:
130			return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
131		case SAVEDATA_EEPROM:
132			return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
133		case SAVEDATA_EEPROM512:
134			return out->write(out, savedata->data, SIZE_CART_EEPROM512) == SIZE_CART_EEPROM512;
135		case SAVEDATA_AUTODETECT:
136		case SAVEDATA_FORCE_NONE:
137			return true;
138		}
139	} else if (savedata->vf) {
140		off_t read = 0;
141		uint8_t buffer[2048];
142		savedata->vf->seek(savedata->vf, 0, SEEK_SET);
143		do {
144			read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
145			out->write(out, buffer, read);
146		} while (read == sizeof(buffer));
147		return read >= 0;
148	}
149	return true;
150}
151
152size_t GBASavedataSize(const struct GBASavedata* savedata) {
153	switch (savedata->type) {
154	case SAVEDATA_SRAM:
155		return SIZE_CART_SRAM;
156	case SAVEDATA_FLASH512:
157		return SIZE_CART_FLASH512;
158	case SAVEDATA_FLASH1M:
159		return SIZE_CART_FLASH1M;
160	case SAVEDATA_EEPROM:
161		return SIZE_CART_EEPROM;
162	case SAVEDATA_EEPROM512:
163		return SIZE_CART_EEPROM512;
164	case SAVEDATA_FORCE_NONE:
165		return 0;
166	case SAVEDATA_AUTODETECT:
167	default:
168		if (savedata->vf) {
169			return savedata->vf->size(savedata->vf);
170		}
171		return 0;
172	}
173}
174
175bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) {
176	if (savedata->data) {
177		if (!in && savedata->type != SAVEDATA_FORCE_NONE) {
178			return false;
179		}
180		ssize_t size = GBASavedataSize(savedata);
181		in->seek(in, 0, SEEK_SET);
182		return in->read(in, savedata->data, size) == size;
183	} else if (savedata->vf) {
184		off_t read = 0;
185		uint8_t buffer[2048];
186		savedata->vf->seek(savedata->vf, 0, SEEK_SET);
187		if (in) {
188			in->seek(in, 0, SEEK_SET);
189			do {
190				read = in->read(in, buffer, sizeof(buffer));
191				read = savedata->vf->write(savedata->vf, buffer, read);
192			} while (read == sizeof(buffer));
193		}
194		memset(buffer, 0xFF, sizeof(buffer));
195		ssize_t fsize = savedata->vf->size(savedata->vf);
196		ssize_t pos = savedata->vf->seek(savedata->vf, 0, SEEK_CUR);
197		while (fsize - pos >= (ssize_t) sizeof(buffer)) {
198			savedata->vf->write(savedata->vf, buffer, sizeof(buffer));
199			pos = savedata->vf->seek(savedata->vf, 0, SEEK_CUR);
200		}
201		if (fsize - pos > 0) {
202			savedata->vf->write(savedata->vf, buffer, fsize - pos);
203		}
204		return read >= 0;
205	}
206	return true;
207}
208
209void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) {
210	if (savedata->type == type) {
211		return;
212	}
213	if (savedata->type != SAVEDATA_AUTODETECT) {
214		struct VFile* vf = savedata->vf;
215		int mapMode = savedata->mapMode;
216		bool maskWriteback = savedata->maskWriteback;
217		GBASavedataDeinit(savedata);
218		GBASavedataInit(savedata, vf);
219		savedata->mapMode = mapMode;
220		savedata->maskWriteback = maskWriteback;
221	}
222	switch (type) {
223	case SAVEDATA_FLASH512:
224	case SAVEDATA_FLASH1M:
225		savedata->type = type;
226		GBASavedataInitFlash(savedata);
227		break;
228	case SAVEDATA_EEPROM:
229	case SAVEDATA_EEPROM512:
230		savedata->type = type;
231		GBASavedataInitEEPROM(savedata);
232		break;
233	case SAVEDATA_SRAM:
234		GBASavedataInitSRAM(savedata);
235		break;
236	case SAVEDATA_FORCE_NONE:
237		savedata->type = SAVEDATA_FORCE_NONE;
238		break;
239	case SAVEDATA_AUTODETECT:
240		break;
241	}
242}
243
244void GBASavedataInitFlash(struct GBASavedata* savedata) {
245	if (savedata->type == SAVEDATA_AUTODETECT) {
246		savedata->type = SAVEDATA_FLASH512;
247	}
248	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
249		mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
250		return;
251	}
252	int32_t flashSize = SIZE_CART_FLASH512;
253	if (savedata->type == SAVEDATA_FLASH1M) {
254		flashSize = SIZE_CART_FLASH1M;
255	}
256	off_t end;
257	if (!savedata->vf) {
258		end = 0;
259		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
260	} else {
261		end = savedata->vf->size(savedata->vf);
262		if (end < flashSize) {
263			savedata->vf->truncate(savedata->vf, flashSize);
264		}
265		savedata->data = savedata->vf->map(savedata->vf, flashSize, savedata->mapMode);
266	}
267
268	savedata->currentBank = savedata->data;
269	if (end < SIZE_CART_FLASH512) {
270		memset(&savedata->data[end], 0xFF, flashSize - end);
271	}
272}
273
274void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
275	if (savedata->type == SAVEDATA_AUTODETECT) {
276		savedata->type = SAVEDATA_EEPROM512;
277	} else if (savedata->type != SAVEDATA_EEPROM512 && savedata->type != SAVEDATA_EEPROM) {
278		mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
279		return;
280	}
281	int32_t eepromSize = SIZE_CART_EEPROM512;
282	if (savedata->type == SAVEDATA_EEPROM) {
283		eepromSize = SIZE_CART_EEPROM;
284	}
285	off_t end;
286	if (!savedata->vf) {
287		end = 0;
288		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
289	} else {
290		end = savedata->vf->size(savedata->vf);
291		if (end < eepromSize) {
292			savedata->vf->truncate(savedata->vf, eepromSize);
293		}
294		savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode);
295	}
296	if (end < SIZE_CART_EEPROM512) {
297		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end);
298	}
299}
300
301void GBASavedataInitSRAM(struct GBASavedata* savedata) {
302	if (savedata->type == SAVEDATA_AUTODETECT) {
303		savedata->type = SAVEDATA_SRAM;
304	} else {
305		mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
306		return;
307	}
308	off_t end;
309	if (!savedata->vf) {
310		end = 0;
311		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
312	} else {
313		end = savedata->vf->size(savedata->vf);
314		if (end < SIZE_CART_SRAM) {
315			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
316		}
317		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
318	}
319
320	if (end < SIZE_CART_SRAM) {
321		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
322	}
323}
324
325uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
326	if (savedata->command == FLASH_COMMAND_ID) {
327		if (savedata->type == SAVEDATA_FLASH512) {
328			if (address < 2) {
329				return FLASH_MFG_PANASONIC >> (address * 8);
330			}
331		} else if (savedata->type == SAVEDATA_FLASH1M) {
332			if (address < 2) {
333				return FLASH_MFG_SANYO >> (address * 8);
334			}
335		}
336	}
337	if (mTimingIsScheduled(savedata->timing, &savedata->dust) && (address >> 12) == savedata->settling) {
338		return 0x5F;
339	}
340	return savedata->currentBank[address];
341}
342
343void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
344	switch (savedata->flashState) {
345	case FLASH_STATE_RAW:
346		switch (savedata->command) {
347		case FLASH_COMMAND_PROGRAM:
348			savedata->dirty |= SAVEDATA_DIRT_NEW;
349			savedata->currentBank[address] = value;
350			savedata->command = FLASH_COMMAND_NONE;
351			mTimingDeschedule(savedata->timing, &savedata->dust);
352			mTimingSchedule(savedata->timing, &savedata->dust, FLASH_PROGRAM_CYCLES);
353			break;
354		case FLASH_COMMAND_SWITCH_BANK:
355			if (address == 0 && value < 2) {
356				_flashSwitchBank(savedata, value);
357			} else {
358				mLOG(GBA_SAVE, GAME_ERROR, "Bad flash bank switch");
359				savedata->command = FLASH_COMMAND_NONE;
360			}
361			savedata->command = FLASH_COMMAND_NONE;
362			break;
363		default:
364			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
365				savedata->flashState = FLASH_STATE_START;
366			} else {
367				mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
368			}
369			break;
370		}
371		break;
372	case FLASH_STATE_START:
373		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
374			savedata->flashState = FLASH_STATE_CONTINUE;
375		} else {
376			mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
377			savedata->flashState = FLASH_STATE_RAW;
378		}
379		break;
380	case FLASH_STATE_CONTINUE:
381		savedata->flashState = FLASH_STATE_RAW;
382		if (address == FLASH_BASE_HI) {
383			switch (savedata->command) {
384			case FLASH_COMMAND_NONE:
385				switch (value) {
386				case FLASH_COMMAND_ERASE:
387				case FLASH_COMMAND_ID:
388				case FLASH_COMMAND_PROGRAM:
389				case FLASH_COMMAND_SWITCH_BANK:
390					savedata->command = value;
391					break;
392				default:
393					mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash operation: %#02x", value);
394					break;
395				}
396				break;
397			case FLASH_COMMAND_ERASE:
398				switch (value) {
399				case FLASH_COMMAND_ERASE_CHIP:
400					_flashErase(savedata);
401					break;
402				default:
403					mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
404					break;
405				}
406				savedata->command = FLASH_COMMAND_NONE;
407				break;
408			case FLASH_COMMAND_ID:
409				if (value == FLASH_COMMAND_TERMINATE) {
410					savedata->command = FLASH_COMMAND_NONE;
411				}
412				break;
413			default:
414				mLOG(GBA_SAVE, ERROR, "Flash entered bad state: %#02x", savedata->command);
415				savedata->command = FLASH_COMMAND_NONE;
416				break;
417			}
418		} else if (savedata->command == FLASH_COMMAND_ERASE) {
419			if (value == FLASH_COMMAND_ERASE_SECTOR) {
420				_flashEraseSector(savedata, address);
421				savedata->command = FLASH_COMMAND_NONE;
422			} else {
423				mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
424			}
425		}
426		break;
427	}
428}
429
430static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
431	if (size < SIZE_CART_EEPROM512) {
432		return;
433	}
434	if (savedata->type == SAVEDATA_EEPROM) {
435		return;
436	}
437	savedata->type = SAVEDATA_EEPROM;
438	if (!savedata->vf) {
439		return;
440	}
441	savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512);
442	if (savedata->vf->size(savedata->vf) < SIZE_CART_EEPROM) {
443		savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
444		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
445		memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512);
446	} else {
447		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
448	}
449}
450
451void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
452	switch (savedata->command) {
453	// Read header
454	case EEPROM_COMMAND_NULL:
455	default:
456		savedata->command = value & 0x1;
457		break;
458	case EEPROM_COMMAND_PENDING:
459		savedata->command <<= 1;
460		savedata->command |= value & 0x1;
461		if (savedata->command == EEPROM_COMMAND_WRITE) {
462			savedata->writeAddress = 0;
463		} else {
464			savedata->readAddress = 0;
465		}
466		break;
467	// Do commands
468	case EEPROM_COMMAND_WRITE:
469		// Write
470		if (writeSize > 65) {
471			savedata->writeAddress <<= 1;
472			savedata->writeAddress |= (value & 0x1) << 6;
473		} else if (writeSize == 1) {
474			savedata->command = EEPROM_COMMAND_NULL;
475		} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
476			_ensureEeprom(savedata, savedata->writeAddress >> 3);
477			uint8_t current = savedata->data[savedata->writeAddress >> 3];
478			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
479			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
480			savedata->dirty |= SAVEDATA_DIRT_NEW;
481			savedata->data[savedata->writeAddress >> 3] = current;
482			mTimingDeschedule(savedata->timing, &savedata->dust);
483			mTimingSchedule(savedata->timing, &savedata->dust, EEPROM_SETTLE_CYCLES);
484			++savedata->writeAddress;
485		} else {
486			mLOG(GBA_SAVE, GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));
487		}
488		break;
489	case EEPROM_COMMAND_READ_PENDING:
490		// Read
491		if (writeSize > 1) {
492			savedata->readAddress <<= 1;
493			if (value & 0x1) {
494				savedata->readAddress |= 0x40;
495			}
496		} else {
497			savedata->readBitsRemaining = 68;
498			savedata->command = EEPROM_COMMAND_READ;
499		}
500		break;
501	}
502}
503
504uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
505	if (savedata->command != EEPROM_COMMAND_READ) {
506		if (!mTimingIsScheduled(savedata->timing, &savedata->dust)) {
507			return 1;
508		} else {
509			return 0;
510		}
511	}
512	--savedata->readBitsRemaining;
513	if (savedata->readBitsRemaining < 64) {
514		int step = 63 - savedata->readBitsRemaining;
515		uint32_t address = (savedata->readAddress + step) >> 3;
516		_ensureEeprom(savedata, address);
517		if (address >= SIZE_CART_EEPROM) {
518			mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
519			return 0xFF;
520		}
521		uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));
522		if (!savedata->readBitsRemaining) {
523			savedata->command = EEPROM_COMMAND_NULL;
524		}
525		return data & 0x1;
526	}
527	return 0;
528}
529
530void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
531	if (!savedata->vf) {
532		return;
533	}
534	if (savedata->dirty & SAVEDATA_DIRT_NEW) {
535		savedata->dirtAge = frameCount;
536		savedata->dirty &= ~SAVEDATA_DIRT_NEW;
537		if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
538			savedata->dirty |= SAVEDATA_DIRT_SEEN;
539		}
540	} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
541		if (savedata->maskWriteback) {
542			GBASavedataUnmask(savedata);
543		}
544		if (savedata->mapMode & MAP_WRITE) {
545			size_t size = GBASavedataSize(savedata);
546			savedata->dirty = 0;
547			if (savedata->data && savedata->vf->sync(savedata->vf, savedata->data, size)) {
548				mLOG(GBA_SAVE, INFO, "Savedata synced");
549			} else {
550				mLOG(GBA_SAVE, INFO, "Savedata failed to sync!");
551			}
552		}
553	}
554}
555
556void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state) {
557	state->savedata.type = savedata->type;
558	state->savedata.command = savedata->command;
559	GBASerializedSavedataFlags flags = 0;
560	flags = GBASerializedSavedataFlagsSetFlashState(flags, savedata->flashState);
561	flags = GBASerializedSavedataFlagsTestFillFlashBank(flags, savedata->currentBank == &savedata->data[0x10000]);
562
563	if (mTimingIsScheduled(savedata->timing, &savedata->dust)) {
564		STORE_32(savedata->dust.when - mTimingCurrentTime(savedata->timing), 0, &state->savedata.settlingDust);
565		flags = GBASerializedSavedataFlagsFillDustSettling(flags);
566	}
567
568	state->savedata.flags = flags;
569	state->savedata.readBitsRemaining = savedata->readBitsRemaining;
570	STORE_32(savedata->readAddress, 0, &state->savedata.readAddress);
571	STORE_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
572	STORE_16(savedata->settling, 0, &state->savedata.settlingSector);
573
574}
575
576void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state) {
577	if (savedata->type != state->savedata.type) {
578		mLOG(GBA_SAVE, DEBUG, "Switching save types");
579		GBASavedataForceType(savedata, state->savedata.type);
580	}
581	savedata->command = state->savedata.command;
582	GBASerializedSavedataFlags flags = state->savedata.flags;
583	savedata->flashState = GBASerializedSavedataFlagsGetFlashState(flags);
584	savedata->readBitsRemaining = state->savedata.readBitsRemaining;
585	LOAD_32(savedata->readAddress, 0, &state->savedata.readAddress);
586	LOAD_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
587	LOAD_16(savedata->settling, 0, &state->savedata.settlingSector);
588
589	if (savedata->type == SAVEDATA_FLASH1M) {
590		_flashSwitchBank(savedata, GBASerializedSavedataFlagsGetFlashBank(flags));
591	}
592
593	if (GBASerializedSavedataFlagsIsDustSettling(flags)) {
594		uint32_t when;
595		LOAD_32(when, 0, &state->savedata.settlingDust);
596		mTimingSchedule(savedata->timing, &savedata->dust, when);
597	}
598}
599
600void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
601	mLOG(GBA_SAVE, DEBUG, "Performing flash bank switch to bank %i", bank);
602	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
603		mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb");
604		savedata->type = SAVEDATA_FLASH1M;
605		if (savedata->vf) {
606			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
607			if (savedata->vf->size(savedata->vf) < SIZE_CART_FLASH1M) {
608				savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
609				savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
610				memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
611			} else {
612				savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
613			}
614		}
615	}
616	savedata->currentBank = &savedata->data[bank << 16];
617}
618
619void _flashErase(struct GBASavedata* savedata) {
620	mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase");
621	savedata->dirty |= SAVEDATA_DIRT_NEW;
622	size_t size = SIZE_CART_FLASH512;
623	if (savedata->type == SAVEDATA_FLASH1M) {
624		size = SIZE_CART_FLASH1M;
625	}
626	memset(savedata->data, 0xFF, size);
627}
628
629void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
630	mLOG(GBA_SAVE, DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
631	savedata->dirty |= SAVEDATA_DIRT_NEW;
632	size_t size = 0x1000;
633	if (savedata->type == SAVEDATA_FLASH1M) {
634		mLOG(GBA_SAVE, DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
635	}
636	savedata->settling = sectorStart >> 12;
637	mTimingDeschedule(savedata->timing, &savedata->dust);
638	mTimingSchedule(savedata->timing, &savedata->dust, FLASH_ERASE_CYCLES);
639	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
640}