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 "core.h"
7
8#include "core/core.h"
9#include "core/log.h"
10#include "gba/gba.h"
11#include "gba/extra/cli.h"
12#include "gba/overrides.h"
13#include "gba/renderers/video-software.h"
14#include "gba/serialize.h"
15#include "util/memory.h"
16#include "util/patch.h"
17#include "util/vfs.h"
18
19struct GBACore {
20 struct mCore d;
21 struct GBAVideoSoftwareRenderer renderer;
22 int keys;
23 struct mCPUComponent* components[CPU_COMPONENT_MAX];
24 const struct Configuration* overrides;
25 struct mDebuggerPlatform* debuggerPlatform;
26};
27
28static bool _GBACoreInit(struct mCore* core) {
29 struct GBACore* gbacore = (struct GBACore*) core;
30
31 struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
32 struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
33 if (!cpu || !gba) {
34 free(cpu);
35 free(gba);
36 return false;
37 }
38 core->cpu = cpu;
39 core->board = gba;
40 core->debugger = NULL;
41 gbacore->debuggerPlatform = NULL;
42 gbacore->overrides = 0;
43
44 GBACreate(gba);
45 // TODO: Restore cheats
46 memset(gbacore->components, 0, sizeof(gbacore->components));
47 ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components);
48 ARMInit(cpu);
49
50 GBAVideoSoftwareRendererCreate(&gbacore->renderer);
51 gbacore->renderer.outputBuffer = NULL;
52
53 gbacore->keys = 0;
54 gba->keySource = &gbacore->keys;
55
56#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
57 mDirectorySetInit(&core->dirs);
58#endif
59
60 return true;
61}
62
63static void _GBACoreDeinit(struct mCore* core) {
64 ARMDeinit(core->cpu);
65 GBADestroy(core->board);
66 mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
67 mappedMemoryFree(core->board, sizeof(struct GBA));
68#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
69 mDirectorySetDeinit(&core->dirs);
70#endif
71 free(core);
72}
73
74static enum mPlatform _GBACorePlatform(struct mCore* core) {
75 UNUSED(core);
76 return PLATFORM_GBA;
77}
78
79static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
80 struct GBA* gba = core->board;
81 gba->sync = sync;
82}
83
84static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
85 struct GBA* gba = core->board;
86 if (core->opts.mute) {
87 gba->audio.masterVolume = 0;
88 } else {
89 gba->audio.masterVolume = core->opts.volume;
90 }
91 gba->video.frameskip = core->opts.frameskip;
92
93#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
94 struct GBACore* gbacore = (struct GBACore*) core;
95 gbacore->overrides = mCoreConfigGetOverridesConst(config);
96
97 struct VFile* bios = 0;
98 if (core->opts.useBios && core->opts.bios) {
99 bios = VFileOpen(core->opts.bios, O_RDONLY);
100 }
101 if (bios) {
102 GBALoadBIOS(gba, bios);
103 }
104#endif
105
106 const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
107 if (idleOptimization) {
108 if (strcasecmp(idleOptimization, "ignore") == 0) {
109 gba->idleOptimization = IDLE_LOOP_IGNORE;
110 } else if (strcasecmp(idleOptimization, "remove") == 0) {
111 gba->idleOptimization = IDLE_LOOP_REMOVE;
112 } else if (strcasecmp(idleOptimization, "detect") == 0) {
113 gba->idleOptimization = IDLE_LOOP_DETECT;
114 }
115 }
116}
117
118static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
119 UNUSED(core);
120 *width = VIDEO_HORIZONTAL_PIXELS;
121 *height = VIDEO_VERTICAL_PIXELS;
122}
123
124static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
125 struct GBACore* gbacore = (struct GBACore*) core;
126 gbacore->renderer.outputBuffer = buffer;
127 gbacore->renderer.outputBufferStride = stride;
128}
129
130static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
131 struct GBACore* gbacore = (struct GBACore*) core;
132 *buffer = gbacore->renderer.outputBuffer;
133 *stride = gbacore->renderer.outputBufferStride;
134}
135
136static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
137 struct GBA* gba = core->board;
138 switch (ch) {
139 case 0:
140 return gba->audio.psg.left;
141 case 1:
142 return gba->audio.psg.right;
143 default:
144 return NULL;
145 }
146}
147
148static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
149 struct GBA* gba = core->board;
150 GBAAudioResizeBuffer(&gba->audio, samples);
151}
152
153static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
154 struct GBA* gba = core->board;
155 return gba->audio.samples;
156}
157
158static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
159 struct GBA* gba = core->board;
160 gba->stream = stream;
161 if (stream && stream->videoDimensionsChanged) {
162 stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
163 }
164}
165
166static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
167 return GBALoadROM(core->board, vf);
168}
169
170static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
171 UNUSED(type);
172 if (!GBAIsBIOS(vf)) {
173 return false;
174 }
175 GBALoadBIOS(core->board, vf);
176 return true;
177}
178
179static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
180 return GBALoadSave(core->board, vf);
181}
182
183static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
184 if (!vf) {
185 return false;
186 }
187 struct Patch patch;
188 if (!loadPatch(vf, &patch)) {
189 return false;
190 }
191 GBAApplyPatch(core->board, &patch);
192 return true;
193}
194
195static void _GBACoreUnloadROM(struct mCore* core) {
196 return GBAUnloadROM(core->board);
197}
198
199static void _GBACoreReset(struct mCore* core) {
200 struct GBACore* gbacore = (struct GBACore*) core;
201 struct GBA* gba = (struct GBA*) core->board;
202 if (gbacore->renderer.outputBuffer) {
203 GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
204 }
205 ARMReset(core->cpu);
206 if (core->opts.skipBios) {
207 GBASkipBIOS(core->board);
208 }
209
210 struct GBACartridgeOverride override;
211 const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
212 if (cart) {
213 memcpy(override.id, &cart->id, sizeof(override.id));
214 if (GBAOverrideFind(gbacore->overrides, &override)) {
215 GBAOverrideApply(gba, &override);
216 }
217 }
218}
219
220static void _GBACoreRunFrame(struct mCore* core) {
221 struct GBA* gba = core->board;
222 int32_t frameCounter = gba->video.frameCounter;
223 while (gba->video.frameCounter == frameCounter) {
224 ARMRunLoop(core->cpu);
225 }
226}
227
228static void _GBACoreRunLoop(struct mCore* core) {
229 ARMRunLoop(core->cpu);
230}
231
232static void _GBACoreStep(struct mCore* core) {
233 ARMRun(core->cpu);
234}
235
236static bool _GBACoreLoadState(struct mCore* core, struct VFile* vf, int flags) {
237 return GBALoadStateNamed(core->board, vf, flags);
238}
239
240static bool _GBACoreSaveState(struct mCore* core, struct VFile* vf, int flags) {
241 return GBASaveStateNamed(core->board, vf, flags);
242}
243
244static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
245 struct GBACore* gbacore = (struct GBACore*) core;
246 gbacore->keys = keys;
247}
248
249static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
250 struct GBACore* gbacore = (struct GBACore*) core;
251 gbacore->keys |= keys;
252}
253
254static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
255 struct GBACore* gbacore = (struct GBACore*) core;
256 gbacore->keys &= ~keys;
257}
258
259static int32_t _GBACoreFrameCounter(struct mCore* core) {
260 struct GBA* gba = core->board;
261 return gba->video.frameCounter;
262}
263
264static int32_t _GBACoreFrameCycles(struct mCore* core) {
265 UNUSED(core);
266 return VIDEO_TOTAL_LENGTH;
267}
268
269static int32_t _GBACoreFrequency(struct mCore* core) {
270 UNUSED(core);
271 return GBA_ARM7TDMI_FREQUENCY;
272}
273
274static void _GBACoreGetGameTitle(struct mCore* core, char* title) {
275 GBAGetGameTitle(core->board, title);
276}
277
278static void _GBACoreGetGameCode(struct mCore* core, char* title) {
279 GBAGetGameCode(core->board, title);
280}
281
282static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
283 struct GBA* gba = core->board;
284 gba->rtcSource = rtc;
285}
286
287static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
288 struct GBA* gba = core->board;
289 gba->rotationSource = rotation;
290}
291
292static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) {
293 struct GBA* gba = core->board;
294 gba->rumble = rumble;
295}
296
297static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) {
298 struct ARMCore* cpu = core->cpu;
299 return cpu->memory.load8(cpu, address, 0);
300}
301
302static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) {
303 struct ARMCore* cpu = core->cpu;
304 return cpu->memory.load16(cpu, address, 0);
305
306}
307
308static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) {
309 struct ARMCore* cpu = core->cpu;
310 return cpu->memory.load32(cpu, address, 0);
311}
312
313static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
314 struct ARMCore* cpu = core->cpu;
315 cpu->memory.store8(cpu, address, value, 0);
316}
317
318static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
319 struct ARMCore* cpu = core->cpu;
320 cpu->memory.store16(cpu, address, value, 0);
321}
322
323static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
324 struct ARMCore* cpu = core->cpu;
325 cpu->memory.store32(cpu, address, value, 0);
326}
327
328static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
329 UNUSED(core);
330 switch (type) {
331#ifdef USE_CLI_DEBUGGER
332 case DEBUGGER_CLI:
333 return true;
334#endif
335#ifdef USE_GDB_STUB
336 case DEBUGGER_GDB:
337 return true;
338#endif
339 default:
340 return false;
341 }
342}
343
344static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) {
345 struct GBACore* gbacore = (struct GBACore*) core;
346 if (!gbacore->debuggerPlatform) {
347 gbacore->debuggerPlatform = ARMDebuggerPlatformCreate();
348 }
349 return gbacore->debuggerPlatform;
350}
351
352static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) {
353#ifdef USE_CLI_DEBUGGER
354 return &GBACLIDebuggerCreate(core)->d;
355#else
356 UNUSED(core);
357 return NULL;
358#endif
359}
360
361static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
362 if (core->debugger) {
363 GBADetachDebugger(core->board);
364 }
365 GBAAttachDebugger(core->board, debugger);
366 core->debugger = debugger;
367}
368
369static void _GBACoreDetachDebugger(struct mCore* core) {
370 GBADetachDebugger(core->board);
371 core->debugger = NULL;
372}
373
374struct mCore* GBACoreCreate(void) {
375 struct GBACore* gbacore = malloc(sizeof(*gbacore));
376 struct mCore* core = &gbacore->d;
377 memset(&core->opts, 0, sizeof(core->opts));
378 core->cpu = NULL;
379 core->board = NULL;
380 core->debugger = NULL;
381 core->init = _GBACoreInit;
382 core->deinit = _GBACoreDeinit;
383 core->platform = _GBACorePlatform;
384 core->setSync = _GBACoreSetSync;
385 core->loadConfig = _GBACoreLoadConfig;
386 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
387 core->setVideoBuffer = _GBACoreSetVideoBuffer;
388 core->getVideoBuffer = _GBACoreGetVideoBuffer;
389 core->getAudioChannel = _GBACoreGetAudioChannel;
390 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
391 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
392 core->setAVStream = _GBACoreSetAVStream;
393 core->isROM = GBAIsROM;
394 core->loadROM = _GBACoreLoadROM;
395 core->loadBIOS = _GBACoreLoadBIOS;
396 core->loadSave = _GBACoreLoadSave;
397 core->loadPatch = _GBACoreLoadPatch;
398 core->unloadROM = _GBACoreUnloadROM;
399 core->reset = _GBACoreReset;
400 core->runFrame = _GBACoreRunFrame;
401 core->runLoop = _GBACoreRunLoop;
402 core->step = _GBACoreStep;
403 core->loadState = _GBACoreLoadState;
404 core->saveState = _GBACoreSaveState;
405 core->setKeys = _GBACoreSetKeys;
406 core->addKeys = _GBACoreAddKeys;
407 core->clearKeys = _GBACoreClearKeys;
408 core->frameCounter = _GBACoreFrameCounter;
409 core->frameCycles = _GBACoreFrameCycles;
410 core->frequency = _GBACoreFrequency;
411 core->getGameTitle = _GBACoreGetGameTitle;
412 core->getGameCode = _GBACoreGetGameCode;
413 core->setRTC = _GBACoreSetRTC;
414 core->setRotation = _GBACoreSetRotation;
415 core->setRumble = _GBACoreSetRumble;
416 core->busRead8 = _GBACoreBusRead8;
417 core->busRead16 = _GBACoreBusRead16;
418 core->busRead32 = _GBACoreBusRead32;
419 core->busWrite8 = _GBACoreBusWrite8;
420 core->busWrite16 = _GBACoreBusWrite16;
421 core->busWrite32 = _GBACoreBusWrite32;
422 core->supportsDebuggerType = _GBACoreSupportsDebuggerType;
423 core->debuggerPlatform = _GBACoreDebuggerPlatform;
424 core->cliDebuggerSystem = _GBACoreCliDebuggerSystem;
425 core->attachDebugger = _GBACoreAttachDebugger;
426 core->detachDebugger = _GBACoreDetachDebugger;
427 return core;
428}