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