all repos — mgba @ ac115422264c242439c19aaf383b6b743a309c69

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