all repos — mgba @ f4fcdf35d4d88616a3bda9bce7384df0e83a6964

mGBA Game Boy Advance Emulator

src/gba/gba-savedata.c (view raw)

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "gba-savedata.h"
  7
  8#include "gba.h"
  9
 10#include "util/memory.h"
 11#include "util/vfs.h"
 12
 13#include <errno.h>
 14#include <fcntl.h>
 15
 16static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
 17static void _flashErase(struct GBASavedata* savedata);
 18static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);
 19
 20void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
 21	savedata->type = SAVEDATA_AUTODETECT;
 22	savedata->data = 0;
 23	savedata->command = EEPROM_COMMAND_NULL;
 24	savedata->flashState = FLASH_STATE_RAW;
 25	savedata->vf = vf;
 26	savedata->realVf = vf;
 27	savedata->mapMode = MAP_WRITE;
 28}
 29
 30void GBASavedataDeinit(struct GBASavedata* savedata) {
 31	if (savedata->vf) {
 32		switch (savedata->type) {
 33		case SAVEDATA_SRAM:
 34			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM);
 35			break;
 36		case SAVEDATA_FLASH512:
 37			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
 38			break;
 39		case SAVEDATA_FLASH1M:
 40			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M);
 41			break;
 42		case SAVEDATA_EEPROM:
 43			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM);
 44			break;
 45		case SAVEDATA_FORCE_NONE:
 46		case SAVEDATA_AUTODETECT:
 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_FORCE_NONE:
 65		case SAVEDATA_AUTODETECT:
 66			break;
 67		}
 68	}
 69	savedata->data = 0;
 70	savedata->type = SAVEDATA_AUTODETECT;
 71}
 72
 73void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
 74	GBASavedataDeinit(savedata);
 75	savedata->vf = vf;
 76	savedata->mapMode = MAP_READ;
 77}
 78
 79void GBASavedataUnmask(struct GBASavedata* savedata) {
 80	if (savedata->mapMode != MAP_READ) {
 81		return;
 82	}
 83	GBASavedataDeinit(savedata);
 84	savedata->vf = savedata->realVf;
 85	savedata->mapMode = MAP_WRITE;
 86}
 87
 88bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
 89	if (savedata->data) {
 90		switch (savedata->type) {
 91		case SAVEDATA_SRAM:
 92			return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
 93		case SAVEDATA_FLASH512:
 94			return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
 95		case SAVEDATA_FLASH1M:
 96			return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
 97		case SAVEDATA_EEPROM:
 98			return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
 99		case SAVEDATA_AUTODETECT:
100		case SAVEDATA_FORCE_NONE:
101			return true;
102		}
103	} else if (savedata->vf) {
104		off_t read = 0;
105		uint8_t buffer[2048];
106		do {
107			read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
108			out->write(out, buffer, read);
109		} while (read == sizeof(buffer));
110		return read >= 0;
111	}
112	return true;
113}
114
115void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type) {
116	switch (type) {
117	case SAVEDATA_FLASH512:
118	case SAVEDATA_FLASH1M:
119		savedata->type = type;
120		GBASavedataInitFlash(savedata);
121		break;
122	case SAVEDATA_EEPROM:
123		GBASavedataInitEEPROM(savedata);
124		break;
125	case SAVEDATA_SRAM:
126		GBASavedataInitSRAM(savedata);
127		break;
128	case SAVEDATA_FORCE_NONE:
129		savedata->type = SAVEDATA_FORCE_NONE;
130		break;
131	case SAVEDATA_AUTODETECT:
132		break;
133	}
134}
135
136void GBASavedataInitFlash(struct GBASavedata* savedata) {
137	if (savedata->type == SAVEDATA_AUTODETECT) {
138		savedata->type = SAVEDATA_FLASH512;
139	}
140	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
141		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
142		return;
143	}
144	size_t flashSize = SIZE_CART_FLASH512;
145	off_t end;
146	if (!savedata->vf) {
147		end = 0;
148		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
149	} else {
150		end = savedata->vf->size(savedata->vf);
151		if (end < SIZE_CART_FLASH512) {
152			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
153			flashSize = SIZE_CART_FLASH1M;
154		}
155		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
156	}
157
158	savedata->currentBank = savedata->data;
159	if (end < SIZE_CART_FLASH512) {
160		memset(&savedata->data[end], 0xFF, flashSize - end);
161	}
162}
163
164void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
165	if (savedata->type == SAVEDATA_AUTODETECT) {
166		savedata->type = SAVEDATA_EEPROM;
167	} else {
168		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
169		return;
170	}
171	off_t end;
172	if (!savedata->vf) {
173		end = 0;
174		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
175	} else {
176		end = savedata->vf->size(savedata->vf);
177		if (end < SIZE_CART_EEPROM) {
178			savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
179		}
180		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
181	}
182	if (end < SIZE_CART_EEPROM) {
183		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
184	}
185}
186
187void GBASavedataInitSRAM(struct GBASavedata* savedata) {
188	if (savedata->type == SAVEDATA_AUTODETECT) {
189		savedata->type = SAVEDATA_SRAM;
190	} else {
191		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
192		return;
193	}
194	off_t end;
195	if (!savedata->vf) {
196		end = 0;
197		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
198	} else {
199		end = savedata->vf->size(savedata->vf);
200		if (end < SIZE_CART_SRAM) {
201			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
202		}
203		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
204	}
205
206	if (end < SIZE_CART_SRAM) {
207		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
208	}
209}
210
211uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
212	if (savedata->command == FLASH_COMMAND_ID) {
213		if (savedata->type == SAVEDATA_FLASH512) {
214			if (address < 2) {
215				return FLASH_MFG_PANASONIC >> (address * 8);
216			}
217		} else if (savedata->type == SAVEDATA_FLASH1M) {
218			if (address < 2) {
219				return FLASH_MFG_SANYO >> (address * 8);
220			}
221		}
222	}
223	return savedata->currentBank[address];
224}
225
226void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
227	switch (savedata->flashState) {
228	case FLASH_STATE_RAW:
229		switch (savedata->command) {
230		case FLASH_COMMAND_PROGRAM:
231			savedata->currentBank[address] = value;
232			savedata->command = FLASH_COMMAND_NONE;
233			break;
234		case FLASH_COMMAND_SWITCH_BANK:
235			if (address == 0 && value < 2) {
236				_flashSwitchBank(savedata, value);
237			} else {
238				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
239				savedata->command = FLASH_COMMAND_NONE;
240			}
241			savedata->command = FLASH_COMMAND_NONE;
242			break;
243		default:
244			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
245				savedata->flashState = FLASH_STATE_START;
246			} else {
247				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
248			}
249			break;
250		}
251		break;
252	case FLASH_STATE_START:
253		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
254			savedata->flashState = FLASH_STATE_CONTINUE;
255		} else {
256			GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
257			savedata->flashState = FLASH_STATE_RAW;
258		}
259		break;
260	case FLASH_STATE_CONTINUE:
261		savedata->flashState = FLASH_STATE_RAW;
262		if (address == FLASH_BASE_HI) {
263			switch (savedata->command) {
264			case FLASH_COMMAND_NONE:
265				switch (value) {
266				case FLASH_COMMAND_ERASE:
267				case FLASH_COMMAND_ID:
268				case FLASH_COMMAND_PROGRAM:
269				case FLASH_COMMAND_SWITCH_BANK:
270					savedata->command = value;
271					break;
272				default:
273					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
274					break;
275				}
276				break;
277			case FLASH_COMMAND_ERASE:
278				switch (value) {
279				case FLASH_COMMAND_ERASE_CHIP:
280					_flashErase(savedata);
281					break;
282				default:
283					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
284					break;
285				}
286				savedata->command = FLASH_COMMAND_NONE;
287				break;
288			case FLASH_COMMAND_ID:
289				if (value == FLASH_COMMAND_TERMINATE) {
290					savedata->command = FLASH_COMMAND_NONE;
291				}
292				break;
293			default:
294				GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
295				savedata->command = FLASH_COMMAND_NONE;
296				break;
297			}
298		} else if (savedata->command == FLASH_COMMAND_ERASE) {
299			if (value == FLASH_COMMAND_ERASE_SECTOR) {
300				_flashEraseSector(savedata, address);
301				savedata->command = FLASH_COMMAND_NONE;
302			} else {
303				GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
304			}
305		}
306		break;
307	}
308}
309
310void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
311	switch (savedata->command) {
312	// Read header
313	case EEPROM_COMMAND_NULL:
314	default:
315		savedata->command = value & 0x1;
316		break;
317	case EEPROM_COMMAND_PENDING:
318		savedata->command <<= 1;
319		savedata->command |= value & 0x1;
320		if (savedata->command == EEPROM_COMMAND_WRITE) {
321			savedata->addressBits = writeSize - 64 - 2;
322			savedata->writeAddress = 0;
323		} else {
324			savedata->addressBits = writeSize - 2;
325			savedata->readAddress = 0;
326		}
327		break;
328	// Do commands
329	case EEPROM_COMMAND_WRITE:
330		// Write
331		if (writeSize > 65) {
332			savedata->writeAddress <<= 1;
333			savedata->writeAddress |= (value & 0x1) << 6;
334		} else if (writeSize == 1) {
335			savedata->command = EEPROM_COMMAND_NULL;
336			savedata->writePending = 1;
337		} else {
338			uint8_t current = savedata->data[savedata->writeAddress >> 3];
339			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
340			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
341			savedata->data[savedata->writeAddress >> 3] = current;
342			++savedata->writeAddress;
343		}
344		break;
345	case EEPROM_COMMAND_READ_PENDING:
346		// Read
347		if (writeSize > 1) {
348			savedata->readAddress <<= 1;
349			if (value & 0x1) {
350				savedata->readAddress |= 0x40;
351			}
352		} else {
353			savedata->readBitsRemaining = 68;
354			savedata->command = EEPROM_COMMAND_READ;
355		}
356		break;
357	}
358}
359
360uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
361	if (savedata->command != EEPROM_COMMAND_READ) {
362		return 1;
363	}
364	--savedata->readBitsRemaining;
365	if (savedata->readBitsRemaining < 64) {
366		int step = 63 - savedata->readBitsRemaining;
367		uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
368		if (!savedata->readBitsRemaining) {
369			savedata->command = EEPROM_COMMAND_NULL;
370		}
371		return data & 0x1;
372	}
373	return 0;
374}
375
376void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
377	GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank);
378	savedata->currentBank = &savedata->data[bank << 16];
379	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
380		savedata->type = SAVEDATA_FLASH1M;
381		if (savedata->vf) {
382			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
383			memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
384		}
385	}
386}
387
388void _flashErase(struct GBASavedata* savedata) {
389	GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
390	size_t size = SIZE_CART_FLASH512;
391	if (savedata->type == SAVEDATA_FLASH1M) {
392		size = SIZE_CART_FLASH1M;
393	}
394	memset(savedata->data, 0xFF, size);
395}
396
397void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
398	GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
399	size_t size = 0x1000;
400	if (savedata->type == SAVEDATA_FLASH1M) {
401		GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
402	}
403	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
404}