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