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