all repos — mgba @ a5f029c2faa14f9e65d6c8413498057348100ede

mGBA Game Boy Advance Emulator

src/gba/core.c (view raw)

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