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