all repos — mgba @ 3c18fe162c2c76eca80692d37083f6809bae4c8d

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#include "gba/serialize.h"
 10
 11#include "util/memory.h"
 12#include "util/vfs.h"
 13
 14#include <errno.h>
 15#include <fcntl.h>
 16
 17#define FLASH_SETTLE_CYCLES 18000
 18
 19static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
 20static void _flashErase(struct GBASavedata* savedata);
 21static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);
 22
 23void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
 24	savedata->type = SAVEDATA_AUTODETECT;
 25	savedata->data = 0;
 26	savedata->command = EEPROM_COMMAND_NULL;
 27	savedata->flashState = FLASH_STATE_RAW;
 28	savedata->vf = vf;
 29	savedata->realVf = vf;
 30	savedata->mapMode = MAP_WRITE;
 31}
 32
 33void GBASavedataDeinit(struct GBASavedata* savedata) {
 34	if (savedata->vf) {
 35		switch (savedata->type) {
 36		case SAVEDATA_SRAM:
 37			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_SRAM);
 38			break;
 39		case SAVEDATA_FLASH512:
 40			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512);
 41			break;
 42		case SAVEDATA_FLASH1M:
 43			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH1M);
 44			break;
 45		case SAVEDATA_EEPROM:
 46			savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM);
 47			break;
 48		case SAVEDATA_FORCE_NONE:
 49		case SAVEDATA_AUTODETECT:
 50			break;
 51		}
 52		savedata->vf = 0;
 53	} else {
 54		switch (savedata->type) {
 55		case SAVEDATA_SRAM:
 56			mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
 57			break;
 58		case SAVEDATA_FLASH512:
 59			mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
 60			break;
 61		case SAVEDATA_FLASH1M:
 62			mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M);
 63			break;
 64		case SAVEDATA_EEPROM:
 65			mappedMemoryFree(savedata->data, SIZE_CART_EEPROM);
 66			break;
 67		case SAVEDATA_FORCE_NONE:
 68		case SAVEDATA_AUTODETECT:
 69			break;
 70		}
 71	}
 72	savedata->data = 0;
 73	savedata->type = SAVEDATA_AUTODETECT;
 74}
 75
 76void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) {
 77	GBASavedataDeinit(savedata);
 78	savedata->vf = vf;
 79	savedata->mapMode = MAP_READ;
 80}
 81
 82void GBASavedataUnmask(struct GBASavedata* savedata) {
 83	if (savedata->mapMode != MAP_READ) {
 84		return;
 85	}
 86	GBASavedataDeinit(savedata);
 87	savedata->vf = savedata->realVf;
 88	savedata->mapMode = MAP_WRITE;
 89}
 90
 91bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
 92	if (savedata->data) {
 93		switch (savedata->type) {
 94		case SAVEDATA_SRAM:
 95			return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
 96		case SAVEDATA_FLASH512:
 97			return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
 98		case SAVEDATA_FLASH1M:
 99			return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M;
100		case SAVEDATA_EEPROM:
101			return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM;
102		case SAVEDATA_AUTODETECT:
103		case SAVEDATA_FORCE_NONE:
104			return true;
105		}
106	} else if (savedata->vf) {
107		off_t read = 0;
108		uint8_t buffer[2048];
109		do {
110			read = savedata->vf->read(savedata->vf, buffer, sizeof(buffer));
111			out->write(out, buffer, read);
112		} while (read == sizeof(buffer));
113		return read >= 0;
114	}
115	return true;
116}
117
118void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming) {
119	if (savedata->type != SAVEDATA_AUTODETECT) {
120		struct VFile* vf = savedata->vf;
121		GBASavedataDeinit(savedata);
122		GBASavedataInit(savedata, vf);
123	}
124	switch (type) {
125	case SAVEDATA_FLASH512:
126	case SAVEDATA_FLASH1M:
127		savedata->type = type;
128		GBASavedataInitFlash(savedata, realisticTiming);
129		break;
130	case SAVEDATA_EEPROM:
131		GBASavedataInitEEPROM(savedata);
132		break;
133	case SAVEDATA_SRAM:
134		GBASavedataInitSRAM(savedata);
135		break;
136	case SAVEDATA_FORCE_NONE:
137		savedata->type = SAVEDATA_FORCE_NONE;
138		break;
139	case SAVEDATA_AUTODETECT:
140		break;
141	}
142}
143
144void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming) {
145	if (savedata->type == SAVEDATA_AUTODETECT) {
146		savedata->type = SAVEDATA_FLASH512;
147	}
148	if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) {
149		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
150		return;
151	}
152	int32_t flashSize = SIZE_CART_FLASH512;
153	if (savedata->type == SAVEDATA_FLASH1M) {
154		flashSize = SIZE_CART_FLASH1M;
155	}
156	off_t end;
157	if (!savedata->vf) {
158		end = 0;
159		savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M);
160	} else {
161		end = savedata->vf->size(savedata->vf);
162		if (end < flashSize) {
163			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
164			flashSize = SIZE_CART_FLASH1M;
165		}
166		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, savedata->mapMode);
167	}
168
169	savedata->currentBank = savedata->data;
170	savedata->dust = 0;
171	savedata->realisticTiming = realisticTiming;
172	if (end < SIZE_CART_FLASH512) {
173		memset(&savedata->data[end], 0xFF, flashSize - end);
174	}
175}
176
177void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
178	if (savedata->type == SAVEDATA_AUTODETECT) {
179		savedata->type = SAVEDATA_EEPROM;
180	} else {
181		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
182		return;
183	}
184	off_t end;
185	if (!savedata->vf) {
186		end = 0;
187		savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM);
188	} else {
189		end = savedata->vf->size(savedata->vf);
190		if (end < SIZE_CART_EEPROM) {
191			savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM);
192		}
193		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode);
194	}
195	if (end < SIZE_CART_EEPROM) {
196		memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM - end);
197	}
198}
199
200void GBASavedataInitSRAM(struct GBASavedata* savedata) {
201	if (savedata->type == SAVEDATA_AUTODETECT) {
202		savedata->type = SAVEDATA_SRAM;
203	} else {
204		GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata");
205		return;
206	}
207	off_t end;
208	if (!savedata->vf) {
209		end = 0;
210		savedata->data = anonymousMemoryMap(SIZE_CART_SRAM);
211	} else {
212		end = savedata->vf->size(savedata->vf);
213		if (end < SIZE_CART_SRAM) {
214			savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM);
215		}
216		savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode);
217	}
218
219	if (end < SIZE_CART_SRAM) {
220		memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end);
221	}
222}
223
224uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
225	if (savedata->command == FLASH_COMMAND_ID) {
226		if (savedata->type == SAVEDATA_FLASH512) {
227			if (address < 2) {
228				return FLASH_MFG_PANASONIC >> (address * 8);
229			}
230		} else if (savedata->type == SAVEDATA_FLASH1M) {
231			if (address < 2) {
232				return FLASH_MFG_SANYO >> (address * 8);
233			}
234		}
235	}
236	if (savedata->dust > 0 && (address >> 12) == savedata->settling) {
237		--savedata->dust;
238		return 0x5F;
239	}
240	return savedata->currentBank[address];
241}
242
243void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value) {
244	switch (savedata->flashState) {
245	case FLASH_STATE_RAW:
246		switch (savedata->command) {
247		case FLASH_COMMAND_PROGRAM:
248			savedata->currentBank[address] = value;
249			savedata->command = FLASH_COMMAND_NONE;
250			break;
251		case FLASH_COMMAND_SWITCH_BANK:
252			if (address == 0 && value < 2) {
253				_flashSwitchBank(savedata, value);
254			} else {
255				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch");
256				savedata->command = FLASH_COMMAND_NONE;
257			}
258			savedata->command = FLASH_COMMAND_NONE;
259			break;
260		default:
261			if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) {
262				savedata->flashState = FLASH_STATE_START;
263			} else {
264				GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
265			}
266			break;
267		}
268		break;
269	case FLASH_STATE_START:
270		if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) {
271			savedata->flashState = FLASH_STATE_CONTINUE;
272		} else {
273			GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value);
274			savedata->flashState = FLASH_STATE_RAW;
275		}
276		break;
277	case FLASH_STATE_CONTINUE:
278		savedata->flashState = FLASH_STATE_RAW;
279		if (address == FLASH_BASE_HI) {
280			switch (savedata->command) {
281			case FLASH_COMMAND_NONE:
282				switch (value) {
283				case FLASH_COMMAND_ERASE:
284				case FLASH_COMMAND_ID:
285				case FLASH_COMMAND_PROGRAM:
286				case FLASH_COMMAND_SWITCH_BANK:
287					savedata->command = value;
288					break;
289				default:
290					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value);
291					break;
292				}
293				break;
294			case FLASH_COMMAND_ERASE:
295				switch (value) {
296				case FLASH_COMMAND_ERASE_CHIP:
297					_flashErase(savedata);
298					break;
299				default:
300					GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
301					break;
302				}
303				savedata->command = FLASH_COMMAND_NONE;
304				break;
305			case FLASH_COMMAND_ID:
306				if (value == FLASH_COMMAND_TERMINATE) {
307					savedata->command = FLASH_COMMAND_NONE;
308				}
309				break;
310			default:
311				GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command);
312				savedata->command = FLASH_COMMAND_NONE;
313				break;
314			}
315		} else if (savedata->command == FLASH_COMMAND_ERASE) {
316			if (value == FLASH_COMMAND_ERASE_SECTOR) {
317				_flashEraseSector(savedata, address);
318				savedata->command = FLASH_COMMAND_NONE;
319			} else {
320				GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value);
321			}
322		}
323		break;
324	}
325}
326
327void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize) {
328	switch (savedata->command) {
329	// Read header
330	case EEPROM_COMMAND_NULL:
331	default:
332		savedata->command = value & 0x1;
333		break;
334	case EEPROM_COMMAND_PENDING:
335		savedata->command <<= 1;
336		savedata->command |= value & 0x1;
337		if (savedata->command == EEPROM_COMMAND_WRITE) {
338			savedata->writeAddress = 0;
339		} else {
340			savedata->readAddress = 0;
341		}
342		break;
343	// Do commands
344	case EEPROM_COMMAND_WRITE:
345		// Write
346		if (writeSize > 65) {
347			savedata->writeAddress <<= 1;
348			savedata->writeAddress |= (value & 0x1) << 6;
349		} else if (writeSize == 1) {
350			savedata->command = EEPROM_COMMAND_NULL;
351		} else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) {
352			uint8_t current = savedata->data[savedata->writeAddress >> 3];
353			current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
354			current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
355			savedata->data[savedata->writeAddress >> 3] = current;
356			++savedata->writeAddress;
357		} else {
358			GBALog(0, GBA_LOG_GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3));
359		}
360		break;
361	case EEPROM_COMMAND_READ_PENDING:
362		// Read
363		if (writeSize > 1) {
364			savedata->readAddress <<= 1;
365			if (value & 0x1) {
366				savedata->readAddress |= 0x40;
367			}
368		} else {
369			savedata->readBitsRemaining = 68;
370			savedata->command = EEPROM_COMMAND_READ;
371		}
372		break;
373	}
374}
375
376uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
377	if (savedata->command != EEPROM_COMMAND_READ) {
378		return 1;
379	}
380	--savedata->readBitsRemaining;
381	if (savedata->readBitsRemaining < 64) {
382		int step = 63 - savedata->readBitsRemaining;
383		uint32_t address = (savedata->readAddress + step) >> 3;
384		if (address >= SIZE_CART_EEPROM) {
385			GBALog(0, GBA_LOG_GAME_ERROR, "Reading beyond end of EEPROM: %08X", address);
386			return 0xFF;
387		}
388		uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));
389		if (!savedata->readBitsRemaining) {
390			savedata->command = EEPROM_COMMAND_NULL;
391		}
392		return data & 0x1;
393	}
394	return 0;
395}
396
397void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
398	state->savedata.type = savedata->type;
399	state->savedata.command = savedata->command;
400	state->savedata.flashState = savedata->flashState;
401	state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000];
402	state->savedata.readBitsRemaining = savedata->readBitsRemaining;
403	state->savedata.readAddress = savedata->readAddress;
404	state->savedata.writeAddress = savedata->writeAddress;
405	state->savedata.settlingSector = savedata->settling;
406	state->savedata.settlingDust = savedata->dust;
407
408	UNUSED(includeData); // TODO
409}
410
411void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData) {
412	if (state->savedata.type == SAVEDATA_FORCE_NONE) {
413		return;
414	}
415	if (savedata->type != state->savedata.type) {
416		GBASavedataForceType(savedata, state->savedata.type, savedata->realisticTiming);
417	}
418	savedata->command = state->savedata.command;
419	savedata->flashState = state->savedata.flashState;
420	savedata->readBitsRemaining = state->savedata.readBitsRemaining;
421	savedata->readAddress = state->savedata.readAddress;
422	savedata->writeAddress = state->savedata.writeAddress;
423	savedata->settling = state->savedata.settlingSector;
424	savedata->dust = state->savedata.settlingDust;
425
426	if (savedata->type == SAVEDATA_FLASH1M) {
427		_flashSwitchBank(savedata, state->savedata.flashBank);
428	}
429
430	UNUSED(includeData); // TODO
431}
432
433void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
434	GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank);
435	savedata->currentBank = &savedata->data[bank << 16];
436	if (bank > 0 && savedata->type == SAVEDATA_FLASH512) {
437		savedata->type = SAVEDATA_FLASH1M;
438		if (savedata->vf) {
439			savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M);
440			memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512);
441		}
442	}
443}
444
445void _flashErase(struct GBASavedata* savedata) {
446	GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
447	size_t size = SIZE_CART_FLASH512;
448	if (savedata->type == SAVEDATA_FLASH1M) {
449		size = SIZE_CART_FLASH1M;
450	}
451	memset(savedata->data, 0xFF, size);
452}
453
454void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
455	GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
456	size_t size = 0x1000;
457	if (savedata->type == SAVEDATA_FLASH1M) {
458		GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
459	}
460	savedata->settling = sectorStart >> 12;
461	if (savedata->realisticTiming) {
462		savedata->dust = FLASH_SETTLE_CYCLES;
463	}
464	memset(&savedata->currentBank[sectorStart & ~(size - 1)], 0xFF, size);
465}