all repos — mgba @ 2bfc3e0ca623e4140e0f44ea75ab04512e41681a

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