all repos — mgba @ bd74fa1fbcd810452602a03682a7677c2efb30d4

mGBA Game Boy Advance Emulator

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