all repos — mgba @ 0de46a78679adf820eba08c3f72e64202540b692

mGBA Game Boy Advance Emulator

src/gba/gba-overrides.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 "gba-overrides.h"
  7
  8#include "gba.h"
  9#include "gba-gpio.h"
 10
 11 #include "util/configuration.h"
 12
 13static const struct GBACartridgeOverride _overrides[] = {
 14	// Boktai: The Sun is in Your Hand
 15	{ "U3IJ", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 16	{ "U3IE", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 17	{ "U3IP", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 18
 19	// Boktai 2: Solar Boy Django
 20	{ "U32J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 21	{ "U32E", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 22	{ "U32P", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 23
 24	// Drill Dozer
 25	{ "V49J", SAVEDATA_SRAM, GPIO_RUMBLE, IDLE_LOOP_NONE },
 26	{ "V49E", SAVEDATA_SRAM, GPIO_RUMBLE, IDLE_LOOP_NONE },
 27
 28	// Final Fantasy Tactics Advance
 29	{ "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000428 },
 30
 31	// Koro Koro Puzzle - Happy Panechu!
 32	{ "KHPJ", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
 33
 34	// Mega Man Battle Network
 35	{ "AREE", SAVEDATA_SRAM, GPIO_NONE, 0x800032E },
 36
 37	// Pokemon Ruby
 38	{ "AXVJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 39	{ "AXVE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 40	{ "AXVP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 41	{ "AXVI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 42	{ "AXVS", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 43	{ "AXVD", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 44	{ "AXVF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 45
 46	// Pokemon Sapphire
 47	{ "AXPJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 48	{ "AXPE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 49	{ "AXPP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 50	{ "AXPI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 51	{ "AXPS", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 52	{ "AXPD", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 53	{ "AXPF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 54
 55	// Pokemon Emerald
 56	{ "BPEJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 57	{ "BPEE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 58	{ "BPEP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 59	{ "BPEI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 60	{ "BPES", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 61	{ "BPED", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 62	{ "BPEF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
 63
 64	// Pokemon Mystery Dungeon
 65	{ "B24J", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 66	{ "B24E", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 67	{ "B24P", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 68	{ "B24U", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 69
 70	// Pokemon FireRed
 71	{ "BPRJ", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 72	{ "BPRE", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 73	{ "BPRP", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 74
 75	// Pokemon LeafGreen
 76	{ "BPGJ", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 77	{ "BPGE", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 78	{ "BPGP", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 79
 80	// RockMan EXE 4.5 - Real Operation
 81	{ "BR4J", SAVEDATA_FLASH512, GPIO_RTC, IDLE_LOOP_NONE },
 82
 83	// Shin Bokura no Taiyou: Gyakushuu no Sabata
 84	{ "U33J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
 85
 86	// Super Mario Advance 4
 87	{ "AX4J", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 88	{ "AX4E", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 89	{ "AX4P", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
 90
 91	// Top Gun - Combat Zones
 92	{ "A2YE", SAVEDATA_FORCE_NONE, GPIO_NONE, IDLE_LOOP_NONE },
 93
 94	// Wario Ware Twisted
 95	{ "RZWJ", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
 96	{ "RZWE", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
 97	{ "RZWP", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
 98
 99	// Yoshi's Universal Gravitation
100	{ "KYGJ", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
101	{ "KYGE", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
102	{ "KYGP", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
103
104	{ { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE }
105};
106
107bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
108	override->savetype = SAVEDATA_AUTODETECT;
109	override->hardware = GPIO_NONE;
110	override->idleLoop = IDLE_LOOP_NONE;
111	bool found;
112
113	if (override->id[0] == 'F') {
114		// Classic NES Series
115		override->savetype = SAVEDATA_EEPROM;
116		found = true;
117	} else {
118		int i;
119		for (i = 0; _overrides[i].id[0]; ++i) {
120			if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
121				*override = _overrides[i];
122				found = true;
123				break;
124			}
125		}
126	}
127
128	if (config) {
129		char sectionName[16];
130		snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
131		const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
132		const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
133		const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
134
135		if (savetype) {
136			if (strcasecmp(savetype, "SRAM") == 0) {
137				found = true;
138				override->savetype = SAVEDATA_SRAM;
139			} else if (strcasecmp(savetype, "EEPROM") == 0) {
140				found = true;
141				override->savetype = SAVEDATA_EEPROM;
142			} else if (strcasecmp(savetype, "FLASH512") == 0) {
143				found = true;
144				override->savetype = SAVEDATA_FLASH512;
145			} else if (strcasecmp(savetype, "FLASH1M") == 0) {
146				found = true;
147				override->savetype = SAVEDATA_FLASH1M;
148			} else if (strcasecmp(savetype, "NONE") == 0) {
149				found = true;
150				override->savetype = SAVEDATA_FORCE_NONE;
151			}
152		}
153
154		if (hardware) {
155			char* end;
156			long type = strtoul(hardware, &end, 0);
157			if (end && !*end) {
158				override->hardware = type;
159				found = true;
160			}
161		}
162
163		if (idleLoop) {
164			char* end;
165			uint32_t address = strtoul(idleLoop, &end, 16);
166			if (end && !*end) {
167				override->idleLoop = address;
168				found = true;
169			}
170		}
171	}
172	return found;
173}
174
175void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
176	char sectionName[16];
177	snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
178	const char* savetype = 0;
179	switch (override->savetype) {
180	case SAVEDATA_SRAM:
181		savetype = "SRAM";
182		break;
183	case SAVEDATA_EEPROM:
184		savetype = "EEPROM";
185		break;
186	case SAVEDATA_FLASH512:
187		savetype = "FLASH512";
188		break;
189	case SAVEDATA_FLASH1M:
190		savetype = "FLASH1M";
191		break;
192	case SAVEDATA_FORCE_NONE:
193		savetype = "NONE";
194		break;
195	case SAVEDATA_AUTODETECT:
196		break;
197	}
198	ConfigurationSetValue(config, sectionName, "savetype", savetype);
199
200	if (override->hardware != GPIO_NO_OVERRIDE) {
201		ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
202	} else {
203		ConfigurationClearValue(config, sectionName, "hardware");
204	}
205
206	if (override->idleLoop != IDLE_LOOP_NONE) {
207		ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
208	} else {
209		ConfigurationClearValue(config, sectionName, "idleLoop");
210	}
211}
212
213void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
214	if (override->savetype != SAVEDATA_AUTODETECT) {
215		GBASavedataForceType(&gba->memory.savedata, override->savetype);
216	}
217
218	if (override->hardware != GPIO_NO_OVERRIDE) {
219		GBAGPIOClear(&gba->memory.gpio);
220
221		if (override->hardware & GPIO_RTC) {
222			GBAGPIOInitRTC(&gba->memory.gpio);
223		}
224
225		if (override->hardware & GPIO_GYRO) {
226			GBAGPIOInitGyro(&gba->memory.gpio);
227		}
228
229		if (override->hardware & GPIO_RUMBLE) {
230			GBAGPIOInitRumble(&gba->memory.gpio);
231		}
232
233		if (override->hardware & GPIO_LIGHT_SENSOR) {
234			GBAGPIOInitLightSensor(&gba->memory.gpio);
235		}
236
237		if (override->hardware & GPIO_TILT) {
238			GBAGPIOInitTilt(&gba->memory.gpio);
239		}
240	}
241
242	if (override->idleLoop != IDLE_LOOP_NONE) {
243		gba->idleLoop = override->idleLoop;
244		if (gba->idleOptimization == IDLE_LOOP_DETECT) {
245			gba->idleOptimization = IDLE_LOOP_REMOVE;
246		}
247	}
248}