src/gba/gba.c (view raw)
1#include "gba.h"
2
3#include "gba-bios.h"
4#include "gba-io.h"
5#include "gba-sio.h"
6#include "gba-thread.h"
7#include "memory.h"
8
9#include "debugger.h"
10
11#include <limits.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16
17const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
18
19enum {
20 SP_BASE_SYSTEM = 0x03FFFF00,
21 SP_BASE_IRQ = 0x03FFFFA0,
22 SP_BASE_SUPERVISOR = 0x03FFFFE0
23};
24
25struct GBACartridgeOverride {
26 const char id[4];
27 enum SavedataType type;
28 int gpio;
29};
30
31static const struct GBACartridgeOverride _overrides[] = {
32 // Boktai: The Sun is in Your Hand
33 { "U3IE", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
34 { "U3IP", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
35
36 // Boktai 2: Solar Boy Django
37 { "U32E", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
38 { "U32P", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
39
40 // Drill Dozer
41 { "V49J", SAVEDATA_SRAM, GPIO_RUMBLE },
42 { "V49E", SAVEDATA_SRAM, GPIO_RUMBLE },
43
44 // Pokemon Ruby
45 { "AXVJ", SAVEDATA_FLASH1M, GPIO_RTC },
46 { "AXVE", SAVEDATA_FLASH1M, GPIO_RTC },
47 { "AXVP", SAVEDATA_FLASH1M, GPIO_RTC },
48 { "AXVI", SAVEDATA_FLASH1M, GPIO_RTC },
49 { "AXVS", SAVEDATA_FLASH1M, GPIO_RTC },
50 { "AXVD", SAVEDATA_FLASH1M, GPIO_RTC },
51 { "AXVF", SAVEDATA_FLASH1M, GPIO_RTC },
52
53 // Pokemon Sapphire
54 { "AXPJ", SAVEDATA_FLASH1M, GPIO_RTC },
55 { "AXPE", SAVEDATA_FLASH1M, GPIO_RTC },
56 { "AXPP", SAVEDATA_FLASH1M, GPIO_RTC },
57 { "AXPI", SAVEDATA_FLASH1M, GPIO_RTC },
58 { "AXPS", SAVEDATA_FLASH1M, GPIO_RTC },
59 { "AXPD", SAVEDATA_FLASH1M, GPIO_RTC },
60 { "AXPF", SAVEDATA_FLASH1M, GPIO_RTC },
61
62 // Pokemon Emerald
63 { "BPEJ", SAVEDATA_FLASH1M, GPIO_RTC },
64 { "BPEE", SAVEDATA_FLASH1M, GPIO_RTC },
65 { "BPEP", SAVEDATA_FLASH1M, GPIO_RTC },
66 { "BPEI", SAVEDATA_FLASH1M, GPIO_RTC },
67 { "BPES", SAVEDATA_FLASH1M, GPIO_RTC },
68 { "BPED", SAVEDATA_FLASH1M, GPIO_RTC },
69 { "BPEF", SAVEDATA_FLASH1M, GPIO_RTC },
70
71 // Pokemon FireRed
72 { "BPRJ", SAVEDATA_FLASH1M, GPIO_NONE },
73 { "BPRE", SAVEDATA_FLASH1M, GPIO_NONE },
74 { "BPRP", SAVEDATA_FLASH1M, GPIO_NONE },
75
76 // Pokemon LeafGreen
77 { "BPGJ", SAVEDATA_FLASH1M, GPIO_NONE },
78 { "BPGE", SAVEDATA_FLASH1M, GPIO_NONE },
79 { "BPGP", SAVEDATA_FLASH1M, GPIO_NONE },
80
81 // RockMan EXE 4.5 - Real Operation
82 { "BR4J", SAVEDATA_FLASH512, GPIO_RTC },
83
84 // Super Mario Advance 4
85 { "AX4J", SAVEDATA_FLASH1M, GPIO_NONE },
86 { "AX4E", SAVEDATA_FLASH1M, GPIO_NONE },
87 { "AX4P", SAVEDATA_FLASH1M, GPIO_NONE },
88
89 // Wario Ware Twisted
90 { "RWZJ", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
91 { "RWZE", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
92 { "RWZP", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
93
94 { { 0, 0, 0, 0 }, 0, 0 }
95};
96
97static void GBAProcessEvents(struct ARMBoard* board);
98static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);
99static void GBAHitStub(struct ARMBoard* board, uint32_t opcode);
100static void GBAIllegal(struct ARMBoard* board, uint32_t opcode);
101
102static void _checkOverrides(struct GBA* gba, uint32_t code);
103
104void GBAInit(struct GBA* gba) {
105 gba->debugger = 0;
106 gba->savefile = 0;
107
108 ARMInit(&gba->cpu);
109
110 gba->memory.p = gba;
111 GBAMemoryInit(&gba->memory);
112 ARMAssociateMemory(&gba->cpu, &gba->memory.d);
113
114 gba->board.p = gba;
115 GBABoardInit(&gba->board);
116 ARMAssociateBoard(&gba->cpu, &gba->board.d);
117
118 gba->video.p = gba;
119 GBAVideoInit(&gba->video);
120
121 gba->audio.p = gba;
122 GBAAudioInit(&gba->audio);
123
124 GBAIOInit(gba);
125
126 gba->sio.p = gba;
127 GBASIOInit(&gba->sio);
128
129 gba->timersEnabled = 0;
130 memset(gba->timers, 0, sizeof(gba->timers));
131
132 gba->springIRQ = 0;
133 gba->keySource = 0;
134 gba->rotationSource = 0;
135 gba->rumble = 0;
136
137 gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
138
139 gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
140
141 ARMReset(&gba->cpu);
142}
143
144void GBADeinit(struct GBA* gba) {
145 GBAMemoryDeinit(&gba->memory);
146 GBAVideoDeinit(&gba->video);
147 GBAAudioDeinit(&gba->audio);
148}
149
150void GBABoardInit(struct GBABoard* board) {
151 board->d.reset = GBABoardReset;
152 board->d.processEvents = GBAProcessEvents;
153 board->d.swi16 = GBASwi16;
154 board->d.swi32 = GBASwi32;
155 board->d.hitIllegal = GBAIllegal;
156 board->d.readCPSR = GBATestIRQ;
157 board->d.hitStub = GBAHitStub;
158}
159
160void GBABoardReset(struct ARMBoard* board) {
161 struct ARMCore* cpu = board->cpu;
162 ARMSetPrivilegeMode(cpu, MODE_IRQ);
163 cpu->gprs[ARM_SP] = SP_BASE_IRQ;
164 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
165 cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
166 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
167 cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
168}
169
170static void GBAProcessEvents(struct ARMBoard* board) {
171 do {
172 struct GBABoard* gbaBoard = (struct GBABoard*) board;
173 int32_t cycles = board->cpu->cycles;
174 int32_t nextEvent = INT_MAX;
175 int32_t testEvent;
176
177 if (gbaBoard->p->springIRQ) {
178 ARMRaiseIRQ(&gbaBoard->p->cpu);
179 gbaBoard->p->springIRQ = 0;
180 }
181
182 testEvent = GBAVideoProcessEvents(&gbaBoard->p->video, cycles);
183 if (testEvent < nextEvent) {
184 nextEvent = testEvent;
185 }
186
187 testEvent = GBAAudioProcessEvents(&gbaBoard->p->audio, cycles);
188 if (testEvent < nextEvent) {
189 nextEvent = testEvent;
190 }
191
192 testEvent = GBATimersProcessEvents(gbaBoard->p, cycles);
193 if (testEvent < nextEvent) {
194 nextEvent = testEvent;
195 }
196
197 testEvent = GBAMemoryRunDMAs(&gbaBoard->p->memory, cycles);
198 if (testEvent < nextEvent) {
199 nextEvent = testEvent;
200 }
201
202 testEvent = GBASIOProcessEvents(&gbaBoard->p->sio, cycles);
203 if (testEvent < nextEvent) {
204 nextEvent = testEvent;
205 }
206
207 board->cpu->cycles -= cycles;
208 board->cpu->nextEvent = nextEvent;
209 } while (board->cpu->cycles >= board->cpu->nextEvent);
210}
211
212static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
213 int32_t nextEvent = INT_MAX;
214 if (gba->timersEnabled) {
215 struct GBATimer* timer;
216 struct GBATimer* nextTimer;
217
218 timer = &gba->timers[0];
219 if (timer->enable) {
220 timer->nextEvent -= cycles;
221 timer->lastEvent -= cycles;
222 if (timer->nextEvent <= 0) {
223 timer->lastEvent = timer->nextEvent;
224 timer->nextEvent += timer->overflowInterval;
225 gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
226 timer->oldReload = timer->reload;
227
228 if (timer->doIrq) {
229 GBARaiseIRQ(gba, IRQ_TIMER0);
230 }
231
232 if (gba->audio.enable) {
233 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 0) {
234 GBAAudioSampleFIFO(&gba->audio, 0, timer->lastEvent);
235 }
236
237 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 0) {
238 GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
239 }
240 }
241
242 nextTimer = &gba->timers[1];
243 if (nextTimer->countUp) {
244 ++gba->memory.io[REG_TM1CNT_LO >> 1];
245 if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
246 nextTimer->nextEvent = 0;
247 }
248 }
249 }
250 nextEvent = timer->nextEvent;
251 }
252
253 timer = &gba->timers[1];
254 if (timer->enable) {
255 timer->nextEvent -= cycles;
256 timer->lastEvent -= cycles;
257 if (timer->nextEvent <= 0) {
258 timer->lastEvent = timer->nextEvent;
259 timer->nextEvent += timer->overflowInterval;
260 gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
261 timer->oldReload = timer->reload;
262
263 if (timer->doIrq) {
264 GBARaiseIRQ(gba, IRQ_TIMER1);
265 }
266
267 if (gba->audio.enable) {
268 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 1) {
269 GBAAudioSampleFIFO(&gba->audio, 0, timer->lastEvent);
270 }
271
272 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 1) {
273 GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
274 }
275 }
276
277 if (timer->countUp) {
278 timer->nextEvent = INT_MAX;
279 }
280
281 nextTimer = &gba->timers[2];
282 if (nextTimer->countUp) {
283 ++gba->memory.io[REG_TM2CNT_LO >> 1];
284 if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
285 nextTimer->nextEvent = 0;
286 }
287 }
288 }
289 if (timer->nextEvent < nextEvent) {
290 nextEvent = timer->nextEvent;
291 }
292 }
293
294 timer = &gba->timers[2];
295 if (timer->enable) {
296 timer->nextEvent -= cycles;
297 timer->lastEvent -= cycles;
298 nextEvent = timer->nextEvent;
299 if (timer->nextEvent <= 0) {
300 timer->lastEvent = timer->nextEvent;
301 timer->nextEvent += timer->overflowInterval;
302 gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
303 timer->oldReload = timer->reload;
304
305 if (timer->doIrq) {
306 GBARaiseIRQ(gba, IRQ_TIMER2);
307 }
308
309 if (timer->countUp) {
310 timer->nextEvent = INT_MAX;
311 }
312
313 nextTimer = &gba->timers[3];
314 if (nextTimer->countUp) {
315 ++gba->memory.io[REG_TM3CNT_LO >> 1];
316 if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
317 nextTimer->nextEvent = 0;
318 }
319 }
320 }
321 if (timer->nextEvent < nextEvent) {
322 nextEvent = timer->nextEvent;
323 }
324 }
325
326 timer = &gba->timers[3];
327 if (timer->enable) {
328 timer->nextEvent -= cycles;
329 timer->lastEvent -= cycles;
330 nextEvent = timer->nextEvent;
331 if (timer->nextEvent <= 0) {
332 timer->lastEvent = timer->nextEvent;
333 timer->nextEvent += timer->overflowInterval;
334 gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
335 timer->oldReload = timer->reload;
336
337 if (timer->doIrq) {
338 GBARaiseIRQ(gba, IRQ_TIMER3);
339 }
340
341 if (timer->countUp) {
342 timer->nextEvent = INT_MAX;
343 }
344 }
345 if (timer->nextEvent < nextEvent) {
346 nextEvent = timer->nextEvent;
347 }
348 }
349 }
350 return nextEvent;
351}
352
353void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
354 ARMDebuggerInit(debugger, &gba->cpu);
355 gba->debugger = debugger;
356}
357
358void GBADetachDebugger(struct GBA* gba) {
359 ARMDebuggerDeinit(gba->debugger);
360 gba->debugger = 0;
361}
362
363void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
364 struct stat info;
365 gba->memory.rom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ);
366 gba->activeFile = fname;
367 fstat(fd, &info);
368 gba->memory.romSize = info.st_size;
369 if (gba->savefile) {
370 GBASavedataInit(&gba->memory.savedata, gba->savefile);
371 }
372 GBAGPIOInit(&gba->memory.gpio, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
373 _checkOverrides(gba, ((struct GBACartridge*) gba->memory.rom)->id);
374 // TODO: error check
375}
376
377void GBALoadBIOS(struct GBA* gba, int fd) {
378 gba->memory.bios = fileMemoryMap(fd, SIZE_BIOS, MEMORY_READ);
379 gba->memory.fullBios = 1;
380 uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
381 GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);
382 if (checksum == GBA_BIOS_CHECKSUM) {
383 GBALog(gba, GBA_LOG_INFO, "Official GBA BIOS detected");
384 } else if (checksum == GBA_DS_BIOS_CHECKSUM) {
385 GBALog(gba, GBA_LOG_INFO, "Official GBA (DS) BIOS detected");
386 } else {
387 GBALog(gba, GBA_LOG_WARN, "BIOS checksum incorrect");
388 }
389 gba->biosChecksum = checksum;
390 if ((gba->cpu.gprs[ARM_PC] >> BASE_OFFSET) == BASE_BIOS) {
391 gba->memory.d.setActiveRegion(&gba->memory.d, gba->cpu.gprs[ARM_PC]);
392 }
393 // TODO: error check
394}
395
396void GBATimerUpdateRegister(struct GBA* gba, int timer) {
397 struct GBATimer* currentTimer = &gba->timers[timer];
398 if (currentTimer->enable && !currentTimer->countUp) {
399 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> currentTimer->prescaleBits);
400 }
401}
402
403void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
404 gba->timers[timer].reload = reload;
405}
406
407void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
408 struct GBATimer* currentTimer = &gba->timers[timer];
409 GBATimerUpdateRegister(gba, timer);
410
411 int oldPrescale = currentTimer->prescaleBits;
412 switch (control & 0x0003) {
413 case 0x0000:
414 currentTimer->prescaleBits = 0;
415 break;
416 case 0x0001:
417 currentTimer->prescaleBits = 6;
418 break;
419 case 0x0002:
420 currentTimer->prescaleBits = 8;
421 break;
422 case 0x0003:
423 currentTimer->prescaleBits = 10;
424 break;
425 }
426 currentTimer->countUp = !!(control & 0x0004);
427 currentTimer->doIrq = !!(control & 0x0040);
428 currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
429 int wasEnabled = currentTimer->enable;
430 currentTimer->enable = !!(control & 0x0080);
431 if (!wasEnabled && currentTimer->enable) {
432 if (!currentTimer->countUp) {
433 currentTimer->nextEvent = gba->cpu.cycles + currentTimer->overflowInterval;
434 } else {
435 currentTimer->nextEvent = INT_MAX;
436 }
437 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
438 currentTimer->oldReload = currentTimer->reload;
439 gba->timersEnabled |= 1 << timer;
440 } else if (wasEnabled && !currentTimer->enable) {
441 if (!currentTimer->countUp) {
442 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> oldPrescale);
443 }
444 gba->timersEnabled &= ~(1 << timer);
445 } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
446 // FIXME: this might be before present
447 currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
448 }
449
450 if (currentTimer->nextEvent < gba->cpu.nextEvent) {
451 gba->cpu.nextEvent = currentTimer->nextEvent;
452 }
453};
454
455void GBAWriteIE(struct GBA* gba, uint16_t value) {
456 if (value & (1 << IRQ_KEYPAD)) {
457 GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented");
458 }
459
460 if (value & (1 << IRQ_GAMEPAK)) {
461 GBALog(gba, GBA_LOG_STUB, "Gamepak interrupts not implemented");
462 }
463
464 if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
465 ARMRaiseIRQ(&gba->cpu);
466 }
467}
468
469void GBAWriteIME(struct GBA* gba, uint16_t value) {
470 if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
471 ARMRaiseIRQ(&gba->cpu);
472 }
473}
474
475void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
476 gba->memory.io[REG_IF >> 1] |= 1 << irq;
477
478 if (gba->memory.io[REG_IME >> 1] && (gba->memory.io[REG_IE >> 1] & 1 << irq)) {
479 ARMRaiseIRQ(&gba->cpu);
480 }
481}
482
483void GBATestIRQ(struct ARMBoard* board) {
484 struct GBABoard* gbaBoard = (struct GBABoard*) board;
485 struct GBA* gba = gbaBoard->p;
486 if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
487 gba->springIRQ = 1;
488 gba->cpu.nextEvent = 0;
489 }
490}
491
492int GBAWaitForIRQ(struct GBA* gba) {
493 int irqs = gba->memory.io[REG_IF >> 1];
494 int newIRQs = 0;
495 gba->memory.io[REG_IF >> 1] = 0;
496 while (1) {
497 if (gba->cpu.nextEvent == INT_MAX) {
498 break;
499 } else {
500 gba->cpu.cycles = gba->cpu.nextEvent;
501 GBAProcessEvents(&gba->board.d);
502 if (gba->memory.io[REG_IF >> 1]) {
503 newIRQs = gba->memory.io[REG_IF >> 1];
504 break;
505 }
506 }
507 }
508 gba->memory.io[REG_IF >> 1] = newIRQs | irqs;
509 return newIRQs;
510}
511
512int GBAHalt(struct GBA* gba) {
513 return GBAWaitForIRQ(gba);
514}
515
516static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format, va_list args) {
517 if (!gba) {
518 struct GBAThread* threadContext = GBAThreadGetContext();
519 if (threadContext) {
520 gba = threadContext->gba;
521 }
522 }
523
524 if (gba && gba->logHandler) {
525 gba->logHandler(gba, level, format, args);
526 return;
527 }
528
529 if (gba && !(level & gba->logLevel) && level != GBA_LOG_FATAL) {
530 return;
531 }
532
533 vprintf(format, args);
534 printf("\n");
535
536 if (level == GBA_LOG_FATAL) {
537 abort();
538 }
539}
540
541void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
542 va_list args;
543 va_start(args, format);
544 _GBAVLog(gba, level, format, args);
545 va_end(args);
546}
547
548void GBADebuggerLogShim(struct ARMDebugger* debugger, enum DebuggerLogLevel level, const char* format, ...) {
549 struct GBABoard* gbaBoard = 0;
550 if (debugger->cpu && debugger->cpu->board) {
551 gbaBoard = (struct GBABoard*) debugger->cpu->board;
552 }
553
554 enum GBALogLevel gbaLevel;
555 switch (level) {
556 case DEBUGGER_LOG_DEBUG:
557 gbaLevel = GBA_LOG_DEBUG;
558 break;
559 case DEBUGGER_LOG_INFO:
560 gbaLevel = GBA_LOG_INFO;
561 break;
562 case DEBUGGER_LOG_WARN:
563 gbaLevel = GBA_LOG_WARN;
564 break;
565 case DEBUGGER_LOG_ERROR:
566 gbaLevel = GBA_LOG_ERROR;
567 break;
568 }
569 va_list args;
570 va_start(args, format);
571 _GBAVLog(gbaBoard ? gbaBoard->p : 0, gbaLevel, format, args);
572 va_end(args);
573}
574
575
576void GBAHitStub(struct ARMBoard* board, uint32_t opcode) {
577 struct GBABoard* gbaBoard = (struct GBABoard*) board;
578 enum GBALogLevel level = GBA_LOG_FATAL;
579 if (gbaBoard->p->debugger) {
580 level = GBA_LOG_STUB;
581 ARMDebuggerEnter(gbaBoard->p->debugger, DEBUGGER_ENTER_ILLEGAL_OP);
582 }
583 GBALog(gbaBoard->p, level, "Stub opcode: %08x", opcode);
584}
585
586void GBAIllegal(struct ARMBoard* board, uint32_t opcode) {
587 struct GBABoard* gbaBoard = (struct GBABoard*) board;
588 GBALog(gbaBoard->p, GBA_LOG_WARN, "Illegal opcode: %08x", opcode);
589 if (gbaBoard->p->debugger) {
590 ARMDebuggerEnter(gbaBoard->p->debugger, DEBUGGER_ENTER_ILLEGAL_OP);
591 }
592}
593
594void _checkOverrides(struct GBA* gba, uint32_t id) {
595 int i;
596 for (i = 0; _overrides[i].id[0]; ++i) {
597 const uint32_t* overrideId = (const uint32_t*) _overrides[i].id;
598 if (*overrideId == id) {
599 switch (_overrides[i].type) {
600 case SAVEDATA_FLASH512:
601 case SAVEDATA_FLASH1M:
602 gba->memory.savedata.type = _overrides[i].type;
603 GBASavedataInitFlash(&gba->memory.savedata);
604 break;
605 case SAVEDATA_EEPROM:
606 GBASavedataInitEEPROM(&gba->memory.savedata);
607 break;
608 case SAVEDATA_SRAM:
609 GBASavedataInitSRAM(&gba->memory.savedata);
610 break;
611 case SAVEDATA_NONE:
612 break;
613 }
614
615 if (_overrides[i].gpio & GPIO_RTC) {
616 GBAGPIOInitRTC(&gba->memory.gpio);
617 }
618
619 if (_overrides[i].gpio & GPIO_GYRO) {
620 GBAGPIOInitGyro(&gba->memory.gpio);
621 }
622
623 if (_overrides[i].gpio & GPIO_RUMBLE) {
624 GBAGPIOInitRumble(&gba->memory.gpio);
625 }
626 return;
627 }
628 }
629}