all repos — mgba @ a55a3cb4d4cad2f838e12ce27e61ad97b79dd525

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