all repos — mgba @ 073019031768db7287a65ace2b8b61dd9bea7d44

mGBA Game Boy Advance Emulator

src/gb/gb.c (view raw)

  1/* Copyright (c) 2013-2016 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/gb/gb.h>
  7
  8#include <mgba/internal/gb/io.h>
  9#include <mgba/internal/gb/mbc.h>
 10#include <mgba/internal/lr35902/lr35902.h>
 11
 12#include <mgba/core/core.h>
 13#include <mgba/core/cheats.h>
 14#include <mgba-util/crc32.h>
 15#include <mgba-util/memory.h>
 16#include <mgba-util/math.h>
 17#include <mgba-util/patch.h>
 18#include <mgba-util/vfs.h>
 19
 20#define CLEANUP_THRESHOLD 15
 21
 22const uint32_t CGB_LR35902_FREQUENCY = 0x800000;
 23const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E;
 24
 25const uint32_t GB_COMPONENT_MAGIC = 0x400000;
 26
 27static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
 28
 29#define DMG_BIOS_CHECKSUM 0xC2F5CC97
 30#define DMG_2_BIOS_CHECKSUM 0x59C8598E
 31#define CGB_BIOS_CHECKSUM 0x41884E46
 32
 33mLOG_DEFINE_CATEGORY(GB, "GB", "gb");
 34
 35static void GBInit(void* cpu, struct mCPUComponent* component);
 36static void GBDeinit(struct mCPUComponent* component);
 37static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
 38static void GBProcessEvents(struct LR35902Core* cpu);
 39static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
 40static void GBIllegal(struct LR35902Core* cpu);
 41static void GBStop(struct LR35902Core* cpu);
 42
 43static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate);
 44
 45#ifdef _3DS
 46extern uint32_t* romBuffer;
 47extern size_t romBufferSize;
 48#endif
 49
 50void GBCreate(struct GB* gb) {
 51	gb->d.id = GB_COMPONENT_MAGIC;
 52	gb->d.init = GBInit;
 53	gb->d.deinit = GBDeinit;
 54}
 55
 56static void GBInit(void* cpu, struct mCPUComponent* component) {
 57	struct GB* gb = (struct GB*) component;
 58	gb->cpu = cpu;
 59	gb->sync = NULL;
 60
 61	GBInterruptHandlerInit(&gb->cpu->irqh);
 62	GBMemoryInit(gb);
 63
 64	gb->video.p = gb;
 65	GBVideoInit(&gb->video);
 66
 67	gb->audio.p = gb;
 68	GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant
 69
 70	gb->sio.p = gb;
 71	GBSIOInit(&gb->sio);
 72
 73	gb->timer.p = gb;
 74
 75	gb->model = GB_MODEL_AUTODETECT;
 76
 77	gb->biosVf = NULL;
 78	gb->romVf = NULL;
 79	gb->sramVf = NULL;
 80	gb->sramRealVf = NULL;
 81
 82	gb->isPristine = false;
 83	gb->pristineRomSize = 0;
 84	gb->yankedRomSize = 0;
 85
 86	mCoreCallbacksListInit(&gb->coreCallbacks, 0);
 87	gb->stream = NULL;
 88
 89	mTimingInit(&gb->timing, &gb->cpu->cycles, &gb->cpu->nextEvent);
 90	gb->audio.timing = &gb->timing;
 91
 92	gb->eiPending.name = "GB EI";
 93	gb->eiPending.callback = _enableInterrupts;
 94	gb->eiPending.context = gb;
 95	gb->eiPending.priority = 0;
 96}
 97
 98static void GBDeinit(struct mCPUComponent* component) {
 99	struct GB* gb = (struct GB*) component;
100	mTimingDeinit(&gb->timing);
101}
102
103bool GBLoadROM(struct GB* gb, struct VFile* vf) {
104	if (!vf) {
105		return false;
106	}
107	GBUnloadROM(gb);
108	gb->romVf = vf;
109	gb->pristineRomSize = vf->size(vf);
110	vf->seek(vf, 0, SEEK_SET);
111	gb->isPristine = true;
112#ifdef _3DS
113	if (gb->pristineRomSize <= romBufferSize) {
114		gb->memory.rom = romBuffer;
115		vf->read(vf, romBuffer, gb->pristineRomSize);
116	}
117#else
118	gb->memory.rom = vf->map(vf, gb->pristineRomSize, MAP_READ);
119#endif
120	if (!gb->memory.rom) {
121		return false;
122	}
123	gb->yankedRomSize = 0;
124	gb->memory.romBase = gb->memory.rom;
125	gb->memory.romSize = gb->pristineRomSize;
126	gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
127	GBMBCInit(gb);
128
129	if (gb->cpu) {
130		struct LR35902Core* cpu = gb->cpu;
131		cpu->memory.setActiveRegion(cpu, cpu->pc);
132	}
133
134	// TODO: error check
135	return true;
136}
137
138static void GBSramDeinit(struct GB* gb) {
139	if (gb->sramVf) {
140		gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize);
141		if (gb->memory.mbcType == GB_MBC3_RTC && gb->sramVf == gb->sramRealVf) {
142			GBMBCRTCWrite(gb);
143		}
144		gb->sramVf = NULL;
145	} else if (gb->memory.sram) {
146		mappedMemoryFree(gb->memory.sram, gb->sramSize);
147	}
148	gb->memory.sram = 0;
149}
150
151bool GBLoadSave(struct GB* gb, struct VFile* vf) {
152	GBSramDeinit(gb);
153	gb->sramVf = vf;
154	gb->sramRealVf = vf;
155	if (gb->sramSize) {
156		GBResizeSram(gb, gb->sramSize);
157	}
158	return vf;
159}
160
161void GBResizeSram(struct GB* gb, size_t size) {
162	if (gb->memory.sram && size <= gb->sramSize) {
163		return;
164	}
165	struct VFile* vf = gb->sramVf;
166	if (vf) {
167		if (vf == gb->sramRealVf) {
168			ssize_t vfSize = vf->size(vf);
169			if (vfSize >= 0 && (size_t) vfSize < size) {
170				uint8_t extdataBuffer[0x100];
171				if (vfSize & 0xFF) {
172					vf->seek(vf, -(vfSize & 0xFF), SEEK_END);
173					vf->read(vf, extdataBuffer, vfSize & 0xFF);
174				}
175				if (gb->memory.sram) {
176					vf->unmap(vf, gb->memory.sram, gb->sramSize);
177				}
178				vf->truncate(vf, size + (vfSize & 0xFF));
179				if (vfSize & 0xFF) {
180					vf->seek(vf, size, SEEK_SET);
181					vf->write(vf, extdataBuffer, vfSize & 0xFF);
182				}
183				gb->memory.sram = vf->map(vf, size, MAP_WRITE);
184				memset(&gb->memory.sram[gb->sramSize], 0xFF, size - gb->sramSize);
185			} else if (size > gb->sramSize || !gb->memory.sram) {
186				if (gb->memory.sram) {
187					vf->unmap(vf, gb->memory.sram, gb->sramSize);
188				}
189				gb->memory.sram = vf->map(vf, size, MAP_WRITE);
190			}
191		} else {
192			if (gb->memory.sram) {
193				vf->unmap(vf, gb->memory.sram, gb->sramSize);
194			}
195			gb->memory.sram = vf->map(vf, size, MAP_READ);
196		}
197		if (gb->memory.sram == (void*) -1) {
198			gb->memory.sram = NULL;
199		}
200	} else {
201		uint8_t* newSram = anonymousMemoryMap(size);
202		if (gb->memory.sram) {
203			if (size > gb->sramSize) {
204				memcpy(newSram, gb->memory.sram, gb->sramSize);
205				memset(&newSram[gb->sramSize], 0xFF, size - gb->sramSize);
206			} else {
207				memcpy(newSram, gb->memory.sram, size);
208			}
209			mappedMemoryFree(gb->memory.sram, gb->sramSize);
210		} else {
211			memset(newSram, 0xFF, size);
212		}
213		gb->memory.sram = newSram;
214	}
215	if (gb->sramSize < size) {
216		gb->sramSize = size;
217	}
218}
219
220void GBSramClean(struct GB* gb, uint32_t frameCount) {
221	// TODO: Share with GBASavedataClean
222	if (!gb->sramVf) {
223		return;
224	}
225	if (gb->sramDirty & GB_SRAM_DIRT_NEW) {
226		gb->sramDirtAge = frameCount;
227		gb->sramDirty &= ~GB_SRAM_DIRT_NEW;
228		if (!(gb->sramDirty & GB_SRAM_DIRT_SEEN)) {
229			gb->sramDirty |= GB_SRAM_DIRT_SEEN;
230		}
231	} else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) {
232		if (gb->sramMaskWriteback) {
233			GBSavedataUnmask(gb);
234		}
235		if (gb->memory.mbcType == GB_MBC3_RTC) {
236			GBMBCRTCWrite(gb);
237		}
238		gb->sramDirty = 0;
239		if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
240			mLOG(GB_MEM, INFO, "Savedata synced");
241		} else {
242			mLOG(GB_MEM, INFO, "Savedata failed to sync!");
243		}
244	}
245}
246
247void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) {
248	GBSramDeinit(gb);
249	gb->sramVf = vf;
250	gb->sramMaskWriteback = writeback;
251	gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);
252	GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
253}
254
255void GBSavedataUnmask(struct GB* gb) {
256	if (gb->sramVf == gb->sramRealVf) {
257		return;
258	}
259	struct VFile* vf = gb->sramVf;
260	GBSramDeinit(gb);
261	gb->sramVf = gb->sramRealVf;
262	gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
263	if (gb->sramMaskWriteback) {
264		vf->seek(vf, 0, SEEK_SET);
265		vf->read(vf, gb->memory.sram, gb->sramSize);
266		gb->sramMaskWriteback = false;
267	}
268	vf->close(vf);
269}
270
271void GBUnloadROM(struct GB* gb) {
272	// TODO: Share with GBAUnloadROM
273	if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && !gb->isPristine) {
274		free(gb->memory.romBase);
275	}
276	if (gb->memory.rom && !gb->isPristine) {
277		if (gb->yankedRomSize) {
278			gb->yankedRomSize = 0;
279		}
280		mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
281	}
282
283	if (gb->romVf) {
284#ifndef _3DS
285		gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
286#endif
287		gb->romVf->close(gb->romVf);
288		gb->romVf = NULL;
289	}
290	gb->memory.rom = NULL;
291	gb->memory.mbcType = GB_MBC_AUTODETECT;
292	gb->isPristine = false;
293
294	gb->sramMaskWriteback = false;
295	GBSavedataUnmask(gb);
296	GBSramDeinit(gb);
297	if (gb->sramRealVf) {
298		gb->sramRealVf->close(gb->sramRealVf);
299	}
300	gb->sramRealVf = NULL;
301	gb->sramVf = NULL;
302}
303
304void GBSynthesizeROM(struct VFile* vf) {
305	if (!vf) {
306		return;
307	}
308	const struct GBCartridge cart = {
309		.logo = { _knownHeader[0], _knownHeader[1], _knownHeader[2], _knownHeader[3]}
310	};
311
312	vf->seek(vf, 0x100, SEEK_SET);
313	vf->write(vf, &cart, sizeof(cart));
314}
315
316void GBLoadBIOS(struct GB* gb, struct VFile* vf) {
317	gb->biosVf = vf;
318}
319
320void GBApplyPatch(struct GB* gb, struct Patch* patch) {
321	size_t patchedSize = patch->outputSize(patch, gb->memory.romSize);
322	if (!patchedSize) {
323		return;
324	}
325	if (patchedSize > GB_SIZE_CART_MAX) {
326		patchedSize = GB_SIZE_CART_MAX;
327	}
328	void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX);
329	if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) {
330		mappedMemoryFree(newRom, GB_SIZE_CART_MAX);
331		return;
332	}
333	if (gb->romVf) {
334#ifndef _3DS
335		gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
336#endif
337		gb->romVf->close(gb->romVf);
338		gb->romVf = NULL;
339	}
340	gb->isPristine = false;
341	if (gb->memory.romBase == gb->memory.rom) {
342		gb->memory.romBase = newRom;
343	}
344	gb->memory.rom = newRom;
345	gb->memory.romSize = patchedSize;
346	gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
347	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
348}
349
350void GBDestroy(struct GB* gb) {
351	GBUnloadROM(gb);
352
353	if (gb->biosVf) {
354		gb->biosVf->close(gb->biosVf);
355		gb->biosVf = 0;
356	}
357
358	GBMemoryDeinit(gb);
359	GBAudioDeinit(&gb->audio);
360	GBVideoDeinit(&gb->video);
361	GBSIODeinit(&gb->sio);
362	mCoreCallbacksListDeinit(&gb->coreCallbacks);
363}
364
365void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
366	irqh->reset = GBReset;
367	irqh->processEvents = GBProcessEvents;
368	irqh->setInterrupts = GBSetInterrupts;
369	irqh->hitIllegal = GBIllegal;
370	irqh->stop = GBStop;
371	irqh->halt = GBHalt;
372}
373
374static uint32_t _GBBiosCRC32(struct VFile* vf) {
375	ssize_t size = vf->size(vf);
376	if (size <= 0 || size > GB_SIZE_CART_BANK0) {
377		return 0;
378	}
379	void* bios = vf->map(vf, size, MAP_READ);
380	uint32_t biosCrc = doCrc32(bios, size);
381	vf->unmap(vf, bios, size);
382	return biosCrc;
383}
384
385bool GBIsBIOS(struct VFile* vf) {
386	switch (_GBBiosCRC32(vf)) {
387	case DMG_BIOS_CHECKSUM:
388	case DMG_2_BIOS_CHECKSUM:
389	case CGB_BIOS_CHECKSUM:
390		return true;
391	default:
392		return false;
393	}
394}
395
396void GBReset(struct LR35902Core* cpu) {
397	struct GB* gb = (struct GB*) cpu->master;
398	gb->memory.romBase = gb->memory.rom;
399	GBDetectModel(gb);
400
401	if (gb->biosVf) {
402		if (!GBIsBIOS(gb->biosVf)) {
403			gb->biosVf->close(gb->biosVf);
404			gb->biosVf = NULL;
405		} else {
406			gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
407			gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
408			ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
409			memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
410			if (size > 0x100) {
411				memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge));
412			}
413
414			cpu->a = 0;
415			cpu->f.packed = 0;
416			cpu->c = 0;
417			cpu->e = 0;
418			cpu->h = 0;
419			cpu->l = 0;
420			cpu->sp = 0;
421			cpu->pc = 0;
422		}
423	}
424
425	cpu->b = 0;
426	cpu->d = 0;
427
428	if (!gb->biosVf) {
429		switch (gb->model) {
430		case GB_MODEL_DMG:
431			// TODO: SGB
432		case GB_MODEL_SGB:
433		case GB_MODEL_AUTODETECT: // Silence warnings
434			gb->model = GB_MODEL_DMG;
435			cpu->a = 1;
436			cpu->f.packed = 0xB0;
437			cpu->c = 0x13;
438			cpu->e = 0xD8;
439			cpu->h = 1;
440			cpu->l = 0x4D;
441			gb->timer.internalDiv = 0x2AF3;
442			break;
443		case GB_MODEL_AGB:
444			cpu->b = 1;
445			// Fall through
446		case GB_MODEL_CGB:
447			cpu->a = 0x11;
448			cpu->f.packed = 0x80;
449			cpu->c = 0;
450			cpu->e = 0x08;
451			cpu->h = 0;
452			cpu->l = 0x7C;
453			gb->timer.internalDiv = 0x7A8;
454			break;
455		}
456
457		cpu->sp = 0xFFFE;
458		cpu->pc = 0x100;
459	}
460
461	gb->cpuBlocked = false;
462	gb->earlyExit = false;
463	gb->doubleSpeed = 0;
464
465	cpu->memory.setActiveRegion(cpu, cpu->pc);
466
467	if (gb->yankedRomSize) {
468		gb->memory.romSize = gb->yankedRomSize;
469		gb->yankedRomSize = 0;
470	}
471
472	mTimingClear(&gb->timing);
473
474	GBMemoryReset(gb);
475	GBVideoReset(&gb->video);
476	GBTimerReset(&gb->timer);
477	mTimingSchedule(&gb->timing, &gb->timer.event, GB_DMG_DIV_PERIOD);
478
479	GBAudioReset(&gb->audio);
480	GBIOReset(gb);
481	GBSIOReset(&gb->sio);
482
483	GBSavedataUnmask(gb);
484}
485
486void GBDetectModel(struct GB* gb) {
487	if (gb->model != GB_MODEL_AUTODETECT) {
488		return;
489	}
490	if (gb->biosVf) {
491		switch (_GBBiosCRC32(gb->biosVf)) {
492		case DMG_BIOS_CHECKSUM:
493		case DMG_2_BIOS_CHECKSUM:
494			gb->model = GB_MODEL_DMG;
495			break;
496		case CGB_BIOS_CHECKSUM:
497			gb->model = GB_MODEL_CGB;
498			break;
499		default:
500			gb->biosVf->close(gb->biosVf);
501			gb->biosVf = NULL;
502		}
503	}
504	if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
505		const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
506		if (cart->cgb & 0x80) {
507			gb->model = GB_MODEL_CGB;
508		} else {
509			gb->model = GB_MODEL_DMG;
510		}
511	}
512
513	switch (gb->model) {
514	case GB_MODEL_DMG:
515	case GB_MODEL_SGB:
516	case GB_MODEL_AUTODETECT: //Silence warnings
517		gb->audio.style = GB_AUDIO_DMG;
518		break;
519	case GB_MODEL_AGB:
520	case GB_MODEL_CGB:
521		gb->audio.style = GB_AUDIO_CGB;
522		break;
523	}
524}
525
526void GBUpdateIRQs(struct GB* gb) {
527	int irqs = gb->memory.ie & gb->memory.io[REG_IF];
528	if (!irqs) {
529		return;
530	}
531	gb->cpu->halted = false;
532
533	if (!gb->memory.ime || gb->cpu->irqPending) {
534		return;
535	}
536
537	if (irqs & (1 << GB_IRQ_VBLANK)) {
538		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
539		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
540		return;
541	}
542	if (irqs & (1 << GB_IRQ_LCDSTAT)) {
543		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
544		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
545		return;
546	}
547	if (irqs & (1 << GB_IRQ_TIMER)) {
548		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
549		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
550		return;
551	}
552	if (irqs & (1 << GB_IRQ_SIO)) {
553		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
554		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
555		return;
556	}
557	if (irqs & (1 << GB_IRQ_KEYPAD)) {
558		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
559		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
560	}
561}
562
563void GBProcessEvents(struct LR35902Core* cpu) {
564	struct GB* gb = (struct GB*) cpu->master;
565	do {
566		int32_t cycles = cpu->cycles;
567		int32_t nextEvent;
568
569		cpu->cycles = 0;
570		cpu->nextEvent = INT_MAX;
571
572		nextEvent = cycles;
573		do {
574			nextEvent = mTimingTick(&gb->timing, nextEvent);
575		} while (gb->cpuBlocked);
576		cpu->nextEvent = nextEvent;
577
578		if (gb->earlyExit) {
579			gb->earlyExit = false;
580			break;
581		}
582		if (cpu->halted) {
583			cpu->cycles = cpu->nextEvent;
584			if (!gb->memory.ie || !gb->memory.ime) {
585				break;
586			}
587		}
588	} while (cpu->cycles >= cpu->nextEvent);
589}
590
591void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
592	struct GB* gb = (struct GB*) cpu->master;
593	if (!enable) {
594		gb->memory.ime = enable;
595		mTimingDeschedule(&gb->timing, &gb->eiPending);
596		GBUpdateIRQs(gb);
597	} else {
598		mTimingDeschedule(&gb->timing, &gb->eiPending);
599		mTimingSchedule(&gb->timing, &gb->eiPending, 4);
600	}
601}
602
603static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
604	UNUSED(timing);
605	UNUSED(cyclesLate);
606	struct GB* gb = user;
607	gb->memory.ime = true;
608	GBUpdateIRQs(gb);
609}
610
611void GBHalt(struct LR35902Core* cpu) {
612	if (!cpu->irqPending) {
613		cpu->cycles = cpu->nextEvent;
614		cpu->halted = true;
615	}
616}
617
618void GBStop(struct LR35902Core* cpu) {
619	struct GB* gb = (struct GB*) cpu->master;
620	if (cpu->bus) {
621		mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X\n", cpu->pc, cpu->bus);
622	}
623	if (gb->memory.io[REG_KEY1] & 1) {
624		gb->doubleSpeed ^= 1;
625		gb->audio.timingFactor = gb->doubleSpeed + 1;
626		gb->memory.io[REG_KEY1] = 0;
627		gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
628	} else if (cpu->bus) {
629#ifdef USE_DEBUGGERS
630		if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
631			struct mDebuggerEntryInfo info = {
632				.address = cpu->pc - 1,
633				.type.bp.opcode = 0x1000 | cpu->bus
634			};
635			mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
636		}
637#endif
638		// Hang forever
639		gb->memory.ime = 0;
640		cpu->pc -= 2;
641	}
642	// TODO: Actually stop
643}
644
645void GBIllegal(struct LR35902Core* cpu) {
646	struct GB* gb = (struct GB*) cpu->master;
647	mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus);
648#ifdef USE_DEBUGGERS
649	if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
650		struct mDebuggerEntryInfo info = {
651			.address = cpu->pc,
652			.type.bp.opcode = cpu->bus
653		};
654		mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
655	}
656#endif
657	// Hang forever
658	gb->memory.ime = 0;
659	--cpu->pc;
660}
661
662bool GBIsROM(struct VFile* vf) {
663	if (!vf) {
664		return false;
665	}
666	vf->seek(vf, 0x104, SEEK_SET);
667	uint8_t header[4];
668
669	if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
670		return false;
671	}
672	if (memcmp(header, _knownHeader, sizeof(header))) {
673		return false;
674	}
675	return true;
676}
677
678void GBGetGameTitle(const struct GB* gb, char* out) {
679	const struct GBCartridge* cart = NULL;
680	if (gb->memory.rom) {
681		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
682	}
683	if (!cart) {
684		return;
685	}
686	if (cart->oldLicensee != 0x33) {
687		memcpy(out, cart->titleLong, 16);
688	} else {
689		memcpy(out, cart->titleShort, 11);
690	}
691}
692
693void GBGetGameCode(const struct GB* gb, char* out) {
694	memset(out, 0, 8);
695	const struct GBCartridge* cart = NULL;
696	if (gb->memory.rom) {
697		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
698	}
699	if (!cart) {
700		return;
701	}
702	if (cart->cgb == 0xC0) {
703		memcpy(out, "CGB-????", 8);
704	} else {
705		memcpy(out, "DMG-????", 8);
706	}
707	if (cart->oldLicensee == 0x33) {
708		memcpy(&out[4], cart->maker, 4);
709	}
710}
711
712void GBFrameEnded(struct GB* gb) {
713	GBSramClean(gb, gb->video.frameCounter);
714
715	if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
716		struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
717		size_t i;
718		for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
719			struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
720			mCheatRefresh(device, cheats);
721		}
722	}
723
724	GBTestKeypadIRQ(gb);
725}