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 savedata->type = type;
230 GBASavedataInitEEPROM(savedata);
231 break;
232 case SAVEDATA_SRAM:
233 GBASavedataInitSRAM(savedata);
234 break;
235 case SAVEDATA_FORCE_NONE:
236 savedata->type = SAVEDATA_FORCE_NONE;
237 break;
238 case SAVEDATA_AUTODETECT:
239 break;
240 }
241}
242
243void GBASavedataInitFlash(struct GBASavedata* savedata) {
244 if (savedata->type == SAVEDATA_AUTODETECT) {
245 savedata->type = SAVEDATA_FLASH512;
246 }
247 if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
248 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
249 return;
250 }
251 int32_t flashSize = SIZE_CART_FLASH512;
252 if (savedata->type == SAVEDATA_FLASH1M) {
253 flashSize = SIZE_CART_FLASH1M;
254 }
255 off_t end;
256 if (!savedata->vf) {
257 end = 0;
258 savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
259 } else {
260 end = savedata->vf->size(savedata->vf);
261 if (end < flashSize) {
262 savedata->vf->truncate(savedata->vf, flashSize);
263 }
264 savedata->data = savedata->vf->map(savedata->vf, flashSize, savedata->mapMode);
265 }
266
267 savedata->currentBank = savedata->data;
268 if (end < SIZE_CART_FLASH512) {
269 memset(&savedata->data[end], 0xFF, flashSize - end);
270 }
271}
272
273void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
274 if (savedata->type == SAVEDATA_AUTODETECT) {
275 savedata->type = SAVEDATA_EEPROM512;
276 } else if (savedata->type != SAVEDATA_EEPROM512 && savedata->type != SAVEDATA_EEPROM) {
277 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
278 return;
279 }
280 int32_t eepromSize = SIZE_CART_EEPROM512;
281 if (savedata->type == SAVEDATA_EEPROM) {
282 eepromSize = SIZE_CART_EEPROM;
283 }
284 off_t end;
285 if (!savedata->vf) {
286 end = 0;
287 savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
288 } else {
289 end = savedata->vf->size(savedata->vf);
290 if (end < eepromSize) {
291 savedata->vf->truncate(savedata->vf, eepromSize);
292 }
293 savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode);
294 }
295 if (end < SIZE_CART_EEPROM512) {
296 memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end);
297 }
298}
299
300void GBASavedataInitSRAM(struct GBASavedata* savedata) {
301 if (savedata->type == SAVEDATA_AUTODETECT) {
302 savedata->type = SAVEDATA_SRAM;
303 } else {
304 mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
305 return;
306 }
307 off_t end;
308 if (!savedata->vf) {
309 end = 0;
310 savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
311 } else {
312 end = savedata->vf->size(savedata->vf);
313 if (end < SIZE_CART_SRAM) {
314 savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
315 }
316 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
317 }
318
319 if (end < SIZE_CART_SRAM) {
320 memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
321 }
322}
323
324uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
325 if (savedata->command == FLASH_COMMAND_ID) {
326 if (savedata->type == SAVEDATA_FLASH512) {
327 if (address < 2) {
328 return FLASH_MFG_PANASONIC >> (address * 8);
329 }
330 } else if (savedata->type == SAVEDATA_FLASH1M) {
331 if (address < 2) {
332 return FLASH_MFG_SANYO >> (address * 8);
333 }
334 }
335 }
336 if (mTimingIsScheduled(savedata->timing, &savedata->dust) && (address >> 12) == savedata->settling) {
337 return 0x5F;
338 }
339 return savedata->currentBank[address];
340}
341
342void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
343 switch (savedata->flashState) {
344 case FLASH_STATE_RAW:
345 switch (savedata->command) {
346 case FLASH_COMMAND_PROGRAM:
347 savedata->dirty |= SAVEDATA_DIRT_NEW;
348 savedata->currentBank[address] = value;
349 savedata->command = FLASH_COMMAND_NONE;
350 mTimingDeschedule(savedata->timing, &savedata->dust);
351 mTimingSchedule(savedata->timing, &savedata->dust, FLASH_PROGRAM_CYCLES);
352 break;
353 case FLASH_COMMAND_SWITCH_BANK:
354 if (address == 0 && value < 2) {
355 _flashSwitchBank(savedata, value);
356 } else {
357 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash bank switch");
358 savedata->command = FLASH_COMMAND_NONE;
359 }
360 savedata->command = FLASH_COMMAND_NONE;
361 break;
362 default:
363 if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
364 savedata->flashState = FLASH_STATE_START;
365 } else {
366 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
367 }
368 break;
369 }
370 break;
371 case FLASH_STATE_START:
372 if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
373 savedata->flashState = FLASH_STATE_CONTINUE;
374 } else {
375 mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
376 savedata->flashState = FLASH_STATE_RAW;
377 }
378 break;
379 case FLASH_STATE_CONTINUE:
380 savedata->flashState = FLASH_STATE_RAW;
381 if (address == FLASH_BASE_HI) {
382 switch (savedata->command) {
383 case FLASH_COMMAND_NONE:
384 switch (value) {
385 case FLASH_COMMAND_ERASE:
386 case FLASH_COMMAND_ID:
387 case FLASH_COMMAND_PROGRAM:
388 case FLASH_COMMAND_SWITCH_BANK:
389 savedata->command = value;
390 break;
391 default:
392 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash operation: %#02x", value);
393 break;
394 }
395 break;
396 case FLASH_COMMAND_ERASE:
397 switch (value) {
398 case FLASH_COMMAND_ERASE_CHIP:
399 _flashErase(savedata);
400 break;
401 default:
402 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
403 break;
404 }
405 savedata->command = FLASH_COMMAND_NONE;
406 break;
407 case FLASH_COMMAND_ID:
408 if (value == FLASH_COMMAND_TERMINATE) {
409 savedata->command = FLASH_COMMAND_NONE;
410 }
411 break;
412 default:
413 mLOG(GBA_SAVE, ERROR, "Flash entered bad state: %#02x", savedata->command);
414 savedata->command = FLASH_COMMAND_NONE;
415 break;
416 }
417 } else if (savedata->command == FLASH_COMMAND_ERASE) {
418 if (value == FLASH_COMMAND_ERASE_SECTOR) {
419 _flashEraseSector(savedata, address);
420 savedata->command = FLASH_COMMAND_NONE;
421 } else {
422 mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
423 }
424 }
425 break;
426 }
427}
428
429static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) {
430 if (size < SIZE_CART_EEPROM512) {
431 return;
432 }
433 if (savedata->type == SAVEDATA_EEPROM) {
434 return;
435 }
436 savedata->type = SAVEDATA_EEPROM;
437 if (!savedata->vf) {
438 return;
439 }
440 savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512);
441 if (savedata->vf->size(savedata->vf) < SIZE_CART_EEPROM) {
442 savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
443 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
444 memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512);
445 } else {
446 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
447 }
448}
449
450void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
451 switch (savedata->command) {
452 // Read header
453 case EEPROM_COMMAND_NULL:
454 default:
455 savedata->command = value & 0x1;
456 break;
457 case EEPROM_COMMAND_PENDING:
458 savedata->command <<= 1;
459 savedata->command |= value & 0x1;
460 if (savedata->command == EEPROM_COMMAND_WRITE) {
461 savedata->writeAddress = 0;
462 } else {
463 savedata->readAddress = 0;
464 }
465 break;
466 // Do commands
467 case EEPROM_COMMAND_WRITE:
468 // Write
469 if (writeSize > 65) {
470 savedata->writeAddress <<= 1;
471 savedata->writeAddress |= (value & 0x1) << 6;
472 } else if (writeSize == 1) {
473 savedata->command = EEPROM_COMMAND_NULL;
474 } else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
475 _ensureEeprom(savedata, savedata->writeAddress >> 3);
476 uint8_t current = savedata->data[savedata->writeAddress >> 3];
477 current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
478 current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
479 savedata->dirty |= SAVEDATA_DIRT_NEW;
480 savedata->data[savedata->writeAddress >> 3] = current;
481 mTimingDeschedule(savedata->timing, &savedata->dust);
482 mTimingSchedule(savedata->timing, &savedata->dust, EEPROM_SETTLE_CYCLES);
483 ++savedata->writeAddress;
484 } else {
485 mLOG(GBA_SAVE, GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));
486 }
487 break;
488 case EEPROM_COMMAND_READ_PENDING:
489 // Read
490 if (writeSize > 1) {
491 savedata->readAddress <<= 1;
492 if (value & 0x1) {
493 savedata->readAddress |= 0x40;
494 }
495 } else {
496 savedata->readBitsRemaining = 68;
497 savedata->command = EEPROM_COMMAND_READ;
498 }
499 break;
500 }
501}
502
503uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
504 if (savedata->command != EEPROM_COMMAND_READ) {
505 if (!mTimingIsScheduled(savedata->timing, &savedata->dust)) {
506 return 1;
507 } else {
508 return 0;
509 }
510 }
511 --savedata->readBitsRemaining;
512 if (savedata->readBitsRemaining < 64) {
513 int step = 63 - savedata->readBitsRemaining;
514 uint32_t address = (savedata->readAddress + step) >> 3;
515 _ensureEeprom(savedata, address);
516 if (address >= SIZE_CART_EEPROM) {
517 mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
518 return 0xFF;
519 }
520 uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));
521 if (!savedata->readBitsRemaining) {
522 savedata->command = EEPROM_COMMAND_NULL;
523 }
524 return data & 0x1;
525 }
526 return 0;
527}
528
529void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
530 if (!savedata->vf) {
531 return;
532 }
533 if (savedata->dirty & SAVEDATA_DIRT_NEW) {
534 savedata->dirtAge = frameCount;
535 savedata->dirty &= ~SAVEDATA_DIRT_NEW;
536 if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
537 savedata->dirty |= SAVEDATA_DIRT_SEEN;
538 }
539 } else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
540 if (savedata->maskWriteback) {
541 GBASavedataUnmask(savedata);
542 }
543 if (savedata->mapMode & MAP_WRITE) {
544 size_t size = GBASavedataSize(savedata);
545 savedata->dirty = 0;
546 if (savedata->data && savedata->vf->sync(savedata->vf, savedata->data, size)) {
547 mLOG(GBA_SAVE, INFO, "Savedata synced");
548 } else {
549 mLOG(GBA_SAVE, INFO, "Savedata failed to sync!");
550 }
551 }
552 }
553}
554
555void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state) {
556 state->savedata.type = savedata->type;
557 state->savedata.command = savedata->command;
558 GBASerializedSavedataFlags flags = 0;
559 flags = GBASerializedSavedataFlagsSetFlashState(flags, savedata->flashState);
560 flags = GBASerializedSavedataFlagsTestFillFlashBank(flags, savedata->currentBank == &savedata->data[0x10000]);
561
562 if (mTimingIsScheduled(savedata->timing, &savedata->dust)) {
563 STORE_32(savedata->dust.when - mTimingCurrentTime(savedata->timing), 0, &state->savedata.settlingDust);
564 flags = GBASerializedSavedataFlagsFillDustSettling(flags);
565 }
566
567 state->savedata.flags = flags;
568 state->savedata.readBitsRemaining = savedata->readBitsRemaining;
569 STORE_32(savedata->readAddress, 0, &state->savedata.readAddress);
570 STORE_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
571 STORE_16(savedata->settling, 0, &state->savedata.settlingSector);
572
573}
574
575void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state) {
576 if (savedata->type != state->savedata.type) {
577 mLOG(GBA_SAVE, DEBUG, "Switching save types");
578 GBASavedataForceType(savedata, state->savedata.type);
579 }
580 savedata->command = state->savedata.command;
581 GBASerializedSavedataFlags flags = state->savedata.flags;
582 savedata->flashState = GBASerializedSavedataFlagsGetFlashState(flags);
583 savedata->readBitsRemaining = state->savedata.readBitsRemaining;
584 LOAD_32(savedata->readAddress, 0, &state->savedata.readAddress);
585 LOAD_32(savedata->writeAddress, 0, &state->savedata.writeAddress);
586 LOAD_16(savedata->settling, 0, &state->savedata.settlingSector);
587
588 if (savedata->type == SAVEDATA_FLASH1M) {
589 _flashSwitchBank(savedata, GBASerializedSavedataFlagsGetFlashBank(flags));
590 }
591
592 if (GBASerializedSavedataFlagsIsDustSettling(flags)) {
593 uint32_t when;
594 LOAD_32(when, 0, &state->savedata.settlingDust);
595 mTimingSchedule(savedata->timing, &savedata->dust, when);
596 }
597}
598
599void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
600 mLOG(GBA_SAVE, DEBUG, "Performing flash bank switch to bank %i", bank);
601 savedata->currentBank = &savedata->data[bank << 16];
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}
617
618void _flashErase(struct GBASavedata* savedata) {
619 mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase");
620 savedata->dirty |= SAVEDATA_DIRT_NEW;
621 size_t size = SIZE_CART_FLASH512;
622 if (savedata->type == SAVEDATA_FLASH1M) {
623 size = SIZE_CART_FLASH1M;
624 }
625 memset(savedata->data, 0xFF, size);
626}
627
628void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
629 mLOG(GBA_SAVE, DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
630 savedata->dirty |= SAVEDATA_DIRT_NEW;
631 size_t size = 0x1000;
632 if (savedata->type == SAVEDATA_FLASH1M) {
633 mLOG(GBA_SAVE, DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
634 }
635 savedata->settling = sectorStart >> 12;
636 mTimingDeschedule(savedata->timing, &savedata->dust);
637 mTimingSchedule(savedata->timing, &savedata->dust, FLASH_ERASE_CYCLES);
638 memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
639}