all repos — mgba @ 3a8c5c4bf16e87f115aa7d960c53ba2f20cb1155

mGBA Game Boy Advance Emulator

src/gb/core.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/gb/core.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/internal/gb/cheats.h>
 10#include <mgba/internal/gb/extra/cli.h>
 11#include <mgba/internal/gb/gb.h>
 12#include <mgba/internal/gb/mbc.h>
 13#include <mgba/internal/gb/overrides.h>
 14#include <mgba/internal/gb/renderers/software.h>
 15#include <mgba/internal/gb/serialize.h>
 16#include <mgba/internal/lr35902/lr35902.h>
 17#include <mgba/internal/lr35902/debugger/debugger.h>
 18#include <mgba-util/crc32.h>
 19#include <mgba-util/memory.h>
 20#include <mgba-util/patch.h>
 21#include <mgba-util/vfs.h>
 22
 23const static struct mCoreChannelInfo _GBVideoLayers[] = {
 24	{ 0, "bg", "Background", NULL },
 25	{ 1, "obj", "Objects", NULL },
 26	{ 2, "win", "Window", NULL },
 27};
 28
 29const static struct mCoreChannelInfo _GBAudioChannels[] = {
 30	{ 0, "ch0", "Channel 0", "Square/Sweep" },
 31	{ 1, "ch1", "Channel 1", "Square" },
 32	{ 2, "ch2", "Channel 2", "PCM" },
 33	{ 3, "ch3", "Channel 3", "Noise" },
 34};
 35
 36struct GBCore {
 37	struct mCore d;
 38	struct GBVideoSoftwareRenderer renderer;
 39	uint8_t keys;
 40	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 41	const struct Configuration* overrides;
 42	struct mDebuggerPlatform* debuggerPlatform;
 43	struct mCheatDevice* cheatDevice;
 44};
 45
 46static bool _GBCoreInit(struct mCore* core) {
 47	struct GBCore* gbcore = (struct GBCore*) core;
 48
 49	struct LR35902Core* cpu = anonymousMemoryMap(sizeof(struct LR35902Core));
 50	struct GB* gb = anonymousMemoryMap(sizeof(struct GB));
 51	if (!cpu || !gb) {
 52		free(cpu);
 53		free(gb);
 54		return false;
 55	}
 56	core->cpu = cpu;
 57	core->board = gb;
 58	gbcore->overrides = NULL;
 59	gbcore->debuggerPlatform = NULL;
 60	gbcore->cheatDevice = NULL;
 61
 62	GBCreate(gb);
 63	memset(gbcore->components, 0, sizeof(gbcore->components));
 64	LR35902SetComponents(cpu, &gb->d, CPU_COMPONENT_MAX, gbcore->components);
 65	LR35902Init(cpu);
 66	mRTCGenericSourceInit(&core->rtc, core);
 67	gb->memory.rtc = &core->rtc.d;
 68
 69	GBVideoSoftwareRendererCreate(&gbcore->renderer);
 70	gbcore->renderer.outputBuffer = NULL;
 71
 72	gbcore->keys = 0;
 73	gb->keySource = &gbcore->keys;
 74
 75#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 76	mDirectorySetInit(&core->dirs);
 77#endif
 78	
 79	return true;
 80}
 81
 82static void _GBCoreDeinit(struct mCore* core) {
 83	LR35902Deinit(core->cpu);
 84	GBDestroy(core->board);
 85	mappedMemoryFree(core->cpu, sizeof(struct LR35902Core));
 86	mappedMemoryFree(core->board, sizeof(struct GB));
 87#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 88	mDirectorySetDeinit(&core->dirs);
 89#endif
 90
 91	struct GBCore* gbcore = (struct GBCore*) core;
 92	free(gbcore->debuggerPlatform);
 93	if (gbcore->cheatDevice) {
 94		mCheatDeviceDestroy(gbcore->cheatDevice);
 95	}
 96	free(gbcore->cheatDevice);
 97	mCoreConfigFreeOpts(&core->opts);
 98	free(core);
 99}
