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