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 do {
143 read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
144 out->write(out, buffer, read);
145 } while (read == sizeof(buffer));
146 return read >= 0;
147 }
148 return true;
149}
150
151size_t GBASavedataSize(const struct GBASavedata* savedata) {
152 switch (savedata->type) {
153 case SAVEDATA_SRAM:
154 return SIZE_CART_SRAM;
155 case SAVEDATA_FLASH512:
156 return SIZE_CART_FLASH512;
157 case SAVEDATA_FLASH1M:
158 return SIZE_CART_FLASH1M;
159 case SAVEDATA_EEPROM:
160 return SIZE_CART_EEPROM;
161 case SAVEDATA_EEPROM512:
162 return SIZE_CART_EEPROM512;
163 case SAVEDATA_FORCE_NONE:
164 return 0;
165 case SAVEDATA_AUTODETECT:
166 default:
167 if (savedata->vf) {
168 return savedata->vf->size(savedata->vf);
169 }
170 return 0;
171 }
172}
173
174bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) {
175 if (savedata->data) {
176 if (!in && savedata->type != SAVEDATA_FORCE_NONE) {
177 return false;
178 }
179 ssize_t size = GBASavedataSize(savedata);
180 in->seek(in, 0, SEEK_SET);
181 return in->read(in, savedata->data, size) == size;
182 } else if (savedata->vf) {
183 off_t read = 0;
184 uint8_t buffer[2048];
185 savedata->vf->seek(savedata->vf, 0, SEEK_SET);
186 if (in) {
187 in->seek(in, 0, SEEK_SET);
188 do {
189 read = in->read(in, buffer, sizeof(buffer));
190 read = savedata->vf->write(savedata->vf, buffer, read);
191 } while (read == sizeof(buffer));
192 }
193 memset(buffer, 0xFF, sizeof(buffer));
194 ssize_t fsize = savedata->vf->size(savedata->vf);
195 ssize_t pos = savedata->vf->seek(savedata->vf, 0, SEEK_CUR);
196 while (fsize - pos >= (ssize_t) sizeof(buffer)) {
197 savedata->vf->write(savedata->vf, buffer, sizeof(buffer));
198 pos = savedata->vf->seek(savedata->vf, 0, SEEK_CUR);
199 }
200 if (fsize - pos > 0) {
201 savedata->vf->write(savedata->vf, buffer, fsize - pos);
202 }
203 return read >= 0;
204 }
205 return true;
206}
207
208void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) {
209 if (savedata->type == type) {
210 return;
211 }
212 if (savedata->type != SAVEDATA_AUTODETECT) {
213 struct VFile* vf = savedata->vf;
214 int mapMode = savedata->mapMode;
215 bool maskWriteback = savedata->maskWriteback;
216 GBASavedataDeinit(savedata);
217 GBASavedataInit(savedata, vf);
218 savedata->mapMode = mapMode;
219 savedata->maskWriteback = maskWriteback;
220 }
221 switch (type) {
222 case SAVEDATA_FLASH512:
223 case SAVEDATA_FLASH1M:
224 savedata->type = type;
225 GBASavedataInitFlash(savedata);
226 break;
227 case SAVEDATA_EEPROM:
228 case SAVEDATA_EEPROM512:
229 GBASavedataInitEEPROM(savedata);
230 break;
231 case SAVEDATA_SRAM:
232 GBASavedataInitSRAM(savedata);
233 break;
234 case SAVEDATA_FORCE_NONE:
235 savedata->type = SAVEDATA_FORCE_NONE;
236 break;
237 case SAVEDATA_AUTODETECT:
238 break;
239 }
240}
241
242void GBASavedataInitFlash(struct GBASavedata* savedata) {
243 if (savedata->type == SAVEDATA_AUTODETECT) {
244 savedata->type = SAVEDATA_FLASH512;
245 }
246 if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
247 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
248 return;
249 }
250 int32_t flashSize = SIZE_CART_FLASH512;
251 if (savedata->type == SAVEDATA_FLASH1M) {
252 flashSize = SIZE_CART_FLASH1M;
253 }
254 off_t end;
255 if (!savedata->vf) {
256 end = 0;
257 savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
258 } else {
259 end = savedata->vf->size(savedata->vf);
260 if (end < flashSize) {
261 savedata->vf->truncate(savedata->vf, flashSize);
262 } else if (end >= SIZE_CART_FLASH1M) {
263 flashSize = SIZE_CART_FLASH1M;
264 savedata->type = SAVEDATA_FLASH1M;
265 }
266 savedata->data = savedata->vf->map(savedata->vf, flashSize, savedata->mapMode);
267 }
268
269 savedata->currentBank = savedata->data;
270 if (end < SIZE_CART_FLASH512) {
271 memset(&savedata->data[end], 0xFF, flashSize - end);
272 }
273}
274
275void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
276 if (savedata->type == SAVEDATA_AUTODETECT) {
277 savedata->type = SAVEDATA_EEPROM512;
278 } else if (savedata->type != SAVEDATA_EEPROM512 && savedata->type != SAVEDATA_EEPROM) {
279 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
280 return;
281 }
282 int32_t eepromSize = SIZE_CART_EEPROM512;
283 if (savedata->type == SAVEDATA_EEPROM) {
284 eepromSize = SIZE_CART_EEPROM;
285 }
286 off_t end;
287 if (!savedata->vf) {
288 end = 0;
289 savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
290 } else {
291 end = savedata->vf->size(savedata->vf);
292 if (end < eepromSize) {
293 savedata->vf->truncate(savedata->vf, eepromSize);
294 } else if (end >= SIZE_CART_EEPROM) {
295 eepromSize = SIZE_CART_EEPROM;
296 savedata->type = SAVEDATA_EEPROM;
297 }
298 savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode);
299 }
300 if (end < SIZE_CART_EEPROM512) {
301 memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end);
302 }
303}
304
305void GBASavedataInitSRAM(struct GBASavedata* savedata) {
306 if (savedata->type == SAVEDATA_AUTODETECT) {
307 savedata->type = SAVEDATA_SRAM;
308 } else {
309 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
310 return;
311 }
312 off_t end;
313 if (!savedata->vf) {
314 end = 0;
315 savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
316 } else {
317 end = savedata->vf->size(savedata->vf);
318 if (end < SIZE_CART_SRAM) {
319 savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
320 }
321 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
322 }
323
324 if (end < SIZE_CART_SRAM) {
325 memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
326 }
327}
328
329uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
330 if (savedata->command == FLASH_COMMAND_ID) {
331 if (savedata->type == SAVEDATA_FLASH512) {
332 if (address < 2) {
333 return FLASH_MFG_PANASONIC >> (address * 8);
334 }
335 } else if (savedata->type == SAVEDATA_FLASH1M) {
336 if (address < 2) {
337 return FLASH_MFG_SANYO >> (address * 8);
338 }
339 }
340 }
341 if (mTimingIsScheduled(savedata->timing, &savedata->dust) && (address >> 12) == savedata->settling) {
342 return 0x5F;
343 }
344 return savedata->currentBank[address];
345}
346
347void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
348 switch (savedata->flashState) {
349 case FLASH_STATE_RAW:
350 switch (savedata->command) {
351 case FLASH_COMMAND_PROGRAM:
352 savedata->dirty |= SAVEDATA_DIRT_NEW;
353 savedata->currentBank[address] = value;
354 savedata->command = FLASH_COMMAND_NONE;
355 mTimingDeschedule(savedata->timing, &savedata->dust);
356 mTimingSchedule(savedata->timing, &savedata->dust, FLASH_PROGRAM_CYCLES);
357 break;
358 case FLASH_COMMAND_SWITCH_BANK:
359 if (address == 0 && value < 2) {
360 _flashSwitchBank(savedata, value);
361 } else {
362 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash bank switch");
363 savedata->command = FLASH_COMMAND_NONE;
364 }
365 savedata->command = FLASH_COMMAND_NONE;
366 break;
367 default:
368 if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
369 savedata->flashState = FLASH_STATE_START;
370 } else {
371 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
372 }
373 break;
374 }
375 break;
376 case FLASH_STATE_START:
377 if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
378 savedata->flashState = FLASH_STATE_CONTINUE;
379 } else {
380 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
381 savedata->flashState = FLASH_STATE_RAW;
382 }
383 break;
384 case FLASH_STATE_CONTINUE:
385 savedata->flashState = FLASH_STATE_RAW;
386 if (address == FLASH_BASE_HI) {
387 switch (savedata->command) {
388 case FLASH_COMMAND_NONE:
389 switch (value) {
390 case FLASH_COMMAND_ERASE:
391 case FLASH_COMMAND_ID:
392 case FLASH_COMMAND_PROGRAM:
393 case FLASH_COMMAND_SWITCH_BANK:
394 savedata->command = value;
395 break;
396 default:
397 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash operation: %#02x", value);
398 break;
399 }
400 break;
401 case FLASH_COMMAND_ERASE:
402 switch (value) {
403 case FLASH_COMMAND_ERASE_CHIP:
404 _flashErase(savedata);
405 break;
406 default:
407 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
408 break;
409 }
410 savedata->command = FLASH_COMMAND_NONE;
411 break;
412 case FLASH_COMMAND_ID:
413 if (value == FLASH_COMMAND_TERMINATE) {
414 savedata->command = FLASH_COMMAND_NONE;
415 }
416 break;
417 default:
418 mLOG(GBA_SAVE, ERROR, "Flash entered bad state: %#02x", savedata->command);
419 savedata->command = FLASH_COMMAND_NONE;
420 break;
421 }
422 } else if (savedata->command == FLASH_COMMAND_ERASE) {
423 if (value == FLASH_COMMAND_ERASE_SECTOR) {
424 _flashEraseSector(savedata, address);
425 savedata->command = FLASH_COMMAND_NONE;
426 } else {
427 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
428 }
429 }
430 break;
431 }
432}
433
434static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
435 if (size < SIZE_CART_EEPROM512) {
436 return;
437 }
438 if (savedata->type == SAVEDATA_EEPROM) {
439 return;
440 }
441 savedata->type = SAVEDATA_EEPROM;
442 if (!savedata->vf || savedata->vf->size(savedata->vf) > SIZE_CART_EEPROM512) {
443 return;
444 }
445 savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512);
446 savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
447 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
448 memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512);
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 savedata->currentBank = &savedata->data[bank << 16];
603 if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
604 mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb");
605 savedata->type = SAVEDATA_FLASH1M;
606 if (savedata->vf) {
607 savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
608 if (savedata->vf->size(savedata->vf) == SIZE_CART_FLASH512) {
609 savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
610 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
611 memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
612 } else {
613 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE);
614 }
615 }
616 }
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}