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