src/gb/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 "gb/cheats.h"
10#include "gb/cli.h"
11#include "gb/gb.h"
12#include "gb/mbc.h"
13#include "gb/renderers/software.h"
14#include "gb/serialize.h"
15#include "lr35902/debugger/debugger.h"
16#include "util/memory.h"
17#include "util/patch.h"
18#include "util/vfs.h"
19
20struct GBCore {
21 struct mCore d;
22 struct GBVideoSoftwareRenderer renderer;
23 uint8_t keys;
24 struct mCPUComponent* components[CPU_COMPONENT_MAX];
25 struct mDebuggerPlatform* debuggerPlatform;
26 struct mCheatDevice* cheatDevice;
27};
28
29static bool _GBCoreInit(struct mCore* core) {
30 struct GBCore* gbcore = (struct GBCore*) core;
31
32 struct LR35902Core* cpu = anonymousMemoryMap(sizeof(struct LR35902Core));
33 struct GB* gb = anonymousMemoryMap(sizeof(struct GB));
34 if (!cpu || !gb) {
35 free(cpu);
36 free(gb);
37 return false;
38 }
39 core->cpu = cpu;
40 core->board = gb;
41 gbcore->debuggerPlatform = NULL;
42 gbcore->cheatDevice = NULL;
43
44 GBCreate(gb);
45 memset(gbcore->components, 0, sizeof(gbcore->components));
46 LR35902SetComponents(cpu, &gb->d, CPU_COMPONENT_MAX, gbcore->components);
47 LR35902Init(cpu);
48
49 GBVideoSoftwareRendererCreate(&gbcore->renderer);
50 gbcore->renderer.outputBuffer = NULL;
51
52 gbcore->keys = 0;
53 gb->keySource = &gbcore->keys;
54
55#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
56 mDirectorySetInit(&core->dirs);
57#endif
58
59 return true;
60}
61
62static void _GBCoreDeinit(struct mCore* core) {
63 LR35902Deinit(core->cpu);
64 GBDestroy(core->board);
65 mappedMemoryFree(core->cpu, sizeof(struct LR35902Core));
66 mappedMemoryFree(core->board, sizeof(struct GB));
67#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
68 mDirectorySetDeinit(&core->dirs);
69#endif
70
71 struct GBCore* gbcore = (struct GBCore*) core;
72 free(gbcore->debuggerPlatform);
73 if (gbcore->cheatDevice) {
74 mCheatDeviceDestroy(gbcore->cheatDevice);
75 }
76 free(gbcore->cheatDevice);
77 free(core);
78}
79
80static enum mPlatform _GBCorePlatform(struct mCore* core) {
81 UNUSED(core);
82 return PLATFORM_GB;
83}
84
85static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
86 struct GB* gb = core->board;
87 gb->sync = sync;
88}
89
90static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
91 UNUSED(config);
92
93 struct GB* gb = core->board;
94 if (core->opts.mute) {
95 gb->audio.masterVolume = 0;
96 } else {
97 gb->audio.masterVolume = core->opts.volume;
98 }
99 gb->video.frameskip = core->opts.frameskip;
100
101#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
102 struct VFile* bios = 0;
103 if (core->opts.useBios && core->opts.bios) {
104 bios = VFileOpen(core->opts.bios, O_RDONLY);
105 }
106 if (bios) {
107 GBLoadBIOS(gb, bios);
108 }
109#endif
110}
111
112static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
113 UNUSED(core);
114 *width = GB_VIDEO_HORIZONTAL_PIXELS;
115 *height = GB_VIDEO_VERTICAL_PIXELS;
116}
117
118static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
119 struct GBCore* gbcore = (struct GBCore*) core;
120 gbcore->renderer.outputBuffer = buffer;
121 gbcore->renderer.outputBufferStride = stride;
122}
123
124static void _GBCoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) {
125 struct GBCore* gbcore = (struct GBCore*) core;
126 *buffer = gbcore->renderer.outputBuffer;
127 *stride = gbcore->renderer.outputBufferStride;
128}
129
130static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
131 struct GB* gb = core->board;
132 switch (ch) {
133 case 0:
134 return gb->audio.left;
135 case 1:
136 return gb->audio.right;
137 default:
138 return NULL;
139 }
140}
141
142static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
143 struct GB* gb = core->board;
144 GBAudioResizeBuffer(&gb->audio, samples);
145}
146
147static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
148 struct GB* gb = core->board;
149 return gb->audio.samples;
150}
151
152static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
153 struct GB* gb = core->board;
154 gb->stream = stream;
155 if (stream && stream->videoDimensionsChanged) {
156 stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
157 }
158}
159
160static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
161 return GBLoadROM(core->board, vf);
162}
163
164static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
165 UNUSED(type);
166 GBLoadBIOS(core->board, vf);
167 return true;
168}
169
170static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) {
171 return GBLoadSave(core->board, vf);
172}
173
174static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
175 struct GB* gb = core->board;
176 GBSavedataMask(gb, vf);
177 return true; // TODO: Return a real value
178}
179
180static bool _GBCoreLoadPatch(struct mCore* core, struct VFile* vf) {
181 if (!vf) {
182 return false;
183 }
184 struct Patch patch;
185 if (!loadPatch(vf, &patch)) {
186 return false;
187 }
188 GBApplyPatch(core->board, &patch);
189 return true;
190}
191
192static void _GBCoreUnloadROM(struct mCore* core) {
193 return GBUnloadROM(core->board);
194}
195
196static void _GBCoreReset(struct mCore* core) {
197 struct GBCore* gbcore = (struct GBCore*) core;
198 struct GB* gb = (struct GB*) core->board;
199 if (gbcore->renderer.outputBuffer) {
200 GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d);
201 }
202 LR35902Reset(core->cpu);
203}
204
205static void _GBCoreRunFrame(struct mCore* core) {
206 struct GB* gb = core->board;
207 int32_t frameCounter = gb->video.frameCounter;
208 while (gb->video.frameCounter == frameCounter) {
209 LR35902Run(core->cpu);
210 }
211}
212
213static void _GBCoreRunLoop(struct mCore* core) {
214 LR35902Run(core->cpu);
215}
216
217static void _GBCoreStep(struct mCore* core) {
218 struct LR35902Core* cpu = core->cpu;
219 do {
220 LR35902Tick(cpu);
221 } while (cpu->executionState != LR35902_CORE_FETCH);
222}
223
224static size_t _GBCoreStateSize(struct mCore* core) {
225 UNUSED(core);
226 return sizeof(struct GBSerializedState);
227}
228
229static bool _GBCoreLoadState(struct mCore* core, const void* state) {
230 return GBDeserialize(core->board, state);
231}
232
233static bool _GBCoreSaveState(struct mCore* core, void* state) {
234 struct LR35902Core* cpu = core->cpu;
235 while (cpu->executionState != LR35902_CORE_FETCH) {
236 LR35902Tick(cpu);
237 }
238 GBSerialize(core->board, state);
239 return true;
240}
241
242static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) {
243 struct GBCore* gbcore = (struct GBCore*) core;
244 gbcore->keys = keys;
245}
246
247static void _GBCoreAddKeys(struct mCore* core, uint32_t keys) {
248 struct GBCore* gbcore = (struct GBCore*) core;
249 gbcore->keys |= keys;
250}
251
252static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) {
253 struct GBCore* gbcore = (struct GBCore*) core;
254 gbcore->keys &= ~keys;
255}
256
257static int32_t _GBCoreFrameCounter(struct mCore* core) {
258 struct GB* gb = core->board;
259 return gb->video.frameCounter;
260}
261
262static int32_t _GBCoreFrameCycles(struct mCore* core) {
263 UNUSED(core);
264 return GB_VIDEO_TOTAL_LENGTH;
265}
266
267static int32_t _GBCoreFrequency(struct mCore* core) {
268 UNUSED(core);
269 // TODO: GB differences
270 return DMG_LR35902_FREQUENCY;
271}
272
273static void _GBCoreGetGameTitle(struct mCore* core, char* title) {
274 GBGetGameTitle(core->board, title);
275}
276
277static void _GBCoreGetGameCode(struct mCore* core, char* title) {
278 GBGetGameCode(core->board, title);
279}
280
281static void _GBCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
282 struct GB* gb = core->board;
283 gb->memory.rtc = rtc;
284}
285
286static void _GBCoreSetRotation(struct mCore* core, struct mRotationSource* rotation) {
287 struct GB* gb = core->board;
288 gb->memory.rotation = rotation;
289}
290
291static void _GBCoreSetRumble(struct mCore* core, struct mRumble* rumble) {
292 struct GB* gb = core->board;
293 gb->memory.rumble = rumble;
294}
295
296static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
297 struct LR35902Core* cpu = core->cpu;
298 return cpu->memory.load8(cpu, address);
299}
300
301static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
302 struct LR35902Core* cpu = core->cpu;
303 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
304}
305
306static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
307 struct LR35902Core* cpu = core->cpu;
308 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
309 (cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
310}
311
312static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
313 struct LR35902Core* cpu = core->cpu;
314 cpu->memory.store8(cpu, address, value);
315}
316
317static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
318 struct LR35902Core* cpu = core->cpu;
319 cpu->memory.store8(cpu, address, value);
320 cpu->memory.store8(cpu, address + 1, value >> 8);
321}
322
323static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
324 struct LR35902Core* cpu = core->cpu;
325 cpu->memory.store8(cpu, address, value);
326 cpu->memory.store8(cpu, address + 1, value >> 8);
327 cpu->memory.store8(cpu, address + 2, value >> 16);
328 cpu->memory.store8(cpu, address + 3, value >> 24);
329}
330
331static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
332 struct LR35902Core* cpu = core->cpu;
333 return GBView8(cpu, address, segment);
334}
335
336static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
337 struct LR35902Core* cpu = core->cpu;
338 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8);
339}
340
341static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
342 struct LR35902Core* cpu = core->cpu;
343 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8) |
344 (GBView8(cpu, address + 2, segment) << 16) | (GBView8(cpu, address + 3, segment) << 24);
345}
346
347static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
348 struct LR35902Core* cpu = core->cpu;
349 GBPatch8(cpu, address, value, NULL);
350}
351
352static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
353 struct LR35902Core* cpu = core->cpu;
354 GBPatch8(cpu, address, value, NULL);
355 GBPatch8(cpu, address + 1, value >> 8, NULL);
356}
357
358static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
359 struct LR35902Core* cpu = core->cpu;
360 GBPatch8(cpu, address, value, NULL);
361 GBPatch8(cpu, address + 1, value >> 8, NULL);
362 GBPatch8(cpu, address + 2, value >> 16, NULL);
363 GBPatch8(cpu, address + 3, value >> 24, NULL);
364}
365
366static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
367 UNUSED(core);
368 switch (type) {
369#ifdef USE_CLI_DEBUGGER
370 case DEBUGGER_CLI:
371 return true;
372#endif
373 default:
374 return false;
375 }
376}
377
378static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
379 struct GBCore* gbcore = (struct GBCore*) core;
380 if (!gbcore->debuggerPlatform) {
381 gbcore->debuggerPlatform = LR35902DebuggerPlatformCreate();
382 }
383 return gbcore->debuggerPlatform;
384}
385
386static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) {
387#ifdef USE_CLI_DEBUGGER
388 return GBCLIDebuggerCreate(core);
389#else
390 UNUSED(core);
391 return NULL;
392#endif
393}
394
395static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
396 struct LR35902Core* cpu = core->cpu;
397 if (core->debugger) {
398 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
399 }
400 cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
401 LR35902HotplugAttach(cpu, CPU_COMPONENT_DEBUGGER);
402 core->debugger = debugger;
403}
404
405static void _GBCoreDetachDebugger(struct mCore* core) {
406 struct LR35902Core* cpu = core->cpu;
407 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
408 cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
409 core->debugger = NULL;
410}
411
412static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) {
413 struct GBCore* gbcore = (struct GBCore*) core;
414 if (!gbcore->cheatDevice) {
415 gbcore->cheatDevice = GBCheatDeviceCreate();
416 ((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d;
417 LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
418 gbcore->cheatDevice->p = core;
419 }
420 return gbcore->cheatDevice;
421}
422
423static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) {
424 struct GB* gb = core->board;
425 struct VFile* vf = gb->sramVf;
426 if (vf) {
427 *sram = malloc(vf->size(vf));
428 vf->seek(vf, 0, SEEK_SET);
429 return vf->read(vf, *sram, vf->size(vf));
430 }
431 *sram = malloc(gb->sramSize);
432 memcpy(*sram, gb->memory.sram, gb->sramSize);
433 return gb->sramSize;
434}
435
436static bool _GBCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) {
437 struct GB* gb = core->board;
438 struct VFile* vf = gb->sramVf;
439 if (vf) {
440 vf->seek(vf, 0, SEEK_SET);
441 return vf->write(vf, sram, size) > 0;
442 }
443 if (size > 0x20000) {
444 size = 0x20000;
445 }
446 GBResizeSram(gb, size);
447 memcpy(gb->memory.sram, sram, size);
448 return true;
449}
450
451struct mCore* GBCoreCreate(void) {
452 struct GBCore* gbcore = malloc(sizeof(*gbcore));
453 struct mCore* core = &gbcore->d;
454 memset(&core->opts, 0, sizeof(core->opts));
455 core->cpu = NULL;
456 core->board = NULL;
457 core->debugger = NULL;
458 core->init = _GBCoreInit;
459 core->deinit = _GBCoreDeinit;
460 core->platform = _GBCorePlatform;
461 core->setSync = _GBCoreSetSync;
462 core->loadConfig = _GBCoreLoadConfig;
463 core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
464 core->setVideoBuffer = _GBCoreSetVideoBuffer;
465 core->getVideoBuffer = _GBCoreGetVideoBuffer;
466 core->getAudioChannel = _GBCoreGetAudioChannel;
467 core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
468 core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
469 core->setAVStream = _GBCoreSetAVStream;
470 core->isROM = GBIsROM;
471 core->loadROM = _GBCoreLoadROM;
472 core->loadBIOS = _GBCoreLoadBIOS;
473 core->loadSave = _GBCoreLoadSave;
474 core->loadTemporarySave = _GBCoreLoadTemporarySave;
475 core->loadPatch = _GBCoreLoadPatch;
476 core->unloadROM = _GBCoreUnloadROM;
477 core->reset = _GBCoreReset;
478 core->runFrame = _GBCoreRunFrame;
479 core->runLoop = _GBCoreRunLoop;
480 core->step = _GBCoreStep;
481 core->stateSize = _GBCoreStateSize;
482 core->loadState = _GBCoreLoadState;
483 core->saveState = _GBCoreSaveState;
484 core->setKeys = _GBCoreSetKeys;
485 core->addKeys = _GBCoreAddKeys;
486 core->clearKeys = _GBCoreClearKeys;
487 core->frameCounter = _GBCoreFrameCounter;
488 core->frameCycles = _GBCoreFrameCycles;
489 core->frequency = _GBCoreFrequency;
490 core->getGameTitle = _GBCoreGetGameTitle;
491 core->getGameCode = _GBCoreGetGameCode;
492 core->setRTC = _GBCoreSetRTC;
493 core->setRotation = _GBCoreSetRotation;
494 core->setRumble = _GBCoreSetRumble;
495 core->busRead8 = _GBCoreBusRead8;
496 core->busRead16 = _GBCoreBusRead16;
497 core->busRead32 = _GBCoreBusRead32;
498 core->busWrite8 = _GBCoreBusWrite8;
499 core->busWrite16 = _GBCoreBusWrite16;
500 core->busWrite32 = _GBCoreBusWrite32;
501 core->rawRead8 = _GBCoreRawRead8;
502 core->rawRead16 = _GBCoreRawRead16;
503 core->rawRead32 = _GBCoreRawRead32;
504 core->rawWrite8 = _GBCoreRawWrite8;
505 core->rawWrite16 = _GBCoreRawWrite16;
506 core->rawWrite32 = _GBCoreRawWrite32;
507 core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
508 core->debuggerPlatform = _GBCoreDebuggerPlatform;
509 core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
510 core->attachDebugger = _GBCoreAttachDebugger;
511 core->detachDebugger = _GBCoreDetachDebugger;
512 core->cheatDevice = _GBCoreCheatDevice;
513 core->savedataClone = _GBCoreSavedataClone;
514 core->savedataLoad = _GBCoreSavedataLoad;
515 return core;
516}