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 off_t end;
121 if (!savedata->vf) {
122 end = 0;
123 savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
124 } else {
125 end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
126 if (end < SIZE_CART_FLASH512) {
127 savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
128 }
129 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
130 }
131
132 savedata->currentBank = savedata->data;
133 if (end < SIZE_CART_FLASH512) {
134 memset(&savedata->data[end], 0xFF, SIZE_CART_FLASH512 - end);
135 }
136}
137
138void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
139 if (savedata->type == SAVEDATA_NONE) {
140 savedata->type = SAVEDATA_EEPROM;
141 } else {
142 GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
143 return;
144 }
145 off_t end;
146 if (!savedata->vf) {
147 end = 0;
148 savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
149 } else {
150 end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
151 if (end < SIZE_CART_EEPROM) {
152 savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
153 }
154 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
155 }
156 if (end < SIZE_CART_EEPROM) {
157 memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
158 }
159}
160
161void GBASavedataInitSRAM(struct GBASavedata* savedata) {
162 if (savedata->type == SAVEDATA_NONE) {
163 savedata->type = SAVEDATA_SRAM;
164 } else {
165 GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
166 return;
167 }
168 off_t end;
169 if (!savedata->vf) {
170 end = 0;
171 savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
172 } else {
173 end = savedata->vf->seek(savedata->vf, 0, SEEK_END);
174 if (end < SIZE_CART_SRAM) {
175 savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
176 }
177 savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
178 }
179
180 if (end < SIZE_CART_SRAM) {
181 memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
182 }
183}
184
185uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
186 if (savedata->command == FLASH_COMMAND_ID) {
187 if (savedata->type == SAVEDATA_FLASH512) {
188 if (address < 2) {
189 return FLASH_MFG_PANASONIC >> (address * 8);
190 }
191 } else if (savedata->type == SAVEDATA_FLASH1M) {
192 if (address < 2) {
193 return FLASH_MFG_SANYO >> (address * 8);
194 }
195 }
196 }
197 return savedata->currentBank[address];
198}
199
200void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
201 switch (savedata->flashState) {
202 case FLASH_STATE_RAW:
203 switch (savedata->command) {
204 case FLASH_COMMAND_PROGRAM:
205 savedata->currentBank[address] = value;
206 savedata->command = FLASH_COMMAND_NONE;
207 break;
208 case FLASH_COMMAND_SWITCH_BANK:
209 if (address == 0 && value < 2) {
210 _flashSwitchBank(savedata, value);
211 } else {
212 GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
213 savedata->command = FLASH_COMMAND_NONE;
214 }
215 savedata->command = FLASH_COMMAND_NONE;
216 break;
217 default:
218 if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
219 savedata->flashState = FLASH_STATE_START;
220 } else {
221 GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
222 }
223 break;
224 }
225 break;
226 case FLASH_STATE_START:
227 if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
228 savedata->flashState = FLASH_STATE_CONTINUE;
229 } else {
230 GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
231 savedata->flashState = FLASH_STATE_RAW;
232 }
233 break;
234 case FLASH_STATE_CONTINUE:
235 savedata->flashState = FLASH_STATE_RAW;
236 if (address == FLASH_BASE_HI) {
237 switch (savedata->command) {
238 case FLASH_COMMAND_NONE:
239 switch (value) {
240 case FLASH_COMMAND_ERASE:
241 case FLASH_COMMAND_ID:
242 case FLASH_COMMAND_PROGRAM:
243 case FLASH_COMMAND_SWITCH_BANK:
244 savedata->command = value;
245 break;
246 default:
247 GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
248 break;
249 }
250 break;
251 case FLASH_COMMAND_ERASE:
252 switch (value) {
253 case FLASH_COMMAND_ERASE_CHIP:
254 _flashErase(savedata);
255 break;
256 default:
257 GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
258 break;
259 }
260 savedata->command = FLASH_COMMAND_NONE;
261 break;
262 case FLASH_COMMAND_ID:
263 if (value == FLASH_COMMAND_TERMINATE) {
264 savedata->command = FLASH_COMMAND_NONE;
265 }
266 break;
267 default:
268 GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
269 savedata->command = FLASH_COMMAND_NONE;
270 break;
271 }
272 } else if (savedata->command == FLASH_COMMAND_ERASE) {
273 if (value == FLASH_COMMAND_ERASE_SECTOR) {
274 _flashEraseSector(savedata, address);
275 savedata->command = FLASH_COMMAND_NONE;
276 } else {
277 GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
278 }
279 }
280 break;
281 }
282}
283
284void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
285 switch (savedata->command) {
286 // Read header
287 case EEPROM_COMMAND_NULL:
288 default:
289 savedata->command = value & 0x1;
290 break;
291 case EEPROM_COMMAND_PENDING:
292 savedata->command <<= 1;
293 savedata->command |= value & 0x1;
294 if (savedata->command == EEPROM_COMMAND_WRITE) {
295 savedata->addressBits = writeSize - 64 - 2;
296 savedata->writeAddress = 0;
297 } else {
298 savedata->addressBits = writeSize - 2;
299 savedata->readAddress = 0;
300 }
301 break;
302 // Do commands
303 case EEPROM_COMMAND_WRITE:
304 // Write
305 if (writeSize > 65) {
306 savedata->writeAddress <<= 1;
307 savedata->writeAddress |= (value & 0x1) << 6;
308 } else if (writeSize == 1) {
309 savedata->command = EEPROM_COMMAND_NULL;
310 savedata->writePending = 1;
311 } else {
312 uint8_t current = savedata->data[savedata->writeAddress >> 3];
313 current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
314 current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
315 savedata->data[savedata->writeAddress >> 3] = current;
316 ++savedata->writeAddress;
317 }
318 break;
319 case EEPROM_COMMAND_READ_PENDING:
320 // Read
321 if (writeSize > 1) {
322 savedata->readAddress <<= 1;
323 if (value & 0x1) {
324 savedata->readAddress |= 0x40;
325 }
326 } else {
327 savedata->readBitsRemaining = 68;
328 savedata->command = EEPROM_COMMAND_READ;
329 }
330 break;
331 }
332}
333
334uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
335 if (savedata->command != EEPROM_COMMAND_READ) {
336 return 1;
337 }
338 --savedata->readBitsRemaining;
339 if (savedata->readBitsRemaining < 64) {
340 int step = 63 - savedata->readBitsRemaining;
341 uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
342 if (!savedata->readBitsRemaining) {
343 savedata->command = EEPROM_COMMAND_NULL;
344 }
345 return data & 0x1;
346 }
347 return 0;
348}
349
350void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
351 savedata->currentBank = &savedata->data[bank << 16];
352 if (bank > 0) {
353 savedata->type = SAVEDATA_FLASH1M;
354 if (savedata->vf) {
355 savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
356 }
357 }
358}
359
360void _flashErase(struct GBASavedata* savedata) {
361 size_t size = 0x10000;
362 if (savedata->type == SAVEDATA_FLASH1M) {
363 size = 0x20000;
364 }
365 memset(savedata->data, 0xFF, size);
366}
367
368void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
369 size_t size = 0x1000;
370 if (savedata->type == SAVEDATA_FLASH1M) {
371 GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at %#04x", sectorStart);
372 }
373 memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
374}