100
101static enum mPlatform _GBCorePlatform(const struct mCore* core) {
102	UNUSED(core);
103	return PLATFORM_GB;
104}
105
106static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
107	struct GB* gb = core->board;
108	gb->sync = sync;
109}
110
111static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
112	UNUSED(config);
113
114	struct GB* gb = core->board;
115	if (core->opts.mute) {
116		gb->audio.masterVolume = 0;
117	} else {
118		gb->audio.masterVolume = core->opts.volume;
119	}
120	gb->video.frameskip = core->opts.frameskip;
121
122	int color;
123	if (mCoreConfigGetIntValue(&core->config, "gb.pal[0]", &color)) {
124			GBVideoSetPalette(&gb->video, 0, color);
125	}
126	if (mCoreConfigGetIntValue(&core->config, "gb.pal[1]", &color)) {
127			GBVideoSetPalette(&gb->video, 1, color);
128	}
129	if (mCoreConfigGetIntValue(&core->config, "gb.pal[2]", &color)) {
130			GBVideoSetPalette(&gb->video, 2, color);
131	}
132	if (mCoreConfigGetIntValue(&core->config, "gb.pal[3]", &color)) {
133			GBVideoSetPalette(&gb->video, 3, color);
134	}
135
136	mCoreConfigCopyValue(&core->config, config, "gb.bios");
137	mCoreConfigCopyValue(&core->config, config, "gbc.bios");
138
139#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
140	struct GBCore* gbcore = (struct GBCore*) core;
141	gbcore->overrides = mCoreConfigGetOverridesConst(config);
142#endif
143}
144
145static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
146	UNUSED(core);
147	*width = GB_VIDEO_HORIZONTAL_PIXELS;
148	*height = GB_VIDEO_VERTICAL_PIXELS;
149}
150
151static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
152	struct GBCore* gbcore = (struct GBCore*) core;
153	gbcore->renderer.outputBuffer = buffer;
154	gbcore->renderer.outputBufferStride = stride;
155}
156
157static void _GBCoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
158	struct GBCore* gbcore = (struct GBCore*) core;
159	gbcore->renderer.d.getPixels(&gbcore->renderer.d, stride, buffer);
160}
161
162static void _GBCorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
163	struct GBCore* gbcore = (struct GBCore*) core;
164	gbcore->renderer.d.putPixels(&gbcore->renderer.d, stride, buffer);
165}
166
167static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
168	struct GB* gb = core->board;
169	switch (ch) {
170	case 0:
171		return gb->audio.left;
172	case 1:
173		return gb->audio.right;
174	default:
175		return NULL;
176	}
177}
178
179static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
180	struct GB* gb = core->board;
181	GBAudioResizeBuffer(&gb->audio, samples);
182}
183
184static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
185	struct GB* gb = core->board;
186	return gb->audio.samples;
187}
188
189static void _GBCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
190	struct GB* gb = core->board;
191	*mCoreCallbacksListAppend(&gb->coreCallbacks) = *coreCallbacks;
192}
193
194static void _GBCoreClearCoreCallbacks(struct mCore* core) {
195	struct GB* gb = core->board;
196	mCoreCallbacksListClear(&gb->coreCallbacks);
197}
198
199static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
200	struct GB* gb = core->board;
201	gb->stream = stream;
202	if (stream && stream->videoDimensionsChanged) {
203		stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
204	}
205}
206
207static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
208	return GBLoadROM(core->board, vf);
209}
210
211static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
212	UNUSED(type);
213	GBLoadBIOS(core->board, vf);
214	return true;
215}
216
217static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) {
218	return GBLoadSave(core->board, vf);
219}
220
221static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
222	struct GB* gb = core->board;
223	GBSavedataMask(gb, vf, false);
224	return true; // TODO: Return a real value
225}
226
227static bool _GBCoreLoadPatch(struct mCore* core, struct VFile* vf) {
228	if (!vf) {
229		return false;
230	}
231	struct Patch patch;
232	if (!loadPatch(vf, &patch)) {
233		return false;
234	}
235	GBApplyPatch(core->board, &patch);
236	return true;
237}
238
239static void _GBCoreUnloadROM(struct mCore* core) {
240	struct GBCore* gbcore = (struct GBCore*) core;
241	struct LR35902Core* cpu = core->cpu;
242	if (gbcore->cheatDevice) {
243		LR35902HotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
244		cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
245		mCheatDeviceDestroy(gbcore->cheatDevice);
246		gbcore->cheatDevice = NULL;
247	}
248	return GBUnloadROM(core->board);
249}
250
251static void _GBCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
252	struct GB* gb = (struct GB*) core->board;
253	switch (type) {
254	case CHECKSUM_CRC32:
255		memcpy(data, &gb->romCrc32, sizeof(gb->romCrc32));
256		break;
257	}
258	return;
259}
260
261static void _GBCoreReset(struct mCore* core) {
262	struct GBCore* gbcore = (struct GBCore*) core;
263	struct GB* gb = (struct GB*) core->board;
264	if (gbcore->renderer.outputBuffer) {
265		GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d);
266	}
267
268	if (gb->memory.rom) {
269		struct GBCartridgeOverride override;
270		const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
271		override.headerCrc32 = doCrc32(cart, sizeof(*cart));
272		if (GBOverrideFind(gbcore->overrides, &override)) {
273			GBOverrideApply(gb, &override);
274		}
275	}
276
277#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
278	if (!gb->biosVf && core->opts.useBios) {
279		struct VFile* bios = NULL;
280		bool found = false;
281		if (core->opts.bios) {
282			bios = VFileOpen(core->opts.bios, O_RDONLY);
283			if (bios && GBIsBIOS(bios)) {
284				found = true;
285			} else if (bios) {
286				bios->close(bios);
287				bios = NULL;
288			}
289		}
290		if (!found) {
291			GBDetectModel(gb);
292			const char* configPath = NULL;
293
294			switch (gb->model) {
295			case GB_MODEL_DMG:
296			case GB_MODEL_SGB: // TODO
297				configPath = mCoreConfigGetValue(&core->config, "gb.bios");
298				break;
299			case GB_MODEL_CGB:
300			case GB_MODEL_AGB:
301				configPath = mCoreConfigGetValue(&core->config, "gbc.bios");
302				break;
303			default:
304				break;
305			};
306			if (configPath) {
307				bios = VFileOpen(configPath, O_RDONLY);
308			}
309			if (bios && GBIsBIOS(bios)) {
310				found = true;
311			} else if (bios) {
312				bios->close(bios);
313				bios = NULL;
314			}
315		}
316		if (!found) {
317			char path[PATH_MAX];
318			mCoreConfigDirectory(path, PATH_MAX);
319			switch (gb->model) {
320			case GB_MODEL_DMG:
321			case GB_MODEL_SGB: // TODO
322				strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path));
323				break;
324			case GB_MODEL_CGB:
325			case GB_MODEL_AGB:
326				strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path));
327				break;
328			default:
329				break;
330			};
331			bios = VFileOpen(path, O_RDONLY);
332			if (bios && GBIsBIOS(bios)) {
333				found = true;
334			} else if (bios) {
335				bios->close(bios);
336				bios = NULL;
337			}
338		}
339		if (bios) {
340			GBLoadBIOS(gb, bios);
341		}
342	}
343#endif
344
345	LR35902Reset(core->cpu);
346}
347
348static void _GBCoreRunFrame(struct mCore* core) {
349	struct GB* gb = core->board;
350	int32_t frameCounter = gb->video.frameCounter;
351	while (gb->video.frameCounter == frameCounter) {
352		LR35902Run(core->cpu);
353	}
354}
355
356static void _GBCoreRunLoop(struct mCore* core) {
357	LR35902Run(core->cpu);
358}
359
360static void _GBCoreStep(struct mCore* core) {
361	struct LR35902Core* cpu = core->cpu;
362	do {
363		LR35902Tick(cpu);
364	} while (cpu->executionState != LR35902_CORE_FETCH);
365}
366
367static size_t _GBCoreStateSize(struct mCore* core) {
368	UNUSED(core);
369	return sizeof(struct GBSerializedState);
370}
371
372static bool _GBCoreLoadState(struct mCore* core, const void* state) {
373	return GBDeserialize(core->board, state);
374}
375
376static bool _GBCoreSaveState(struct mCore* core, void* state) {
377	struct LR35902Core* cpu = core->cpu;
378	while (cpu->executionState != LR35902_CORE_FETCH) {
379		LR35902Tick(cpu);
380	}
381	GBSerialize(core->board, state);
382	return true;
383}
384
385static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) {
386	struct GBCore* gbcore = (struct GBCore*) core;
387	gbcore->keys = keys;
388}
389
390static void _GBCoreAddKeys(struct mCore* core, uint32_t keys) {
391	struct GBCore* gbcore = (struct GBCore*) core;
392	gbcore->keys |= keys;
393}
394
395static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) {
396	struct GBCore* gbcore = (struct GBCore*) core;
397	gbcore->keys &= ~keys;
398}
399
400static int32_t _GBCoreFrameCounter(const struct mCore* core) {
401	const struct GB* gb = core->board;
402	return gb->video.frameCounter;
403}
404
405static int32_t _GBCoreFrameCycles(const  struct mCore* core) {
406	UNUSED(core);
407	return GB_VIDEO_TOTAL_LENGTH;
408}
409
410static int32_t _GBCoreFrequency(const struct mCore* core) {
411	UNUSED(core);
412	// TODO: GB differences
413	return DMG_LR35902_FREQUENCY;
414}
415
416static void _GBCoreGetGameTitle(const struct mCore* core, char* title) {
417	GBGetGameTitle(core->board, title);
418}
419
420static void _GBCoreGetGameCode(const struct mCore* core, char* title) {
421	GBGetGameCode(core->board, title);
422}
423
424static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
425	struct GB* gb = core->board;
426	switch (type) {
427	case mPERIPH_ROTATION:
428		gb->memory.rotation = periph;
429		break;
430	case mPERIPH_RUMBLE:
431		gb->memory.rumble = periph;
432		break;
433	default:
434		return;
435	}
436}
437
438static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
439	struct LR35902Core* cpu = core->cpu;
440	return cpu->memory.load8(cpu, address);
441}
442
443static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
444	struct LR35902Core* cpu = core->cpu;
445	return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
446}
447
448static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
449	struct LR35902Core* cpu = core->cpu;
450	return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
451	       (cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
452}
453
454static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
455	struct LR35902Core* cpu = core->cpu;
456	cpu->memory.store8(cpu, address, value);
457}
458
459static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
460	struct LR35902Core* cpu = core->cpu;
461	cpu->memory.store8(cpu, address, value);
462	cpu->memory.store8(cpu, address + 1, value >> 8);
463}
464
465static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
466	struct LR35902Core* cpu = core->cpu;
467	cpu->memory.store8(cpu, address, value);
468	cpu->memory.store8(cpu, address + 1, value >> 8);
469	cpu->memory.store8(cpu, address + 2, value >> 16);
470	cpu->memory.store8(cpu, address + 3, value >> 24);
471}
472
473static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
474	struct LR35902Core* cpu = core->cpu;
475	return GBView8(cpu, address, segment);
476}
477
478static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
479	struct LR35902Core* cpu = core->cpu;
480	return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8);
481}
482
483static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
484	struct LR35902Core* cpu = core->cpu;
485	return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8) |
486	       (GBView8(cpu, address + 2, segment) << 16) | (GBView8(cpu, address + 3, segment) << 24);
487}
488
489static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
490	struct LR35902Core* cpu = core->cpu;
491	GBPatch8(cpu, address, value, NULL, segment);
492}
493
494static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
495	struct LR35902Core* cpu = core->cpu;
496	GBPatch8(cpu, address, value, NULL, segment);
497	GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
498}
499
500static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
501	struct LR35902Core* cpu = core->cpu;
502	GBPatch8(cpu, address, value, NULL, segment);
503	GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
504	GBPatch8(cpu, address + 2, value >> 16, NULL, segment);
505	GBPatch8(cpu, address + 3, value >> 24, NULL, segment);
506}
507
508#ifdef USE_DEBUGGERS
509static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
510	UNUSED(core);
511	switch (type) {
512	case DEBUGGER_CLI:
513		return true;
514	default:
515		return false;
516	}
517}
518
519static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
520	struct GBCore* gbcore = (struct GBCore*) core;
521	if (!gbcore->debuggerPlatform) {
522		gbcore->debuggerPlatform = LR35902DebuggerPlatformCreate();
523	}
524	return gbcore->debuggerPlatform;
525}
526
527static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) {
528	return GBCLIDebuggerCreate(core);
529}
530
531static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
532	struct LR35902Core* cpu = core->cpu;
533	if (core->debugger) {
534		LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
535	}
536	cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
537	LR35902HotplugAttach(cpu, CPU_COMPONENT_DEBUGGER);
538	core->debugger = debugger;
539}
540
541static void _GBCoreDetachDebugger(struct mCore* core) {
542	struct LR35902Core* cpu = core->cpu;
543	if (core->debugger) {
544		LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
545	}
546	cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
547	core->debugger = NULL;
548}
549#endif
550
551static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) {
552	struct GBCore* gbcore = (struct GBCore*) core;
553	if (!gbcore->cheatDevice) {
554		gbcore->cheatDevice = GBCheatDeviceCreate();
555		((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d;
556		LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
557		gbcore->cheatDevice->p = core;
558	}
559	return gbcore->cheatDevice;
560}
561
562static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) {
563	struct GB* gb = core->board;
564	struct VFile* vf = gb->sramVf;
565	if (vf) {
566		*sram = malloc(vf->size(vf));
567		vf->seek(vf, 0, SEEK_SET);
568		return vf->read(vf, *sram, vf->size(vf));
569	}
570	*sram = malloc(gb->sramSize);
571	memcpy(*sram, gb->memory.sram, gb->sramSize);
572	return gb->sramSize;
573}
574
575static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
576	struct GB* gb = core->board;
577	if (!writeback) {
578		struct VFile* vf = VFileMemChunk(sram, size);
579		GBSavedataMask(gb, vf, true);
580		return true;
581	}
582	struct VFile* vf = gb->sramVf;
583	if (vf) {
584		vf->seek(vf, 0, SEEK_SET);
585		return vf->write(vf, sram, size) > 0;
586	}
587	if (size > 0x20000) {
588		size = 0x20000;
589	}
590	GBResizeSram(gb, size);
591	memcpy(gb->memory.sram, sram, size);
592	return true;
593}
594
595static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
596	UNUSED(core);
597	*info = _GBVideoLayers;
598	return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
599}
600
601static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
602	UNUSED(core);
603	*info = _GBAudioChannels;
604	return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
605}
606
607static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
608	struct GB* gb = core->board;
609	switch (id) {
610	case 0:
611		gb->video.renderer->disableBG = !enable;
612		break;
613	case 1:
614		gb->video.renderer->disableOBJ = !enable;
615		break;
616	case 2:
617		gb->video.renderer->disableWIN = !enable;
618		break;
619	default:
620		break;
621	}
622}
623
624static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
625	struct GB* gb = core->board;
626	switch (id) {
627	case 0:
628	case 1:
629	case 2:
630	case 3:
631		gb->audio.forceDisableCh[id] = !enable;
632		break;
633	default:
634		break;
635	}
636}
637
638struct mCore* GBCoreCreate(void) {
639	struct GBCore* gbcore = malloc(sizeof(*gbcore));
640	struct mCore* core = &gbcore->d;
641	memset(&core->opts, 0, sizeof(core->opts));
642	core->cpu = NULL;
643	core->board = NULL;
644	core->debugger = NULL;
645	core->init = _GBCoreInit;
646	core->deinit = _GBCoreDeinit;
647	core->platform = _GBCorePlatform;
648	core->setSync = _GBCoreSetSync;
649	core->loadConfig = _GBCoreLoadConfig;
650	core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
651	core->setVideoBuffer = _GBCoreSetVideoBuffer;
652	core->getPixels = _GBCoreGetPixels;
653	core->putPixels = _GBCorePutPixels;
654	core->getAudioChannel = _GBCoreGetAudioChannel;
655	core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
656	core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
657	core->setAVStream = _GBCoreSetAVStream;
658	core->addCoreCallbacks = _GBCoreAddCoreCallbacks;
659	core->clearCoreCallbacks = _GBCoreClearCoreCallbacks;
660	core->isROM = GBIsROM;
661	core->loadROM = _GBCoreLoadROM;
662	core->loadBIOS = _GBCoreLoadBIOS;
663	core->loadSave = _GBCoreLoadSave;
664	core->loadTemporarySave = _GBCoreLoadTemporarySave;
665	core->loadPatch = _GBCoreLoadPatch;
666	core->unloadROM = _GBCoreUnloadROM;
667	core->checksum = _GBCoreChecksum;
668	core->reset = _GBCoreReset;
669	core->runFrame = _GBCoreRunFrame;
670	core->runLoop = _GBCoreRunLoop;
671	core->step = _GBCoreStep;
672	core->stateSize = _GBCoreStateSize;
673	core->loadState = _GBCoreLoadState;
674	core->saveState = _GBCoreSaveState;
675	core->setKeys = _GBCoreSetKeys;
676	core->addKeys = _GBCoreAddKeys;
677	core->clearKeys = _GBCoreClearKeys;
678	core->frameCounter = _GBCoreFrameCounter;
679	core->frameCycles = _GBCoreFrameCycles;
680	core->frequency = _GBCoreFrequency;
681	core->getGameTitle = _GBCoreGetGameTitle;
682	core->getGameCode = _GBCoreGetGameCode;
683	core->setPeripheral = _GBCoreSetPeripheral;
684	core->busRead8 = _GBCoreBusRead8;
685	core->busRead16 = _GBCoreBusRead16;
686	core->busRead32 = _GBCoreBusRead32;
687	core->busWrite8 = _GBCoreBusWrite8;
688	core->busWrite16 = _GBCoreBusWrite16;
689	core->busWrite32 = _GBCoreBusWrite32;
690	core->rawRead8 = _GBCoreRawRead8;
691	core->rawRead16 = _GBCoreRawRead16;
692	core->rawRead32 = _GBCoreRawRead32;
693	core->rawWrite8 = _GBCoreRawWrite8;
694	core->rawWrite16 = _GBCoreRawWrite16;
695	core->rawWrite32 = _GBCoreRawWrite32;
696#ifdef USE_DEBUGGERS
697	core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
698	core->debuggerPlatform = _GBCoreDebuggerPlatform;
699	core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
700	core->attachDebugger = _GBCoreAttachDebugger;
701	core->detachDebugger = _GBCoreDetachDebugger;
702#endif
703	core->cheatDevice = _GBCoreCheatDevice;
704	core->savedataClone = _GBCoreSavedataClone;
705	core->savedataRestore = _GBCoreSavedataRestore;
706	core->listVideoLayers = _GBCoreListVideoLayers;
707	core->listAudioChannels = _GBCoreListAudioChannels;
708	core->enableVideoLayer = _GBCoreEnableVideoLayer;
709	core->enableAudioChannel = _GBCoreEnableAudioChannel;
710	return core;
711}