src/gba/gba.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 "gba.h"
7
8#include "gba/bios.h"
9#include "gba/cheats.h"
10#include "gba/io.h"
11#include "gba/supervisor/rr.h"
12#include "gba/supervisor/thread.h"
13#include "gba/serialize.h"
14#include "gba/sio.h"
15
16#include "isa-inlines.h"
17
18#include "util/crc32.h"
19#include "util/memory.h"
20#include "util/patch.h"
21#include "util/vfs.h"
22
23const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000;
24const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
25
26static const size_t GBA_ROM_MAGIC_OFFSET = 3;
27static const uint8_t GBA_ROM_MAGIC[] = { 0xEA };
28
29static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component);
30static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh);
31static void GBAProcessEvents(struct ARMCore* cpu);
32static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);
33static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
34static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
35static void GBABreakpoint(struct ARMCore* cpu, int immediate);
36
37static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
38static bool _clearSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
39
40void GBACreate(struct GBA* gba) {
41 gba->d.id = GBA_COMPONENT_MAGIC;
42 gba->d.init = GBAInit;
43 gba->d.deinit = 0;
44}
45
46static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) {
47 struct GBA* gba = (struct GBA*) component;
48 gba->cpu = cpu;
49 gba->debugger = 0;
50
51 GBAInterruptHandlerInit(&cpu->irqh);
52 GBAMemoryInit(gba);
53 GBASavedataInit(&gba->memory.savedata, 0);
54
55 gba->video.p = gba;
56 GBAVideoInit(&gba->video);
57
58 gba->audio.p = gba;
59 GBAAudioInit(&gba->audio, GBA_AUDIO_SAMPLES);
60
61 GBAIOInit(gba);
62
63 gba->sio.p = gba;
64 GBASIOInit(&gba->sio);
65
66 gba->timersEnabled = 0;
67 memset(gba->timers, 0, sizeof(gba->timers));
68
69 gba->springIRQ = 0;
70 gba->keySource = 0;
71 gba->rotationSource = 0;
72 gba->luminanceSource = 0;
73 gba->rtcSource = 0;
74 gba->rumble = 0;
75 gba->rr = 0;
76
77 gba->romVf = 0;
78 gba->biosVf = 0;
79
80 gba->logHandler = 0;
81 gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
82 gba->stream = 0;
83
84 gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
85
86 gba->idleOptimization = IDLE_LOOP_REMOVE;
87 gba->idleLoop = IDLE_LOOP_NONE;
88 gba->lastJump = 0;
89 gba->idleDetectionStep = 0;
90 gba->idleDetectionFailures = 0;
91 gba->performingDMA = false;
92}
93
94void GBADestroy(struct GBA* gba) {
95 if (gba->pristineRom == gba->memory.rom) {
96 gba->memory.rom = 0;
97 }
98
99 if (gba->romVf) {
100 gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize);
101 }
102
103 if (gba->biosVf) {
104 gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
105 }
106
107 GBAMemoryDeinit(gba);
108 GBAVideoDeinit(&gba->video);
109 GBAAudioDeinit(&gba->audio);
110 GBASIODeinit(&gba->sio);
111 gba->rr = 0;
112}
113
114void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh) {
115 irqh->reset = GBAReset;
116 irqh->processEvents = GBAProcessEvents;
117 irqh->swi16 = GBASwi16;
118 irqh->swi32 = GBASwi32;
119 irqh->hitIllegal = GBAIllegal;
120 irqh->readCPSR = GBATestIRQ;
121 irqh->hitStub = GBAHitStub;
122 irqh->bkpt16 = GBABreakpoint;
123 irqh->bkpt32 = GBABreakpoint;
124}
125
126void GBAReset(struct ARMCore* cpu) {
127 ARMSetPrivilegeMode(cpu, MODE_IRQ);
128 cpu->gprs[ARM_SP] = SP_BASE_IRQ;
129 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
130 cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
131 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
132 cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
133
134 struct GBA* gba = (struct GBA*) cpu->master;
135 if (!gba->rr || (!gba->rr->isPlaying(gba->rr) && !gba->rr->isRecording(gba->rr))) {
136 GBASavedataUnmask(&gba->memory.savedata);
137 }
138 GBAMemoryReset(gba);
139 GBAVideoReset(&gba->video);
140 GBAAudioReset(&gba->audio);
141 GBAIOInit(gba);
142
143 GBASIODeinit(&gba->sio);
144 GBASIOInit(&gba->sio);
145
146 gba->timersEnabled = 0;
147 memset(gba->timers, 0, sizeof(gba->timers));
148}
149
150void GBASkipBIOS(struct ARMCore* cpu) {
151 if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) {
152 cpu->gprs[ARM_PC] = BASE_CART0;
153 int currentCycles = 0;
154 ARM_WRITE_PC;
155 }
156}
157
158static void GBAProcessEvents(struct ARMCore* cpu) {
159 do {
160 struct GBA* gba = (struct GBA*) cpu->master;
161 int32_t cycles = cpu->nextEvent;
162 int32_t nextEvent = INT_MAX;
163 int32_t testEvent;
164
165 gba->bus = cpu->prefetch[1];
166 if (cpu->executionMode == MODE_THUMB) {
167 gba->bus |= cpu->prefetch[1] << 16;
168 }
169
170 if (gba->springIRQ) {
171 ARMRaiseIRQ(cpu);
172 gba->springIRQ = 0;
173 }
174
175 testEvent = GBAVideoProcessEvents(&gba->video, cycles);
176 if (testEvent < nextEvent) {
177 nextEvent = testEvent;
178 }
179
180 testEvent = GBAAudioProcessEvents(&gba->audio, cycles);
181 if (testEvent < nextEvent) {
182 nextEvent = testEvent;
183 }
184
185 testEvent = GBATimersProcessEvents(gba, cycles);
186 if (testEvent < nextEvent) {
187 nextEvent = testEvent;
188 }
189
190 testEvent = GBAMemoryRunDMAs(gba, cycles);
191 if (testEvent < nextEvent) {
192 nextEvent = testEvent;
193 }
194
195 testEvent = GBASIOProcessEvents(&gba->sio, cycles);
196 if (testEvent < nextEvent) {
197 nextEvent = testEvent;
198 }
199
200 cpu->cycles -= cycles;
201 cpu->nextEvent = nextEvent;
202
203 if (cpu->halted) {
204 cpu->cycles = cpu->nextEvent;
205 }
206 } while (cpu->cycles >= cpu->nextEvent);
207}
208
209static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
210 int32_t nextEvent = INT_MAX;
211 if (gba->timersEnabled) {
212 struct GBATimer* timer;
213 struct GBATimer* nextTimer;
214
215 timer = &gba->timers[0];
216 if (timer->enable) {
217 timer->nextEvent -= cycles;
218 timer->lastEvent -= cycles;
219 if (timer->nextEvent <= 0) {
220 timer->lastEvent = timer->nextEvent;
221 timer->nextEvent += timer->overflowInterval;
222 gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
223 timer->oldReload = timer->reload;
224
225 if (timer->doIrq) {
226 GBARaiseIRQ(gba, IRQ_TIMER0);
227 }
228
229 if (gba->audio.enable) {
230 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 0) {
231 GBAAudioSampleFIFO(&gba->audio, 0, timer->lastEvent);
232 }
233
234 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 0) {
235 GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
236 }
237 }
238
239 nextTimer = &gba->timers[1];
240 if (nextTimer->countUp) {
241 ++gba->memory.io[REG_TM1CNT_LO >> 1];
242 if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
243 nextTimer->nextEvent = 0;
244 }
245 }
246 }
247 nextEvent = timer->nextEvent;
248 }
249
250 timer = &gba->timers[1];
251 if (timer->enable) {
252 timer->nextEvent -= cycles;
253 timer->lastEvent -= cycles;
254 if (timer->nextEvent <= 0) {
255 timer->lastEvent = timer->nextEvent;
256 timer->nextEvent += timer->overflowInterval;
257 gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
258 timer->oldReload = timer->reload;
259
260 if (timer->doIrq) {
261 GBARaiseIRQ(gba, IRQ_TIMER1);
262 }
263
264 if (gba->audio.enable) {
265 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 1) {
266 GBAAudioSampleFIFO(&gba->audio, 0, timer->lastEvent);
267 }
268
269 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 1) {
270 GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
271 }
272 }
273
274 if (timer->countUp) {
275 timer->nextEvent = INT_MAX;
276 }
277
278 nextTimer = &gba->timers[2];
279 if (nextTimer->countUp) {
280 ++gba->memory.io[REG_TM2CNT_LO >> 1];
281 if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
282 nextTimer->nextEvent = 0;
283 }
284 }
285 }
286 if (timer->nextEvent < nextEvent) {
287 nextEvent = timer->nextEvent;
288 }
289 }
290
291 timer = &gba->timers[2];
292 if (timer->enable) {
293 timer->nextEvent -= cycles;
294 timer->lastEvent -= cycles;
295 if (timer->nextEvent <= 0) {
296 timer->lastEvent = timer->nextEvent;
297 timer->nextEvent += timer->overflowInterval;
298 gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
299 timer->oldReload = timer->reload;
300
301 if (timer->doIrq) {
302 GBARaiseIRQ(gba, IRQ_TIMER2);
303 }
304
305 if (timer->countUp) {
306 timer->nextEvent = INT_MAX;
307 }
308
309 nextTimer = &gba->timers[3];
310 if (nextTimer->countUp) {
311 ++gba->memory.io[REG_TM3CNT_LO >> 1];
312 if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
313 nextTimer->nextEvent = 0;
314 }
315 }
316 }
317 if (timer->nextEvent < nextEvent) {
318 nextEvent = timer->nextEvent;
319 }
320 }
321
322 timer = &gba->timers[3];
323 if (timer->enable) {
324 timer->nextEvent -= cycles;
325 timer->lastEvent -= cycles;
326 if (timer->nextEvent <= 0) {
327 timer->lastEvent = timer->nextEvent;
328 timer->nextEvent += timer->overflowInterval;
329 gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
330 timer->oldReload = timer->reload;
331
332 if (timer->doIrq) {
333 GBARaiseIRQ(gba, IRQ_TIMER3);
334 }
335
336 if (timer->countUp) {
337 timer->nextEvent = INT_MAX;
338 }
339 }
340 if (timer->nextEvent < nextEvent) {
341 nextEvent = timer->nextEvent;
342 }
343 }
344 }
345 return nextEvent;
346}
347
348void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
349 debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint;
350 debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint;
351 gba->debugger = debugger;
352 gba->cpu->components[GBA_COMPONENT_DEBUGGER] = &debugger->d;
353 ARMHotplugAttach(gba->cpu, GBA_COMPONENT_DEBUGGER);
354}
355
356void GBADetachDebugger(struct GBA* gba) {
357 gba->debugger = 0;
358 ARMHotplugDetach(gba->cpu, GBA_COMPONENT_DEBUGGER);
359 gba->cpu->components[GBA_COMPONENT_DEBUGGER] = 0;
360}
361
362void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) {
363 gba->romVf = vf;
364 gba->pristineRomSize = vf->size(vf);
365 vf->seek(vf, 0, SEEK_SET);
366 if (gba->pristineRomSize > SIZE_CART0) {
367 gba->pristineRomSize = SIZE_CART0;
368 }
369 gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ);
370 if (!gba->pristineRom) {
371 GBALog(gba, GBA_LOG_WARN, "Couldn't map ROM");
372 return;
373 }
374 gba->memory.rom = gba->pristineRom;
375 gba->activeFile = fname;
376 gba->memory.romSize = gba->pristineRomSize;
377 gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
378 GBASavedataInit(&gba->memory.savedata, sav);
379 GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
380 // TODO: error check
381}
382
383void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
384 gba->biosVf = vf;
385 uint32_t* bios = vf->map(vf, SIZE_BIOS, MAP_READ);
386 if (!bios) {
387 GBALog(gba, GBA_LOG_WARN, "Couldn't map BIOS");
388 return;
389 }
390 gba->memory.bios = bios;
391 gba->memory.fullBios = 1;
392 uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
393 GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);
394 if (checksum == GBA_BIOS_CHECKSUM) {
395 GBALog(gba, GBA_LOG_INFO, "Official GBA BIOS detected");
396 } else if (checksum == GBA_DS_BIOS_CHECKSUM) {
397 GBALog(gba, GBA_LOG_INFO, "Official GBA (DS) BIOS detected");
398 } else {
399 GBALog(gba, GBA_LOG_WARN, "BIOS checksum incorrect");
400 }
401 gba->biosChecksum = checksum;
402 if (gba->memory.activeRegion == REGION_BIOS) {
403 gba->cpu->memory.activeRegion = gba->memory.bios;
404 }
405 // TODO: error check
406}
407
408void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
409 size_t patchedSize = patch->outputSize(patch, gba->memory.romSize);
410 if (!patchedSize) {
411 return;
412 }
413 gba->memory.rom = anonymousMemoryMap(patchedSize);
414 if (!patch->applyPatch(patch, gba->pristineRom, gba->pristineRomSize, gba->memory.rom, patchedSize)) {
415 mappedMemoryFree(gba->memory.rom, patchedSize);
416 gba->memory.rom = gba->pristineRom;
417 return;
418 }
419 gba->memory.romSize = patchedSize;
420 gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
421}
422
423void GBATimerUpdateRegister(struct GBA* gba, int timer) {
424 struct GBATimer* currentTimer = &gba->timers[timer];
425 if (currentTimer->enable && !currentTimer->countUp) {
426 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> currentTimer->prescaleBits);
427 }
428}
429
430void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
431 gba->timers[timer].reload = reload;
432}
433
434void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
435 struct GBATimer* currentTimer = &gba->timers[timer];
436 GBATimerUpdateRegister(gba, timer);
437
438 int oldPrescale = currentTimer->prescaleBits;
439 switch (control & 0x0003) {
440 case 0x0000:
441 currentTimer->prescaleBits = 0;
442 break;
443 case 0x0001:
444 currentTimer->prescaleBits = 6;
445 break;
446 case 0x0002:
447 currentTimer->prescaleBits = 8;
448 break;
449 case 0x0003:
450 currentTimer->prescaleBits = 10;
451 break;
452 }
453 currentTimer->countUp = !!(control & 0x0004);
454 currentTimer->doIrq = !!(control & 0x0040);
455 currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
456 int wasEnabled = currentTimer->enable;
457 currentTimer->enable = !!(control & 0x0080);
458 if (!wasEnabled && currentTimer->enable) {
459 if (!currentTimer->countUp) {
460 currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval;
461 } else {
462 currentTimer->nextEvent = INT_MAX;
463 }
464 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
465 currentTimer->oldReload = currentTimer->reload;
466 currentTimer->lastEvent = 0;
467 gba->timersEnabled |= 1 << timer;
468 } else if (wasEnabled && !currentTimer->enable) {
469 if (!currentTimer->countUp) {
470 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale);
471 }
472 gba->timersEnabled &= ~(1 << timer);
473 } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
474 // FIXME: this might be before present
475 currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
476 }
477
478 if (currentTimer->nextEvent < gba->cpu->nextEvent) {
479 gba->cpu->nextEvent = currentTimer->nextEvent;
480 }
481};
482
483void GBAWriteIE(struct GBA* gba, uint16_t value) {
484 if (value & (1 << IRQ_KEYPAD)) {
485 GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented");
486 }
487
488 if (value & (1 << IRQ_GAMEPAK)) {
489 GBALog(gba, GBA_LOG_STUB, "Gamepak interrupts not implemented");
490 }
491
492 if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
493 ARMRaiseIRQ(gba->cpu);
494 }
495}
496
497void GBAWriteIME(struct GBA* gba, uint16_t value) {
498 if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
499 ARMRaiseIRQ(gba->cpu);
500 }
501}
502
503void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
504 gba->memory.io[REG_IF >> 1] |= 1 << irq;
505 gba->cpu->halted = 0;
506
507 if (gba->memory.io[REG_IME >> 1] && (gba->memory.io[REG_IE >> 1] & 1 << irq)) {
508 ARMRaiseIRQ(gba->cpu);
509 }
510}
511
512void GBATestIRQ(struct ARMCore* cpu) {
513 struct GBA* gba = (struct GBA*) cpu->master;
514 if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
515 gba->springIRQ = 1;
516 gba->cpu->nextEvent = 0;
517 }
518}
519
520void GBAHalt(struct GBA* gba) {
521 gba->cpu->nextEvent = 0;
522 gba->cpu->halted = 1;
523}
524
525static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format, va_list args) {
526 struct GBAThread* threadContext = GBAThreadGetContext();
527 enum GBALogLevel logLevel = -1;
528
529 if (gba) {
530 logLevel = gba->logLevel;
531 }
532
533 if (threadContext) {
534 logLevel = threadContext->logLevel;
535 gba = threadContext->gba;
536 }
537
538 if (!(level & logLevel) && level != GBA_LOG_FATAL) {
539 return;
540 }
541
542 if (level == GBA_LOG_FATAL && gba) {
543 gba->cpu->nextEvent = 0;
544 }
545
546 if (threadContext) {
547 if (level == GBA_LOG_FATAL) {
548 MutexLock(&threadContext->stateMutex);
549 threadContext->state = THREAD_CRASHED;
550 MutexUnlock(&threadContext->stateMutex);
551 }
552 }
553 if (gba && gba->logHandler) {
554 gba->logHandler(threadContext, level, format, args);
555 return;
556 }
557
558 vprintf(format, args);
559 printf("\n");
560
561 if (level == GBA_LOG_FATAL && !threadContext) {
562 abort();
563 }
564}
565
566void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
567 va_list args;
568 va_start(args, format);
569 _GBAVLog(gba, level, format, args);
570 va_end(args);
571}
572
573void GBADebuggerLogShim(struct ARMDebugger* debugger, enum DebuggerLogLevel level, const char* format, ...) {
574 struct GBA* gba = 0;
575 if (debugger->cpu) {
576 gba = (struct GBA*) debugger->cpu->master;
577 }
578
579 enum GBALogLevel gbaLevel;
580 switch (level) {
581 default: // Avoids compiler warning
582 case DEBUGGER_LOG_DEBUG:
583 gbaLevel = GBA_LOG_DEBUG;
584 break;
585 case DEBUGGER_LOG_INFO:
586 gbaLevel = GBA_LOG_INFO;
587 break;
588 case DEBUGGER_LOG_WARN:
589 gbaLevel = GBA_LOG_WARN;
590 break;
591 case DEBUGGER_LOG_ERROR:
592 gbaLevel = GBA_LOG_ERROR;
593 break;
594 }
595 va_list args;
596 va_start(args, format);
597 _GBAVLog(gba, gbaLevel, format, args);
598 va_end(args);
599}
600
601bool GBAIsROM(struct VFile* vf) {
602 if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
603 return false;
604 }
605 uint8_t signature[sizeof(GBA_ROM_MAGIC)];
606 if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
607 return false;
608 }
609 return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0;
610}
611
612bool GBAIsBIOS(struct VFile* vf) {
613 if (vf->seek(vf, 0, SEEK_SET) < 0) {
614 return false;
615 }
616 uint32_t interruptTable[7];
617 if (vf->read(vf, &interruptTable, sizeof(interruptTable)) != sizeof(interruptTable)) {
618 return false;
619 }
620 int i;
621 for (i = 0; i < 7; ++i) {
622 if ((interruptTable[i] & 0xFFFF0000) != 0xEA000000) {
623 return false;
624 }
625 }
626 return true;
627}
628
629void GBAGetGameCode(struct GBA* gba, char* out) {
630 memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4);
631}
632
633void GBAGetGameTitle(struct GBA* gba, char* out) {
634 memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12);
635}
636
637void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {
638 struct GBA* gba = (struct GBA*) cpu->master;
639 enum GBALogLevel level = GBA_LOG_FATAL;
640 if (gba->debugger) {
641 level = GBA_LOG_STUB;
642 struct DebuggerEntryInfo info = {
643 .address = _ARMPCAddress(cpu),
644 .opcode = opcode
645 };
646 ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info);
647 }
648 GBALog(gba, level, "Stub opcode: %08x", opcode);
649}
650
651void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
652 struct GBA* gba = (struct GBA*) cpu->master;
653 GBALog(gba, GBA_LOG_WARN, "Illegal opcode: %08x", opcode);
654 if (gba->debugger) {
655 struct DebuggerEntryInfo info = {
656 .address = _ARMPCAddress(cpu),
657 .opcode = opcode
658 };
659 ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info);
660 }
661}
662
663void GBABreakpoint(struct ARMCore* cpu, int immediate) {
664 struct GBA* gba = (struct GBA*) cpu->master;
665 if (immediate >= GBA_COMPONENT_MAX) {
666 return;
667 }
668 switch (immediate) {
669 case GBA_COMPONENT_DEBUGGER:
670 if (gba->debugger) {
671 struct DebuggerEntryInfo info = {
672 .address = _ARMPCAddress(cpu)
673 };
674 ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_BREAKPOINT, &info);
675 }
676 break;
677 case GBA_COMPONENT_CHEAT_DEVICE:
678 if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
679 struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
680 struct GBACheatHook* hook = 0;
681 size_t i;
682 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
683 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
684 if (cheats->hook && cheats->hook->address == _ARMPCAddress(cpu)) {
685 GBACheatRefresh(device, cheats);
686 hook = cheats->hook;
687 }
688 }
689 if (hook) {
690 ARMRunFake(cpu, hook->patchedOpcode);
691 }
692 }
693 break;
694 default:
695 break;
696 }
697}
698
699void GBAFrameStarted(struct GBA* gba) {
700 UNUSED(gba);
701
702 struct GBAThread* thread = GBAThreadGetContext();
703 if (!thread) {
704 return;
705 }
706
707 if (thread->rewindBuffer) {
708 --thread->rewindBufferNext;
709 if (thread->rewindBufferNext <= 0) {
710 thread->rewindBufferNext = thread->rewindBufferInterval;
711 GBARecordFrame(thread);
712 }
713 }
714}
715
716void GBAFrameEnded(struct GBA* gba) {
717 if (gba->rr) {
718 gba->rr->nextFrame(gba->rr);
719 }
720
721 if (gba->cpu->components && gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
722 struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE];
723 size_t i;
724 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
725 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
726 if (!cheats->hook) {
727 GBACheatRefresh(device, cheats);
728 }
729 }
730 }
731
732
733 struct GBAThread* thread = GBAThreadGetContext();
734 if (!thread) {
735 return;
736 }
737
738 if (gba->stream) {
739 gba->stream->postVideoFrame(gba->stream, gba->video.renderer);
740 }
741
742 if (thread->frameCallback) {
743 thread->frameCallback(thread);
744 }
745}
746
747void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
748 size_t immediate;
749 for (immediate = 0; immediate < gba->cpu->numComponents; ++immediate) {
750 if (gba->cpu->components[immediate] == component) {
751 break;
752 }
753 }
754 if (immediate == gba->cpu->numComponents) {
755 return;
756 }
757 if (mode == MODE_ARM) {
758 int32_t value;
759 int32_t old;
760 value = 0xE1200070;
761 value |= immediate & 0xF;
762 value |= (immediate & 0xFFF0) << 4;
763 GBAPatch32(gba->cpu, address, value, &old);
764 *opcode = old;
765 } else {
766 int16_t value;
767 int16_t old;
768 value = 0xBE00;
769 value |= immediate & 0xFF;
770 GBAPatch16(gba->cpu, address, value, &old);
771 *opcode = (uint16_t) old;
772 }
773}
774
775void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
776 if (mode == MODE_ARM) {
777 GBAPatch32(gba->cpu, address, opcode, 0);
778 } else {
779 GBAPatch16(gba->cpu, address, opcode, 0);
780 }
781}
782
783static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
784 GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d, address, mode, opcode);
785 return true;
786}
787
788static bool _clearSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
789 GBAClearBreakpoint((struct GBA*) debugger->cpu->master, address, mode, opcode);
790 return true;
791}