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