all repos — mgba @ df8cddb289bece5bd4ed0db9355048ecd006d12c

mGBA Game Boy Advance Emulator

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