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