all repos — mgba @ d7fc09768d0c5771f11ad4cf1b40851e7a11a6aa

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) {
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->sramMaskWriteback) {
234			GBSavedataUnmask(gb);
235		}
236		if (gb->memory.mbcType == GB_MBC3_RTC) {
237			GBMBCRTCWrite(gb);
238		}
239		gb->sramDirty = 0;
240		if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
241			mLOG(GB_MEM, INFO, "Savedata synced");
242		} else {
243			mLOG(GB_MEM, INFO, "Savedata failed to sync!");
244		}
245	}
246}
247
248void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) {
249	GBSramDeinit(gb);
250	gb->sramVf = vf;
251	gb->sramMaskWriteback = writeback;
252	gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);
253	GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
254}
255
256void GBSavedataUnmask(struct GB* gb) {
257	if (gb->sramVf == gb->sramRealVf) {
258		return;
259	}
260	struct VFile* vf = gb->sramVf;
261	GBSramDeinit(gb);
262	gb->sramVf = gb->sramRealVf;
263	gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
264	if (gb->sramMaskWriteback) {
265		vf->seek(vf, 0, SEEK_SET);
266		vf->read(vf, gb->memory.sram, gb->sramSize);
267		gb->sramMaskWriteback = false;
268	}
269	vf->close(vf);
270}
271
272void GBUnloadROM(struct GB* gb) {
273	// TODO: Share with GBAUnloadROM
274	if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && !gb->isPristine) {
275		free(gb->memory.romBase);
276	}
277	if (gb->memory.rom && !gb->isPristine) {
278		if (gb->yankedRomSize) {
279			gb->yankedRomSize = 0;
280		}
281		mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
282	}
283
284	if (gb->romVf) {
285#ifndef FIXED_ROM_BUFFER
286		gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
287#endif
288		gb->romVf->close(gb->romVf);
289		gb->romVf = NULL;
290	}
291	gb->memory.rom = NULL;
292	gb->memory.mbcType = GB_MBC_AUTODETECT;
293	gb->isPristine = false;
294
295	gb->sramMaskWriteback = false;
296	GBSavedataUnmask(gb);
297	GBSramDeinit(gb);
298	if (gb->sramRealVf) {
299		gb->sramRealVf->close(gb->sramRealVf);
300	}
301	gb->sramRealVf = NULL;
302	gb->sramVf = NULL;
303	if (gb->memory.cam && gb->memory.cam->stopRequestImage) {
304		gb->memory.cam->stopRequestImage(gb->memory.cam);
305	}
306}
307
308void GBSynthesizeROM(struct VFile* vf) {
309	if (!vf) {
310		return;
311	}
312	const struct GBCartridge cart = {
313		.logo = { _knownHeader[0], _knownHeader[1], _knownHeader[2], _knownHeader[3]}
314	};
315
316	vf->seek(vf, 0x100, SEEK_SET);
317	vf->write(vf, &cart, sizeof(cart));
318}
319
320void GBLoadBIOS(struct GB* gb, struct VFile* vf) {
321	gb->biosVf = vf;
322}
323
324void GBApplyPatch(struct GB* gb, struct Patch* patch) {
325	size_t patchedSize = patch->outputSize(patch, gb->memory.romSize);
326	if (!patchedSize) {
327		return;
328	}
329	if (patchedSize > GB_SIZE_CART_MAX) {
330		patchedSize = GB_SIZE_CART_MAX;
331	}
332	void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX);
333	if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) {
334		mappedMemoryFree(newRom, GB_SIZE_CART_MAX);
335		return;
336	}
337	if (gb->romVf) {
338#ifndef FIXED_ROM_BUFFER
339		gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
340#endif
341		gb->romVf->close(gb->romVf);
342		gb->romVf = NULL;
343	}
344	gb->isPristine = false;
345	if (gb->memory.romBase == gb->memory.rom) {
346		gb->memory.romBase = newRom;
347	}
348	gb->memory.rom = newRom;
349	gb->memory.romSize = patchedSize;
350	gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
351	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
352}
353
354void GBDestroy(struct GB* gb) {
355	GBUnloadROM(gb);
356
357	if (gb->biosVf) {
358		gb->biosVf->close(gb->biosVf);
359		gb->biosVf = 0;
360	}
361
362	GBMemoryDeinit(gb);
363	GBAudioDeinit(&gb->audio);
364	GBVideoDeinit(&gb->video);
365	GBSIODeinit(&gb->sio);
366	mCoreCallbacksListDeinit(&gb->coreCallbacks);
367}
368
369void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
370	irqh->reset = GBReset;
371	irqh->processEvents = GBProcessEvents;
372	irqh->setInterrupts = GBSetInterrupts;
373	irqh->hitIllegal = GBIllegal;
374	irqh->stop = GBStop;
375	irqh->halt = GBHalt;
376}
377
378static uint32_t _GBBiosCRC32(struct VFile* vf) {
379	ssize_t size = vf->size(vf);
380	if (size <= 0 || size > GB_SIZE_CART_BANK0) {
381		return 0;
382	}
383	void* bios = vf->map(vf, size, MAP_READ);
384	uint32_t biosCrc = doCrc32(bios, size);
385	vf->unmap(vf, bios, size);
386	return biosCrc;
387}
388
389bool GBIsBIOS(struct VFile* vf) {
390	switch (_GBBiosCRC32(vf)) {
391	case DMG_BIOS_CHECKSUM:
392	case DMG_2_BIOS_CHECKSUM:
393	case SGB_BIOS_CHECKSUM:
394	case CGB_BIOS_CHECKSUM:
395		return true;
396	default:
397		return false;
398	}
399}
400
401void GBReset(struct LR35902Core* cpu) {
402	struct GB* gb = (struct GB*) cpu->master;
403	gb->memory.romBase = gb->memory.rom;
404	GBDetectModel(gb);
405
406	if (gb->biosVf) {
407		if (!GBIsBIOS(gb->biosVf)) {
408			gb->biosVf->close(gb->biosVf);
409			gb->biosVf = NULL;
410		} else {
411			gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
412			gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
413			ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
414			memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
415			if (size > 0x100) {
416				memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge));
417			}
418
419			cpu->a = 0;
420			cpu->f.packed = 0;
421			cpu->c = 0;
422			cpu->e = 0;
423			cpu->h = 0;
424			cpu->l = 0;
425			cpu->sp = 0;
426			cpu->pc = 0;
427		}
428	}
429
430	cpu->b = 0;
431	cpu->d = 0;
432
433	if (!gb->biosVf) {
434		switch (gb->model) {
435		case GB_MODEL_AUTODETECT: // Silence warnings
436			gb->model = GB_MODEL_DMG;
437			// TODO: SGB registers
438		case GB_MODEL_SGB:
439		case GB_MODEL_DMG:
440			cpu->a = 1;
441			cpu->f.packed = 0xB0;
442			cpu->c = 0x13;
443			cpu->e = 0xD8;
444			cpu->h = 1;
445			cpu->l = 0x4D;
446			gb->timer.internalDiv = 0x2AF3;
447			break;
448		case GB_MODEL_AGB:
449			cpu->b = 1;
450			// Fall through
451		case GB_MODEL_CGB:
452			cpu->a = 0x11;
453			cpu->f.packed = 0x80;
454			cpu->c = 0;
455			cpu->e = 0x08;
456			cpu->h = 0;
457			cpu->l = 0x7C;
458			gb->timer.internalDiv = 0x7A8;
459			break;
460		}
461
462		cpu->sp = 0xFFFE;
463		cpu->pc = 0x100;
464	}
465
466	gb->cpuBlocked = false;
467	gb->earlyExit = false;
468	gb->doubleSpeed = 0;
469
470	cpu->memory.setActiveRegion(cpu, cpu->pc);
471
472	if (gb->yankedRomSize) {
473		gb->memory.romSize = gb->yankedRomSize;
474		gb->yankedRomSize = 0;
475	}
476
477	gb->sgbBit = -1;
478	gb->currentSgbBits = 0;
479	memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
480
481	mTimingClear(&gb->timing);
482
483	GBMemoryReset(gb);
484	GBVideoReset(&gb->video);
485	GBTimerReset(&gb->timer);
486	mTimingSchedule(&gb->timing, &gb->timer.event, GB_DMG_DIV_PERIOD);
487
488	GBAudioReset(&gb->audio);
489	GBIOReset(gb);
490	GBSIOReset(&gb->sio);
491
492	GBSavedataUnmask(gb);
493}
494
495void GBDetectModel(struct GB* gb) {
496	if (gb->model != GB_MODEL_AUTODETECT) {
497		return;
498	}
499	if (gb->biosVf) {
500		switch (_GBBiosCRC32(gb->biosVf)) {
501		case DMG_BIOS_CHECKSUM:
502		case DMG_2_BIOS_CHECKSUM:
503			gb->model = GB_MODEL_DMG;
504			break;
505		case SGB_BIOS_CHECKSUM:
506			gb->model = GB_MODEL_SGB;
507			break;
508		case CGB_BIOS_CHECKSUM:
509			gb->model = GB_MODEL_CGB;
510			break;
511		default:
512			gb->biosVf->close(gb->biosVf);
513			gb->biosVf = NULL;
514		}
515	}
516	if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
517		const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
518		if (cart->cgb & 0x80) {
519			gb->model = GB_MODEL_CGB;
520		} else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
521			gb->model = GB_MODEL_SGB;
522		} else {
523			gb->model = GB_MODEL_DMG;
524		}
525	}
526
527	switch (gb->model) {
528	case GB_MODEL_DMG:
529	case GB_MODEL_SGB:
530	case GB_MODEL_AUTODETECT: //Silence warnings
531		gb->audio.style = GB_AUDIO_DMG;
532		break;
533	case GB_MODEL_AGB:
534	case GB_MODEL_CGB:
535		gb->audio.style = GB_AUDIO_CGB;
536		break;
537	}
538}
539
540void GBUpdateIRQs(struct GB* gb) {
541	int irqs = gb->memory.ie & gb->memory.io[REG_IF];
542	if (!irqs) {
543		return;
544	}
545	gb->cpu->halted = false;
546
547	if (!gb->memory.ime || gb->cpu->irqPending) {
548		return;
549	}
550
551	if (irqs & (1 << GB_IRQ_VBLANK)) {
552		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
553		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
554		return;
555	}
556	if (irqs & (1 << GB_IRQ_LCDSTAT)) {
557		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
558		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
559		return;
560	}
561	if (irqs & (1 << GB_IRQ_TIMER)) {
562		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
563		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
564		return;
565	}
566	if (irqs & (1 << GB_IRQ_SIO)) {
567		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
568		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
569		return;
570	}
571	if (irqs & (1 << GB_IRQ_KEYPAD)) {
572		LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
573		gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
574	}
575}
576
577void GBProcessEvents(struct LR35902Core* cpu) {
578	struct GB* gb = (struct GB*) cpu->master;
579	do {
580		int32_t cycles = cpu->cycles;
581		int32_t nextEvent;
582
583		cpu->cycles = 0;
584		cpu->nextEvent = INT_MAX;
585
586		nextEvent = cycles;
587		do {
588			nextEvent = mTimingTick(&gb->timing, nextEvent);
589		} while (gb->cpuBlocked);
590		cpu->nextEvent = nextEvent;
591
592		if (gb->earlyExit) {
593			gb->earlyExit = false;
594			break;
595		}
596		if (cpu->halted) {
597			cpu->cycles = cpu->nextEvent;
598			if (!gb->memory.ie || !gb->memory.ime) {
599				break;
600			}
601		}
602	} while (cpu->cycles >= cpu->nextEvent);
603}
604
605void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
606	struct GB* gb = (struct GB*) cpu->master;
607	if (!enable) {
608		gb->memory.ime = enable;
609		mTimingDeschedule(&gb->timing, &gb->eiPending);
610		GBUpdateIRQs(gb);
611	} else {
612		mTimingDeschedule(&gb->timing, &gb->eiPending);
613		mTimingSchedule(&gb->timing, &gb->eiPending, 4);
614	}
615}
616
617static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
618	UNUSED(timing);
619	UNUSED(cyclesLate);
620	struct GB* gb = user;
621	gb->memory.ime = true;
622	GBUpdateIRQs(gb);
623}
624
625void GBHalt(struct LR35902Core* cpu) {
626	if (!cpu->irqPending) {
627		cpu->cycles = cpu->nextEvent;
628		cpu->halted = true;
629	}
630}
631
632void GBStop(struct LR35902Core* cpu) {
633	struct GB* gb = (struct GB*) cpu->master;
634	if (cpu->bus) {
635		mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X", cpu->pc, cpu->bus);
636	}
637	if (gb->memory.io[REG_KEY1] & 1) {
638		gb->doubleSpeed ^= 1;
639		gb->audio.timingFactor = gb->doubleSpeed + 1;
640		gb->memory.io[REG_KEY1] = 0;
641		gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
642	} else if (cpu->bus) {
643#ifdef USE_DEBUGGERS
644		if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
645			struct mDebuggerEntryInfo info = {
646				.address = cpu->pc - 1,
647				.opcode = 0x1000 | cpu->bus
648			};
649			mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
650		}
651#endif
652		// Hang forever
653		gb->memory.ime = 0;
654		cpu->pc -= 2;
655	}
656	// TODO: Actually stop
657}
658
659void GBIllegal(struct LR35902Core* cpu) {
660	struct GB* gb = (struct GB*) cpu->master;
661	mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X", cpu->pc, cpu->bus);
662#ifdef USE_DEBUGGERS
663	if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
664		struct mDebuggerEntryInfo info = {
665			.address = cpu->pc,
666			.opcode = cpu->bus
667		};
668		mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
669	}
670#endif
671	// Hang forever
672	gb->memory.ime = 0;
673	--cpu->pc;
674}
675
676bool GBIsROM(struct VFile* vf) {
677	if (!vf) {
678		return false;
679	}
680	vf->seek(vf, 0x104, SEEK_SET);
681	uint8_t header[4];
682
683	if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
684		return false;
685	}
686	if (memcmp(header, _knownHeader, sizeof(header))) {
687		return false;
688	}
689	return true;
690}
691
692void GBGetGameTitle(const struct GB* gb, char* out) {
693	const struct GBCartridge* cart = NULL;
694	if (gb->memory.rom) {
695		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
696	}
697	if (!cart) {
698		return;
699	}
700	if (cart->oldLicensee != 0x33) {
701		memcpy(out, cart->titleLong, 16);
702	} else {
703		memcpy(out, cart->titleShort, 11);
704	}
705}
706
707void GBGetGameCode(const struct GB* gb, char* out) {
708	memset(out, 0, 8);
709	const struct GBCartridge* cart = NULL;
710	if (gb->memory.rom) {
711		cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
712	}
713	if (!cart) {
714		return;
715	}
716	if (cart->cgb == 0xC0) {
717		memcpy(out, "CGB-????", 8);
718	} else {
719		memcpy(out, "DMG-????", 8);
720	}
721	if (cart->oldLicensee == 0x33) {
722		memcpy(&out[4], cart->maker, 4);
723	}
724}
725
726void GBFrameEnded(struct GB* gb) {
727	GBSramClean(gb, gb->video.frameCounter);
728
729	if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
730		struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
731		size_t i;
732		for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
733			struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
734			mCheatRefresh(device, cheats);
735		}
736	}
737
738	GBTestKeypadIRQ(gb);
739}