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