all repos — mgba @ 51b8c862b969390582cb39b3ac98239cdea9a4b1

mGBA Game Boy Advance Emulator

src/gba/supervisor/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 "overrides.h"
  7
  8#include "gba/gba.h"
  9#include "gba/hardware.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, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 16	{ "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 17	{ "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 18
 19	// Boktai 2: Solar Boy Django
 20	{ "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 21	{ "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 22	{ "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
 23
 24	// Dragon Ball Z - The Legacy of Goku
 25	{ "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
 26
 27	// Dragon Ball Z - Taiketsu
 28	{ "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
 29	{ "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
 30
 31	// Drill Dozer
 32	{ "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE },
 33	{ "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE },
 34
 35	// Final Fantasy Tactics Advance
 36	{ "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428 },
 37
 38	// F-Zero - Climax
 39	{ "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 40
 41	// Golden Sun: The Lost Age
 42	{ "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A },
 43
 44	// Koro Koro Puzzle - Happy Panechu!
 45	{ "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
 46
 47	// Mega Man Battle Network
 48	{ "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E },
 49
 50	// Metal Slug Advance
 51	{ "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290 },
 52
 53	// Pokemon Ruby
 54	{ "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 55	{ "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 56	{ "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 57	{ "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 58	{ "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 59	{ "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 60	{ "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 61
 62	// Pokemon Sapphire
 63	{ "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 64	{ "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 65	{ "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 66	{ "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 67	{ "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 68	{ "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 69	{ "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 70
 71	// Pokemon Emerald
 72	{ "BPEJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 73	{ "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 },
 74	{ "BPEP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 75	{ "BPEI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 76	{ "BPES", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 77	{ "BPED", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 78	{ "BPEF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
 79
 80	// Pokemon Mystery Dungeon
 81	{ "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 82	{ "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 83	{ "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 84	{ "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 85
 86	// Pokemon FireRed
 87	{ "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 88	{ "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 89	{ "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 90	{ "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 91	{ "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 92	{ "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 93	{ "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 94
 95	// Pokemon LeafGreen
 96	{ "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 97	{ "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 98	{ "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
 99	{ "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
100	{ "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
101	{ "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
102	{ "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
103
104	// RockMan EXE 4.5 - Real Operation
105	{ "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE },
106
107	// Rocky
108	{ "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
109	{ "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
110
111	// Sennen Kazoku
112	{ "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
113
114	// Shin Bokura no Taiyou: Gyakushuu no Sabata
115	{ "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
116
117	// Super Mario Advance 2
118	{ "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E },
119
120	// Super Mario Advance 3
121	{ "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C },
122
123	// Super Mario Advance 4
124	{ "AX4J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
125	{ "AX4E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
126	{ "AX4P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
127
128	// Top Gun - Combat Zones
129	{ "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE },
130
131	// Wario Ware Twisted
132	{ "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
133	{ "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
134	{ "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
135
136	// Yoshi's Universal Gravitation
137	{ "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
138	{ "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
139	{ "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
140
141	{ { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE }
142};
143
144bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
145	override->savetype = SAVEDATA_AUTODETECT;
146	override->hardware = HW_NONE;
147	override->idleLoop = IDLE_LOOP_NONE;
148	bool found;
149
150	if (override->id[0] == 'F') {
151		// Classic NES Series
152		override->savetype = SAVEDATA_EEPROM;
153		found = true;
154	} else {
155		int i;
156		for (i = 0; _overrides[i].id[0]; ++i) {
157			if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
158				*override = _overrides[i];
159				found = true;
160				break;
161			}
162		}
163	}
164
165	if (config) {
166		char sectionName[16];
167		snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
168		const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
169		const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
170		const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
171
172		if (savetype) {
173			if (strcasecmp(savetype, "SRAM") == 0) {
174				found = true;
175				override->savetype = SAVEDATA_SRAM;
176			} else if (strcasecmp(savetype, "EEPROM") == 0) {
177				found = true;
178				override->savetype = SAVEDATA_EEPROM;
179			} else if (strcasecmp(savetype, "FLASH512") == 0) {
180				found = true;
181				override->savetype = SAVEDATA_FLASH512;
182			} else if (strcasecmp(savetype, "FLASH1M") == 0) {
183				found = true;
184				override->savetype = SAVEDATA_FLASH1M;
185			} else if (strcasecmp(savetype, "NONE") == 0) {
186				found = true;
187				override->savetype = SAVEDATA_FORCE_NONE;
188			}
189		}
190
191		if (hardware) {
192			char* end;
193			long type = strtoul(hardware, &end, 0);
194			if (end && !*end) {
195				override->hardware = type;
196				found = true;
197			}
198		}
199
200		if (idleLoop) {
201			char* end;
202			uint32_t address = strtoul(idleLoop, &end, 16);
203			if (end && !*end) {
204				override->idleLoop = address;
205				found = true;
206			}
207		}
208	}
209	return found;
210}
211
212void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
213	char sectionName[16];
214	snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
215	const char* savetype = 0;
216	switch (override->savetype) {
217	case SAVEDATA_SRAM:
218		savetype = "SRAM";
219		break;
220	case SAVEDATA_EEPROM:
221		savetype = "EEPROM";
222		break;
223	case SAVEDATA_FLASH512:
224		savetype = "FLASH512";
225		break;
226	case SAVEDATA_FLASH1M:
227		savetype = "FLASH1M";
228		break;
229	case SAVEDATA_FORCE_NONE:
230		savetype = "NONE";
231		break;
232	case SAVEDATA_AUTODETECT:
233		break;
234	}
235	ConfigurationSetValue(config, sectionName, "savetype", savetype);
236
237	if (override->hardware != HW_NO_OVERRIDE) {
238		ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
239	} else {
240		ConfigurationClearValue(config, sectionName, "hardware");
241	}
242
243	if (override->idleLoop != IDLE_LOOP_NONE) {
244		ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
245	} else {
246		ConfigurationClearValue(config, sectionName, "idleLoop");
247	}
248}
249
250void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
251	if (override->savetype != SAVEDATA_AUTODETECT) {
252		GBASavedataForceType(&gba->memory.savedata, override->savetype);
253	}
254
255	if (override->hardware != HW_NO_OVERRIDE) {
256		GBAHardwareClear(&gba->memory.hw);
257
258		if (override->hardware & HW_RTC) {
259			GBAHardwareInitRTC(&gba->memory.hw);
260		}
261
262		if (override->hardware & HW_GYRO) {
263			GBAHardwareInitGyro(&gba->memory.hw);
264		}
265
266		if (override->hardware & HW_RUMBLE) {
267			GBAHardwareInitRumble(&gba->memory.hw);
268		}
269
270		if (override->hardware & HW_LIGHT_SENSOR) {
271			GBAHardwareInitLight(&gba->memory.hw);
272		}
273
274		if (override->hardware & HW_TILT) {
275			GBAHardwareInitTilt(&gba->memory.hw);
276		}
277	}
278
279	if (override->idleLoop != IDLE_LOOP_NONE) {
280		gba->idleLoop = override->idleLoop;
281		if (gba->idleOptimization == IDLE_LOOP_DETECT) {
282			gba->idleOptimization = IDLE_LOOP_REMOVE;
283		}
284	}
285}