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