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