all repos — mgba @ medusa

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