all repos — mgba @ f03389bfca8e6ec52815ae2d9941ec7f0a9e691c

mGBA Game Boy Advance Emulator

src/ds/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/ds/core.h>
  7
  8#include <mgba/core/cheats.h>
  9#include <mgba/core/core.h>
 10#include <mgba/core/log.h>
 11#include <mgba/internal/arm/debugger/debugger.h>
 12#include <mgba/internal/debugger/symbols.h>
 13#include <mgba/internal/ds/ds.h>
 14#include <mgba/internal/ds/extra/cli.h>
 15#include <mgba/internal/ds/gx/software.h>
 16#include <mgba/internal/ds/input.h>
 17#include <mgba/internal/ds/renderers/software.h>
 18#include <mgba-util/elf-read.h>
 19#include <mgba-util/memory.h>
 20#include <mgba-util/patch.h>
 21#include <mgba-util/vfs.h>
 22
 23const static struct mCoreChannelInfo _DSVideoLayers[] = {
 24	{ 0, "abg0", "A BG0", "2D/3D" },
 25	{ 1, "abg1", "A BG1", NULL },
 26	{ 2, "abg2", "A BG2", NULL },
 27	{ 3, "abg3", "A BG3", NULL },
 28	{ 4, "aobj", "A OBJ", NULL },
 29	{ 10, "bbg0", "B BG0", "2D/3D" },
 30	{ 11, "bbg1", "B BG1", NULL },
 31	{ 12, "bbg2", "B BG2", NULL },
 32	{ 13, "bbg3", "B BG3", NULL },
 33	{ 14, "bobj", "B OBJ", NULL },
 34};
 35
 36const static struct mCoreChannelInfo _DSAudioChannels[] = {
 37	{ 0, "ch00", "Channel 0", NULL },
 38	{ 1, "ch01", "Channel 1", NULL },
 39	{ 2, "ch02", "Channel 2", NULL },
 40	{ 3, "ch03", "Channel 3", NULL },
 41	{ 4, "ch04", "Channel 4", NULL },
 42	{ 5, "ch05", "Channel 5", NULL },
 43	{ 6, "ch06", "Channel 6", NULL },
 44	{ 7, "ch07", "Channel 7", NULL },
 45	{ 8, "ch08", "Channel 8", NULL },
 46	{ 9, "ch09", "Channel 9", NULL },
 47	{ 10, "ch10", "Channel 10", NULL },
 48	{ 11, "ch11", "Channel 11", NULL },
 49	{ 12, "ch12", "Channel 12", NULL },
 50	{ 13, "ch13", "Channel 13", NULL },
 51	{ 14, "ch14", "Channel 14", NULL },
 52	{ 15, "ch15", "Channel 15", NULL },
 53};
 54
 55struct DSCore {
 56	struct mCore d;
 57	struct ARMCore* arm7;
 58	struct ARMCore* arm9;
 59	struct DSVideoSoftwareRenderer renderer;
 60	struct DSGXSoftwareRenderer gxRenderer;
 61	int keys;
 62	int cursorX;
 63	int cursorY;
 64	bool touchDown;
 65	struct mCPUComponent* components[CPU_COMPONENT_MAX];
 66	struct mDebuggerPlatform* debuggerPlatform;
 67	struct mCheatDevice* cheatDevice;
 68};
 69
 70static bool _DSCoreInit(struct mCore* core) {
 71	struct DSCore* dscore = (struct DSCore*) core;
 72
 73	struct ARMCore* arm7 = anonymousMemoryMap(sizeof(struct ARMCore));
 74	struct ARMCore* arm9 = anonymousMemoryMap(sizeof(struct ARMCore));
 75	struct DS* ds = anonymousMemoryMap(sizeof(struct DS));
 76	if (!arm7 || !arm9 || !ds) {
 77		free(arm7);
 78		free(arm9);
 79		free(ds);
 80		return false;
 81	}
 82	core->cpu = arm9;
 83	core->board = ds;
 84	core->debugger = NULL;
 85	dscore->arm7 = arm7;
 86	dscore->arm9 = arm9;
 87	dscore->debuggerPlatform = NULL;
 88	dscore->cheatDevice = NULL;
 89
 90	DSCreate(ds);
 91	memset(dscore->components, 0, sizeof(dscore->components));
 92	ARMSetComponents(arm7, &ds->d, CPU_COMPONENT_MAX, dscore->components);
 93	ARMSetComponents(arm9, &ds->d, CPU_COMPONENT_MAX, dscore->components);
 94	ARMInit(arm7);
 95	ARMInit(arm9);
 96
 97	DSVideoSoftwareRendererCreate(&dscore->renderer);
 98	DSGXSoftwareRendererCreate(&dscore->gxRenderer);
 99	dscore->renderer.outputBuffer = NULL;
100
101	dscore->keys = 0;
102	ds->keySource = &dscore->keys;
103	dscore->cursorX = 0;
104	ds->cursorSourceX = &dscore->cursorX;
105	dscore->cursorY = 0;
106	ds->cursorSourceY = &dscore->cursorY;
107	dscore->touchDown = false;
108	ds->touchSource = &dscore->touchDown;
109
110#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
111	mDirectorySetInit(&core->dirs);
112#endif
113
114#ifndef MINIMAL_CORE
115	core->inputInfo = &DSInputInfo; // TODO: GBInputInfo
116#endif
117
118	return true;
119}
120
121static void _DSCoreDeinit(struct mCore* core) {
122	struct DSCore* dscore = (struct DSCore*) core;
123	ARMDeinit(dscore->arm7);
124	ARMDeinit(dscore->arm9);
125	DSDestroy(core->board);
126	mappedMemoryFree(dscore->arm7, sizeof(struct ARMCore));
127	mappedMemoryFree(dscore->arm9, sizeof(struct ARMCore));
128	mappedMemoryFree(core->board, sizeof(struct DS));
129#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
130	mDirectorySetDeinit(&core->dirs);
131#endif
132
133	free(dscore->debuggerPlatform);
134	if (dscore->cheatDevice) {
135		mCheatDeviceDestroy(dscore->cheatDevice);
136	}
137	free(dscore->cheatDevice);
138	free(core);
139}
140
141static enum mPlatform _DSCorePlatform(const struct mCore* core) {
142	UNUSED(core);
143	return PLATFORM_DS;
144}
145
146static bool _DSCoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) {
147	UNUSED(core);
148	switch (feature) {
149	case mCORE_FEATURE_OPENGL:
150		return false;
151	default:
152		return false;
153	}
154}
155
156static void _DSCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
157	struct DS* ds = core->board;
158	ds->sync = sync;
159}
160
161static void _DSCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
162	struct DS* ds = core->board;
163	struct VFile* bios = NULL;
164
165	mCoreConfigCopyValue(&core->config, config, "ds.bios7");
166	mCoreConfigCopyValue(&core->config, config, "ds.bios9");
167	mCoreConfigCopyValue(&core->config, config, "ds.firmware");
168}
169
170
171static void _DSCoreReloadConfigOption(struct mCore* core, const char* option, const struct mCoreConfig* config) {
172	struct DS* ds = core->board;
173	if (!config) {
174		config = &core->config;
175	}
176
177	if (!option) {
178		// Reload options from opts
179		if (core->opts.mute) {
180			ds->audio.masterVolume = 0;
181		} else {
182			ds->audio.masterVolume = core->opts.volume;
183		}
184		ds->video.frameskip = core->opts.frameskip;
185		return;
186	}
187
188	int fakeBool;
189	if (strcmp("mute", option) == 0) {
190		if (mCoreConfigGetIntValue(config, "mute", &fakeBool)) {
191			core->opts.mute = fakeBool;
192
193			if (core->opts.mute) {
194				ds->audio.masterVolume = 0;
195			} else {
196				ds->audio.masterVolume = core->opts.volume;
197			}
198		}
199		return;
200	}
201	if (strcmp("volume", option) == 0) {
202		if (mCoreConfigGetIntValue(config, "volume", &core->opts.volume) && !core->opts.mute) {
203			ds->audio.masterVolume = core->opts.volume;
204		}
205		return;
206	}
207	if (strcmp("frameskip", option) == 0) {
208		if (mCoreConfigGetIntValue(config, "frameskip", &core->opts.frameskip)) {
209			ds->video.frameskip = core->opts.frameskip;
210		}
211		return;
212	}
213}
214
215static void _DSCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
216	UNUSED(core);
217	*width = DS_VIDEO_HORIZONTAL_PIXELS;
218	*height = DS_VIDEO_VERTICAL_PIXELS * 2;
219}
220
221static void _DSCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
222	struct DSCore* dscore = (struct DSCore*) core;
223	dscore->renderer.outputBuffer = buffer;
224	dscore->renderer.outputBufferStride = stride;
225}
226
227static void _DSCoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
228	struct DSCore* dscore = (struct DSCore*) core;
229	dscore->renderer.d.getPixels(&dscore->renderer.d, stride, buffer);
230}
231
232static void _DSCorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
233	struct DSCore* dscore = (struct DSCore*) core;
234	dscore->renderer.d.putPixels(&dscore->renderer.d, stride, buffer);
235}
236
237static struct blip_t* _DSCoreGetAudioChannel(struct mCore* core, int ch) {
238	struct DS* ds = core->board;
239	switch (ch) {
240	case 0:
241		return ds->audio.left;
242	case 1:
243		return ds->audio.right;
244	default:
245		return NULL;
246	}
247}
248
249static void _DSCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
250	struct DS* ds = core->board;
251	DSAudioResizeBuffer(&ds->audio, samples);
252}
253
254static size_t _DSCoreGetAudioBufferSize(struct mCore* core) {
255	struct DS* ds = core->board;
256	return ds->audio.samples;
257}
258
259static void _DSCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
260	struct DS* ds = core->board;
261	*mCoreCallbacksListAppend(&ds->coreCallbacks) = *coreCallbacks;
262}
263
264static void _DSCoreClearCoreCallbacks(struct mCore* core) {
265	struct DS* ds = core->board;
266	mCoreCallbacksListClear(&ds->coreCallbacks);
267}
268
269static void _DSCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
270	struct DS* ds = core->board;
271	ds->stream = stream;
272	if (stream && stream->videoDimensionsChanged) {
273		stream->videoDimensionsChanged(stream, DS_VIDEO_HORIZONTAL_PIXELS, DS_VIDEO_VERTICAL_PIXELS * 2);
274	}
275	if (stream && stream->videoFrameRateChanged) {
276		stream->videoFrameRateChanged(stream, core->frameCycles(core), core->frequency(core));
277	}
278}
279
280static bool _DSCoreLoadROM(struct mCore* core, struct VFile* vf) {
281	return DSLoadROM(core->board, vf);
282}
283
284static bool _DSCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
285	UNUSED(type);
286	return DSLoadBIOS(core->board, vf);
287}
288
289static bool _DSCoreLoadSave(struct mCore* core, struct VFile* vf) {
290	return DSLoadSave(core->board, vf);
291}
292
293static bool _DSCoreLoadPatch(struct mCore* core, struct VFile* vf) {
294	return false;
295}
296
297static void _DSCoreUnloadROM(struct mCore* core) {
298	return DSUnloadROM(core->board);
299}
300
301static void _DSCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
302}
303
304static void _DSCoreReset(struct mCore* core) {
305	struct DSCore* dscore = (struct DSCore*) core;
306	struct DS* ds = (struct DS*) core->board;
307
308	if (dscore->renderer.outputBuffer) {
309		struct DSVideoRenderer* renderer = &dscore->renderer.d;
310		DSVideoAssociateRenderer(&ds->video, renderer);
311
312		struct DSGXRenderer* gxRenderer = &dscore->gxRenderer.d;
313		DSGXAssociateRenderer(&ds->gx, gxRenderer);
314	}
315
316#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
317	struct VFile* bios7 = NULL;
318	struct VFile* bios9 = NULL;
319	struct VFile* firm = NULL;
320	if (core->opts.useBios) {
321		bool found7 = false;
322		bool found9 = false;
323		bool foundFirm = false;
324
325		if (!found7) {
326			const char* configPath = mCoreConfigGetValue(&core->config, "ds.bios7");
327			bios7 = VFileOpen(configPath, O_RDONLY);
328			if (bios7 && DSIsBIOS7(bios7)) {
329				found7 = true;
330			} else if (bios7) {
331				bios7->close(bios7);
332				bios7 = NULL;
333			}
334		}
335
336		if (!found9) {
337			const char* configPath = mCoreConfigGetValue(&core->config, "ds.bios9");
338			bios9 = VFileOpen(configPath, O_RDONLY);
339			if (bios9 && DSIsBIOS9(bios9)) {
340				found9 = true;
341			} else if (bios9) {
342				bios9->close(bios9);
343				bios9 = NULL;
344			}
345		}
346
347		if (!foundFirm) {
348			const char* configPath = mCoreConfigGetValue(&core->config, "ds.firmware");
349			firm = VFileOpen(configPath, O_RDONLY);
350			if (firm && DSIsFirmware(firm)) {
351				foundFirm = true;
352			} else if (firm) {
353				firm->close(firm);
354				firm = NULL;
355			}
356		}
357
358		if (!found7) {
359			char path[PATH_MAX];
360			mCoreConfigDirectory(path, PATH_MAX);
361			strncat(path, PATH_SEP "ds7_bios.bin", PATH_MAX - strlen(path));
362			bios7 = VFileOpen(path, O_RDONLY);
363		}
364
365		if (!found9) {
366			char path[PATH_MAX];
367			mCoreConfigDirectory(path, PATH_MAX);
368			strncat(path, PATH_SEP "ds9_bios.bin", PATH_MAX - strlen(path));
369			bios9 = VFileOpen(path, O_RDONLY);
370		}
371
372		if (!foundFirm) {
373			char path[PATH_MAX];
374			mCoreConfigDirectory(path, PATH_MAX);
375			strncat(path, PATH_SEP "ds_firmware.bin", PATH_MAX - strlen(path));
376			firm = VFileOpen(path, O_RDWR);
377		}
378	}
379	if (bios7) {
380		DSLoadBIOS(ds, bios7);
381	}
382	if (bios9) {
383		DSLoadBIOS(ds, bios9);
384	}
385	if (firm) {
386		DSLoadFirmware(ds, firm);
387	}
388#endif
389
390	ARMReset(ds->ds7.cpu);
391	ARMReset(ds->ds9.cpu);
392}
393
394static void _DSCoreRunFrame(struct mCore* core) {
395	struct DSCore* dscore = (struct DSCore*) core;
396	struct DS* ds = core->board;
397	int32_t frameCounter = ds->video.frameCounter;
398	while (ds->video.frameCounter == frameCounter) {
399		DSRunLoop(core->board);
400	}
401}
402
403static void _DSCoreRunLoop(struct mCore* core) {
404	DSRunLoop(core->board);
405}
406
407static void _DSCoreStep(struct mCore* core) {
408	struct DSCore* dscore = (struct DSCore*) core;
409	if (core->cpu == dscore->arm9) {
410		DS9Step(core->board);
411	} else {
412		DS7Step(core->board);
413	}
414}
415
416static size_t _DSCoreStateSize(struct mCore* core) {
417	UNUSED(core);
418	return 0;
419}
420
421static bool _DSCoreLoadState(struct mCore* core, const void* state) {
422	return false;
423}
424
425static bool _DSCoreSaveState(struct mCore* core, void* state) {
426	return false;
427}
428
429static void _DSCoreSetKeys(struct mCore* core, uint32_t keys) {
430	struct DSCore* dscore = (struct DSCore*) core;
431	dscore->keys = keys;
432}
433
434static void _DSCoreAddKeys(struct mCore* core, uint32_t keys) {
435	struct DSCore* dscore = (struct DSCore*) core;
436	dscore->keys |= keys;
437}
438
439static void _DSCoreClearKeys(struct mCore* core, uint32_t keys) {
440	struct DSCore* dscore = (struct DSCore*) core;
441	dscore->keys &= ~keys;
442}
443
444static void _DSCoreSetCursorLocation(struct mCore* core, int x, int y) {
445	struct DSCore* dscore = (struct DSCore*) core;
446	dscore->cursorX = x;
447	dscore->cursorY = y - DS_VIDEO_VERTICAL_PIXELS;
448	if (dscore->cursorY < 0) {
449		dscore->cursorY = 0;
450	} else if (dscore->cursorY >= DS_VIDEO_VERTICAL_PIXELS) {
451		dscore->cursorY = DS_VIDEO_VERTICAL_PIXELS - 1;
452	}
453	if (dscore->cursorX < 0) {
454		dscore->cursorX = 0;
455	} else if (dscore->cursorX >= DS_VIDEO_HORIZONTAL_PIXELS) {
456		dscore->cursorX = DS_VIDEO_HORIZONTAL_PIXELS - 1;
457	}
458}
459
460static void _DSCoreSetCursorDown(struct mCore* core, bool down) {
461	struct DSCore* dscore = (struct DSCore*) core;
462	dscore->touchDown = down;
463}
464
465static int32_t _DSCoreFrameCounter(const struct mCore* core) {
466	struct DS* ds = core->board;
467	return ds->video.frameCounter;
468}
469
470static int32_t _DSCoreFrameCycles(const struct mCore* core) {
471	UNUSED(core);
472	return DS_VIDEO_TOTAL_LENGTH * 2;
473}
474
475static int32_t _DSCoreFrequency(const struct mCore* core) {
476	UNUSED(core);
477	return DS_ARM946ES_FREQUENCY;
478}
479
480static void _DSCoreGetGameTitle(const struct mCore* core, char* title) {
481	DSGetGameTitle(core->board, title);
482}
483
484static void _DSCoreGetGameCode(const struct mCore* core, char* title) {
485	DSGetGameCode(core->board, title);
486}
487
488static void _DSCoreSetPeripheral(struct mCore* core, int type, void* periph) {
489	struct DS* ds = core->board;
490	switch (type) {
491	case mPERIPH_RUMBLE:
492		ds->rumble = periph;
493		break;
494	default:
495		break;
496	}
497}
498
499static uint32_t _DSCoreBusRead8(struct mCore* core, uint32_t address) {
500	struct ARMCore* cpu = core->cpu;
501	return cpu->memory.load8(cpu, address, 0);
502}
503
504static uint32_t _DSCoreBusRead16(struct mCore* core, uint32_t address) {
505	struct ARMCore* cpu = core->cpu;
506	return cpu->memory.load16(cpu, address, 0);
507
508}
509
510static uint32_t _DSCoreBusRead32(struct mCore* core, uint32_t address) {
511	struct ARMCore* cpu = core->cpu;
512	return cpu->memory.load32(cpu, address, 0);
513}
514
515static void _DSCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
516	struct ARMCore* cpu = core->cpu;
517	cpu->memory.store8(cpu, address, value, 0);
518}
519
520static void _DSCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
521	struct ARMCore* cpu = core->cpu;
522	cpu->memory.store16(cpu, address, value, 0);
523}
524
525static void _DSCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
526	struct ARMCore* cpu = core->cpu;
527	cpu->memory.store32(cpu, address, value, 0);
528}
529
530static uint32_t _DSCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
531	// TODO: Raw
532	struct ARMCore* cpu = core->cpu;
533	return cpu->memory.load8(cpu, address, 0);
534}
535
536static uint32_t _DSCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
537	// TODO: Raw
538	struct ARMCore* cpu = core->cpu;
539	return cpu->memory.load16(cpu, address, 0);
540}
541
542static uint32_t _DSCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
543	// TODO: Raw
544	struct ARMCore* cpu = core->cpu;
545	return cpu->memory.load32(cpu, address, 0);
546}
547
548static void _DSCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
549}
550
551static void _DSCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
552}
553
554static void _DSCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
555}
556
557#ifdef USE_DEBUGGERS
558static bool _DSCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
559	UNUSED(core);
560	switch (type) {
561	case DEBUGGER_CLI:
562		return true;
563#ifdef USE_GDB_STUB
564	case DEBUGGER_GDB:
565		return true;
566#endif
567	default:
568		return false;
569	}
570}
571
572static struct mDebuggerPlatform* _DSCoreDebuggerPlatform(struct mCore* core) {
573	struct DSCore* dscore = (struct DSCore*) core;
574	if (!dscore->debuggerPlatform) {
575		dscore->debuggerPlatform = ARMDebuggerPlatformCreate();
576	}
577	return dscore->debuggerPlatform;
578}
579
580static struct CLIDebuggerSystem* _DSCoreCliDebuggerSystem(struct mCore* core) {
581	return &DSCLIDebuggerCreate(core)->d;
582}
583
584static void _DSCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
585	if (core->debugger) {
586		DSDetachDebugger(core->board);
587	}
588	DSAttachDebugger(core->board, debugger);
589	core->debugger = debugger;
590}
591
592static void _DSCoreDetachDebugger(struct mCore* core) {
593	DSDetachDebugger(core->board);
594	core->debugger = NULL;
595}
596
597static void _DSCoreLoadSymbols(struct mCore* core, struct VFile* vf) {
598#ifdef USE_ELF
599	bool closeAfter = false;
600	core->symbolTable = mDebuggerSymbolTableCreate();
601#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
602	if (!vf) {
603		closeAfter = true;
604		vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".elf", O_RDONLY);
605	}
606#endif
607	if (!vf) {
608		return;
609	}
610	struct ELF* elf = ELFOpen(vf);
611	if (elf) {
612		mCoreLoadELFSymbols(core->symbolTable, elf);
613		ELFClose(elf);
614	}
615	if (closeAfter) {
616		vf->close(vf);
617	}
618#endif
619}
620#endif
621
622static struct mCheatDevice* _DSCoreCheatDevice(struct mCore* core) {
623	return NULL;
624}
625
626static size_t _DSCoreSavedataClone(struct mCore* core, void** sram) {
627	return 0;
628}
629
630static bool _DSCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
631	return false;
632}
633
634static size_t _DSCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
635	UNUSED(core);
636	*info = _DSVideoLayers;
637	return sizeof(_DSVideoLayers) / sizeof(*_DSVideoLayers);
638}
639
640static size_t _DSCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
641	UNUSED(core);
642	*info = _DSAudioChannels;
643	return sizeof(_DSAudioChannels) / sizeof(*_DSAudioChannels);
644}
645
646static void _DSCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
647	struct DS* ds = core->board;
648	switch (id) {
649	case 0:
650	case 1:
651	case 2:
652	case 3:
653		ds->video.renderer->disableABG[id] = !enable;
654		break;
655	case 4:
656		ds->video.renderer->disableAOBJ = !enable;
657		break;
658	case 10:
659	case 11:
660	case 12:
661	case 13:
662		ds->video.renderer->disableBBG[id - 10] = !enable;
663		break;
664	case 14:
665		ds->video.renderer->disableBOBJ = !enable;
666		break;
667	default:
668		break;
669	}
670}
671
672static void _DSCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
673	struct DS* ds = core->board;
674}
675
676struct mCore* DSCoreCreate(void) {
677	struct DSCore* dscore = malloc(sizeof(*dscore));
678	struct mCore* core = &dscore->d;
679	memset(&core->opts, 0, sizeof(core->opts));
680	core->cpu = NULL;
681	core->board = NULL;
682	core->debugger = NULL;
683	core->init = _DSCoreInit;
684	core->deinit = _DSCoreDeinit;
685	core->platform = _DSCorePlatform;
686	core->supportsFeature = _DSCoreSupportsFeature;
687	core->setSync = _DSCoreSetSync;
688	core->loadConfig = _DSCoreLoadConfig;
689	core->reloadConfigOption = _DSCoreReloadConfigOption;
690	core->desiredVideoDimensions = _DSCoreDesiredVideoDimensions;
691	core->setVideoBuffer = _DSCoreSetVideoBuffer;
692	core->getPixels = _DSCoreGetPixels;
693	core->putPixels = _DSCorePutPixels;
694	core->getAudioChannel = _DSCoreGetAudioChannel;
695	core->setAudioBufferSize = _DSCoreSetAudioBufferSize;
696	core->getAudioBufferSize = _DSCoreGetAudioBufferSize;
697	core->addCoreCallbacks = _DSCoreAddCoreCallbacks;
698	core->clearCoreCallbacks = _DSCoreClearCoreCallbacks;
699	core->setAVStream = _DSCoreSetAVStream;
700	core->isROM = DSIsROM;
701	core->loadROM = _DSCoreLoadROM;
702	core->loadBIOS = _DSCoreLoadBIOS;
703	core->loadSave = _DSCoreLoadSave;
704	core->loadPatch = _DSCoreLoadPatch;
705	core->unloadROM = _DSCoreUnloadROM;
706	core->checksum = _DSCoreChecksum;
707	core->reset = _DSCoreReset;
708	core->runFrame = _DSCoreRunFrame;
709	core->runLoop = _DSCoreRunLoop;
710	core->step = _DSCoreStep;
711	core->stateSize = _DSCoreStateSize;
712	core->loadState = _DSCoreLoadState;
713	core->saveState = _DSCoreSaveState;
714	core->setKeys = _DSCoreSetKeys;
715	core->addKeys = _DSCoreAddKeys;
716	core->clearKeys = _DSCoreClearKeys;
717	core->setCursorLocation = _DSCoreSetCursorLocation;
718	core->setCursorDown = _DSCoreSetCursorDown;
719	core->frameCounter = _DSCoreFrameCounter;
720	core->frameCycles = _DSCoreFrameCycles;
721	core->frequency = _DSCoreFrequency;
722	core->getGameTitle = _DSCoreGetGameTitle;
723	core->getGameCode = _DSCoreGetGameCode;
724	core->setPeripheral = _DSCoreSetPeripheral;
725	core->busRead8 = _DSCoreBusRead8;
726	core->busRead16 = _DSCoreBusRead16;
727	core->busRead32 = _DSCoreBusRead32;
728	core->busWrite8 = _DSCoreBusWrite8;
729	core->busWrite16 = _DSCoreBusWrite16;
730	core->busWrite32 = _DSCoreBusWrite32;
731	core->rawRead8 = _DSCoreRawRead8;
732	core->rawRead16 = _DSCoreRawRead16;
733	core->rawRead32 = _DSCoreRawRead32;
734	core->rawWrite8 = _DSCoreRawWrite8;
735	core->rawWrite16 = _DSCoreRawWrite16;
736	core->rawWrite32 = _DSCoreRawWrite32;
737#ifdef USE_DEBUGGERS
738	core->supportsDebuggerType = _DSCoreSupportsDebuggerType;
739	core->debuggerPlatform = _DSCoreDebuggerPlatform;
740	core->cliDebuggerSystem = _DSCoreCliDebuggerSystem;
741	core->attachDebugger = _DSCoreAttachDebugger;
742	core->detachDebugger = _DSCoreDetachDebugger;
743	core->loadSymbols = _DSCoreLoadSymbols;
744#endif
745	core->cheatDevice = _DSCoreCheatDevice;
746	core->savedataClone = _DSCoreSavedataClone;
747	core->savedataRestore = _DSCoreSavedataRestore;
748	core->listVideoLayers = _DSCoreListVideoLayers;
749	core->listAudioChannels = _DSCoreListAudioChannels;
750	core->enableVideoLayer = _DSCoreEnableVideoLayer;
751	core->enableAudioChannel = _DSCoreEnableAudioChannel;
752	return core;
753}