all repos — mgba @ 9902e2eeeed324eecf813b4dd93ceafc03fc6ae7

mGBA Game Boy Advance Emulator

src/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 <mgba/internal/gba/overrides.h>
  7
  8#include <mgba/internal/gba/gba.h>
  9#include <mgba/internal/gba/hardware.h>
 10
 11#include <mgba-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	// Crash Bandicoot 2 - N-Tranced
 33	{ "AC8J", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 34	{ "AC8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 35	{ "AC8P", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 36
 37	// Dragon Ball Z - The Legacy of Goku
 38	{ "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 39
 40	// Dragon Ball Z - The Legacy of Goku II
 41	{ "ALFJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 42	{ "ALFE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 43	{ "ALFP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 44
 45	// Dragon Ball Z - Taiketsu
 46	{ "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 47	{ "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
 48
 49	// Drill Dozer
 50	{ "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
 51	{ "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
 52
 53	// e-Reader
 54	{ "PEAJ", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
 55	{ "PSAJ", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
 56	{ "PSAE", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
 57
 58	// Final Fantasy Tactics Advance
 59	{ "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428, false },
 60
 61	// F-Zero - Climax
 62	{ "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
 63
 64	// Iridion II
 65	{ "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
 66	{ "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
 67
 68	// Golden Sun: The Lost Age
 69	{ "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A, false },
 70
 71	// Koro Koro Puzzle - Happy Panechu!
 72	{ "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
 73
 74	// Legendz - Yomigaeru Shiren no Shima
 75	{ "BLJJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
 76	{ "BLJK", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
 77
 78	// Legendz - Sign of Nekuromu
 79	{ "BLVJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
 80
 81	// Mega Man Battle Network
 82	{ "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false },
 83
 84	// Mega Man Zero
 85	{ "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8, false },
 86
 87	// Metal Slug Advance
 88	{ "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290, false },
 89
 90	// Pokemon Pinball: Ruby & Sapphire
 91	{ "BPPJ", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
 92	{ "BPPE", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
 93	{ "BPPP", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
 94	{ "BPPU", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
 95
 96	// Pokemon Ruby
 97	{ "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
 98	{ "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
 99	{ "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
100	{ "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
101	{ "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
102	{ "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
103	{ "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
104
105	// Pokemon Sapphire
106	{ "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
107	{ "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
108	{ "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
109	{ "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
110	{ "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
111	{ "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
112	{ "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
113
114	// Pokemon Emerald
115	{ "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
116	{ "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
117	{ "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
118	{ "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
119	{ "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
120	{ "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
121	{ "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
122
123	// Pokemon Mystery Dungeon
124	{ "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
125	{ "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
126	{ "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
127	{ "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
128
129	// Pokemon FireRed
130	{ "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
131	{ "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
132	{ "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
133	{ "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
134	{ "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
135	{ "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
136	{ "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
137
138	// Pokemon LeafGreen
139	{ "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
140	{ "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
141	{ "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
142	{ "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
143	{ "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
144	{ "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
145	{ "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
146
147	// RockMan EXE 4.5 - Real Operation
148	{ "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
149
150	// Rocky
151	{ "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
152	{ "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
153
154	// Sennen Kazoku
155	{ "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
156
157	// Shin Bokura no Taiyou: Gyakushuu no Sabata
158	{ "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
159
160	// Super Mario Advance 2
161	{ "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
162	{ "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
163	{ "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E, false },
164
165	// Super Mario Advance 3
166	{ "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
167	{ "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
168	{ "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
169
170	// Super Mario Advance 4
171	{ "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
172	{ "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
173	{ "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
174
175	// Super Monkey Ball Jr.
176	{ "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
177	{ "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
178
179	// Top Gun - Combat Zones
180	{ "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
181
182	// Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle
183	{ "BUHJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
184
185	// Wario Ware Twisted
186	{ "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
187	{ "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
188	{ "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
189
190	// Yoshi's Universal Gravitation
191	{ "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
192	{ "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
193	{ "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
194
195	// Aging cartridge
196	{ "TCHK", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
197
198	// Famicom Mini series 3 (FDS), some aren't mirrored (22 - 28)
199	// See https://forum.no-intro.org/viewtopic.php?f=2&t=4221 for discussion
200	{ "FNMJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
201	{ "FMRJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
202	{ "FPTJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
203	{ "FLBJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
204	{ "FFMJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
205	{ "FTKJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
206	{ "FTUJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
207
208	{ { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false }
209};
210
211bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
212	override->savetype = SAVEDATA_AUTODETECT;
213	override->hardware = HW_NONE;
214	override->idleLoop = IDLE_LOOP_NONE;
215	override->mirroring = false;
216	bool found = false;
217
218	int i;
219	for (i = 0; _overrides[i].id[0]; ++i) {
220		if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
221			*override = _overrides[i];
222			found = true;
223			break;
224		}
225	}
226	if (!found && override->id[0] == 'F') {
227		// Classic NES Series
228		override->savetype = SAVEDATA_EEPROM;
229		override->mirroring = true;
230		found = true;
231	}
232
233	if (config) {
234		char sectionName[16];
235		snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
236		const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
237		const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
238		const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
239
240		if (savetype) {
241			if (strcasecmp(savetype, "SRAM") == 0) {
242				found = true;
243				override->savetype = SAVEDATA_SRAM;
244			} else if (strcasecmp(savetype, "EEPROM") == 0) {
245				found = true;
246				override->savetype = SAVEDATA_EEPROM;
247			} else if (strcasecmp(savetype, "EEPROM512") == 0) {
248				found = true;
249				override->savetype = SAVEDATA_EEPROM512;
250			} else if (strcasecmp(savetype, "FLASH512") == 0) {
251				found = true;
252				override->savetype = SAVEDATA_FLASH512;
253			} else if (strcasecmp(savetype, "FLASH1M") == 0) {
254				found = true;
255				override->savetype = SAVEDATA_FLASH1M;
256			} else if (strcasecmp(savetype, "NONE") == 0) {
257				found = true;
258				override->savetype = SAVEDATA_FORCE_NONE;
259			}
260		}
261
262		if (hardware) {
263			char* end;
264			long type = strtoul(hardware, &end, 0);
265			if (end && !*end) {
266				override->hardware = type;
267				found = true;
268			}
269		}
270
271		if (idleLoop) {
272			char* end;
273			uint32_t address = strtoul(idleLoop, &end, 16);
274			if (end && !*end) {
275				override->idleLoop = address;
276				found = true;
277			}
278		}
279	}
280	return found;
281}
282
283void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
284	char sectionName[16];
285	snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
286	const char* savetype = 0;
287	switch (override->savetype) {
288	case SAVEDATA_SRAM:
289		savetype = "SRAM";
290		break;
291	case SAVEDATA_EEPROM:
292		savetype = "EEPROM";
293		break;
294	case SAVEDATA_EEPROM512:
295		savetype = "EEPROM512";
296		break;
297	case SAVEDATA_FLASH512:
298		savetype = "FLASH512";
299		break;
300	case SAVEDATA_FLASH1M:
301		savetype = "FLASH1M";
302		break;
303	case SAVEDATA_FORCE_NONE:
304		savetype = "NONE";
305		break;
306	case SAVEDATA_AUTODETECT:
307		break;
308	}
309	ConfigurationSetValue(config, sectionName, "savetype", savetype);
310
311	if (override->hardware != HW_NO_OVERRIDE) {
312		ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
313	} else {
314		ConfigurationClearValue(config, sectionName, "hardware");
315	}
316
317	if (override->idleLoop != IDLE_LOOP_NONE) {
318		ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
319	} else {
320		ConfigurationClearValue(config, sectionName, "idleLoop");
321	}
322}
323
324void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
325	if (override->savetype != SAVEDATA_AUTODETECT) {
326		GBASavedataForceType(&gba->memory.savedata, override->savetype);
327	}
328
329	if (override->hardware != HW_NO_OVERRIDE) {
330		GBAHardwareClear(&gba->memory.hw);
331
332		if (override->hardware & HW_RTC) {
333			GBAHardwareInitRTC(&gba->memory.hw);
334		}
335
336		if (override->hardware & HW_GYRO) {
337			GBAHardwareInitGyro(&gba->memory.hw);
338		}
339
340		if (override->hardware & HW_RUMBLE) {
341			GBAHardwareInitRumble(&gba->memory.hw);
342		}
343
344		if (override->hardware & HW_LIGHT_SENSOR) {
345			GBAHardwareInitLight(&gba->memory.hw);
346		}
347
348		if (override->hardware & HW_TILT) {
349			GBAHardwareInitTilt(&gba->memory.hw);
350		}
351
352		if (override->hardware & HW_EREADER) {
353			GBAHardwareInitEReader(&gba->memory.hw);
354		}
355
356		if (override->hardware & HW_GB_PLAYER_DETECTION) {
357			gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION;
358		} else {
359			gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION;
360		}
361	}
362
363	if (override->idleLoop != IDLE_LOOP_NONE) {
364		gba->idleLoop = override->idleLoop;
365		if (gba->idleOptimization == IDLE_LOOP_DETECT) {
366			gba->idleOptimization = IDLE_LOOP_REMOVE;
367		}
368	}
369
370	if (override->mirroring) {
371		gba->memory.mirroring = true;
372	}
373}
374
375void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overrides) {
376	struct GBACartridgeOverride override = { .idleLoop = IDLE_LOOP_NONE };
377	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
378	if (cart) {
379		memcpy(override.id, &cart->id, sizeof(override.id));
380
381		if (!strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20) && gba->romCrc32 != 0xDD88761C) {
382			// Enable FLASH1M and RTC on Pokémon FireRed ROM hacks
383			override.savetype = SAVEDATA_FLASH1M;
384			override.hardware = HW_RTC;
385			GBAOverrideApply(gba, &override);
386		} else if (GBAOverrideFind(overrides, &override)) {
387			GBAOverrideApply(gba, &override);
388		}
389	}
390}