all repos — mgba @ 82b31c46f11c81193809e26479d8699b771b1be1

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