all repos — mgba @ 7149dd3102a6bbb7f73cae7da0c01dc784b0f601

mGBA Game Boy Advance Emulator

src/gba/savedata.c (view raw)

  1/* Copyright (c) 2013-2015 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 "savedata.h"
  7
  8#include "gba/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	if (savedata->type != SAVEDATA_AUTODETECT) {
117		struct VFile* vf = savedata->vf;
118		GBASavedataDeinit(savedata);
119		GBASavedataInit(savedata, vf);
120	}
121	switch (type) {
122	case SAVEDATA_FLASH512:
123	case SAVEDATA_FLASH1M:
124		savedata->type = type;
125		GBASavedataInitFlash(savedata);
126		break;
127	case SAVEDATA_EEPROM:
128		GBASavedataInitEEPROM(savedata);
129		break;
130	case SAVEDATA_SRAM:
131		GBASavedataInitSRAM(savedata);
132		break;
133	case SAVEDATA_FORCE_NONE:
134		savedata->type = SAVEDATA_FORCE_NONE;
135		break;
136	case SAVEDATA_AUTODETECT:
137		break;
138	}
139}
140
141void GBASavedataInitFlash(struct GBASavedata* savedata) {
142	if (savedata->type == SAVEDATA_AUTODETECT) {
143		savedata->type = SAVEDATA_FLASH512;
144	}
145	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
146		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
147		return;
148	}
149	size_t flashSize = SIZE_CART_FLASH512;
150	off_t end;
151	if (!savedata->vf) {
152		end = 0;
153		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
154	} else {
155		end = savedata->vf->size(savedata->vf);
156		if (end < SIZE_CART_FLASH512) {
157			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
158			flashSize = SIZE_CART_FLASH1M;
159		}
160		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
161	}
162
163	savedata->currentBank = savedata->data;
164	if (end < SIZE_CART_FLASH512) {
165		memset(&savedata->data[end], 0xFF, flashSize - end);
166	}
167}
168
169void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
170	if (savedata->type == SAVEDATA_AUTODETECT) {
171		savedata->type = SAVEDATA_EEPROM;
172	} else {
173		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
174		return;
175	}
176	off_t end;
177	if (!savedata->vf) {
178		end = 0;
179		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
180	} else {
181		end = savedata->vf->size(savedata->vf);
182		if (end < SIZE_CART_EEPROM) {
183			savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
184		}
185		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
186	}
187	if (end < SIZE_CART_EEPROM) {
188		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
189	}
190}
191
192void GBASavedataInitSRAM(struct GBASavedata* savedata) {
193	if (savedata->type == SAVEDATA_AUTODETECT) {
194		savedata->type = SAVEDATA_SRAM;
195	} else {
196		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
197		return;
198	}
199	off_t end;
200	if (!savedata->vf) {
201		end = 0;
202		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
203	} else {
204		end = savedata->vf->size(savedata->vf);
205		if (end < SIZE_CART_SRAM) {
206			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
207		}
208		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
209	}
210
211	if (end < SIZE_CART_SRAM) {
212		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
213	}
214}
215
216uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
217	if (savedata->command == FLASH_COMMAND_ID) {
218		if (savedata->type == SAVEDATA_FLASH512) {
219			if (address < 2) {
220				return FLASH_MFG_PANASONIC >> (address * 8);
221			}
222		} else if (savedata->type == SAVEDATA_FLASH1M) {
223			if (address < 2) {
224				return FLASH_MFG_SANYO >> (address * 8);
225			}
226		}
227	}
228	return savedata->currentBank[address];
229}
230
231void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
232	switch (savedata->flashState) {
233	case FLASH_STATE_RAW:
234		switch (savedata->command) {
235		case FLASH_COMMAND_PROGRAM:
236			savedata->currentBank[address] = value;
237			savedata->command = FLASH_COMMAND_NONE;
238			break;
239		case FLASH_COMMAND_SWITCH_BANK:
240			if (address == 0 && value < 2) {
241				_flashSwitchBank(savedata, value);
242			} else {
243				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
244				savedata->command = FLASH_COMMAND_NONE;
245			}
246			savedata->command = FLASH_COMMAND_NONE;
247			break;
248		default:
249			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
250				savedata->flashState = FLASH_STATE_START;
251			} else {
252				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
253			}
254			break;
255		}
256		break;
257	case FLASH_STATE_START:
258		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
259			savedata->flashState = FLASH_STATE_CONTINUE;
260		} else {
261			GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
262			savedata->flashState = FLASH_STATE_RAW;
263		}
264		break;
265	case FLASH_STATE_CONTINUE:
266		savedata->flashState = FLASH_STATE_RAW;
267		if (address == FLASH_BASE_HI) {
268			switch (savedata->command) {
269			case FLASH_COMMAND_NONE:
270				switch (value) {
271				case FLASH_COMMAND_ERASE:
272				case FLASH_COMMAND_ID:
273				case FLASH_COMMAND_PROGRAM:
274				case FLASH_COMMAND_SWITCH_BANK:
275					savedata->command = value;
276					break;
277				default:
278					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
279					break;
280				}
281				break;
282			case FLASH_COMMAND_ERASE:
283				switch (value) {
284				case FLASH_COMMAND_ERASE_CHIP:
285					_flashErase(savedata);
286					break;
287				default:
288					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
289					break;
290				}
291				savedata->command = FLASH_COMMAND_NONE;
292				break;
293			case FLASH_COMMAND_ID:
294				if (value == FLASH_COMMAND_TERMINATE) {
295					savedata->command = FLASH_COMMAND_NONE;
296				}
297				break;
298			default:
299				GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
300				savedata->command = FLASH_COMMAND_NONE;
301				break;
302			}
303		} else if (savedata->command == FLASH_COMMAND_ERASE) {
304			if (value == FLASH_COMMAND_ERASE_SECTOR) {
305				_flashEraseSector(savedata, address);
306				savedata->command = FLASH_COMMAND_NONE;
307			} else {
308				GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
309			}
310		}
311		break;
312	}
313}
314
315void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
316	switch (savedata->command) {
317	// Read header
318	case EEPROM_COMMAND_NULL:
319	default:
320		savedata->command = value & 0x1;
321		break;
322	case EEPROM_COMMAND_PENDING:
323		savedata->command <<= 1;
324		savedata->command |= value & 0x1;
325		if (savedata->command == EEPROM_COMMAND_WRITE) {
326			savedata->addressBits = writeSize - 64 - 2;
327			savedata->writeAddress = 0;
328		} else {
329			savedata->addressBits = writeSize - 2;
330			savedata->readAddress = 0;
331		}
332		break;
333	// Do commands
334	case EEPROM_COMMAND_WRITE:
335		// Write
336		if (writeSize > 65) {
337			savedata->writeAddress <<= 1;
338			savedata->writeAddress |= (value & 0x1) << 6;
339		} else if (writeSize == 1) {
340			savedata->command = EEPROM_COMMAND_NULL;
341			savedata->writePending = 1;
342		} else {
343			uint8_t current = savedata->data[savedata->writeAddress >> 3];
344			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
345			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
346			savedata->data[savedata->writeAddress >> 3] = current;
347			++savedata->writeAddress;
348		}
349		break;
350	case EEPROM_COMMAND_READ_PENDING:
351		// Read
352		if (writeSize > 1) {
353			savedata->readAddress <<= 1;
354			if (value & 0x1) {
355				savedata->readAddress |= 0x40;
356			}
357		} else {
358			savedata->readBitsRemaining = 68;
359			savedata->command = EEPROM_COMMAND_READ;
360		}
361		break;
362	}
363}
364
365uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
366	if (savedata->command != EEPROM_COMMAND_READ) {
367		return 1;
368	}
369	--savedata->readBitsRemaining;
370	if (savedata->readBitsRemaining < 64) {
371		int step = 63 - savedata->readBitsRemaining;
372		uint8_t data = savedata->data[(savedata->readAddress + step) >> 3] >> (0x7 - (step & 0x7));
373		if (!savedata->readBitsRemaining) {
374			savedata->command = EEPROM_COMMAND_NULL;
375		}
376		return data & 0x1;
377	}
378	return 0;
379}
380
381void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
382	GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank);
383	savedata->currentBank = &savedata->data[bank << 16];
384	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
385		savedata->type = SAVEDATA_FLASH1M;
386		if (savedata->vf) {
387			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
388			memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
389		}
390	}
391}
392
393void _flashErase(struct GBASavedata* savedata) {
394	GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
395	size_t size = SIZE_CART_FLASH512;
396	if (savedata->type == SAVEDATA_FLASH1M) {
397		size = SIZE_CART_FLASH1M;
398	}
399	memset(savedata->data, 0xFF, size);
400}
401
402void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
403	GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
404	size_t size = 0x1000;
405	if (savedata->type == SAVEDATA_FLASH1M) {
406		GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
407	}
408	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
409}