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