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 if (stream && stream->videoFrameRateChanged) {
233 stream->videoFrameRateChanged(stream, core->frameCycles(core), core->frequency(core));
234 }
235}
236
237static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
238 if (GBAIsMB(vf)) {
239 return GBALoadMB(core->board, vf);
240 }
241 return GBALoadROM(core->board, vf);
242}
243
244static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
245 UNUSED(type);
246 if (!GBAIsBIOS(vf)) {
247 return false;
248 }
249 GBALoadBIOS(core->board, vf);
250 return true;
251}
252
253static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
254 return GBALoadSave(core->board, vf);
255}
256
257static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
258 struct GBA* gba = core->board;
259 GBASavedataMask(&gba->memory.savedata, vf, false);
260 return true; // TODO: Return a real value
261}
262
263static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
264 if (!vf) {
265 return false;
266 }
267 struct Patch patch;
268 if (!loadPatch(vf, &patch)) {
269 return false;
270 }
271 GBAApplyPatch(core->board, &patch);
272 return true;
273}
274
275static void _GBACoreUnloadROM(struct mCore* core) {
276 struct GBACore* gbacore = (struct GBACore*) core;
277 struct ARMCore* cpu = core->cpu;
278 if (gbacore->cheatDevice) {
279 ARMHotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
280 cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
281 mCheatDeviceDestroy(gbacore->cheatDevice);
282 gbacore->cheatDevice = NULL;
283 }
284 return GBAUnloadROM(core->board);
285}
286
287static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
288 struct GBA* gba = (struct GBA*) core->board;
289 switch (type) {
290 case CHECKSUM_CRC32:
291 memcpy(data, &gba->romCrc32, sizeof(gba->romCrc32));
292 break;
293 }
294 return;
295}
296
297static void _GBACoreReset(struct mCore* core) {
298 struct GBACore* gbacore = (struct GBACore*) core;
299 struct GBA* gba = (struct GBA*) core->board;
300 if (gbacore->renderer.outputBuffer) {
301 struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
302#ifndef DISABLE_THREADING
303 if (gbacore->threadedVideo) {
304 renderer = &gbacore->threadProxy.d;
305 }
306#endif
307 GBAVideoAssociateRenderer(&gba->video, renderer);
308 }
309
310 struct GBACartridgeOverride override;
311 const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
312 if (cart) {
313 memcpy(override.id, &cart->id, sizeof(override.id));
314 if (GBAOverrideFind(gbacore->overrides, &override)) {
315 GBAOverrideApply(gba, &override);
316 }
317 }
318
319#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
320 if (!gba->biosVf && core->opts.useBios) {
321 struct VFile* bios = NULL;
322 bool found = false;
323 if (core->opts.bios) {
324 bios = VFileOpen(core->opts.bios, O_RDONLY);
325 if (bios && GBAIsBIOS(bios)) {
326 found = true;
327 } else if (bios) {
328 bios->close(bios);
329 bios = NULL;
330 }
331 }
332 if (!found) {
333 const char* configPath = mCoreConfigGetValue(&core->config, "gba.bios");
334 if (configPath) {
335 bios = VFileOpen(configPath, O_RDONLY);
336 }
337 if (bios && GBAIsBIOS(bios)) {
338 found = true;
339 } else if (bios) {
340 bios->close(bios);
341 bios = NULL;
342 }
343 }
344 if (!found) {
345 char path[PATH_MAX];
346 mCoreConfigDirectory(path, PATH_MAX);
347 strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path));
348 bios = VFileOpen(path, O_RDONLY);
349 if (bios && GBIsBIOS(bios)) {
350 found = true;
351 } else if (bios) {
352 bios->close(bios);
353 bios = NULL;
354 }
355 }
356 if (bios) {
357 GBALoadBIOS(gba, bios);
358 }
359 }
360#endif
361
362 ARMReset(core->cpu);
363 if (core->opts.skipBios && gba->isPristine) {
364 GBASkipBIOS(core->board);
365 }
366}
367
368static void _GBACoreRunFrame(struct mCore* core) {
369 struct GBA* gba = core->board;
370 int32_t frameCounter = gba->video.frameCounter;
371 while (gba->video.frameCounter == frameCounter) {
372 ARMv4RunLoop(core->cpu);
373 }
374}
375
376static void _GBACoreRunLoop(struct mCore* core) {
377 ARMv4RunLoop(core->cpu);
378}
379
380static void _GBACoreStep(struct mCore* core) {
381 ARMv4Run(core->cpu);
382}
383
384static size_t _GBACoreStateSize(struct mCore* core) {
385 UNUSED(core);
386 return sizeof(struct GBASerializedState);
387}
388
389static bool _GBACoreLoadState(struct mCore* core, const void* state) {
390 return GBADeserialize(core->board, state);
391}
392
393static bool _GBACoreSaveState(struct mCore* core, void* state) {
394 GBASerialize(core->board, state);
395 return true;
396}
397
398static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
399 struct GBACore* gbacore = (struct GBACore*) core;
400 gbacore->keys = keys;
401}
402
403static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
404 struct GBACore* gbacore = (struct GBACore*) core;
405 gbacore->keys |= keys;
406}
407
408static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
409 struct GBACore* gbacore = (struct GBACore*) core;
410 gbacore->keys &= ~keys;
411}
412
413static void _GBACoreSetCursorLocation(struct mCore* core, int x, int y) {
414 UNUSED(core);
415 UNUSED(x);
416 UNUSED(y);
417}
418
419static void _GBACoreSetCursorDown(struct mCore* core, bool down) {
420 UNUSED(core);
421 UNUSED(down);
422}
423
424static int32_t _GBACoreFrameCounter(const struct mCore* core) {
425 const struct GBA* gba = core->board;
426 return gba->video.frameCounter;
427}
428
429static int32_t _GBACoreFrameCycles(const struct mCore* core) {
430 UNUSED(core);
431 return VIDEO_TOTAL_LENGTH;
432}
433
434static int32_t _GBACoreFrequency(const struct mCore* core) {
435 UNUSED(core);
436 return GBA_ARM7TDMI_FREQUENCY;
437}
438
439static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
440 GBAGetGameTitle(core->board, title);
441}
442
443static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
444 GBAGetGameCode(core->board, title);
445}
446
447static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) {
448 struct GBA* gba = core->board;
449 switch (type) {
450 case mPERIPH_ROTATION:
451 gba->rotationSource = periph;
452 break;
453 case mPERIPH_RUMBLE:
454 gba->rumble = periph;
455 break;
456 case mPERIPH_GBA_LUMINANCE:
457 gba->luminanceSource = periph;
458 break;
459 default:
460 return;
461 }
462}
463
464static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
465 struct ARMCore* cpu = core->cpu;
466 return cpu->memory.load8(cpu, address, 0);
467}
468
469static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
470 struct ARMCore* cpu = core->cpu;
471 return cpu->memory.load16(cpu, address, 0);
472
473}
474
475static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
476 struct ARMCore* cpu = core->cpu;
477 return cpu->memory.load32(cpu, address, 0);
478}
479
480static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
481 struct ARMCore* cpu = core->cpu;
482 cpu->memory.store8(cpu, address, value, 0);
483}
484
485static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
486 struct ARMCore* cpu = core->cpu;
487 cpu->memory.store16(cpu, address, value, 0);
488}
489
490static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
491 struct ARMCore* cpu = core->cpu;
492 cpu->memory.store32(cpu, address, value, 0);
493}
494
495static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) {
496 UNUSED(segment);
497 struct ARMCore* cpu = core->cpu;
498 return GBAView8(cpu, address);
499}
500
501static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) {
502 UNUSED(segment);
503 struct ARMCore* cpu = core->cpu;
504 return GBAView16(cpu, address);
505}
506
507static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) {
508 UNUSED(segment);
509 struct ARMCore* cpu = core->cpu;
510 return GBAView32(cpu, address);
511}
512
513static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
514 UNUSED(segment);
515 struct ARMCore* cpu = core->cpu;
516 GBAPatch8(cpu, address, value, NULL);
517}
518
519static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
520 UNUSED(segment);
521 struct ARMCore* cpu = core->cpu;
522 GBAPatch16(cpu, address, value, NULL);
523}
524
525static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
526 UNUSED(segment);
527 struct ARMCore* cpu = core->cpu;
528 GBAPatch32(cpu, address, value, NULL);
529}
530
531#ifdef USE_DEBUGGERS
532static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
533 UNUSED(core);
534 switch (type) {
535 case DEBUGGER_CLI:
536 return true;
537#ifdef USE_GDB_STUB
538 case DEBUGGER_GDB:
539 return true;
540#endif
541 default:
542 return false;
543 }
544}
545
546static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
547 struct GBACore* gbacore = (struct GBACore*) core;
548 if (!gbacore->debuggerPlatform) {
549 gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
550 }
551 return gbacore->debuggerPlatform;
552}
553
554static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
555 return &GBACLIDebuggerCreate(core)->d;
556}
557
558static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
559 if (core->debugger) {
560 GBADetachDebugger(core->board);
561 }
562 GBAAttachDebugger(core->board, debugger);
563 core->debugger = debugger;
564}
565
566static void _GBACoreDetachDebugger(struct mCore* core) {
567 GBADetachDebugger(core->board);
568 core->debugger = NULL;
569}
570#endif
571
572static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
573 struct GBACore* gbacore = (struct GBACore*) core;
574 if (!gbacore->cheatDevice) {
575 gbacore->cheatDevice = GBACheatDeviceCreate();
576 ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
577 ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
578 gbacore->cheatDevice->p = core;
579 }
580 return gbacore->cheatDevice;
581}
582
583static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
584 struct GBA* gba = core->board;
585 size_t size = GBASavedataSize(&gba->memory.savedata);
586 if (!size) {
587 *sram = NULL;
588 return 0;
589 }
590 *sram = malloc(size);
591 struct VFile* vf = VFileFromMemory(*sram, size);
592 if (!vf) {
593 free(*sram);
594 *sram = NULL;
595 return 0;
596 }
597 bool success = GBASavedataClone(&gba->memory.savedata, vf);
598 vf->close(vf);
599 if (!success) {
600 free(*sram);
601 *sram = NULL;
602 return 0;
603 }
604 return size;
605}
606
607static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
608 struct VFile* vf = VFileMemChunk(sram, size);
609 if (!vf) {
610 return false;
611 }
612 struct GBA* gba = core->board;
613 bool success = true;
614 if (writeback) {
615 success = GBASavedataLoad(&gba->memory.savedata, vf);
616 vf->close(vf);
617 } else {
618 GBASavedataMask(&gba->memory.savedata, vf, true);
619 }
620 return success;
621}
622
623static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
624 UNUSED(core);
625 *info = _GBAVideoLayers;
626 return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
627}
628
629static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
630 UNUSED(core);
631 *info = _GBAAudioChannels;
632 return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
633}
634
635static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
636 struct GBA* gba = core->board;
637 switch (id) {
638 case 0:
639 case 1:
640 case 2:
641 case 3:
642 gba->video.renderer->disableBG[id] = !enable;
643 break;
644 case 4:
645 gba->video.renderer->disableOBJ = !enable;
646 break;
647 default:
648 break;
649 }
650}
651
652static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
653 struct GBA* gba = core->board;
654 switch (id) {
655 case 0:
656 case 1:
657 case 2:
658 case 3:
659 gba->audio.psg.forceDisableCh[id] = !enable;
660 break;
661 case 4:
662 gba->audio.forceDisableChA = !enable;
663 case 5:
664 gba->audio.forceDisableChB = !enable;
665 break;
666 default:
667 break;
668 }
669}
670
671struct mCore* GBACoreCreate(void) {
672 struct GBACore* gbacore = malloc(sizeof(*gbacore));
673 struct mCore* core = &gbacore->d;
674 memset(&core->opts, 0, sizeof(core->opts));
675 core->cpu = NULL;
676 core->board = NULL;
677 core->debugger = NULL;
678 core->init = _GBACoreInit;
679 core->deinit = _GBACoreDeinit;
680 core->platform = _GBACorePlatform;
681 core->setSync = _GBACoreSetSync;
682 core->loadConfig = _GBACoreLoadConfig;
683 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
684 core->setVideoBuffer = _GBACoreSetVideoBuffer;
685 core->getPixels = _GBACoreGetPixels;
686 core->putPixels = _GBACorePutPixels;
687 core->getAudioChannel = _GBACoreGetAudioChannel;
688 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
689 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
690 core->addCoreCallbacks = _GBACoreAddCoreCallbacks;
691 core->clearCoreCallbacks = _GBACoreClearCoreCallbacks;
692 core->setAVStream = _GBACoreSetAVStream;
693 core->isROM = GBAIsROM;
694 core->loadROM = _GBACoreLoadROM;
695 core->loadBIOS = _GBACoreLoadBIOS;
696 core->loadSave = _GBACoreLoadSave;
697 core->loadTemporarySave = _GBACoreLoadTemporarySave;
698 core->loadPatch = _GBACoreLoadPatch;
699 core->unloadROM = _GBACoreUnloadROM;
700 core->checksum = _GBACoreChecksum;
701 core->reset = _GBACoreReset;
702 core->runFrame = _GBACoreRunFrame;
703 core->runLoop = _GBACoreRunLoop;
704 core->step = _GBACoreStep;
705 core->stateSize = _GBACoreStateSize;
706 core->loadState = _GBACoreLoadState;
707 core->saveState = _GBACoreSaveState;
708 core->setKeys = _GBACoreSetKeys;
709 core->addKeys = _GBACoreAddKeys;
710 core->clearKeys = _GBACoreClearKeys;
711 core->setCursorLocation = _GBACoreSetCursorLocation;
712 core->setCursorDown = _GBACoreSetCursorDown;
713 core->frameCounter = _GBACoreFrameCounter;
714 core->frameCycles = _GBACoreFrameCycles;
715 core->frequency = _GBACoreFrequency;
716 core->getGameTitle = _GBACoreGetGameTitle;
717 core->getGameCode = _GBACoreGetGameCode;
718 core->setPeripheral = _GBACoreSetPeripheral;
719 core->busRead8 = _GBACoreBusRead8;
720 core->busRead16 = _GBACoreBusRead16;
721 core->busRead32 = _GBACoreBusRead32;
722 core->busWrite8 = _GBACoreBusWrite8;
723 core->busWrite16 = _GBACoreBusWrite16;
724 core->busWrite32 = _GBACoreBusWrite32;
725 core->rawRead8 = _GBACoreRawRead8;
726 core->rawRead16 = _GBACoreRawRead16;
727 core->rawRead32 = _GBACoreRawRead32;
728 core->rawWrite8 = _GBACoreRawWrite8;
729 core->rawWrite16 = _GBACoreRawWrite16;
730 core->rawWrite32 = _GBACoreRawWrite32;
731#ifdef USE_DEBUGGERS
732 core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
733 core->debuggerPlatform = _GBACoreDebuggerPlatform;
734 core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
735 core->attachDebugger = _GBACoreAttachDebugger;
736 core->detachDebugger = _GBACoreDetachDebugger;
737#endif
738 core->cheatDevice = _GBACoreCheatDevice;
739 core->savedataClone = _GBACoreSavedataClone;
740 core->savedataRestore = _GBACoreSavedataRestore;
741 core->listVideoLayers = _GBACoreListVideoLayers;
742 core->listAudioChannels = _GBACoreListAudioChannels;
743 core->enableVideoLayer = _GBACoreEnableVideoLayer;
744 core->enableAudioChannel = _GBACoreEnableAudioChannel;
745 return core;
746}