all repos — mgba @ d5548f6da87cd39070d96e69bc4293c9a121ce89

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