all repos — mgba @ e456798712bb3c89462a2080033982675a52ade2

mGBA Game Boy Advance Emulator

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 <mgba/internal/gba/gba.h>
  7
  8#include <mgba/internal/arm/isa-inlines.h>
  9#include <mgba/internal/arm/debugger/debugger.h>
 10#include <mgba/internal/arm/decoder.h>
 11
 12#include <mgba/internal/gba/bios.h>
 13#include <mgba/internal/gba/cheats.h>
 14#include <mgba/internal/gba/io.h>
 15#include <mgba/internal/gba/overrides.h>
 16#include <mgba/internal/gba/rr/rr.h>
 17
 18#include <mgba-util/patch.h>
 19#include <mgba-util/crc32.h>
 20#include <mgba-util/math.h>
 21#include <mgba-util/memory.h>
 22#include <mgba-util/vfs.h>
 23
 24mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba");
 25mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");
 26
 27const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
 28
 29static const size_t GBA_ROM_MAGIC_OFFSET = 3;
 30static const uint8_t GBA_ROM_MAGIC[] = { 0xEA };
 31
 32static const size_t GBA_MB_MAGIC_OFFSET = 0xC0;
 33
 34static void GBAInit(void* cpu, struct mCPUComponent* component);
 35static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh);
 36static void GBAProcessEvents(struct ARMCore* cpu);
 37static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
 38static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
 39static void GBABreakpoint(struct ARMCore* cpu, int immediate);
 40
 41static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
 42static bool _clearSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
 43
 44
 45#ifdef _3DS
 46extern uint32_t* romBuffer;
 47extern size_t romBufferSize;
 48#endif
 49
 50void GBACreate(struct GBA* gba) {
 51	gba->d.id = GBA_COMPONENT_MAGIC;
 52	gba->d.init = GBAInit;
 53	gba->d.deinit = 0;
 54}
 55
 56static void GBAInit(void* cpu, struct mCPUComponent* component) {
 57	struct GBA* gba = (struct GBA*) component;
 58	gba->cpu = cpu;
 59	gba->debugger = 0;
 60	gba->sync = 0;
 61
 62	GBAInterruptHandlerInit(&gba->cpu->irqh);
 63	GBAMemoryInit(gba);
 64
 65	gba->memory.savedata.timing = &gba->timing;
 66	GBASavedataInit(&gba->memory.savedata, NULL);
 67
 68	gba->video.p = gba;
 69	GBAVideoInit(&gba->video);
 70
 71	gba->audio.p = gba;
 72	GBAAudioInit(&gba->audio, GBA_AUDIO_SAMPLES);
 73
 74	GBAIOInit(gba);
 75
 76	gba->sio.p = gba;
 77	GBASIOInit(&gba->sio);
 78
 79	GBAHardwareInit(&gba->memory.hw, NULL);
 80
 81	gba->springIRQ = 0;
 82	gba->keySource = 0;
 83	gba->rotationSource = 0;
 84	gba->luminanceSource = 0;
 85	gba->rtcSource = 0;
 86	gba->rumble = 0;
 87	gba->rr = 0;
 88
 89	gba->romVf = 0;
 90	gba->biosVf = 0;
 91
 92	gba->stream = NULL;
 93	gba->keyCallback = NULL;
 94	mCoreCallbacksListInit(&gba->coreCallbacks, 0);
 95
 96	gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
 97
 98	gba->idleOptimization = IDLE_LOOP_REMOVE;
 99	gba->idleLoop = IDLE_LOOP_NONE;
100
101	gba->realisticTiming = true;
102	gba->hardCrash = true;
103	gba->allowOpposingDirections = true;
104
105	gba->performingDMA = false;
106
107	gba->isPristine = false;
108	gba->pristineRomSize = 0;
109	gba->yankedRomSize = 0;
110
111	mTimingInit(&gba->timing, &gba->cpu->cycles, &gba->cpu->nextEvent);
112}
113
114void GBAUnloadROM(struct GBA* gba) {
115	if (gba->memory.rom && !gba->isPristine) {
116		if (gba->yankedRomSize) {
117			gba->yankedRomSize = 0;
118		}
119		mappedMemoryFree(gba->memory.rom, SIZE_CART0);
120	}
121
122	if (gba->romVf) {
123#ifndef _3DS
124		gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
125#endif
126		gba->romVf->close(gba->romVf);
127		gba->romVf = NULL;
128	}
129	gba->memory.rom = NULL;
130	gba->isPristine = false;
131
132	GBASavedataDeinit(&gba->memory.savedata);
133	if (gba->memory.savedata.realVf) {
134		gba->memory.savedata.realVf->close(gba->memory.savedata.realVf);
135		gba->memory.savedata.realVf = 0;
136	}
137	gba->idleLoop = IDLE_LOOP_NONE;
138}
139
140void GBADestroy(struct GBA* gba) {
141	GBAUnloadROM(gba);
142
143	if (gba->biosVf) {
144		gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS);
145		gba->biosVf->close(gba->biosVf);
146		gba->biosVf = 0;
147	}
148
149	GBAMemoryDeinit(gba);
150	GBAVideoDeinit(&gba->video);
151	GBAAudioDeinit(&gba->audio);
152	GBASIODeinit(&gba->sio);
153	gba->rr = 0;
154	mTimingDeinit(&gba->timing);
155	mCoreCallbacksListDeinit(&gba->coreCallbacks);
156}
157
158void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh) {
159	irqh->reset = GBAReset;
160	irqh->processEvents = GBAProcessEvents;
161	irqh->swi16 = GBASwi16;
162	irqh->swi32 = GBASwi32;
163	irqh->hitIllegal = GBAIllegal;
164	irqh->readCPSR = GBATestIRQ;
165	irqh->hitStub = GBAHitStub;
166	irqh->bkpt16 = GBABreakpoint;
167	irqh->bkpt32 = GBABreakpoint;
168}
169
170void GBAReset(struct ARMCore* cpu) {
171	ARMSetPrivilegeMode(cpu, MODE_IRQ);
172	cpu->gprs[ARM_SP] = SP_BASE_IRQ;
173	ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
174	cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
175	ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
176	cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
177
178	struct GBA* gba = (struct GBA*) cpu->master;
179	if (!gba->rr || (!gba->rr->isPlaying(gba->rr) && !gba->rr->isRecording(gba->rr))) {
180		GBASavedataUnmask(&gba->memory.savedata);
181	}
182
183	gba->cpuBlocked = false;
184	gba->earlyExit = false;
185	if (gba->yankedRomSize) {
186		gba->memory.romSize = gba->yankedRomSize;
187		gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
188		gba->yankedRomSize = 0;
189	}
190	mTimingClear(&gba->timing);
191	GBAMemoryReset(gba);
192	GBAVideoReset(&gba->video);
193	GBAAudioReset(&gba->audio);
194	GBAIOInit(gba);
195	GBATimerInit(gba);
196
197	GBASIOReset(&gba->sio);
198
199	gba->lastJump = 0;
200	gba->haltPending = false;
201	gba->idleDetectionStep = 0;
202	gba->idleDetectionFailures = 0;
203
204	gba->debug = false;
205	memset(gba->debugString, 0, sizeof(gba->debugString));
206}
207
208void GBASkipBIOS(struct GBA* gba) {
209	struct ARMCore* cpu = gba->cpu;
210	if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) {
211		if (gba->memory.rom) {
212			cpu->gprs[ARM_PC] = BASE_CART0;
213		} else {
214			cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
215		}
216		gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
217		gba->memory.io[REG_POSTFLG >> 1] = 1;
218		int currentCycles = 0;
219		ARM_WRITE_PC;
220	}
221}
222
223static void GBAProcessEvents(struct ARMCore* cpu) {
224	struct GBA* gba = (struct GBA*) cpu->master;
225
226	gba->bus = cpu->prefetch[1];
227	if (cpu->executionMode == MODE_THUMB) {
228		gba->bus |= cpu->prefetch[1] << 16;
229	}
230
231	if (gba->springIRQ && !cpu->cpsr.i) {
232		ARMRaiseIRQ(cpu);
233		gba->springIRQ = 0;
234	}
235
236	int32_t nextEvent = cpu->nextEvent;
237	while (cpu->cycles >= nextEvent) {
238		int32_t cycles = cpu->cycles;
239
240		cpu->cycles = 0;
241		cpu->nextEvent = INT_MAX;
242
243#ifndef NDEBUG
244		if (cycles < 0) {
245			mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
246		}
247#endif
248		nextEvent = cycles;
249		do {
250			nextEvent = mTimingTick(&gba->timing, nextEvent);
251		} while (gba->cpuBlocked);
252
253		cpu->nextEvent = nextEvent;
254
255		if (gba->earlyExit) {
256			gba->earlyExit = false;
257			break;
258		}
259		if (cpu->halted) {
260			cpu->cycles = nextEvent;
261			if (!gba->memory.io[REG_IME >> 1] || !gba->memory.io[REG_IE >> 1]) {
262				break;
263			}
264		}
265#ifndef NDEBUG
266		else if (nextEvent < 0) {
267			mLOG(GBA, FATAL, "Negative cycles will pass: %i", nextEvent);
268		}
269#endif
270	}
271}
272
273#ifdef USE_DEBUGGERS
274void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger) {
275	gba->debugger = (struct ARMDebugger*) debugger->platform;
276	gba->debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint;
277	gba->debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint;
278	gba->cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
279	ARMHotplugAttach(gba->cpu, CPU_COMPONENT_DEBUGGER);
280}
281
282void GBADetachDebugger(struct GBA* gba) {
283	if (gba->debugger) {
284		ARMHotplugDetach(gba->cpu, CPU_COMPONENT_DEBUGGER);
285	}
286	gba->cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
287	gba->debugger = NULL;
288}
289#endif
290
291bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
292	GBAUnloadROM(gba);
293	gba->romVf = vf;
294	gba->pristineRomSize = vf->size(vf);
295	vf->seek(vf, 0, SEEK_SET);
296	if (gba->pristineRomSize > SIZE_WORKING_RAM) {
297		gba->pristineRomSize = SIZE_WORKING_RAM;
298	}
299	gba->isPristine = true;
300	gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
301	memset(gba->memory.wram, 0, SIZE_WORKING_RAM);
302	vf->read(vf, gba->memory.wram, gba->pristineRomSize);
303	if (!gba->memory.wram) {
304		mLOG(GBA, WARN, "Couldn't map ROM");
305		return false;
306	}
307	gba->yankedRomSize = 0;
308	gba->memory.romSize = 0;
309	gba->memory.romMask = 0;
310	gba->romCrc32 = doCrc32(gba->memory.wram, gba->pristineRomSize);
311	if (gba->cpu && gba->memory.activeRegion == REGION_WORKING_RAM) {
312		gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
313	}
314	return true;
315}
316
317bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
318	if (!vf) {
319		return false;
320	}
321	GBAUnloadROM(gba);
322	gba->romVf = vf;
323	gba->pristineRomSize = vf->size(vf);
324	vf->seek(vf, 0, SEEK_SET);
325	if (gba->pristineRomSize > SIZE_CART0) {
326		gba->pristineRomSize = SIZE_CART0;
327	}
328	gba->isPristine = true;
329#ifdef _3DS
330	if (gba->pristineRomSize <= romBufferSize) {
331		gba->memory.rom = romBuffer;
332		vf->read(vf, romBuffer, gba->pristineRomSize);
333	}
334#else
335	gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ);
336#endif
337	if (!gba->memory.rom) {
338		mLOG(GBA, WARN, "Couldn't map ROM");
339		return false;
340	}
341	gba->yankedRomSize = 0;
342	gba->memory.romSize = gba->pristineRomSize;
343	gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
344	gba->memory.mirroring = false;
345	gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
346	GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
347	GBAVFameDetect(&gba->memory.vfame, gba->memory.rom, gba->memory.romSize);
348	if (gba->cpu && gba->memory.activeRegion >= REGION_CART0) {
349		gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
350	}
351	// TODO: error check
352	return true;
353}
354
355bool GBALoadSave(struct GBA* gba, struct VFile* sav) {
356	GBASavedataInit(&gba->memory.savedata, sav);
357	return true;
358}
359
360void GBAYankROM(struct GBA* gba) {
361	gba->yankedRomSize = gba->memory.romSize;
362	gba->memory.romSize = 0;
363	gba->memory.romMask = 0;
364	GBARaiseIRQ(gba, IRQ_GAMEPAK);
365}
366
367void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
368	gba->biosVf = vf;
369	uint32_t* bios = vf->map(vf, SIZE_BIOS, MAP_READ);
370	if (!bios) {
371		mLOG(GBA, WARN, "Couldn't map BIOS");
372		return;
373	}
374	gba->memory.bios = bios;
375	gba->memory.fullBios = 1;
376	uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
377	mLOG(GBA, DEBUG, "BIOS Checksum: 0x%X", checksum);
378	if (checksum == GBA_BIOS_CHECKSUM) {
379		mLOG(GBA, INFO, "Official GBA BIOS detected");
380	} else if (checksum == GBA_DS_BIOS_CHECKSUM) {
381		mLOG(GBA, INFO, "Official GBA (DS) BIOS detected");
382	} else {
383		mLOG(GBA, WARN, "BIOS checksum incorrect");
384	}
385	gba->biosChecksum = checksum;
386	if (gba->memory.activeRegion == REGION_BIOS) {
387		gba->cpu->memory.activeRegion = gba->memory.bios;
388	}
389	// TODO: error check
390}
391
392void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
393	size_t patchedSize = patch->outputSize(patch, gba->memory.romSize);
394	if (!patchedSize || patchedSize > SIZE_CART0) {
395		return;
396	}
397	void* newRom = anonymousMemoryMap(SIZE_CART0);
398	if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) {
399		mappedMemoryFree(newRom, SIZE_CART0);
400		return;
401	}
402	if (gba->romVf) {
403#ifndef _3DS
404		gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
405#endif
406		gba->romVf->close(gba->romVf);
407		gba->romVf = NULL;
408	}
409	gba->isPristine = false;
410	gba->memory.rom = newRom;
411	gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1];
412	gba->memory.romSize = patchedSize;
413	gba->memory.romMask = SIZE_CART0 - 1;
414	gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
415}
416
417void GBAWriteIE(struct GBA* gba, uint16_t value) {
418	if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
419		ARMRaiseIRQ(gba->cpu);
420	}
421}
422
423void GBAWriteIME(struct GBA* gba, uint16_t value) {
424	if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
425		ARMRaiseIRQ(gba->cpu);
426	}
427}
428
429void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
430	gba->memory.io[REG_IF >> 1] |= 1 << irq;
431
432	if (gba->memory.io[REG_IE >> 1] & 1 << irq) {
433		gba->cpu->halted = 0;
434		if (gba->memory.io[REG_IME >> 1]) {
435			ARMRaiseIRQ(gba->cpu);
436		}
437	}
438}
439
440void GBATestIRQ(struct ARMCore* cpu) {
441	struct GBA* gba = (struct GBA*) cpu->master;
442	if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
443		gba->springIRQ = gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1];
444		gba->cpu->nextEvent = gba->cpu->cycles;
445	}
446}
447
448void GBAHalt(struct GBA* gba) {
449	gba->cpu->nextEvent = gba->cpu->cycles;
450	gba->cpu->halted = 1;
451}
452
453void GBAStop(struct GBA* gba) {
454	size_t c;
455	for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
456		struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
457		if (callbacks->sleep) {
458			callbacks->sleep(callbacks->context);
459		}
460	}
461	gba->cpu->nextEvent = gba->cpu->cycles;
462}
463
464void GBADebug(struct GBA* gba, uint16_t flags) {
465	gba->debugFlags = flags;
466	if (GBADebugFlagsIsSend(gba->debugFlags)) {
467		int level = 1 << GBADebugFlagsGetLevel(gba->debugFlags);
468		level &= 0x1F;
469		char oolBuf[0x101];
470		strncpy(oolBuf, gba->debugString, sizeof(gba->debugString));
471		oolBuf[0x100] = '\0';
472		mLog(_mLOG_CAT_GBA_DEBUG(), level, "%s", oolBuf);
473	}
474	gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags);
475}
476
477bool GBAIsROM(struct VFile* vf) {
478	if (!vf) {
479		return false;
480	}
481	if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
482		return false;
483	}
484	uint8_t signature[sizeof(GBA_ROM_MAGIC)];
485	if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
486		return false;
487	}
488	if (GBAIsBIOS(vf)) {
489		return false;
490	}
491	return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0;
492}
493
494bool GBAIsMB(struct VFile* vf) {
495	if (!GBAIsROM(vf)) {
496		return false;
497	}
498	if (vf->size(vf) > SIZE_WORKING_RAM) {
499		return false;
500	}
501	if (vf->seek(vf, GBA_MB_MAGIC_OFFSET, SEEK_SET) < 0) {
502		return false;
503	}
504	uint32_t signature;
505	if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
506		return false;
507	}
508	uint32_t opcode;
509	LOAD_32(opcode, 0, &signature);
510	struct ARMInstructionInfo info;
511	ARMDecodeARM(opcode, &info);
512	if (info.branchType == ARM_BRANCH) {
513		if (info.op1.immediate <= 0) {
514			return false;
515		} else if (info.op1.immediate == 28) {
516			// Ancient toolchain that is known to throw MB detection for a loop
517			return false;
518		} else if (info.op1.immediate != 24) {
519			return true;
520		}
521	}
522
523	uint32_t pc = GBA_MB_MAGIC_OFFSET;
524	int i;
525	for (i = 0; i < 80; ++i) {
526		if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
527			break;
528		}
529		pc += 4;
530		LOAD_32(opcode, 0, &signature);
531		ARMDecodeARM(opcode, &info);
532		if (info.mnemonic != ARM_MN_LDR) {
533			continue;
534		}
535		if ((info.operandFormat & ARM_OPERAND_MEMORY) && info.memory.baseReg == ARM_PC && info.memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
536			uint32_t immediate = info.memory.offset.immediate;
537			if (info.memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
538				immediate = -immediate;
539			}
540			immediate += pc + 8;
541			if (vf->seek(vf, immediate, SEEK_SET) < 0) {
542				break;
543			}
544			if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
545				break;
546			}
547			LOAD_32(immediate, 0, &signature);
548			if (vf->seek(vf, pc, SEEK_SET) < 0) {
549				break;
550			}
551			if ((immediate & ~0x7FF) == BASE_WORKING_RAM) {
552				return true;
553			}
554		}
555	}
556	// Found a libgba-linked cart...these are a bit harder to detect.
557	return false;
558}
559
560bool GBAIsBIOS(struct VFile* vf) {
561	if (vf->seek(vf, 0, SEEK_SET) < 0) {
562		return false;
563	}
564	uint8_t interruptTable[7 * 4];
565	if (vf->read(vf, &interruptTable, sizeof(interruptTable)) != sizeof(interruptTable)) {
566		return false;
567	}
568	int i;
569	for (i = 0; i < 7; ++i) {
570		if (interruptTable[4 * i + 3] != 0xEA || interruptTable[4 * i + 2]) {
571			return false;
572		}
573	}
574	return true;
575}
576
577void GBAGetGameCode(const struct GBA* gba, char* out) {
578	memset(out, 0, 8);
579	if (!gba->memory.rom) {
580		return;
581	}
582
583	memcpy(out, "AGB-", 4);
584	memcpy(&out[4], &((struct GBACartridge*) gba->memory.rom)->id, 4);
585}
586
587void GBAGetGameTitle(const struct GBA* gba, char* out) {
588	if (gba->memory.rom) {
589		memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12);
590		return;
591	}
592	if (gba->isPristine && gba->memory.wram) {
593		memcpy(out, &((struct GBACartridge*) gba->memory.wram)->title, 12);
594		return;
595	}
596	strncpy(out, "(BIOS)", 12);
597}
598
599void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) {
600	struct GBA* gba = (struct GBA*) cpu->master;
601#ifdef USE_DEBUGGERS
602	if (gba->debugger) {
603		struct mDebuggerEntryInfo info = {
604			.address = _ARMPCAddress(cpu),
605			.type.bp.opcode = opcode
606		};
607		mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
608	}
609#endif
610	// TODO: More sensible category?
611	mLOG(GBA, ERROR, "Stub opcode: %08x", opcode);
612}
613
614void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
615	struct GBA* gba = (struct GBA*) cpu->master;
616	if (!gba->yankedRomSize) {
617		// TODO: More sensible category?
618		mLOG(GBA, WARN, "Illegal opcode: %08x", opcode);
619	}
620	if (cpu->executionMode == MODE_THUMB && (opcode & 0xFFC0) == 0xE800) {
621		mLOG(GBA, DEBUG, "Hit Wii U VC opcode: %08x", opcode);
622		return;
623	}
624#ifdef USE_DEBUGGERS
625	if (gba->debugger) {
626		struct mDebuggerEntryInfo info = {
627			.address = _ARMPCAddress(cpu),
628			.type.bp.opcode = opcode
629		};
630		mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
631	} else
632#endif
633	{
634		ARMRaiseUndefined(cpu);
635	}
636}
637
638void GBABreakpoint(struct ARMCore* cpu, int immediate) {
639	struct GBA* gba = (struct GBA*) cpu->master;
640	if (immediate >= CPU_COMPONENT_MAX) {
641		return;
642	}
643	switch (immediate) {
644#ifdef USE_DEBUGGERS
645	case CPU_COMPONENT_DEBUGGER:
646		if (gba->debugger) {
647			struct mDebuggerEntryInfo info = {
648				.address = _ARMPCAddress(cpu),
649				.type.bp.breakType = BREAKPOINT_SOFTWARE
650			};
651			mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
652		}
653		break;
654#endif
655	case CPU_COMPONENT_CHEAT_DEVICE:
656		if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
657			struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
658			struct GBACheatHook* hook = 0;
659			size_t i;
660			for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
661				struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i);
662				if (cheats->hook && cheats->hook->address == _ARMPCAddress(cpu)) {
663					mCheatRefresh(device, &cheats->d);
664					hook = cheats->hook;
665				}
666			}
667			if (hook) {
668				ARMRunFake(cpu, hook->patchedOpcode);
669			}
670		}
671		break;
672	default:
673		break;
674	}
675}
676
677void GBAFrameStarted(struct GBA* gba) {
678	GBATestKeypadIRQ(gba);
679
680	size_t c;
681	for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
682		struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
683		if (callbacks->videoFrameStarted) {
684			callbacks->videoFrameStarted(callbacks->context);
685		}
686	}
687}
688
689void GBAFrameEnded(struct GBA* gba) {
690	GBASavedataClean(&gba->memory.savedata, gba->video.frameCounter);
691
692	if (gba->rr) {
693		gba->rr->nextFrame(gba->rr);
694	}
695
696	if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
697		struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
698		size_t i;
699		for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
700			struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i);
701			mCheatRefresh(device, &cheats->d);
702		}
703	}
704
705	if (gba->stream && gba->stream->postVideoFrame) {
706		const color_t* pixels;
707		size_t stride;
708		gba->video.renderer->getPixels(gba->video.renderer, &stride, (const void**) &pixels);
709		gba->stream->postVideoFrame(gba->stream, pixels, stride);
710	}
711
712	if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) {
713		GBAHardwarePlayerUpdate(gba);
714	}
715
716	size_t c;
717	for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
718		struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
719		if (callbacks->videoFrameEnded) {
720			callbacks->videoFrameEnded(callbacks->context);
721		}
722	}
723}
724
725void GBATestKeypadIRQ(struct GBA* gba) {
726	uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1];
727	if (!(keycnt & 0x4000)) {
728		return;
729	}
730	int isAnd = keycnt & 0x8000;
731	if (!gba->keySource) {
732		// TODO?
733		return;
734	}
735
736	keycnt &= 0x3FF;
737	uint16_t keyInput = *gba->keySource & keycnt;
738
739	if (isAnd && keycnt == keyInput) {
740		GBARaiseIRQ(gba, IRQ_KEYPAD);
741	} else if (!isAnd && keyInput) {
742		GBARaiseIRQ(gba, IRQ_KEYPAD);
743	}
744}
745
746void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
747	size_t immediate;
748	for (immediate = 0; immediate < gba->cpu->numComponents; ++immediate) {
749		if (gba->cpu->components[immediate] == component) {
750			break;
751		}
752	}
753	if (immediate == gba->cpu->numComponents) {
754		return;
755	}
756	if (mode == MODE_ARM) {
757		int32_t value;
758		int32_t old;
759		value = 0xE1200070;
760		value |= immediate & 0xF;
761		value |= (immediate & 0xFFF0) << 4;
762		GBAPatch32(gba->cpu, address, value, &old);
763		*opcode = old;
764	} else {
765		int16_t value;
766		int16_t old;
767		value = 0xBE00;
768		value |= immediate & 0xFF;
769		GBAPatch16(gba->cpu, address, value, &old);
770		*opcode = (uint16_t) old;
771	}
772}
773
774void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
775	if (mode == MODE_ARM) {
776		GBAPatch32(gba->cpu, address, opcode, 0);
777	} else {
778		GBAPatch16(gba->cpu, address, opcode, 0);
779	}
780}
781
782static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
783	GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d.p->d, address, mode, opcode);
784	return true;
785}
786
787static bool _clearSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
788	GBAClearBreakpoint((struct GBA*) debugger->cpu->master, address, mode, opcode);
789	return true;
790}