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