all repos — mgba @ b11528c69df86c3be49ac4715495d38b1309b53e

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