all repos — mgba @ 000b49e45b30ec9c856b7b2e8cf8baee21daa56d

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