all repos — mgba @ 5b1e65052c04b48ba2f5ef44847aa140ef27c2aa

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