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}