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