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