all repos — mgba @ 7bb5e29a984c2d509b072eafddc78ec712426c5a

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