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 && GBIsBIOS(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}