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/debugger/symbols.h>
12#include <mgba/internal/gba/cheats.h>
13#include <mgba/internal/gba/gba.h>
14#include <mgba/internal/gba/io.h>
15#include <mgba/internal/gba/extra/audio-mixer.h>
16#include <mgba/internal/gba/extra/cli.h>
17#include <mgba/internal/gba/overrides.h>
18#ifndef DISABLE_THREADING
19#include <mgba/feature/thread-proxy.h>
20#endif
21#ifdef BUILD_GLES2
22#include <mgba/internal/gba/renderers/gl.h>
23#endif
24#include <mgba/internal/gba/renderers/proxy.h>
25#include <mgba/internal/gba/renderers/video-software.h>
26#include <mgba/internal/gba/savedata.h>
27#include <mgba/internal/gba/serialize.h>
28#ifdef USE_ELF
29#include <mgba-util/elf-read.h>
30#endif
31#include <mgba-util/memory.h>
32#include <mgba-util/patch.h>
33#include <mgba-util/vfs.h>
34
35static const struct mCoreChannelInfo _GBAVideoLayers[] = {
36 { 0, "bg0", "Background 0", NULL },
37 { 1, "bg1", "Background 1", NULL },
38 { 2, "bg2", "Background 2", NULL },
39 { 3, "bg3", "Background 3", NULL },
40 { 4, "obj", "Objects", NULL },
41};
42
43static const struct mCoreChannelInfo _GBAAudioChannels[] = {
44 { 0, "ch1", "PSG Channel 1", "Square/Sweep" },
45 { 1, "ch2", "PSG Channel 2", "Square" },
46 { 2, "ch3", "PSG Channel 3", "PCM" },
47 { 3, "ch4", "PSG Channel 4", "Noise" },
48 { 4, "chA", "FIFO Channel A", NULL },
49 { 5, "chB", "FIFO Channel B", NULL },
50};
51
52static const struct mCoreMemoryBlock _GBAMemoryBlocks[] = {
53 { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
54 { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
55 { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
56 { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
57 { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
58 { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
59 { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
60 { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
61 { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
62 { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
63 { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
64};
65
66static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = {
67 { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
68 { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
69 { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
70 { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
71 { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
72 { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
73 { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
74 { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
75 { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
76 { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
77 { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
78 { REGION_CART_SRAM, "sram", "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_SRAM, SIZE_CART_SRAM, true },
79};
80
81static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = {
82 { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
83 { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
84 { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
85 { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
86 { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
87 { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
88 { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
89 { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
90 { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
91 { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
92 { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
93 { REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
94};
95
96static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = {
97 { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
98 { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
99 { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
100 { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
101 { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
102 { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
103 { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
104 { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
105 { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
106 { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
107 { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
108 { REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
109};
110
111static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = {
112 { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL },
113 { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
114 { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
115 { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
116 { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
117 { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
118 { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
119 { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
120 { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
121 { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
122 { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED },
123 { REGION_CART_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, SIZE_CART_EEPROM, SIZE_CART_EEPROM, mCORE_MEMORY_RW },
124};
125
126struct mVideoLogContext;
127
128#define CPU_COMPONENT_AUDIO_MIXER CPU_COMPONENT_MISC_1
129
130struct GBACore {
131 struct mCore d;
132 struct GBAVideoSoftwareRenderer renderer;
133#ifdef BUILD_GLES2
134 struct GBAVideoGLRenderer glRenderer;
135#endif
136 struct GBAVideoProxyRenderer proxyRenderer;
137 struct mVideoLogContext* logContext;
138 struct mCoreCallbacks logCallbacks;
139#ifndef DISABLE_THREADING
140 struct mVideoThreadProxy threadProxy;
141#endif
142 int keys;
143 struct mCPUComponent* components[CPU_COMPONENT_MAX];
144 const struct Configuration* overrides;
145 struct mDebuggerPlatform* debuggerPlatform;
146 struct mCheatDevice* cheatDevice;
147 struct GBAAudioMixer* audioMixer;
148};
149
150static bool _GBACoreInit(struct mCore* core) {
151 struct GBACore* gbacore = (struct GBACore*) core;
152
153 struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
154 struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
155 if (!cpu || !gba) {
156 free(cpu);
157 free(gba);
158 return false;
159 }
160 core->cpu = cpu;
161 core->board = gba;
162 core->timing = &gba->timing;
163 core->debugger = NULL;
164 core->symbolTable = NULL;
165 core->videoLogger = NULL;
166 gbacore->overrides = NULL;
167 gbacore->debuggerPlatform = NULL;
168 gbacore->cheatDevice = NULL;
169 gbacore->logContext = NULL;
170 gbacore->audioMixer = NULL;
171
172 GBACreate(gba);
173 // TODO: Restore cheats
174 memset(gbacore->components, 0, sizeof(gbacore->components));
175 ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
176 ARMInit(cpu);
177 mRTCGenericSourceInit(&core->rtc, core);
178 gba->rtcSource = &core->rtc.d;
179
180 GBAVideoSoftwareRendererCreate(&gbacore->renderer);
181 gbacore->renderer.outputBuffer = NULL;
182
183#ifdef BUILD_GLES2
184 GBAVideoGLRendererCreate(&gbacore->glRenderer);
185 gbacore->glRenderer.outputTex = -1;
186#endif
187
188#ifndef DISABLE_THREADING
189 mVideoThreadProxyCreate(&gbacore->threadProxy);
190#endif
191 gbacore->proxyRenderer.logger = NULL;
192
193 gbacore->keys = 0;
194 gba->keySource = &gbacore->keys;
195
196#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
197 mDirectorySetInit(&core->dirs);
198#endif
199
200 return true;
201}
202
203static void _GBACoreDeinit(struct mCore* core) {
204 ARMDeinit(core->cpu);
205 GBADestroy(core->board);
206 mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
207 mappedMemoryFree(core->board, sizeof(struct GBA));
208#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
209 mDirectorySetDeinit(&core->dirs);
210#endif
211
212 struct GBACore* gbacore = (struct GBACore*) core;
213 free(gbacore->debuggerPlatform);
214 if (gbacore->cheatDevice) {
215 mCheatDeviceDestroy(gbacore->cheatDevice);
216 }
217 free(gbacore->cheatDevice);
218 free(gbacore->audioMixer);
219 mCoreConfigFreeOpts(&core->opts);
220 free(core);
221}
222
223static enum mPlatform _GBACorePlatform(const struct mCore* core) {
224 UNUSED(core);
225 return PLATFORM_GBA;
226}
227
228static bool _GBACoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) {
229 UNUSED(core);
230 switch (feature) {
231 case mCORE_FEATURE_OPENGL:
232#ifdef BUILD_GLES2
233 return true;
234#else
235 return false;
236#endif
237 default:
238 return false;
239 }
240}
241
242static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
243 struct GBA* gba = core->board;
244 gba->sync = sync;
245}
246
247static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
248 struct GBA* gba = core->board;
249 if (core->opts.mute) {
250 gba->audio.masterVolume = 0;
251 } else {
252 gba->audio.masterVolume = core->opts.volume;
253 }
254 gba->video.frameskip = core->opts.frameskip;
255
256#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
257 struct GBACore* gbacore = (struct GBACore*) core;
258 gbacore->overrides = mCoreConfigGetOverridesConst(config);
259#endif
260
261 const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
262 if (idleOptimization) {
263 if (strcasecmp(idleOptimization, "ignore") == 0) {
264 gba->idleOptimization = IDLE_LOOP_IGNORE;
265 } else if (strcasecmp(idleOptimization, "remove") == 0) {
266 gba->idleOptimization = IDLE_LOOP_REMOVE;
267 } else if (strcasecmp(idleOptimization, "detect") == 0) {
268 if (gba->idleLoop == IDLE_LOOP_NONE) {
269 gba->idleOptimization = IDLE_LOOP_DETECT;
270 } else {
271 gba->idleOptimization = IDLE_LOOP_REMOVE;
272 }
273 }
274 }
275
276 int fakeBool = 0;
277 mCoreConfigGetIntValue(config, "allowOpposingDirections", &fakeBool);
278 gba->allowOpposingDirections = fakeBool;
279
280 mCoreConfigCopyValue(&core->config, config, "allowOpposingDirections");
281 mCoreConfigCopyValue(&core->config, config, "gba.bios");
282 mCoreConfigCopyValue(&core->config, config, "gba.audioHle");
283
284#ifndef DISABLE_THREADING
285 mCoreConfigCopyValue(&core->config, config, "threadedVideo");
286#endif
287 mCoreConfigCopyValue(&core->config, config, "hwaccelVideo");
288 mCoreConfigCopyValue(&core->config, config, "videoScale");
289}
290
291static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
292#ifdef BUILD_GLES2
293 struct GBACore* gbacore = (struct GBACore*) core;
294 int scale = gbacore->glRenderer.scale;
295#else
296 int scale = 1;
297#endif
298
299 *width = GBA_VIDEO_HORIZONTAL_PIXELS * scale;
300 *height = GBA_VIDEO_VERTICAL_PIXELS * scale;
301}
302
303static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
304 struct GBACore* gbacore = (struct GBACore*) core;
305 gbacore->renderer.outputBuffer = buffer;
306 gbacore->renderer.outputBufferStride = stride;
307 memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty));
308}
309
310static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) {
311#ifdef BUILD_GLES2
312 struct GBACore* gbacore = (struct GBACore*) core;
313 gbacore->glRenderer.outputTex = texid;
314#else
315 UNUSED(core);
316 UNUSED(texid);
317#endif
318}
319
320static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
321 struct GBA* gba = core->board;
322 gba->video.renderer->getPixels(gba->video.renderer, stride, buffer);
323}
324
325static void _GBACorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
326 struct GBA* gba = core->board;
327 gba->video.renderer->putPixels(gba->video.renderer, stride, buffer);
328}
329
330static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
331 struct GBA* gba = core->board;
332 switch (ch) {
333 case 0:
334 return gba->audio.psg.left;
335 case 1:
336 return gba->audio.psg.right;
337 default:
338 return NULL;
339 }
340}
341
342static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
343 struct GBA* gba = core->board;
344 GBAAudioResizeBuffer(&gba->audio, samples);
345}
346
347static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
348 struct GBA* gba = core->board;
349 return gba->audio.samples;
350}
351
352static void _GBACoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
353 struct GBA* gba = core->board;
354 *mCoreCallbacksListAppend(&gba->coreCallbacks) = *coreCallbacks;
355}
356
357static void _GBACoreClearCoreCallbacks(struct mCore* core) {
358 struct GBA* gba = core->board;
359 mCoreCallbacksListClear(&gba->coreCallbacks);
360}
361
362static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
363 struct GBA* gba = core->board;
364 gba->stream = stream;
365 if (stream && stream->videoDimensionsChanged) {
366 unsigned width, height;
367 core->desiredVideoDimensions(core, &width, &height);
368 stream->videoDimensionsChanged(stream, width, height);
369 }
370}
371
372static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
373#ifdef USE_ELF
374 struct ELF* elf = ELFOpen(vf);
375 if (elf) {
376 GBALoadNull(core->board);
377 bool success = mCoreLoadELF(core, elf);
378 ELFClose(elf);
379 return success;
380 }
381#endif
382 if (GBAIsMB(vf)) {
383 return GBALoadMB(core->board, vf);
384 }
385 return GBALoadROM(core->board, vf);
386}
387
388static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
389 UNUSED(type);
390 if (!GBAIsBIOS(vf)) {
391 return false;
392 }
393 GBALoadBIOS(core->board, vf);
394 return true;
395}
396
397static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
398 return GBALoadSave(core->board, vf);
399}
400
401static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
402 struct GBA* gba = core->board;
403 GBASavedataMask(&gba->memory.savedata, vf, false);
404 return true; // TODO: Return a real value
405}
406
407static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
408 if (!vf) {
409 return false;
410 }
411 struct Patch patch;
412 if (!loadPatch(vf, &patch)) {
413 return false;
414 }
415 GBAApplyPatch(core->board, &patch);
416 return true;
417}
418
419static void _GBACoreUnloadROM(struct mCore* core) {
420 struct GBACore* gbacore = (struct GBACore*) core;
421 struct ARMCore* cpu = core->cpu;
422 if (gbacore->cheatDevice) {
423 ARMHotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
424 cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
425 mCheatDeviceDestroy(gbacore->cheatDevice);
426 gbacore->cheatDevice = NULL;
427 }
428 return GBAUnloadROM(core->board);
429}
430
431static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
432 struct GBA* gba = (struct GBA*) core->board;
433 switch (type) {
434 case CHECKSUM_CRC32:
435 memcpy(data, &gba->romCrc32, sizeof(gba->romCrc32));
436 break;
437 }
438 return;
439}
440
441static void _GBACoreReset(struct mCore* core) {
442 struct GBACore* gbacore = (struct GBACore*) core;
443 struct GBA* gba = (struct GBA*) core->board;
444 if (gbacore->renderer.outputBuffer
445#ifdef BUILD_GLES2
446 || gbacore->glRenderer.outputTex != (unsigned) -1
447#endif
448 ) {
449 struct GBAVideoRenderer* renderer;
450 if (gbacore->renderer.outputBuffer) {
451 renderer = &gbacore->renderer.d;
452 }
453 int fakeBool;
454#ifdef BUILD_GLES2
455 if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
456 renderer = &gbacore->glRenderer.d;
457 mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);
458 }
459#endif
460#ifndef DISABLE_THREADING
461 if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) {
462 if (!core->videoLogger) {
463 core->videoLogger = &gbacore->threadProxy.d;
464 }
465 }
466#endif
467 if (core->videoLogger) {
468 gbacore->proxyRenderer.logger = core->videoLogger;
469 GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, renderer);
470 renderer = &gbacore->proxyRenderer.d;
471 }
472 GBAVideoAssociateRenderer(&gba->video, renderer);
473 }
474
475#ifndef MINIMAL_CORE
476 int useAudioMixer;
477 if (!gbacore->audioMixer && mCoreConfigGetIntValue(&core->config, "gba.audioHle", &useAudioMixer) && useAudioMixer) {
478 gbacore->audioMixer = malloc(sizeof(*gbacore->audioMixer));
479 GBAAudioMixerCreate(gbacore->audioMixer);
480 ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_AUDIO_MIXER] = &gbacore->audioMixer->d;
481 ARMHotplugAttach(core->cpu, CPU_COMPONENT_AUDIO_MIXER);
482 }
483#endif
484
485 GBAOverrideApplyDefaults(gba, gbacore->overrides);
486
487#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
488 if (!gba->biosVf && core->opts.useBios) {
489 struct VFile* bios = NULL;
490 bool found = false;
491 if (core->opts.bios) {
492 bios = VFileOpen(core->opts.bios, O_RDONLY);
493 if (bios && GBAIsBIOS(bios)) {
494 found = true;
495 } else if (bios) {
496 bios->close(bios);
497 bios = NULL;
498 }
499 }
500 if (!found) {
501 const char* configPath = mCoreConfigGetValue(&core->config, "gba.bios");
502 if (configPath) {
503 bios = VFileOpen(configPath, O_RDONLY);
504 }
505 if (bios && GBAIsBIOS(bios)) {
506 found = true;
507 } else if (bios) {
508 bios->close(bios);
509 bios = NULL;
510 }
511 }
512 if (!found) {
513 char path[PATH_MAX];
514 mCoreConfigDirectory(path, PATH_MAX);
515 strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path));
516 bios = VFileOpen(path, O_RDONLY);
517 if (bios && GBAIsBIOS(bios)) {
518 found = true;
519 } else if (bios) {
520 bios->close(bios);
521 bios = NULL;
522 }
523 }
524 if (bios) {
525 GBALoadBIOS(gba, bios);
526 }
527 }
528#endif
529
530 ARMReset(core->cpu);
531 if (core->opts.skipBios && (gba->romVf || gba->memory.rom)) {
532 GBASkipBIOS(core->board);
533 }
534}
535
536static void _GBACoreRunFrame(struct mCore* core) {
537 struct GBA* gba = core->board;
538 int32_t frameCounter = gba->video.frameCounter;
539 while (gba->video.frameCounter == frameCounter) {
540 ARMRunLoop(core->cpu);
541 }
542}
543
544static void _GBACoreRunLoop(struct mCore* core) {
545 ARMRunLoop(core->cpu);
546}
547
548static void _GBACoreStep(struct mCore* core) {
549 ARMRun(core->cpu);
550}
551
552static size_t _GBACoreStateSize(struct mCore* core) {
553 UNUSED(core);
554 return sizeof(struct GBASerializedState);
555}
556
557static bool _GBACoreLoadState(struct mCore* core, const void* state) {
558 return GBADeserialize(core->board, state);
559}
560
561static bool _GBACoreSaveState(struct mCore* core, void* state) {
562 GBASerialize(core->board, state);
563 return true;
564}
565
566static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
567 struct GBACore* gbacore = (struct GBACore*) core;
568 gbacore->keys = keys;
569 GBATestKeypadIRQ(core->board);
570}
571
572static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
573 struct GBACore* gbacore = (struct GBACore*) core;
574 gbacore->keys |= keys;
575 GBATestKeypadIRQ(core->board);
576}
577
578static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
579 struct GBACore* gbacore = (struct GBACore*) core;
580 gbacore->keys &= ~keys;
581}
582
583static int32_t _GBACoreFrameCounter(const struct mCore* core) {
584 const struct GBA* gba = core->board;
585 return gba->video.frameCounter;
586}
587
588static int32_t _GBACoreFrameCycles(const struct mCore* core) {
589 UNUSED(core);
590 return VIDEO_TOTAL_LENGTH;
591}
592
593static int32_t _GBACoreFrequency(const struct mCore* core) {
594 UNUSED(core);
595 return GBA_ARM7TDMI_FREQUENCY;
596}
597
598static void _GBACoreGetGameTitle(const struct mCore* core, char* title) {
599 GBAGetGameTitle(core->board, title);
600}
601
602static void _GBACoreGetGameCode(const struct mCore* core, char* title) {
603 GBAGetGameCode(core->board, title);
604}
605
606static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) {
607 struct GBA* gba = core->board;
608 switch (type) {
609 case mPERIPH_ROTATION:
610 gba->rotationSource = periph;
611 break;
612 case mPERIPH_RUMBLE:
613 gba->rumble = periph;
614 break;
615 case mPERIPH_GBA_LUMINANCE:
616 gba->luminanceSource = periph;
617 break;
618 case mPERIPH_GBA_BATTLECHIP_GATE:
619 GBASIOSetDriver(&gba->sio, periph, SIO_MULTI);
620 GBASIOSetDriver(&gba->sio, periph, SIO_NORMAL_32);
621 break;
622 default:
623 return;
624 }
625}
626
627static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
628 struct ARMCore* cpu = core->cpu;
629 return cpu->memory.load8(cpu, address, 0);
630}
631
632static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
633 struct ARMCore* cpu = core->cpu;
634 return cpu->memory.load16(cpu, address, 0);
635
636}
637
638static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
639 struct ARMCore* cpu = core->cpu;
640 return cpu->memory.load32(cpu, address, 0);
641}
642
643static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
644 struct ARMCore* cpu = core->cpu;
645 cpu->memory.store8(cpu, address, value, 0);
646}
647
648static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
649 struct ARMCore* cpu = core->cpu;
650 cpu->memory.store16(cpu, address, value, 0);
651}
652
653static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
654 struct ARMCore* cpu = core->cpu;
655 cpu->memory.store32(cpu, address, value, 0);
656}
657
658static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address, int segment) {
659 UNUSED(segment);
660 struct ARMCore* cpu = core->cpu;
661 return GBAView8(cpu, address);
662}
663
664static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address, int segment) {
665 UNUSED(segment);
666 struct ARMCore* cpu = core->cpu;
667 return GBAView16(cpu, address);
668}
669
670static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address, int segment) {
671 UNUSED(segment);
672 struct ARMCore* cpu = core->cpu;
673 return GBAView32(cpu, address);
674}
675
676static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
677 UNUSED(segment);
678 struct ARMCore* cpu = core->cpu;
679 GBAPatch8(cpu, address, value, NULL);
680}
681
682static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
683 UNUSED(segment);
684 struct ARMCore* cpu = core->cpu;
685 GBAPatch16(cpu, address, value, NULL);
686}
687
688static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
689 UNUSED(segment);
690 struct ARMCore* cpu = core->cpu;
691 GBAPatch32(cpu, address, value, NULL);
692}
693
694size_t _GBAListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) {
695 const struct GBA* gba = core->board;
696 switch (gba->memory.savedata.type) {
697 case SAVEDATA_SRAM:
698 *blocks = _GBAMemoryBlocksSRAM;
699 return sizeof(_GBAMemoryBlocksSRAM) / sizeof(*_GBAMemoryBlocksSRAM);
700 case SAVEDATA_FLASH512:
701 *blocks = _GBAMemoryBlocksFlash512;
702 return sizeof(_GBAMemoryBlocksFlash512) / sizeof(*_GBAMemoryBlocksFlash512);
703 case SAVEDATA_FLASH1M:
704 *blocks = _GBAMemoryBlocksFlash1M;
705 return sizeof(_GBAMemoryBlocksFlash1M) / sizeof(*_GBAMemoryBlocksFlash1M);
706 case SAVEDATA_EEPROM:
707 *blocks = _GBAMemoryBlocksEEPROM;
708 return sizeof(_GBAMemoryBlocksEEPROM) / sizeof(*_GBAMemoryBlocksEEPROM);
709 default:
710 *blocks = _GBAMemoryBlocks;
711 return sizeof(_GBAMemoryBlocks) / sizeof(*_GBAMemoryBlocks);
712 }
713}
714
715void* _GBAGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) {
716 struct GBA* gba = core->board;
717 switch (id) {
718 default:
719 return NULL;
720 case REGION_BIOS:
721 *sizeOut = SIZE_BIOS;
722 return gba->memory.bios;
723 case REGION_WORKING_RAM:
724 *sizeOut = SIZE_WORKING_RAM;
725 return gba->memory.wram;
726 case REGION_WORKING_IRAM:
727 *sizeOut = SIZE_WORKING_IRAM;
728 return gba->memory.iwram;
729 case REGION_PALETTE_RAM:
730 *sizeOut = SIZE_PALETTE_RAM;
731 return gba->video.palette;
732 case REGION_VRAM:
733 *sizeOut = SIZE_VRAM;
734 return gba->video.vram;
735 case REGION_OAM:
736 *sizeOut = SIZE_OAM;
737 return gba->video.oam.raw;
738 case REGION_CART0:
739 case REGION_CART1:
740 case REGION_CART2:
741 *sizeOut = gba->memory.romSize;
742 return gba->memory.rom;
743 case REGION_CART_SRAM:
744 if (gba->memory.savedata.type == SAVEDATA_FLASH1M) {
745 *sizeOut = SIZE_CART_FLASH1M;
746 return gba->memory.savedata.currentBank;
747 }
748 // Fall through
749 case REGION_CART_SRAM_MIRROR:
750 *sizeOut = GBASavedataSize(&gba->memory.savedata);
751 return gba->memory.savedata.data;
752 }
753}
754
755#ifdef USE_DEBUGGERS
756static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
757 UNUSED(core);
758 switch (type) {
759 case DEBUGGER_CLI:
760 return true;
761#ifdef USE_GDB_STUB
762 case DEBUGGER_GDB:
763 return true;
764#endif
765 default:
766 return false;
767 }
768}
769
770static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
771 struct GBACore* gbacore = (struct GBACore*) core;
772 if (!gbacore->debuggerPlatform) {
773 gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
774 }
775 return gbacore->debuggerPlatform;
776}
777
778static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
779 return &GBACLIDebuggerCreate(core)->d;
780}
781
782static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
783 if (core->debugger) {
784 GBADetachDebugger(core->board);
785 }
786 GBAAttachDebugger(core->board, debugger);
787 core->debugger = debugger;
788}
789
790static void _GBACoreDetachDebugger(struct mCore* core) {
791 GBADetachDebugger(core->board);
792 core->debugger = NULL;
793}
794
795static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
796 bool closeAfter = false;
797 core->symbolTable = mDebuggerSymbolTableCreate();
798#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
799#ifdef USE_ELF
800 if (!vf) {
801 closeAfter = true;
802 vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".elf", O_RDONLY);
803 }
804#endif
805 if (!vf) {
806 closeAfter = true;
807 vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY);
808 }
809#endif
810 if (!vf) {
811 return;
812 }
813#ifdef USE_ELF
814 struct ELF* elf = ELFOpen(vf);
815 if (elf) {
816#ifdef USE_DEBUGGERS
817 mCoreLoadELFSymbols(core->symbolTable, elf);
818#endif
819 ELFClose(elf);
820 } else
821#endif
822 {
823 mDebuggerLoadARMIPSSymbols(core->symbolTable, vf);
824 }
825 if (closeAfter) {
826 vf->close(vf);
827 }
828}
829
830static bool _GBACoreLookupIdentifier(struct mCore* core, const char* name, int32_t* value, int* segment) {
831 UNUSED(core);
832 *segment = -1;
833 int i;
834 for (i = 0; i < REG_MAX; i += 2) {
835 const char* reg = GBAIORegisterNames[i >> 1];
836 if (reg && strcasecmp(reg, name) == 0) {
837 *value = BASE_IO | i;
838 return true;
839 }
840 }
841 return false;
842}
843#endif
844
845static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) {
846 struct GBACore* gbacore = (struct GBACore*) core;
847 if (!gbacore->cheatDevice) {
848 gbacore->cheatDevice = GBACheatDeviceCreate();
849 ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d;
850 ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
851 gbacore->cheatDevice->p = core;
852 }
853 return gbacore->cheatDevice;
854}
855
856static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) {
857 struct GBA* gba = core->board;
858 size_t size = GBASavedataSize(&gba->memory.savedata);
859 if (!size) {
860 *sram = NULL;
861 return 0;
862 }
863 *sram = malloc(size);
864 struct VFile* vf = VFileFromMemory(*sram, size);
865 if (!vf) {
866 free(*sram);
867 *sram = NULL;
868 return 0;
869 }
870 bool success = GBASavedataClone(&gba->memory.savedata, vf);
871 vf->close(vf);
872 if (!success) {
873 free(*sram);
874 *sram = NULL;
875 return 0;
876 }
877 return size;
878}
879
880static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
881 struct VFile* vf = VFileMemChunk(sram, size);
882 if (!vf) {
883 return false;
884 }
885 struct GBA* gba = core->board;
886 bool success = true;
887 if (writeback) {
888 success = GBASavedataLoad(&gba->memory.savedata, vf);
889 vf->close(vf);
890 } else {
891 GBASavedataMask(&gba->memory.savedata, vf, true);
892 }
893 return success;
894}
895
896static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
897 UNUSED(core);
898 if (info) {
899 *info = _GBAVideoLayers;
900 }
901 return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
902}
903
904static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
905 UNUSED(core);
906 if (info) {
907 *info = _GBAAudioChannels;
908 }
909 return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
910}
911
912static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
913 struct GBA* gba = core->board;
914 switch (id) {
915 case 0:
916 case 1:
917 case 2:
918 case 3:
919 gba->video.renderer->disableBG[id] = !enable;
920 break;
921 case 4:
922 gba->video.renderer->disableOBJ = !enable;
923 break;
924 default:
925 break;
926 }
927}
928
929static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
930 struct GBA* gba = core->board;
931 switch (id) {
932 case 0:
933 case 1:
934 case 2:
935 case 3:
936 gba->audio.psg.forceDisableCh[id] = !enable;
937 break;
938 case 4:
939 gba->audio.forceDisableChA = !enable;
940 break;
941 case 5:
942 gba->audio.forceDisableChB = !enable;
943 break;
944 default:
945 break;
946 }
947}
948
949static void _GBACoreAdjustVideoLayer(struct mCore* core, size_t id, int32_t x, int32_t y) {
950 struct GBACore* gbacore = (struct GBACore*) core;
951 switch (id) {
952 case 0:
953 case 1:
954 case 2:
955 case 3:
956 gbacore->renderer.bg[id].offsetX = x;
957 gbacore->renderer.bg[id].offsetY = y;
958 break;
959 case 4:
960 gbacore->renderer.objOffsetX = x;
961 gbacore->renderer.objOffsetY = y;
962 gbacore->renderer.oamDirty = 1;
963 break;
964 default:
965 return;
966 }
967 memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty));
968}
969
970#ifndef MINIMAL_CORE
971static void _GBACoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
972 struct GBACore* gbacore = (struct GBACore*) core;
973 struct GBA* gba = core->board;
974 gbacore->logContext = context;
975
976 struct GBASerializedState* state = mVideoLogContextInitialState(context, NULL);
977 state->id = 0;
978 state->cpu.gprs[ARM_PC] = BASE_WORKING_RAM;
979
980 int channelId = mVideoLoggerAddChannel(context);
981 gbacore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
982 mVideoLoggerRendererCreate(gbacore->proxyRenderer.logger, false);
983 mVideoLoggerAttachChannel(gbacore->proxyRenderer.logger, context, channelId);
984 gbacore->proxyRenderer.logger->block = false;
985
986 GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, &gbacore->renderer.d);
987 GBAVideoProxyRendererShim(&gba->video, &gbacore->proxyRenderer);
988}
989
990static void _GBACoreEndVideoLog(struct mCore* core) {
991 struct GBACore* gbacore = (struct GBACore*) core;
992 struct GBA* gba = core->board;
993 GBAVideoProxyRendererUnshim(&gba->video, &gbacore->proxyRenderer);
994 free(gbacore->proxyRenderer.logger);
995 gbacore->proxyRenderer.logger = NULL;
996}
997#endif
998
999struct mCore* GBACoreCreate(void) {
1000 struct GBACore* gbacore = malloc(sizeof(*gbacore));
1001 struct mCore* core = &gbacore->d;
1002 memset(&core->opts, 0, sizeof(core->opts));
1003 core->cpu = NULL;
1004 core->board = NULL;
1005 core->debugger = NULL;
1006 core->init = _GBACoreInit;
1007 core->deinit = _GBACoreDeinit;
1008 core->platform = _GBACorePlatform;
1009 core->supportsFeature = _GBACoreSupportsFeature;
1010 core->setSync = _GBACoreSetSync;
1011 core->loadConfig = _GBACoreLoadConfig;
1012 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
1013 core->setVideoBuffer = _GBACoreSetVideoBuffer;
1014 core->setVideoGLTex = _GBACoreSetVideoGLTex;
1015 core->getPixels = _GBACoreGetPixels;
1016 core->putPixels = _GBACorePutPixels;
1017 core->getAudioChannel = _GBACoreGetAudioChannel;
1018 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
1019 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
1020 core->addCoreCallbacks = _GBACoreAddCoreCallbacks;
1021 core->clearCoreCallbacks = _GBACoreClearCoreCallbacks;
1022 core->setAVStream = _GBACoreSetAVStream;
1023 core->isROM = GBAIsROM;
1024 core->loadROM = _GBACoreLoadROM;
1025 core->loadBIOS = _GBACoreLoadBIOS;
1026 core->loadSave = _GBACoreLoadSave;
1027 core->loadTemporarySave = _GBACoreLoadTemporarySave;
1028 core->loadPatch = _GBACoreLoadPatch;
1029 core->unloadROM = _GBACoreUnloadROM;
1030 core->checksum = _GBACoreChecksum;
1031 core->reset = _GBACoreReset;
1032 core->runFrame = _GBACoreRunFrame;
1033 core->runLoop = _GBACoreRunLoop;
1034 core->step = _GBACoreStep;
1035 core->stateSize = _GBACoreStateSize;
1036 core->loadState = _GBACoreLoadState;
1037 core->saveState = _GBACoreSaveState;
1038 core->setKeys = _GBACoreSetKeys;
1039 core->addKeys = _GBACoreAddKeys;
1040 core->clearKeys = _GBACoreClearKeys;
1041 core->frameCounter = _GBACoreFrameCounter;
1042 core->frameCycles = _GBACoreFrameCycles;
1043 core->frequency = _GBACoreFrequency;
1044 core->getGameTitle = _GBACoreGetGameTitle;
1045 core->getGameCode = _GBACoreGetGameCode;
1046 core->setPeripheral = _GBACoreSetPeripheral;
1047 core->busRead8 = _GBACoreBusRead8;
1048 core->busRead16 = _GBACoreBusRead16;
1049 core->busRead32 = _GBACoreBusRead32;
1050 core->busWrite8 = _GBACoreBusWrite8;
1051 core->busWrite16 = _GBACoreBusWrite16;
1052 core->busWrite32 = _GBACoreBusWrite32;
1053 core->rawRead8 = _GBACoreRawRead8;
1054 core->rawRead16 = _GBACoreRawRead16;
1055 core->rawRead32 = _GBACoreRawRead32;
1056 core->rawWrite8 = _GBACoreRawWrite8;
1057 core->rawWrite16 = _GBACoreRawWrite16;
1058 core->rawWrite32 = _GBACoreRawWrite32;
1059 core->listMemoryBlocks = _GBAListMemoryBlocks;
1060 core->getMemoryBlock = _GBAGetMemoryBlock;
1061#ifdef USE_DEBUGGERS
1062 core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
1063 core->debuggerPlatform = _GBACoreDebuggerPlatform;
1064 core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
1065 core->attachDebugger = _GBACoreAttachDebugger;
1066 core->detachDebugger = _GBACoreDetachDebugger;
1067 core->loadSymbols = _GBACoreLoadSymbols;
1068 core->lookupIdentifier = _GBACoreLookupIdentifier;
1069#endif
1070 core->cheatDevice = _GBACoreCheatDevice;
1071 core->savedataClone = _GBACoreSavedataClone;
1072 core->savedataRestore = _GBACoreSavedataRestore;
1073 core->listVideoLayers = _GBACoreListVideoLayers;
1074 core->listAudioChannels = _GBACoreListAudioChannels;
1075 core->enableVideoLayer = _GBACoreEnableVideoLayer;
1076 core->enableAudioChannel = _GBACoreEnableAudioChannel;
1077 core->adjustVideoLayer = _GBACoreAdjustVideoLayer;
1078#ifndef MINIMAL_CORE
1079 core->startVideoLog = _GBACoreStartVideoLog;
1080 core->endVideoLog = _GBACoreEndVideoLog;
1081#endif
1082 return core;
1083}
1084
1085#ifndef MINIMAL_CORE
1086static void _GBAVLPStartFrameCallback(void *context) {
1087 struct mCore* core = context;
1088 struct GBACore* gbacore = (struct GBACore*) core;
1089 struct GBA* gba = core->board;
1090
1091 if (!mVideoLoggerRendererRun(gbacore->proxyRenderer.logger, true)) {
1092 GBAVideoProxyRendererUnshim(&gba->video, &gbacore->proxyRenderer);
1093 mVideoLogContextRewind(gbacore->logContext, core);
1094 GBAVideoProxyRendererShim(&gba->video, &gbacore->proxyRenderer);
1095 }
1096}
1097
1098static bool _GBAVLPInit(struct mCore* core) {
1099 struct GBACore* gbacore = (struct GBACore*) core;
1100 if (!_GBACoreInit(core)) {
1101 return false;
1102 }
1103 gbacore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
1104 mVideoLoggerRendererCreate(gbacore->proxyRenderer.logger, true);
1105 GBAVideoProxyRendererCreate(&gbacore->proxyRenderer, NULL);
1106 memset(&gbacore->logCallbacks, 0, sizeof(gbacore->logCallbacks));
1107 gbacore->logCallbacks.videoFrameStarted = _GBAVLPStartFrameCallback;
1108 gbacore->logCallbacks.context = core;
1109 core->addCoreCallbacks(core, &gbacore->logCallbacks);
1110 return true;
1111}
1112
1113static void _GBAVLPDeinit(struct mCore* core) {
1114 struct GBACore* gbacore = (struct GBACore*) core;
1115 if (gbacore->logContext) {
1116 mVideoLogContextDestroy(core, gbacore->logContext);
1117 }
1118 _GBACoreDeinit(core);
1119}
1120
1121static void _GBAVLPReset(struct mCore* core) {
1122 struct GBACore* gbacore = (struct GBACore*) core;
1123 struct GBA* gba = (struct GBA*) core->board;
1124 if (gba->video.renderer == &gbacore->proxyRenderer.d) {
1125 GBAVideoProxyRendererUnshim(&gba->video, &gbacore->proxyRenderer);
1126 } else if (gbacore->renderer.outputBuffer) {
1127 struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
1128 GBAVideoAssociateRenderer(&gba->video, renderer);
1129 }
1130
1131 ARMReset(core->cpu);
1132 mVideoLogContextRewind(gbacore->logContext, core);
1133 GBAVideoProxyRendererShim(&gba->video, &gbacore->proxyRenderer);
1134
1135 // Make sure CPU loop never spins
1136 GBAHalt(gba);
1137 gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL);
1138 gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL);
1139}
1140
1141static bool _GBAVLPLoadROM(struct mCore* core, struct VFile* vf) {
1142 struct GBACore* gbacore = (struct GBACore*) core;
1143 gbacore->logContext = mVideoLogContextCreate(NULL);
1144 if (!mVideoLogContextLoad(gbacore->logContext, vf)) {
1145 mVideoLogContextDestroy(core, gbacore->logContext);
1146 gbacore->logContext = NULL;
1147 return false;
1148 }
1149 mVideoLoggerAttachChannel(gbacore->proxyRenderer.logger, gbacore->logContext, 0);
1150 return true;
1151}
1152
1153static bool _GBAVLPLoadState(struct mCore* core, const void* state) {
1154 struct GBA* gba = (struct GBA*) core->board;
1155
1156 gba->timing.root = NULL;
1157 gba->cpu->gprs[ARM_PC] = BASE_WORKING_RAM;
1158 gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
1159
1160 // Make sure CPU loop never spins
1161 GBAHalt(gba);
1162 gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL);
1163 gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL);
1164 GBAVideoDeserialize(&gba->video, state);
1165 GBAIODeserialize(gba, state);
1166 GBAAudioReset(&gba->audio);
1167
1168 return true;
1169}
1170
1171static bool _returnTrue(struct VFile* vf) {
1172 UNUSED(vf);
1173 return true;
1174}
1175
1176struct mCore* GBAVideoLogPlayerCreate(void) {
1177 struct mCore* core = GBACoreCreate();
1178 core->init = _GBAVLPInit;
1179 core->deinit = _GBAVLPDeinit;
1180 core->reset = _GBAVLPReset;
1181 core->loadROM = _GBAVLPLoadROM;
1182 core->loadState = _GBAVLPLoadState;
1183 core->isROM = _returnTrue;
1184 return core;
1185}
1186#else
1187struct mCore* GBAVideoLogPlayerCreate(void) {
1188 return false;
1189}
1190#endif