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