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 ARMRunLoop(core->cpu);
353 }
354}
355
356static void _GBACoreRunLoop(struct mCore* core) {
357 ARMRunLoop(core->cpu);
358}
359
360static void _GBACoreStep(struct mCore* core) {
361 ARMRun(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 int32_t _GBACoreFrameCounter(const struct mCore* core) {
394 const struct GBA* gba = core->board;
395 return gba->video.frameCounter;
396}
397
398static int32_t _GBACoreFrameCycles(const struct mCore* core) {
399 UNUSED(core);
400 return VIDEO_TOTAL_LENGTH;
401}
402
403static int32_t _GBACoreFrequency(const struct mCore* core) {
404 UNUSED(core);
405 return GBA_ARM7TDMI_FREQUENCY;
406}
407
408static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
409 GBAGetGameTitle(core->board, title);
410}
411
412static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
413 GBAGetGameCode(core->board, title);
414}
415
416static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
417 struct GBA* gba = core->board;
418 gba->rotationSource = rotation;
419}
420
421static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
422 struct GBA* gba = core->board;
423 gba->rumble = rumble;
424}
425
426static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
427 struct ARMCore* cpu = core->cpu;
428 return cpu->memory.load8(cpu, address, 0);
429}
430
431static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
432 struct ARMCore* cpu = core->cpu;
433 return cpu->memory.load16(cpu, address, 0);
434
435}
436
437static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
438 struct ARMCore* cpu = core->cpu;
439 return cpu->memory.load32(cpu, address, 0);
440}
441
442static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
443 struct ARMCore* cpu = core->cpu;
444 cpu->memory.store8(cpu, address, value, 0);
445}
446
447static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
448 struct ARMCore* cpu = core->cpu;
449 cpu->memory.store16(cpu, address, value, 0);
450}
451
452static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
453 struct ARMCore* cpu = core->cpu;
454 cpu->memory.store32(cpu, address, value, 0);
455}
456
457static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) {
458 UNUSED(segment);
459 struct ARMCore* cpu = core->cpu;
460 return GBAView8(cpu, address);
461}
462
463static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) {
464 UNUSED(segment);
465 struct ARMCore* cpu = core->cpu;
466 return GBAView16(cpu, address);
467}
468
469static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) {
470 UNUSED(segment);
471 struct ARMCore* cpu = core->cpu;
472 return GBAView32(cpu, address);
473}
474
475static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
476 UNUSED(segment);
477 struct ARMCore* cpu = core->cpu;
478 GBAPatch8(cpu, address, value, NULL);
479}
480
481static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
482 UNUSED(segment);
483 struct ARMCore* cpu = core->cpu;
484 GBAPatch16(cpu, address, value, NULL);
485}
486
487static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
488 UNUSED(segment);
489 struct ARMCore* cpu = core->cpu;
490 GBAPatch32(cpu, address, value, NULL);
491}
492
493#ifdef USE_DEBUGGERS
494static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
495 UNUSED(core);
496 switch (type) {
497 case DEBUGGER_CLI:
498 return true;
499#ifdef USE_GDB_STUB
500 case DEBUGGER_GDB:
501 return true;
502#endif
503 default:
504 return false;
505 }
506}
507
508static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
509 struct GBACore* gbacore = (struct GBACore*) core;
510 if (!gbacore->debuggerPlatform) {
511 gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
512 }
513 return gbacore->debuggerPlatform;
514}
515
516static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
517 return &GBACLIDebuggerCreate(core)->d;
518}
519
520static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
521 if (core->debugger) {
522 GBADetachDebugger(core->board);
523 }
524 GBAAttachDebugger(core->board, debugger);
525 core->debugger = debugger;
526}
527
528static void _GBACoreDetachDebugger(struct mCore* core) {
529 GBADetachDebugger(core->board);
530 core->debugger = NULL;
531}
532#endif
533
534static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
535 struct GBACore* gbacore = (struct GBACore*) core;
536 if (!gbacore->cheatDevice) {
537 gbacore->cheatDevice = GBACheatDeviceCreate();
538 ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
539 ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
540 gbacore->cheatDevice->p = core;
541 }
542 return gbacore->cheatDevice;
543}
544
545static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
546 struct GBA* gba = core->board;
547 size_t size = GBASavedataSize(&gba->memory.savedata);
548 if (!size) {
549 *sram = NULL;
550 return 0;
551 }
552 *sram = malloc(size);
553 struct VFile* vf = VFileFromMemory(*sram, size);
554 if (!vf) {
555 free(*sram);
556 *sram = NULL;
557 return 0;
558 }
559 bool success = GBASavedataClone(&gba->memory.savedata, vf);
560 vf->close(vf);
561 if (!success) {
562 free(*sram);
563 *sram = NULL;
564 return 0;
565 }
566 return size;
567}
568
569static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
570 struct VFile* vf = VFileMemChunk(sram, size);
571 if (!vf) {
572 return false;
573 }
574 struct GBA* gba = core->board;
575 bool success = true;
576 if (writeback) {
577 success = GBASavedataLoad(&gba->memory.savedata, vf);
578 vf->close(vf);
579 } else {
580 GBASavedataMask(&gba->memory.savedata, vf, true);
581 }
582 return success;
583}
584
585struct mCore* GBACoreCreate(void) {
586 struct GBACore* gbacore = malloc(sizeof(*gbacore));
587 struct mCore* core = &gbacore->d;
588 memset(&core->opts, 0, sizeof(core->opts));
589 core->cpu = NULL;
590 core->board = NULL;
591 core->debugger = NULL;
592 core->init = _GBACoreInit;
593 core->deinit = _GBACoreDeinit;
594 core->platform = _GBACorePlatform;
595 core->setSync = _GBACoreSetSync;
596 core->loadConfig = _GBACoreLoadConfig;
597 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
598 core->setVideoBuffer = _GBACoreSetVideoBuffer;
599 core->getPixels = _GBACoreGetPixels;
600 core->putPixels = _GBACorePutPixels;
601 core->getAudioChannel = _GBACoreGetAudioChannel;
602 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
603 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
604 core->addCoreCallbacks = _GBACoreAddCoreCallbacks;
605 core->clearCoreCallbacks = _GBACoreClearCoreCallbacks;
606 core->setAVStream = _GBACoreSetAVStream;
607 core->isROM = GBAIsROM;
608 core->loadROM = _GBACoreLoadROM;
609 core->loadBIOS = _GBACoreLoadBIOS;
610 core->loadSave = _GBACoreLoadSave;
611 core->loadTemporarySave = _GBACoreLoadTemporarySave;
612 core->loadPatch = _GBACoreLoadPatch;
613 core->unloadROM = _GBACoreUnloadROM;
614 core->checksum = _GBACoreChecksum;
615 core->reset = _GBACoreReset;
616 core->runFrame = _GBACoreRunFrame;
617 core->runLoop = _GBACoreRunLoop;
618 core->step = _GBACoreStep;
619 core->stateSize = _GBACoreStateSize;
620 core->loadState = _GBACoreLoadState;
621 core->saveState = _GBACoreSaveState;
622 core->setKeys = _GBACoreSetKeys;
623 core->addKeys = _GBACoreAddKeys;
624 core->clearKeys = _GBACoreClearKeys;
625 core->frameCounter = _GBACoreFrameCounter;
626 core->frameCycles = _GBACoreFrameCycles;
627 core->frequency = _GBACoreFrequency;
628 core->getGameTitle = _GBACoreGetGameTitle;
629 core->getGameCode = _GBACoreGetGameCode;
630 core->setRotation = _GBACoreSetRotation;
631 core->setRumble = _GBACoreSetRumble;
632 core->busRead8 = _GBACoreBusRead8;
633 core->busRead16 = _GBACoreBusRead16;
634 core->busRead32 = _GBACoreBusRead32;
635 core->busWrite8 = _GBACoreBusWrite8;
636 core->busWrite16 = _GBACoreBusWrite16;
637 core->busWrite32 = _GBACoreBusWrite32;
638 core->rawRead8 = _GBACoreRawRead8;
639 core->rawRead16 = _GBACoreRawRead16;
640 core->rawRead32 = _GBACoreRawRead32;
641 core->rawWrite8 = _GBACoreRawWrite8;
642 core->rawWrite16 = _GBACoreRawWrite16;
643 core->rawWrite32 = _GBACoreRawWrite32;
644#ifdef USE_DEBUGGERS
645 core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
646 core->debuggerPlatform = _GBACoreDebuggerPlatform;
647 core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
648 core->attachDebugger = _GBACoreAttachDebugger;
649 core->detachDebugger = _GBACoreDetachDebugger;
650#endif
651 core->cheatDevice = _GBACoreCheatDevice;
652 core->savedataClone = _GBACoreSavedataClone;
653 core->savedataRestore = _GBACoreSavedataRestore;
654 return core;
655}