all repos — mgba @ 4fd170ac38a9c312f3dd1d0dd912d2c761f60fdb

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