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}