all repos — mgba @ faadb5d6a6357c59a5b70ecbdf4fa204a9c96f9a

mGBA Game Boy Advance Emulator

src/gba/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/gba/core.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/core/log.h>
 10#include <mgba/internal/arm/debugger/debugger.h>
 11#include <mgba/internal/gba/cheats.h>
 12#include <mgba/internal/gba/gba.h>
 13#include <mgba/internal/gba/extra/cli.h>
 14#include <mgba/internal/gba/overrides.h>
 15#ifndef DISABLE_THREADING
 16#include <mgba/internal/gba/renderers/thread-proxy.h>
 17#endif
 18#include <mgba/internal/gba/renderers/video-software.h>
 19#include <mgba/internal/gba/savedata.h>
 20#include <mgba/internal/gba/serialize.h>
 21#include <mgba-util/memory.h>
 22#include <mgba-util/patch.h>
 23#include <mgba-util/vfs.h>
 24
 25#ifndef MINIMAL_CORE
 26#include <mgba/internal/gba/input.h>
 27#endif
 28
 29const static struct mCoreChannelInfo _GBAVideoLayers[] = {
 30	{ 0, "bg0", "Background 0", NULL },
 31	{ 1, "bg1", "Background 1", NULL },
 32	{ 2, "bg2", "Background 2", NULL },
 33	{ 3, "bg3", "Background 3", NULL },
 34	{ 4, "obj", "Objects", NULL },
 35};
 36
 37const static struct mCoreChannelInfo _GBAAudioChannels[] = {
 38	{ 0, "ch0", "PSG Channel 0", "Square/Sweep" },
 39	{ 1, "ch1", "PSG Channel 1", "Square" },
 40	{ 2, "ch2", "PSG Channel 2", "PCM" },
 41	{ 3, "ch3", "PSG Channel 3", "Noise" },
 42	{ 4, "chA", "FIFO Channel A", NULL },
 43	{ 5, "chB", "FIFO Channel B", NULL },
 44};
 45
 46struct GBACore {
 47	struct mCore d;
 48	struct GBAVideoSoftwareRenderer renderer;
 49#ifndef DISABLE_THREADING
 50	struct GBAVideoThreadProxyRenderer threadProxy;
 51	int threadedVideo;
 52#endif
 53	int keys;
 54	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 55	const struct Configuration* overrides;
 56	struct mDebuggerPlatform* debuggerPlatform;
 57	struct mCheatDevice* cheatDevice;
 58};
 59
 60static bool _GBACoreInit(struct mCore* core) {
 61	struct GBACore* gbacore = (struct GBACore*) core;
 62
 63	struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
 64	struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
 65	if (!cpu || !gba) {
 66		free(cpu);
 67		free(gba);
 68		return false;
 69	}
 70	core->cpu = cpu;
 71	core->board = gba;
 72	core->debugger = NULL;
 73	gbacore->overrides = NULL;
 74	gbacore->debuggerPlatform = NULL;
 75	gbacore->cheatDevice = NULL;
 76
 77	GBACreate(gba);
 78	// TODO: Restore cheats
 79	memset(gbacore->components, 0, sizeof(gbacore->components));
 80	ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
 81	ARMInit(cpu);
 82	mRTCGenericSourceInit(&core->rtc, core);
 83	gba->rtcSource = &core->rtc.d;
 84
 85	GBAVideoSoftwareRendererCreate(&gbacore->renderer);
 86	gbacore->renderer.outputBuffer = NULL;
 87
 88#ifndef DISABLE_THREADING
 89	gbacore->threadedVideo = false;
 90	GBAVideoThreadProxyRendererCreate(&gbacore->threadProxy, &gbacore->renderer.d);
 91#endif
 92
 93	gbacore->keys = 0;
 94	gba->keySource = &gbacore->keys;
 95
 96#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
 97	mDirectorySetInit(&core->dirs);
 98#endif
 99
100#ifndef MINIMAL_CORE
101	core->inputInfo = &GBAInputInfo;
102#endif
103	
104	return true;
105}
106
107static void _GBACoreDeinit(struct mCore* core) {
108	ARMDeinit(core->cpu);
109	GBADestroy(core->board);
110	mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
111	mappedMemoryFree(core->board, sizeof(struct GBA));
112#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
113	mDirectorySetDeinit(&core->dirs);
114#endif
115
116	struct GBACore* gbacore = (struct GBACore*) core;
117	free(gbacore->debuggerPlatform);
118	if (gbacore->cheatDevice) {
119		mCheatDeviceDestroy(gbacore->cheatDevice);
120	}
121	free(gbacore->cheatDevice);
122	mCoreConfigFreeOpts(&core->opts);
123	free(core);
124}
125
126static enum mPlatform _GBACorePlatform(const struct mCore* core) {
127	UNUSED(core);
128	return PLATFORM_GBA;
129}
130
131static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
132	struct GBA* gba = core->board;
133	gba->sync = sync;
134}
135
136static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
137	struct GBA* gba = core->board;
138	if (core->opts.mute) {
139		gba->audio.masterVolume = 0;
140	} else {
141		gba->audio.masterVolume = core->opts.volume;
142	}
143	gba->video.frameskip = core->opts.frameskip;
144
145#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
146	struct GBACore* gbacore = (struct GBACore*) core;
147	gbacore->overrides = mCoreConfigGetOverridesConst(config);
148#endif
149
150	const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
151	if (idleOptimization) {
152		if (strcasecmp(idleOptimization, "ignore") == 0) {
153			gba->idleOptimization = IDLE_LOOP_IGNORE;
154		} else if (strcasecmp(idleOptimization, "remove") == 0) {
155			gba->idleOptimization = IDLE_LOOP_REMOVE;
156		} else if (strcasecmp(idleOptimization, "detect") == 0) {
157			if (gba->idleLoop == IDLE_LOOP_NONE) {
158				gba->idleOptimization = IDLE_LOOP_DETECT;
159			} else {
160				gba->idleOptimization = IDLE_LOOP_REMOVE;
161			}
162		}
163	}
164
165	mCoreConfigCopyValue(&core->config, config, "gba.bios");
166
167#ifndef DISABLE_THREADING
168	mCoreConfigGetIntValue(config, "threadedVideo", &gbacore->threadedVideo);
169#endif
170}
171
172static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
173	UNUSED(core);
174	*width = VIDEO_HORIZONTAL_PIXELS;
175	*height = VIDEO_VERTICAL_PIXELS;
176}
177
178static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
179	struct GBACore* gbacore = (struct GBACore*) core;
180	gbacore->renderer.outputBuffer = buffer;
181	gbacore->renderer.outputBufferStride = stride;
182}
183
184static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
185	struct GBACore* gbacore = (struct GBACore*) core;
186	gbacore->renderer.d.getPixels(&gbacore->renderer.d, stride, buffer);
187}
188
189static void _GBACorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
190	struct GBACore* gbacore = (struct GBACore*) core;
191	gbacore->renderer.d.putPixels(&gbacore->renderer.d, stride, buffer);
192}
193
194static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
195	struct GBA* gba = core->board;
196	switch (ch) {
197	case 0:
198		return gba->audio.psg.left;
199	case 1:
200		return gba->audio.psg.right;
201	default:
202		return NULL;
203	}
204}
205
206static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
207	struct GBA* gba = core->board;
208	GBAAudioResizeBuffer(&gba->audio, samples);
209}
210
211static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
212	struct GBA* gba = core->board;
213	return gba->audio.samples;
214}
215
216static void _GBACoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
217	struct GBA* gba = core->board;
218	*mCoreCallbacksListAppend(&gba->coreCallbacks) = *coreCallbacks;
219}
220
221static void _GBACoreClearCoreCallbacks(struct mCore* core) {
222	struct GBA* gba = core->board;
223	mCoreCallbacksListClear(&gba->coreCallbacks);
224}
225
226static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
227	struct GBA* gba = core->board;
228	gba->stream = stream;
229	if (stream && stream->videoDimensionsChanged) {
230		stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
231	}
232	if (stream && stream->videoFrameRateChanged) {
233		stream->videoFrameRateChanged(stream, core->frameCycles(core), core->frequency(core));
234	}
235}
236
237static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
238	if (GBAIsMB(vf)) {
239		return GBALoadMB(core->board, vf);
240	}
241	return GBALoadROM(core->board, vf);
242}
243
244static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
245	UNUSED(type);
246	if (!GBAIsBIOS(vf)) {
247		return false;
248	}
249	GBALoadBIOS(core->board, vf);
250	return true;
251}
252
253static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
254	return GBALoadSave(core->board, vf);
255}
256
257static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
258	struct GBA* gba = core->board;
259	GBASavedataMask(&gba->memory.savedata, vf, false);
260	return true; // TODO: Return a real value
261}
262
263static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
264	if (!vf) {
265		return false;
266	}
267	struct Patch patch;
268	if (!loadPatch(vf, &patch)) {
269		return false;
270	}
271	GBAApplyPatch(core->board, &patch);
272	return true;
273}
274
275static void _GBACoreUnloadROM(struct mCore* core) {
276	struct GBACore* gbacore = (struct GBACore*) core;
277	struct ARMCore* cpu = core->cpu;
278	if (gbacore->cheatDevice) {
279		ARMHotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
280		cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
281		mCheatDeviceDestroy(gbacore->cheatDevice);
282		gbacore->cheatDevice = NULL;
283	}
284	return GBAUnloadROM(core->board);
285}
286
287static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
288	struct GBA* gba = (struct GBA*) core->board;
289	switch (type) {
290	case CHECKSUM_CRC32:
291		memcpy(data, &gba->romCrc32, sizeof(gba->romCrc32));
292		break;
293	}
294	return;
295}
296
297static void _GBACoreReset(struct mCore* core) {
298	struct GBACore* gbacore = (struct GBACore*) core;
299	struct GBA* gba = (struct GBA*) core->board;
300	if (gbacore->renderer.outputBuffer) {
301		struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
302#ifndef DISABLE_THREADING
303		if (gbacore->threadedVideo) {
304			renderer = &gbacore->threadProxy.d;
305		}
306#endif
307		GBAVideoAssociateRenderer(&gba->video, renderer);
308	}
309
310	struct GBACartridgeOverride override;
311	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
312	if (cart) {
313		memcpy(override.id, &cart->id, sizeof(override.id));
314		if (GBAOverrideFind(gbacore->overrides, &override)) {
315			GBAOverrideApply(gba, &override);
316		}
317	}
318
319#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
320	if (!gba->biosVf && core->opts.useBios) {
321		struct VFile* bios = NULL;
322		bool found = false;
323		if (core->opts.bios) {
324			bios = VFileOpen(core->opts.bios, O_RDONLY);
325			if (bios && GBAIsBIOS(bios)) {
326				found = true;
327			} else if (bios) {
328				bios->close(bios);
329				bios = NULL;
330			}
331		}
332		if (!found) {
333			const char* configPath = mCoreConfigGetValue(&core->config, "gba.bios");
334			if (configPath) {
335				bios = VFileOpen(configPath, O_RDONLY);
336			}
337			if (bios && GBAIsBIOS(bios)) {
338				found = true;
339			} else if (bios) {
340				bios->close(bios);
341				bios = NULL;
342			}
343		}
344		if (!found) {
345			char path[PATH_MAX];
346			mCoreConfigDirectory(path, PATH_MAX);
347			strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path));
348			bios = VFileOpen(path, O_RDONLY);
349			if (bios && GBIsBIOS(bios)) {
350				found = true;
351			} else if (bios) {
352				bios->close(bios);
353				bios = NULL;
354			}
355		}
356		if (bios) {
357			GBALoadBIOS(gba, bios);
358		}
359	}
360#endif
361
362	ARMReset(core->cpu);
363	if (core->opts.skipBios && gba->isPristine) {
364		GBASkipBIOS(core->board);
365	}
366}
367
368static void _GBACoreRunFrame(struct mCore* core) {
369	struct GBA* gba = core->board;
370	int32_t frameCounter = gba->video.frameCounter;
371	while (gba->video.frameCounter == frameCounter) {
372		ARMv4RunLoop(core->cpu);
373	}
374}
375
376static void _GBACoreRunLoop(struct mCore* core) {
377	ARMv4RunLoop(core->cpu);
378}
379
380static void _GBACoreStep(struct mCore* core) {
381	ARMv4Run(core->cpu);
382}
383
384static size_t _GBACoreStateSize(struct mCore* core) {
385	UNUSED(core);
386	return sizeof(struct GBASerializedState);
387}
388
389static bool _GBACoreLoadState(struct mCore* core, const void* state) {
390	return GBADeserialize(core->board, state);
391}
392
393static bool _GBACoreSaveState(struct mCore* core, void* state) {
394	GBASerialize(core->board, state);
395	return true;
396}
397
398static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
399	struct GBACore* gbacore = (struct GBACore*) core;
400	gbacore->keys = keys;
401}
402
403static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
404	struct GBACore* gbacore = (struct GBACore*) core;
405	gbacore->keys |= keys;
406}
407
408static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
409	struct GBACore* gbacore = (struct GBACore*) core;
410	gbacore->keys &= ~keys;
411}
412
413static void _GBACoreSetCursorLocation(struct mCore* core, int x, int y) {
414	UNUSED(core);
415	UNUSED(x);
416	UNUSED(y);
417}
418
419static void _GBACoreSetCursorDown(struct mCore* core, bool down) {
420	UNUSED(core);
421	UNUSED(down);
422}
423
424static int32_t _GBACoreFrameCounter(const struct mCore* core) {
425	const struct GBA* gba = core->board;
426	return gba->video.frameCounter;
427}
428
429static int32_t _GBACoreFrameCycles(const struct mCore* core) {
430	UNUSED(core);
431	return VIDEO_TOTAL_LENGTH;
432}
433
434static int32_t _GBACoreFrequency(const struct mCore* core) {
435	UNUSED(core);
436	return GBA_ARM7TDMI_FREQUENCY;
437}
438
439static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
440	GBAGetGameTitle(core->board, title);
441}
442
443static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
444	GBAGetGameCode(core->board, title);
445}
446
447static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) {
448	struct GBA* gba = core->board;
449	switch (type) {
450	case mPERIPH_ROTATION:
451		gba->rotationSource = periph;
452		break;
453	case mPERIPH_RUMBLE:
454		gba->rumble = periph;
455		break;
456	case mPERIPH_GBA_LUMINANCE:
457		gba->luminanceSource = periph;
458		break;
459	default:
460		return;
461	}
462}
463
464static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
465	struct ARMCore* cpu = core->cpu;
466	return cpu->memory.load8(cpu, address, 0);
467}
468
469static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
470	struct ARMCore* cpu = core->cpu;
471	return cpu->memory.load16(cpu, address, 0);
472
473}
474
475static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
476	struct ARMCore* cpu = core->cpu;
477	return cpu->memory.load32(cpu, address, 0);
478}
479
480static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
481	struct ARMCore* cpu = core->cpu;
482	cpu->memory.store8(cpu, address, value, 0);
483}
484
485static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
486	struct ARMCore* cpu = core->cpu;
487	cpu->memory.store16(cpu, address, value, 0);
488}
489
490static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
491	struct ARMCore* cpu = core->cpu;
492	cpu->memory.store32(cpu, address, value, 0);
493}
494
495static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) {
496	UNUSED(segment);
497	struct ARMCore* cpu = core->cpu;
498	return GBAView8(cpu, address);
499}
500
501static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) {
502	UNUSED(segment);
503	struct ARMCore* cpu = core->cpu;
504	return GBAView16(cpu, address);
505}
506
507static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) {
508	UNUSED(segment);
509	struct ARMCore* cpu = core->cpu;
510	return GBAView32(cpu, address);
511}
512
513static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
514	UNUSED(segment);
515	struct ARMCore* cpu = core->cpu;
516	GBAPatch8(cpu, address, value, NULL);
517}
518
519static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
520	UNUSED(segment);
521	struct ARMCore* cpu = core->cpu;
522	GBAPatch16(cpu, address, value, NULL);
523}
524
525static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
526	UNUSED(segment);
527	struct ARMCore* cpu = core->cpu;
528	GBAPatch32(cpu, address, value, NULL);
529}
530
531#ifdef USE_DEBUGGERS
532static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
533	UNUSED(core);
534	switch (type) {
535	case DEBUGGER_CLI:
536		return true;
537#ifdef USE_GDB_STUB
538	case DEBUGGER_GDB:
539		return true;
540#endif
541	default:
542		return false;
543	}
544}
545
546static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
547	struct GBACore* gbacore = (struct GBACore*) core;
548	if (!gbacore->debuggerPlatform) {
549		gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
550	}
551	return gbacore->debuggerPlatform;
552}
553
554static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
555	return &GBACLIDebuggerCreate(core)->d;
556}
557
558static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
559	if (core->debugger) {
560		GBADetachDebugger(core->board);
561	}
562	GBAAttachDebugger(core->board, debugger);
563	core->debugger = debugger;
564}
565
566static void _GBACoreDetachDebugger(struct mCore* core) {
567	GBADetachDebugger(core->board);
568	core->debugger = NULL;
569}
570#endif
571
572static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
573	struct GBACore* gbacore = (struct GBACore*) core;
574	if (!gbacore->cheatDevice) {
575		gbacore->cheatDevice = GBACheatDeviceCreate();
576		((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
577		ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
578		gbacore->cheatDevice->p = core;
579	}
580	return gbacore->cheatDevice;
581}
582
583static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
584	struct GBA* gba = core->board;
585	size_t size = GBASavedataSize(&gba->memory.savedata);
586	if (!size) {
587		*sram = NULL;
588		return 0;
589	}
590	*sram = malloc(size);
591	struct VFile* vf = VFileFromMemory(*sram, size);
592	if (!vf) {
593		free(*sram);
594		*sram = NULL;
595		return 0;
596	}
597	bool success = GBASavedataClone(&gba->memory.savedata, vf);
598	vf->close(vf);
599	if (!success) {
600		free(*sram);
601		*sram = NULL;
602		return 0;
603	}
604	return size;
605}
606
607static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
608	struct VFile* vf = VFileMemChunk(sram, size);
609	if (!vf) {
610		return false;
611	}
612	struct GBA* gba = core->board;
613	bool success = true;
614	if (writeback) {
615		success = GBASavedataLoad(&gba->memory.savedata, vf);
616		vf->close(vf);
617	} else {
618		GBASavedataMask(&gba->memory.savedata, vf, true);
619	}
620	return success;
621}
622
623static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
624	UNUSED(core);
625	*info = _GBAVideoLayers;
626	return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
627}
628
629static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
630	UNUSED(core);
631	*info = _GBAAudioChannels;
632	return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
633}
634
635static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
636	struct GBA* gba = core->board;
637	switch (id) {
638	case 0:
639	case 1:
640	case 2:
641	case 3:
642		gba->video.renderer->disableBG[id] = !enable;
643		break;
644	case 4:
645		gba->video.renderer->disableOBJ = !enable;
646		break;
647	default:
648		break;
649	}
650}
651
652static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
653	struct GBA* gba = core->board;
654	switch (id) {
655	case 0:
656	case 1:
657	case 2:
658	case 3:
659		gba->audio.psg.forceDisableCh[id] = !enable;
660		break;
661	case 4:
662		gba->audio.forceDisableChA = !enable;
663	case 5:
664		gba->audio.forceDisableChB = !enable;
665		break;
666	default:
667		break;
668	}
669}
670
671struct mCore* GBACoreCreate(void) {
672	struct GBACore* gbacore = malloc(sizeof(*gbacore));
673	struct mCore* core = &gbacore->d;
674	memset(&core->opts, 0, sizeof(core->opts));
675	core->cpu = NULL;
676	core->board = NULL;
677	core->debugger = NULL;
678	core->init = _GBACoreInit;
679	core->deinit = _GBACoreDeinit;
680	core->platform = _GBACorePlatform;
681	core->setSync = _GBACoreSetSync;
682	core->loadConfig = _GBACoreLoadConfig;
683	core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
684	core->setVideoBuffer = _GBACoreSetVideoBuffer;
685	core->getPixels = _GBACoreGetPixels;
686	core->putPixels = _GBACorePutPixels;
687	core->getAudioChannel = _GBACoreGetAudioChannel;
688	core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
689	core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
690	core->addCoreCallbacks = _GBACoreAddCoreCallbacks;
691	core->clearCoreCallbacks = _GBACoreClearCoreCallbacks;
692	core->setAVStream = _GBACoreSetAVStream;
693	core->isROM = GBAIsROM;
694	core->loadROM = _GBACoreLoadROM;
695	core->loadBIOS = _GBACoreLoadBIOS;
696	core->loadSave = _GBACoreLoadSave;
697	core->loadTemporarySave = _GBACoreLoadTemporarySave;
698	core->loadPatch = _GBACoreLoadPatch;
699	core->unloadROM = _GBACoreUnloadROM;
700	core->checksum = _GBACoreChecksum;
701	core->reset = _GBACoreReset;
702	core->runFrame = _GBACoreRunFrame;
703	core->runLoop = _GBACoreRunLoop;
704	core->step = _GBACoreStep;
705	core->stateSize = _GBACoreStateSize;
706	core->loadState = _GBACoreLoadState;
707	core->saveState = _GBACoreSaveState;
708	core->setKeys = _GBACoreSetKeys;
709	core->addKeys = _GBACoreAddKeys;
710	core->clearKeys = _GBACoreClearKeys;
711	core->setCursorLocation = _GBACoreSetCursorLocation;
712	core->setCursorDown = _GBACoreSetCursorDown;
713	core->frameCounter = _GBACoreFrameCounter;
714	core->frameCycles = _GBACoreFrameCycles;
715	core->frequency = _GBACoreFrequency;
716	core->getGameTitle = _GBACoreGetGameTitle;
717	core->getGameCode = _GBACoreGetGameCode;
718	core->setPeripheral = _GBACoreSetPeripheral;
719	core->busRead8 = _GBACoreBusRead8;
720	core->busRead16 = _GBACoreBusRead16;
721	core->busRead32 = _GBACoreBusRead32;
722	core->busWrite8 = _GBACoreBusWrite8;
723	core->busWrite16 = _GBACoreBusWrite16;
724	core->busWrite32 = _GBACoreBusWrite32;
725	core->rawRead8 = _GBACoreRawRead8;
726	core->rawRead16 = _GBACoreRawRead16;
727	core->rawRead32 = _GBACoreRawRead32;
728	core->rawWrite8 = _GBACoreRawWrite8;
729	core->rawWrite16 = _GBACoreRawWrite16;
730	core->rawWrite32 = _GBACoreRawWrite32;
731#ifdef USE_DEBUGGERS
732	core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
733	core->debuggerPlatform = _GBACoreDebuggerPlatform;
734	core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
735	core->attachDebugger = _GBACoreAttachDebugger;
736	core->detachDebugger = _GBACoreDetachDebugger;
737#endif
738	core->cheatDevice = _GBACoreCheatDevice;
739	core->savedataClone = _GBACoreSavedataClone;
740	core->savedataRestore = _GBACoreSavedataRestore;
741	core->listVideoLayers = _GBACoreListVideoLayers;
742	core->listAudioChannels = _GBACoreListAudioChannels;
743	core->enableVideoLayer = _GBACoreEnableVideoLayer;
744	core->enableAudioChannel = _GBACoreEnableAudioChannel;
745	return core;
746}