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