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/context/overrides.h"
12#include "gba/renderers/video-software.h"
13#include "gba/serialize.h"
14#include "util/memory.h"
15#include "util/patch.h"
16#include "util/vfs.h"
17
18struct GBACore {
19 struct mCore d;
20 struct GBAVideoSoftwareRenderer renderer;
21 int keys;
22 struct mCPUComponent* components[GBA_COMPONENT_MAX];
23 const struct Configuration* overrides;
24};
25
26static bool _GBACoreInit(struct mCore* core) {
27 struct GBACore* gbacore = (struct GBACore*) core;
28
29 struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
30 struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
31 if (!cpu || !gba) {
32 free(cpu);
33 free(gba);
34 return false;
35 }
36 core->cpu = cpu;
37 core->board = gba;
38 gbacore->overrides = 0;
39
40 GBACreate(gba);
41 // TODO: Restore debugger and cheats
42 memset(gbacore->components, 0, sizeof(gbacore->components));
43 ARMSetComponents(cpu, &gba->d, GBA_COMPONENT_MAX, gbacore->components);
44 ARMInit(cpu);
45
46 GBAVideoSoftwareRendererCreate(&gbacore->renderer);
47
48 gba->keySource = &gbacore->keys;
49
50#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
51 mDirectorySetInit(&core->dirs);
52#endif
53
54 return true;
55}
56
57static void _GBACoreDeinit(struct mCore* core) {
58 ARMDeinit(core->cpu);
59 GBADestroy(core->board);
60 mappedMemoryFree(core->cpu, sizeof(struct ARMCore));
61 mappedMemoryFree(core->board, sizeof(struct GBA));
62#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
63 mDirectorySetDeinit(&core->dirs);
64#endif
65}
66
67static enum mPlatform _GBACorePlatform(struct mCore* core) {
68 UNUSED(core);
69 return PLATFORM_GBA;
70}
71
72static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
73 struct GBA* gba = core->board;
74 gba->sync = sync;
75}
76
77static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
78 struct GBA* gba = core->board;
79
80#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
81 struct GBACore* gbacore = (struct GBACore*) core;
82 gbacore->overrides = mCoreConfigGetOverridesConst(config);
83
84 struct VFile* bios = 0;
85 if (core->opts.useBios) {
86 bios = VFileOpen(core->opts.bios, O_RDONLY);
87 }
88 if (bios) {
89 GBALoadBIOS(gba, bios);
90 }
91#endif
92
93 const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization");
94 if (idleOptimization) {
95 if (strcasecmp(idleOptimization, "ignore") == 0) {
96 gba->idleOptimization = IDLE_LOOP_IGNORE;
97 } else if (strcasecmp(idleOptimization, "remove") == 0) {
98 gba->idleOptimization = IDLE_LOOP_REMOVE;
99 } else if (strcasecmp(idleOptimization, "detect") == 0) {
100 gba->idleOptimization = IDLE_LOOP_DETECT;
101 }
102 }
103}
104
105static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
106 UNUSED(core);
107 *width = VIDEO_HORIZONTAL_PIXELS;
108 *height = VIDEO_VERTICAL_PIXELS;
109}
110
111static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
112 struct GBACore* gbacore = (struct GBACore*) core;
113 gbacore->renderer.outputBuffer = buffer;
114 gbacore->renderer.outputBufferStride = stride;
115}
116
117static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
118 struct GBACore* gbacore = (struct GBACore*) core;
119 *buffer = gbacore->renderer.outputBuffer;
120 *stride = gbacore->renderer.outputBufferStride;
121}
122
123static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) {
124 struct GBA* gba = core->board;
125 switch (ch) {
126 case 0:
127 return gba->audio.psg.left;
128 case 1:
129 return gba->audio.psg.right;
130 default:
131 return NULL;
132 }
133}
134
135static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) {
136 struct GBA* gba = core->board;
137 GBAAudioResizeBuffer(&gba->audio, samples);
138}
139
140static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
141 struct GBA* gba = core->board;
142 return gba->audio.samples;
143}
144
145static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
146 struct GBA* gba = core->board;
147 gba->stream = stream;
148}
149
150static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
151 return GBALoadROM2(core->board, vf);
152}
153
154static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
155 UNUSED(type);
156 if (!GBAIsBIOS(vf)) {
157 return false;
158 }
159 GBALoadBIOS(core->board, vf);
160 return true;
161}
162
163static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) {
164 return GBALoadSave(core->board, vf);
165}
166
167static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) {
168 if (!vf) {
169 return false;
170 }
171 struct Patch patch;
172 if (!loadPatch(vf, &patch)) {
173 return false;
174 }
175 GBAApplyPatch(core->board, &patch);
176 return true;
177}
178
179static void _GBACoreUnloadROM(struct mCore* core) {
180 return GBAUnloadROM(core->board);
181}
182
183static void _GBACoreReset(struct mCore* core) {
184 struct GBACore* gbacore = (struct GBACore*) core;
185 struct GBA* gba = (struct GBA*) core->board;
186 if (gbacore->renderer.outputBuffer) {
187 GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d);
188 }
189 ARMReset(core->cpu);
190 if (core->opts.skipBios) {
191 GBASkipBIOS(core->board);
192 }
193
194 struct GBACartridgeOverride override;
195 const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
196 memcpy(override.id, &cart->id, sizeof(override.id));
197 if (GBAOverrideFind(gbacore->overrides, &override)) {
198 GBAOverrideApply(gba, &override);
199 }
200}
201
202static void _GBACoreRunFrame(struct mCore* core) {
203 struct GBA* gba = core->board;
204 int32_t frameCounter = gba->video.frameCounter;
205 while (gba->video.frameCounter == frameCounter) {
206 ARMRunLoop(core->cpu);
207 }
208}
209
210static void _GBACoreRunLoop(struct mCore* core) {
211 ARMRunLoop(core->cpu);
212}
213
214static void _GBACoreStep(struct mCore* core) {
215 ARMRun(core->cpu);
216}
217
218static bool _GBACoreLoadState(struct mCore* core, struct VFile* vf, int flags) {
219 return GBALoadStateNamed(core->board, vf, flags);
220}
221
222static bool _GBACoreSaveState(struct mCore* core, struct VFile* vf, int flags) {
223 return GBASaveStateNamed(core->board, vf, flags);
224}
225
226static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
227 struct GBACore* gbacore = (struct GBACore*) core;
228 gbacore->keys = keys;
229}
230
231static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
232 struct GBACore* gbacore = (struct GBACore*) core;
233 gbacore->keys |= keys;
234}
235
236static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
237 struct GBACore* gbacore = (struct GBACore*) core;
238 gbacore->keys &= ~keys;
239}
240
241static int32_t _GBACoreFrameCounter(struct mCore* core) {
242 struct GBA* gba = core->board;
243 return gba->video.frameCounter;
244}
245
246static int32_t _GBACoreFrameCycles(struct mCore* core) {
247 UNUSED(core);
248 return VIDEO_TOTAL_LENGTH;
249}
250
251static int32_t _GBACoreFrequency(struct mCore* core) {
252 UNUSED(core);
253 return GBA_ARM7TDMI_FREQUENCY;
254}
255
256static void _GBACoreGetGameTitle(struct mCore* core, char* title) {
257 GBAGetGameTitle(core->board, title);
258}
259
260static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
261 struct GBA* gba = core->board;
262 gba->rtcSource = rtc;
263}
264
265struct mCore* GBACoreCreate(void) {
266 struct GBACore* gbacore = malloc(sizeof(*gbacore));
267 struct mCore* core = &gbacore->d;
268 memset(&core->opts, 0, sizeof(core->opts));
269 core->cpu = 0;
270 core->board = 0;
271 core->init = _GBACoreInit;
272 core->deinit = _GBACoreDeinit;
273 core->platform = _GBACorePlatform;
274 core->setSync = _GBACoreSetSync;
275 core->loadConfig = _GBACoreLoadConfig;
276 core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
277 core->setVideoBuffer = _GBACoreSetVideoBuffer;
278 core->getVideoBuffer = _GBACoreGetVideoBuffer;
279 core->getAudioChannel = _GBACoreGetAudioChannel;
280 core->setAudioBufferSize = _GBACoreSetAudioBufferSize;
281 core->getAudioBufferSize = _GBACoreGetAudioBufferSize;
282 core->setAVStream = _GBACoreSetAVStream;
283 core->isROM = GBAIsROM;
284 core->loadROM = _GBACoreLoadROM;
285 core->loadBIOS = _GBACoreLoadBIOS;
286 core->loadSave = _GBACoreLoadSave;
287 core->loadPatch = _GBACoreLoadPatch;
288 core->unloadROM = _GBACoreUnloadROM;
289 core->reset = _GBACoreReset;
290 core->runFrame = _GBACoreRunFrame;
291 core->runLoop = _GBACoreRunLoop;
292 core->step = _GBACoreStep;
293 core->loadState = _GBACoreLoadState;
294 core->saveState = _GBACoreSaveState;
295 core->setKeys = _GBACoreSetKeys;
296 core->addKeys = _GBACoreAddKeys;
297 core->clearKeys = _GBACoreClearKeys;
298 core->frameCounter = _GBACoreFrameCounter;
299 core->frameCycles = _GBACoreFrameCycles;
300 core->frequency = _GBACoreFrequency;
301 core->getGameTitle = _GBACoreGetGameTitle;
302 core->setRTC = _GBACoreSetRTC;
303 return core;
304}