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