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