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 if (configPath) {
315 bios = VFileOpen(configPath, O_RDONLY);
316 }
317 if (bios && GBAIsBIOS(bios)) {
318 found = true;
319 } else if (bios) {
320 bios->close(bios);
321 bios = NULL;
322 }
323 }
324 if (!found) {
325 char path[PATH_MAX];
326 mCoreConfigDirectory(path, PATH_MAX);
327 strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path));
328 bios = VFileOpen(path, O_RDONLY);
329 if (bios && GBIsBIOS(bios)) {
330 found = true;
331 } else if (bios) {
332 bios->close(bios);
333 bios = NULL;
334 }
335 }
336 if (bios) {
337 GBALoadBIOS(gba, bios);
338 }
339 }
340#endif
341
342 ARMReset(core->cpu);
343 if (core->opts.skipBios && gba->isPristine) {
344 GBASkipBIOS(core->board);
345 }
346}
347
348static void _GBACoreRunFrame(struct mCore* core) {
349 struct GBA* gba = core->board;
350 int32_t frameCounter = gba->video.frameCounter;
351 while (gba->video.frameCounter == frameCounter) {
352 ARMv4RunLoop(core->cpu);
353 }
354}
355
356static void _GBACoreRunLoop(struct mCore* core) {
357 ARMv4RunLoop(core->cpu);
358}
359
360static void _GBACoreStep(struct mCore* core) {
361 ARMv4Run(core->cpu);
362}
363
364static size_t _GBACoreStateSize(struct mCore* core) {
365 UNUSED(core);
366 return sizeof(struct GBASerializedState);
367}
368
369static bool _GBACoreLoadState(struct mCore* core, const void* state) {
370 return GBADeserialize(core->board, state);
371}
372
373static bool _GBACoreSaveState(struct mCore* core, void* state) {
374 GBASerialize(core->board, state);
375 return true;
376}
377
378static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
379 struct GBACore* gbacore = (struct GBACore*) core;
380 gbacore->keys = keys;
381}
382
383static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
384 struct GBACore* gbacore = (struct GBACore*) core;
385 gbacore->keys |= keys;
386}
387
388static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
389 struct GBACore* gbacore = (struct GBACore*) core;
390 gbacore->keys &= ~keys;
391}
392
393static void _GBACoreSetCursorLocation(struct mCore* core, int x, int y) {
394 UNUSED(core);
395 UNUSED(x);
396 UNUSED(y);
397}
398
399static void _GBACoreSetCursorDown(struct mCore* core, bool down) {
400 UNUSED(core);
401 UNUSED(down);
402}
403
404static int32_t _GBACoreFrameCounter(const struct mCore* core) {
405 const struct GBA* gba = core->board;
406 return gba->video.frameCounter;
407}
408
409static int32_t _GBACoreFrameCycles(const struct mCore* core) {
410 UNUSED(core);
411 return VIDEO_TOTAL_LENGTH;
412}
413
414static int32_t _GBACoreFrequency(const struct mCore* core) {
415 UNUSED(core);
416 return GBA_ARM7TDMI_FREQUENCY;
417}
418
419static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
420 GBAGetGameTitle(core->board, title);
421}
422
423static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
424 GBAGetGameCode(core->board, title);
425}
426
427static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) {
428 struct GBA* gba = core->board;
429 switch (type) {
430 case mPERIPH_ROTATION:
431 gba->rotationSource = periph;
432 break;
433 case mPERIPH_RUMBLE:
434 gba->rumble = periph;
435 break;
436 case mPERIPH_GBA_LUMINANCE:
437 gba->luminanceSource = periph;
438 break;
439 default:
440 return;
441 }
442}
443
444static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
445 struct ARMCore* cpu = core->cpu;
446 return cpu->memory.load8(cpu, address, 0);
447}
448
449static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
450 struct ARMCore* cpu = core->cpu;
451 return cpu->memory.load16(cpu, address, 0);
452
453}
454
455static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
456 struct ARMCore* cpu = core->cpu;
457 return cpu->memory.load32(cpu, address, 0);
458}
459
460static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
461 struct ARMCore* cpu = core->cpu;
462 cpu->memory.store8(cpu, address, value, 0);
463}
464
465static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
466 struct ARMCore* cpu = core->cpu;
467 cpu->memory.store16(cpu, address, value, 0);
468}
469
470static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
471 struct ARMCore* cpu = core->cpu;
472 cpu->memory.store32(cpu, address, value, 0);
473}
474
475static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) {
476 UNUSED(segment);
477 struct ARMCore* cpu = core->cpu;
478 return GBAView8(cpu, address);
479}
480
481static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) {
482 UNUSED(segment);
483 struct ARMCore* cpu = core->cpu;
484 return GBAView16(cpu, address);
485}
486
487static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) {
488 UNUSED(segment);
489 struct ARMCore* cpu = core->cpu;
490 return GBAView32(cpu, address);
491}
492
493static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
494 UNUSED(segment);
495 struct ARMCore* cpu = core->cpu;
496 GBAPatch8(cpu, address, value, NULL);
497}
498
499static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
500 UNUSED(segment);
501 struct ARMCore* cpu = core->cpu;
502 GBAPatch16(cpu, address, value, NULL);
503}
504
505static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
506 UNUSED(segment);
507 struct ARMCore* cpu = core->cpu;
508 GBAPatch32(cpu, address, value, NULL);
509}
510
511#ifdef USE_DEBUGGERS
512static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
513 UNUSED(core);
514 switch (type) {
515 case DEBUGGER_CLI:
516 return true;
517#ifdef USE_GDB_STUB
518 case DEBUGGER_GDB:
519 return true;
520#endif
521 default:
522 return false;
523 }
524}
525
526static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
527 struct GBACore* gbacore = (struct GBACore*) core;
528 if (!gbacore->debuggerPlatform) {
529 gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
530 }
531 return gbacore->debuggerPlatform;
532}
533
534static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
535 return &GBACLIDebuggerCreate(core)->d;
536}
537
538static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
539 if (core->debugger) {
540 GBADetachDebugger(core->board);
541 }
542 GBAAttachDebugger(core->board, debugger);
543 core->debugger = debugger;
544}
545
546static void _GBACoreDetachDebugger(struct mCore* core) {
547 GBADetachDebugger(core->board);
548 core->debugger = NULL;
549}
550#endif
551
552static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
553 struct GBACore* gbacore = (struct GBACore*) core;
554 if (!gbacore->cheatDevice) {
555 gbacore->cheatDevice = GBACheatDeviceCreate();
556 ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
557 ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
558 gbacore->cheatDevice->p = core;
559 }
560 return gbacore->cheatDevice;
561}
562
563static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
564 struct GBA* gba = core->board;
565 size_t size = GBASavedataSize(&gba->memory.savedata);
566 if (!size) {
567 *sram = NULL;
568 return 0;
569 }
570 *sram = malloc(size);
571 struct VFile* vf = VFileFromMemory(*sram, size);
572 if (!vf) {
573 free(*sram);
574 *sram = NULL;
575 return 0;
576 }
577 bool success = GBASavedataClone(&gba->memory.savedata, vf);
578 vf->close(vf);
579 if (!success) {
580 free(*sram);
581 *sram = NULL;
582 return 0;
583 }
584 return size;
585}
586
587static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
588 struct VFile* vf = VFileMemChunk(sram, size);
589 if (!vf) {
590 return false;
591 }
592 struct GBA* gba = core->board;
593 bool success = true;
594 if (writeback) {
595 success = GBASavedataLoad(&gba->memory.savedata, vf);
596 vf->close(vf);
597 } else {
598 GBASavedataMask(&gba->memory.savedata, vf, true);
599 }
600 return success;
601}
602
603struct mCore* GBACoreCreate(void) {
604 struct GBACore* gbacore = malloc(sizeof(*gbacore));
605 struct mCore* core = &gbacore->d;
606 memset(&core->opts, 0, sizeof(core->opts));
607 core->cpu = NULL;
608 core->board = NULL;
609 core->debugger = NULL;
610 core->init = _GBACoreInit;
611 core->deinit = _GBACoreDeinit;
612 core->platform = _GBACorePlatform;
613 core->setSync = _GBACoreSetSync;
614 core->loadConfig = _GBACoreLoadConfig;
615 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
616 core->setVideoBuffer = _GBACoreSetVideoBuffer;
617 core->getPixels = _GBACoreGetPixels;
618 core->putPixels = _GBACorePutPixels;
619 core->getAudioChannel = _GBACoreGetAudioChannel;
620 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
621 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
622 core->addCoreCallbacks = _GBACoreAddCoreCallbacks;
623 core->clearCoreCallbacks = _GBACoreClearCoreCallbacks;
624 core->setAVStream = _GBACoreSetAVStream;
625 core->isROM = GBAIsROM;
626 core->loadROM = _GBACoreLoadROM;
627 core->loadBIOS = _GBACoreLoadBIOS;
628 core->loadSave = _GBACoreLoadSave;
629 core->loadTemporarySave = _GBACoreLoadTemporarySave;
630 core->loadPatch = _GBACoreLoadPatch;
631 core->unloadROM = _GBACoreUnloadROM;
632 core->checksum = _GBACoreChecksum;
633 core->reset = _GBACoreReset;
634 core->runFrame = _GBACoreRunFrame;
635 core->runLoop = _GBACoreRunLoop;
636 core->step = _GBACoreStep;
637 core->stateSize = _GBACoreStateSize;
638 core->loadState = _GBACoreLoadState;
639 core->saveState = _GBACoreSaveState;
640 core->setKeys = _GBACoreSetKeys;
641 core->addKeys = _GBACoreAddKeys;
642 core->clearKeys = _GBACoreClearKeys;
643 core->setCursorLocation = _GBACoreSetCursorLocation;
644 core->setCursorDown = _GBACoreSetCursorDown;
645 core->frameCounter = _GBACoreFrameCounter;
646 core->frameCycles = _GBACoreFrameCycles;
647 core->frequency = _GBACoreFrequency;
648 core->getGameTitle = _GBACoreGetGameTitle;
649 core->getGameCode = _GBACoreGetGameCode;
650 core->setPeripheral = _GBACoreSetPeripheral;
651 core->busRead8 = _GBACoreBusRead8;
652 core->busRead16 = _GBACoreBusRead16;
653 core->busRead32 = _GBACoreBusRead32;
654 core->busWrite8 = _GBACoreBusWrite8;
655 core->busWrite16 = _GBACoreBusWrite16;
656 core->busWrite32 = _GBACoreBusWrite32;
657 core->rawRead8 = _GBACoreRawRead8;
658 core->rawRead16 = _GBACoreRawRead16;
659 core->rawRead32 = _GBACoreRawRead32;
660 core->rawWrite8 = _GBACoreRawWrite8;
661 core->rawWrite16 = _GBACoreRawWrite16;
662 core->rawWrite32 = _GBACoreRawWrite32;
663#ifdef USE_DEBUGGERS
664 core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
665 core->debuggerPlatform = _GBACoreDebuggerPlatform;
666 core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
667 core->attachDebugger = _GBACoreAttachDebugger;
668 core->detachDebugger = _GBACoreDetachDebugger;
669#endif
670 core->cheatDevice = _GBACoreCheatDevice;
671 core->savedataClone = _GBACoreSavedataClone;
672 core->savedataRestore = _GBACoreSavedataRestore;
673 return core;
674}