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/debugger/symbols.h>
10#include <mgba/internal/gb/cheats.h>
11#include <mgba/internal/gb/debugger/symbols.h>
12#include <mgba/internal/gb/extra/cli.h>
13#include <mgba/internal/gb/io.h>
14#include <mgba/internal/gb/gb.h>
15#include <mgba/internal/gb/mbc.h>
16#include <mgba/internal/gb/overrides.h>
17#include <mgba/internal/gb/renderers/software.h>
18#include <mgba/internal/gb/renderers/proxy.h>
19#include <mgba/internal/gb/serialize.h>
20#include <mgba/internal/lr35902/lr35902.h>
21#include <mgba/internal/lr35902/debugger/debugger.h>
22#include <mgba-util/crc32.h>
23#include <mgba-util/memory.h>
24#include <mgba-util/patch.h>
25#include <mgba-util/vfs.h>
26
27static const struct mCoreChannelInfo _GBVideoLayers[] = {
28 { 0, "bg", "Background", NULL },
29 { 1, "obj", "Objects", NULL },
30 { 2, "win", "Window", NULL },
31};
32
33static const struct mCoreChannelInfo _GBAudioChannels[] = {
34 { 0, "ch1", "Channel 1", "Square/Sweep" },
35 { 1, "ch2", "Channel 2", "Square" },
36 { 2, "ch3", "Channel 3", "PCM" },
37 { 3, "ch4", "Channel 4", "Noise" },
38};
39
40static const struct LR35902Segment _GBSegments[] = {
41 { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
42 { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
43 { 0 }
44};
45
46static const struct LR35902Segment _GBCSegments[] = {
47 { .name = "ROM", .start = GB_BASE_CART_BANK1, .end = GB_BASE_VRAM },
48 { .name = "RAM", .start = GB_BASE_EXTERNAL_RAM, .end = GB_BASE_WORKING_RAM_BANK0 },
49 { .name = "WRAM", .start = GB_BASE_WORKING_RAM_BANK1, .end = 0xE000 },
50 { .name = "VRAM", .start = GB_BASE_VRAM, .end = GB_BASE_EXTERNAL_RAM },
51 { 0 }
52};
53
54static const struct mCoreMemoryBlock _GBMemoryBlocks[] = {
55 { -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
56 { GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
57 { GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
58 { GB_REGION_EXTERNAL_RAM, "sram", "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_BASE_EXTERNAL_RAM + GB_SIZE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM * 4, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 3 },
59 { GB_REGION_WORKING_RAM_BANK0, "wram", "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_BASE_WORKING_RAM_BANK0 + GB_SIZE_WORKING_RAM_BANK0 * 2 , GB_SIZE_WORKING_RAM_BANK0 * 2, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
60 { GB_BASE_OAM, "oam", "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_BASE_OAM + GB_SIZE_OAM, GB_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
61 { GB_BASE_IO, "io", "MMIO", "Memory-Mapped I/O", GB_BASE_IO, GB_BASE_IO + GB_SIZE_IO, GB_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
62 { GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
63};
64
65static const struct mCoreMemoryBlock _GBCMemoryBlocks[] = {
66 { -1, "mem", "All", "All", 0, 0x10000, 0x10000, mCORE_MEMORY_VIRTUAL },
67 { GB_REGION_CART_BANK0, "cart0", "ROM Bank", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2, 0x800000, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED, 511 },
68 { GB_REGION_VRAM, "vram", "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_BASE_VRAM + GB_SIZE_VRAM, GB_SIZE_VRAM * 2, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 },
69 { GB_REGION_EXTERNAL_RAM, "sram", "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_BASE_EXTERNAL_RAM + GB_SIZE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM * 4, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 3 },
70 { GB_REGION_WORKING_RAM_BANK0, "wram", "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_BASE_WORKING_RAM_BANK0 + GB_SIZE_WORKING_RAM_BANK0 * 2, GB_SIZE_WORKING_RAM_BANK0 * 8, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 7 },
71 { GB_BASE_OAM, "oam", "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_BASE_OAM + GB_SIZE_OAM, GB_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
72 { GB_BASE_IO, "io", "MMIO", "Memory-Mapped I/O", GB_BASE_IO, GB_BASE_IO + GB_SIZE_IO, GB_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
73 { GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED },
74};
75
76struct mVideoLogContext;
77struct GBCore {
78 struct mCore d;
79 struct GBVideoSoftwareRenderer renderer;
80 struct GBVideoProxyRenderer proxyRenderer;
81 struct mVideoLogContext* logContext;
82 struct mCoreCallbacks logCallbacks;
83 uint8_t keys;
84 struct mCPUComponent* components[CPU_COMPONENT_MAX];
85 const struct Configuration* overrides;
86 struct mDebuggerPlatform* debuggerPlatform;
87 struct mCheatDevice* cheatDevice;
88};
89
90static bool _GBCoreInit(struct mCore* core) {
91 struct GBCore* gbcore = (struct GBCore*) core;
92
93 struct LR35902Core* cpu = anonymousMemoryMap(sizeof(struct LR35902Core));
94 struct GB* gb = anonymousMemoryMap(sizeof(struct GB));
95 if (!cpu || !gb) {
96 free(cpu);
97 free(gb);
98 return false;
99 }
100 core->cpu = cpu;
101 core->board = gb;
102 gbcore->overrides = NULL;
103 gbcore->debuggerPlatform = NULL;
104 gbcore->cheatDevice = NULL;
105
106 GBCreate(gb);
107 memset(gbcore->components, 0, sizeof(gbcore->components));
108 LR35902SetComponents(cpu, &gb->d, CPU_COMPONENT_MAX, gbcore->components);
109 LR35902Init(cpu);
110 mRTCGenericSourceInit(&core->rtc, core);
111 gb->memory.rtc = &core->rtc.d;
112
113 GBVideoSoftwareRendererCreate(&gbcore->renderer);
114 gbcore->renderer.outputBuffer = NULL;
115
116 gbcore->keys = 0;
117 gb->keySource = &gbcore->keys;
118
119#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
120 mDirectorySetInit(&core->dirs);
121#endif
122
123 return true;
124}
125
126static void _GBCoreDeinit(struct mCore* core) {
127 LR35902Deinit(core->cpu);
128 GBDestroy(core->board);
129 mappedMemoryFree(core->cpu, sizeof(struct LR35902Core));
130 mappedMemoryFree(core->board, sizeof(struct GB));
131#if defined USE_DEBUGGERS && (!defined(MINIMAL_CORE) || MINIMAL_CORE < 2)
132 mDirectorySetDeinit(&core->dirs);
133 if (core->symbolTable) {
134 mDebuggerSymbolTableDestroy(core->symbolTable);
135 }
136#endif
137
138 struct GBCore* gbcore = (struct GBCore*) core;
139 free(gbcore->debuggerPlatform);
140 if (gbcore->cheatDevice) {
141 mCheatDeviceDestroy(gbcore->cheatDevice);
142 }
143 free(gbcore->cheatDevice);
144 mCoreConfigFreeOpts(&core->opts);
145 free(core);
146}
147
148static enum mPlatform _GBCorePlatform(const struct mCore* core) {
149 UNUSED(core);
150 return PLATFORM_GB;
151}
152
153static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
154 struct GB* gb = core->board;
155 gb->sync = sync;
156}
157
158static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) {
159 UNUSED(config);
160
161 struct GB* gb = core->board;
162 if (core->opts.mute) {
163 gb->audio.masterVolume = 0;
164 } else {
165 gb->audio.masterVolume = core->opts.volume;
166 }
167 gb->video.frameskip = core->opts.frameskip;
168
169 int color;
170 if (mCoreConfigGetIntValue(config, "gb.pal[0]", &color)) {
171 GBVideoSetPalette(&gb->video, 0, color);
172 }
173 if (mCoreConfigGetIntValue(config, "gb.pal[1]", &color)) {
174 GBVideoSetPalette(&gb->video, 1, color);
175 }
176 if (mCoreConfigGetIntValue(config, "gb.pal[2]", &color)) {
177 GBVideoSetPalette(&gb->video, 2, color);
178 }
179 if (mCoreConfigGetIntValue(config, "gb.pal[3]", &color)) {
180 GBVideoSetPalette(&gb->video, 3, color);
181 }
182
183 mCoreConfigCopyValue(&core->config, config, "gb.bios");
184 mCoreConfigCopyValue(&core->config, config, "sgb.bios");
185 mCoreConfigCopyValue(&core->config, config, "gbc.bios");
186 mCoreConfigCopyValue(&core->config, config, "gb.model");
187 mCoreConfigCopyValue(&core->config, config, "sgb.model");
188 mCoreConfigCopyValue(&core->config, config, "cgb.model");
189
190#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
191 struct GBCore* gbcore = (struct GBCore*) core;
192 gbcore->overrides = mCoreConfigGetOverridesConst(config);
193#endif
194}
195
196static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
197 struct GB* gb = core->board;
198 if (!gb || gb->model != GB_MODEL_SGB) {
199 *width = GB_VIDEO_HORIZONTAL_PIXELS;
200 *height = GB_VIDEO_VERTICAL_PIXELS;
201 } else {
202 *width = 256;
203 *height = 224;
204 }
205}
206
207static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
208 struct GBCore* gbcore = (struct GBCore*) core;
209 gbcore->renderer.outputBuffer = buffer;
210 gbcore->renderer.outputBufferStride = stride;
211}
212
213static void _GBCoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
214 struct GBCore* gbcore = (struct GBCore*) core;
215 gbcore->renderer.d.getPixels(&gbcore->renderer.d, stride, buffer);
216}
217
218static void _GBCorePutPixels(struct mCore* core, const void* buffer, size_t stride) {
219 struct GBCore* gbcore = (struct GBCore*) core;
220 gbcore->renderer.d.putPixels(&gbcore->renderer.d, stride, buffer);
221}
222
223static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
224 struct GB* gb = core->board;
225 switch (ch) {
226 case 0:
227 return gb->audio.left;
228 case 1:
229 return gb->audio.right;
230 default:
231 return NULL;
232 }
233}
234
235static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
236 struct GB* gb = core->board;
237 GBAudioResizeBuffer(&gb->audio, samples);
238}
239
240static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
241 struct GB* gb = core->board;
242 return gb->audio.samples;
243}
244
245static void _GBCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) {
246 struct GB* gb = core->board;
247 *mCoreCallbacksListAppend(&gb->coreCallbacks) = *coreCallbacks;
248}
249
250static void _GBCoreClearCoreCallbacks(struct mCore* core) {
251 struct GB* gb = core->board;
252 mCoreCallbacksListClear(&gb->coreCallbacks);
253}
254
255static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
256 struct GB* gb = core->board;
257 gb->stream = stream;
258 if (stream && stream->videoDimensionsChanged) {
259 stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
260 }
261}
262
263static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
264 return GBLoadROM(core->board, vf);
265}
266
267static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
268 UNUSED(type);
269 GBLoadBIOS(core->board, vf);
270 return true;
271}
272
273static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) {
274 return GBLoadSave(core->board, vf);
275}
276
277static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
278 struct GB* gb = core->board;
279 GBSavedataMask(gb, vf, false);
280 return true; // TODO: Return a real value
281}
282
283static bool _GBCoreLoadPatch(struct mCore* core, struct VFile* vf) {
284 if (!vf) {
285 return false;
286 }
287 struct Patch patch;
288 if (!loadPatch(vf, &patch)) {
289 return false;
290 }
291 GBApplyPatch(core->board, &patch);
292 return true;
293}
294
295static void _GBCoreUnloadROM(struct mCore* core) {
296 struct GBCore* gbcore = (struct GBCore*) core;
297 struct LR35902Core* cpu = core->cpu;
298 if (gbcore->cheatDevice) {
299 LR35902HotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
300 cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
301 mCheatDeviceDestroy(gbcore->cheatDevice);
302 gbcore->cheatDevice = NULL;
303 }
304 return GBUnloadROM(core->board);
305}
306
307static void _GBCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
308 struct GB* gb = (struct GB*) core->board;
309 switch (type) {
310 case CHECKSUM_CRC32:
311 memcpy(data, &gb->romCrc32, sizeof(gb->romCrc32));
312 break;
313 }
314 return;
315}
316
317static void _GBCoreReset(struct mCore* core) {
318 struct GBCore* gbcore = (struct GBCore*) core;
319 struct GB* gb = (struct GB*) core->board;
320 if (gbcore->renderer.outputBuffer) {
321 GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d);
322 }
323
324 if (gb->memory.rom) {
325 struct GBCartridgeOverride override;
326 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
327 override.headerCrc32 = doCrc32(cart, sizeof(*cart));
328 if (GBOverrideFind(gbcore->overrides, &override)) {
329 GBOverrideApply(gb, &override);
330 }
331 }
332
333 const char* modelGB = mCoreConfigGetValue(&core->config, "gb.model");
334 const char* modelCGB = mCoreConfigGetValue(&core->config, "cgb.model");
335 const char* modelSGB = mCoreConfigGetValue(&core->config, "sgb.model");
336 if (modelGB || modelCGB || modelSGB) {
337 GBDetectModel(gb);
338 if (gb->model == GB_MODEL_DMG && modelGB) {
339 gb->model = GBNameToModel(modelGB);
340 } else if (gb->model == GB_MODEL_CGB && modelCGB) {
341 gb->model = GBNameToModel(modelCGB);
342 } else if (gb->model == GB_MODEL_SGB && modelSGB) {
343 gb->model = GBNameToModel(modelSGB);
344 }
345 }
346
347#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
348 if (!gb->biosVf && core->opts.useBios) {
349 struct VFile* bios = NULL;
350 bool found = false;
351 if (core->opts.bios) {
352 bios = VFileOpen(core->opts.bios, O_RDONLY);
353 if (bios && GBIsBIOS(bios)) {
354 found = true;
355 } else if (bios) {
356 bios->close(bios);
357 bios = NULL;
358 }
359 }
360 if (!found) {
361 GBDetectModel(gb);
362 const char* configPath = NULL;
363
364 switch (gb->model) {
365 case GB_MODEL_DMG:
366 case GB_MODEL_MGB: // TODO
367 configPath = mCoreConfigGetValue(&core->config, "gb.bios");
368 break;
369 case GB_MODEL_SGB:
370 case GB_MODEL_SGB2: // TODO
371 configPath = mCoreConfigGetValue(&core->config, "sgb.bios");
372 break;
373 case GB_MODEL_CGB:
374 case GB_MODEL_AGB:
375 configPath = mCoreConfigGetValue(&core->config, "gbc.bios");
376 break;
377 default:
378 break;
379 };
380 if (configPath) {
381 bios = VFileOpen(configPath, O_RDONLY);
382 }
383 if (bios && GBIsBIOS(bios)) {
384 found = true;
385 } else if (bios) {
386 bios->close(bios);
387 bios = NULL;
388 }
389 }
390 if (!found) {
391 char path[PATH_MAX];
392 mCoreConfigDirectory(path, PATH_MAX);
393 switch (gb->model) {
394 case GB_MODEL_DMG:
395 case GB_MODEL_MGB: // TODO
396 strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path));
397 break;
398 case GB_MODEL_SGB:
399 case GB_MODEL_SGB2: // TODO
400 strncat(path, PATH_SEP "sgb_bios.bin", PATH_MAX - strlen(path));
401 break;
402 case GB_MODEL_CGB:
403 case GB_MODEL_AGB:
404 strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path));
405 break;
406 default:
407 break;
408 };
409 bios = VFileOpen(path, O_RDONLY);
410 if (bios && GBIsBIOS(bios)) {
411 found = true;
412 } else if (bios) {
413 bios->close(bios);
414 bios = NULL;
415 }
416 }
417 if (bios) {
418 GBLoadBIOS(gb, bios);
419 }
420 }
421#endif
422
423 LR35902Reset(core->cpu);
424}
425
426static void _GBCoreRunFrame(struct mCore* core) {
427 struct GB* gb = core->board;
428 int32_t frameCounter = gb->video.frameCounter;
429 while (gb->video.frameCounter == frameCounter) {
430 LR35902Run(core->cpu);
431 }
432}
433
434static void _GBCoreRunLoop(struct mCore* core) {
435 LR35902Run(core->cpu);
436}
437
438static void _GBCoreStep(struct mCore* core) {
439 struct LR35902Core* cpu = core->cpu;
440 do {
441 LR35902Tick(cpu);
442 } while (cpu->executionState != LR35902_CORE_FETCH);
443}
444
445static size_t _GBCoreStateSize(struct mCore* core) {
446 UNUSED(core);
447 return sizeof(struct GBSerializedState);
448}
449
450static bool _GBCoreLoadState(struct mCore* core, const void* state) {
451 return GBDeserialize(core->board, state);
452}
453
454static bool _GBCoreSaveState(struct mCore* core, void* state) {
455 struct LR35902Core* cpu = core->cpu;
456 while (cpu->executionState != LR35902_CORE_FETCH) {
457 LR35902Tick(cpu);
458 }
459 GBSerialize(core->board, state);
460 return true;
461}
462
463static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) {
464 struct GBCore* gbcore = (struct GBCore*) core;
465 gbcore->keys = keys;
466 GBTestKeypadIRQ(core->board);
467}
468
469static void _GBCoreAddKeys(struct mCore* core, uint32_t keys) {
470 struct GBCore* gbcore = (struct GBCore*) core;
471 gbcore->keys |= keys;
472 GBTestKeypadIRQ(core->board);
473}
474
475static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) {
476 struct GBCore* gbcore = (struct GBCore*) core;
477 gbcore->keys &= ~keys;
478}
479
480static int32_t _GBCoreFrameCounter(const struct mCore* core) {
481 const struct GB* gb = core->board;
482 return gb->video.frameCounter;
483}
484
485static int32_t _GBCoreFrameCycles(const struct mCore* core) {
486 UNUSED(core);
487 return GB_VIDEO_TOTAL_LENGTH;
488}
489
490static int32_t _GBCoreFrequency(const struct mCore* core) {
491 UNUSED(core);
492 // TODO: GB differences
493 return DMG_LR35902_FREQUENCY;
494}
495
496static void _GBCoreGetGameTitle(const struct mCore* core, char* title) {
497 GBGetGameTitle(core->board, title);
498}
499
500static void _GBCoreGetGameCode(const struct mCore* core, char* title) {
501 GBGetGameCode(core->board, title);
502}
503
504static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
505 struct GB* gb = core->board;
506 switch (type) {
507 case mPERIPH_ROTATION:
508 gb->memory.rotation = periph;
509 break;
510 case mPERIPH_RUMBLE:
511 gb->memory.rumble = periph;
512 break;
513 case mPERIPH_IMAGE_SOURCE:
514 gb->memory.cam = periph;
515 break;
516 default:
517 return;
518 }
519}
520
521static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
522 struct LR35902Core* cpu = core->cpu;
523 return cpu->memory.load8(cpu, address);
524}
525
526static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
527 struct LR35902Core* cpu = core->cpu;
528 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
529}
530
531static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
532 struct LR35902Core* cpu = core->cpu;
533 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
534 (cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
535}
536
537static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
538 struct LR35902Core* cpu = core->cpu;
539 cpu->memory.store8(cpu, address, value);
540}
541
542static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
543 struct LR35902Core* cpu = core->cpu;
544 cpu->memory.store8(cpu, address, value);
545 cpu->memory.store8(cpu, address + 1, value >> 8);
546}
547
548static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
549 struct LR35902Core* cpu = core->cpu;
550 cpu->memory.store8(cpu, address, value);
551 cpu->memory.store8(cpu, address + 1, value >> 8);
552 cpu->memory.store8(cpu, address + 2, value >> 16);
553 cpu->memory.store8(cpu, address + 3, value >> 24);
554}
555
556static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
557 struct LR35902Core* cpu = core->cpu;
558 return GBView8(cpu, address, segment);
559}
560
561static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
562 struct LR35902Core* cpu = core->cpu;
563 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8);
564}
565
566static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
567 struct LR35902Core* cpu = core->cpu;
568 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8) |
569 (GBView8(cpu, address + 2, segment) << 16) | (GBView8(cpu, address + 3, segment) << 24);
570}
571
572static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
573 struct LR35902Core* cpu = core->cpu;
574 GBPatch8(cpu, address, value, NULL, segment);
575}
576
577static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
578 struct LR35902Core* cpu = core->cpu;
579 GBPatch8(cpu, address, value, NULL, segment);
580 GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
581}
582
583static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
584 struct LR35902Core* cpu = core->cpu;
585 GBPatch8(cpu, address, value, NULL, segment);
586 GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
587 GBPatch8(cpu, address + 2, value >> 16, NULL, segment);
588 GBPatch8(cpu, address + 3, value >> 24, NULL, segment);
589}
590
591size_t _GBListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) {
592 const struct GB* gb = core->board;
593 switch (gb->model) {
594 case GB_MODEL_DMG:
595 case GB_MODEL_MGB:
596 case GB_MODEL_SGB:
597 case GB_MODEL_SGB2:
598 default:
599 *blocks = _GBMemoryBlocks;
600 return sizeof(_GBMemoryBlocks) / sizeof(*_GBMemoryBlocks);
601 case GB_MODEL_CGB:
602 case GB_MODEL_AGB:
603 *blocks = _GBCMemoryBlocks;
604 return sizeof(_GBCMemoryBlocks) / sizeof(*_GBCMemoryBlocks);
605 }
606}
607
608void* _GBGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) {
609 struct GB* gb = core->board;
610 bool isCgb = gb->model >= GB_MODEL_CGB;
611 switch (id) {
612 default:
613 return NULL;
614 case GB_REGION_CART_BANK0:
615 *sizeOut = gb->memory.romSize;
616 return gb->memory.rom;
617 case GB_REGION_VRAM:
618 *sizeOut = GB_SIZE_WORKING_RAM_BANK0 * (isCgb ? 1 : 2);
619 return gb->video.vram;
620 case GB_REGION_EXTERNAL_RAM:
621 *sizeOut = gb->sramSize;
622 return gb->memory.sram;
623 case GB_REGION_WORKING_RAM_BANK0:
624 *sizeOut = GB_SIZE_VRAM * (isCgb ? 8 : 2);
625 return gb->memory.wram;
626 case GB_BASE_OAM:
627 *sizeOut = GB_SIZE_OAM;
628 return gb->video.oam.raw;
629 case GB_BASE_HRAM:
630 *sizeOut = GB_SIZE_HRAM;
631 return gb->memory.hram;
632 }
633}
634
635#ifdef USE_DEBUGGERS
636static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
637 UNUSED(core);
638 switch (type) {
639 case DEBUGGER_CLI:
640 return true;
641 default:
642 return false;
643 }
644}
645
646static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
647 struct GBCore* gbcore = (struct GBCore*) core;
648 struct GB* gb = core->board;
649 if (!gbcore->debuggerPlatform) {
650 struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate();
651 if (gb->model >= GB_MODEL_CGB) {
652 platform->segments = _GBCSegments;
653 } else {
654 platform->segments = _GBSegments;
655 }
656 gbcore->debuggerPlatform = &platform->d;
657 }
658 return gbcore->debuggerPlatform;
659}
660
661static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) {
662 return GBCLIDebuggerCreate(core);
663}
664
665static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
666 struct LR35902Core* cpu = core->cpu;
667 if (core->debugger) {
668 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
669 }
670 cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
671 LR35902HotplugAttach(cpu, CPU_COMPONENT_DEBUGGER);
672 core->debugger = debugger;
673}
674
675static void _GBCoreDetachDebugger(struct mCore* core) {
676 struct LR35902Core* cpu = core->cpu;
677 if (core->debugger) {
678 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
679 }
680 cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
681 core->debugger = NULL;
682}
683
684static void _GBCoreLoadSymbols(struct mCore* core, struct VFile* vf) {
685 core->symbolTable = mDebuggerSymbolTableCreate();
686#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
687 if (!vf) {
688 vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY);
689 }
690#endif
691 if (!vf) {
692 return;
693 }
694 GBLoadSymbols(core->symbolTable, vf);
695}
696#endif
697
698static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) {
699 struct GBCore* gbcore = (struct GBCore*) core;
700 if (!gbcore->cheatDevice) {
701 gbcore->cheatDevice = GBCheatDeviceCreate();
702 ((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d;
703 LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
704 gbcore->cheatDevice->p = core;
705 }
706 return gbcore->cheatDevice;
707}
708
709static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) {
710 struct GB* gb = core->board;
711 struct VFile* vf = gb->sramVf;
712 if (vf) {
713 *sram = malloc(vf->size(vf));
714 vf->seek(vf, 0, SEEK_SET);
715 return vf->read(vf, *sram, vf->size(vf));
716 }
717 *sram = malloc(gb->sramSize);
718 memcpy(*sram, gb->memory.sram, gb->sramSize);
719 return gb->sramSize;
720}
721
722static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
723 struct GB* gb = core->board;
724 if (!writeback) {
725 struct VFile* vf = VFileMemChunk(sram, size);
726 GBSavedataMask(gb, vf, true);
727 return true;
728 }
729 struct VFile* vf = gb->sramVf;
730 if (vf) {
731 vf->seek(vf, 0, SEEK_SET);
732 return vf->write(vf, sram, size) > 0;
733 }
734 if (size > 0x20000) {
735 size = 0x20000;
736 }
737 GBResizeSram(gb, size);
738 memcpy(gb->memory.sram, sram, size);
739 return true;
740}
741
742static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
743 UNUSED(core);
744 *info = _GBVideoLayers;
745 return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
746}
747
748static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
749 UNUSED(core);
750 *info = _GBAudioChannels;
751 return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
752}
753
754static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
755 struct GB* gb = core->board;
756 switch (id) {
757 case 0:
758 gb->video.renderer->disableBG = !enable;
759 break;
760 case 1:
761 gb->video.renderer->disableOBJ = !enable;
762 break;
763 case 2:
764 gb->video.renderer->disableWIN = !enable;
765 break;
766 default:
767 break;
768 }
769}
770
771static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
772 struct GB* gb = core->board;
773 switch (id) {
774 case 0:
775 case 1:
776 case 2:
777 case 3:
778 gb->audio.forceDisableCh[id] = !enable;
779 break;
780 default:
781 break;
782 }
783}
784
785static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
786 struct GBCore* gbcore = (struct GBCore*) core;
787 struct GB* gb = core->board;
788 gbcore->logContext = context;
789
790 int channelId = mVideoLoggerAddChannel(context);
791 gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
792 mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, false);
793 mVideoLoggerAttachChannel(gbcore->proxyRenderer.logger, context, channelId);
794 gbcore->proxyRenderer.logger->block = false;
795
796 GBVideoProxyRendererCreate(&gbcore->proxyRenderer, &gbcore->renderer.d);
797 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
798}
799
800static void _GBCoreEndVideoLog(struct mCore* core) {
801 struct GBCore* gbcore = (struct GBCore*) core;
802 struct GB* gb = core->board;
803 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
804 free(gbcore->proxyRenderer.logger);
805 gbcore->proxyRenderer.logger = NULL;
806}
807
808struct mCore* GBCoreCreate(void) {
809 struct GBCore* gbcore = malloc(sizeof(*gbcore));
810 struct mCore* core = &gbcore->d;
811 memset(&core->opts, 0, sizeof(core->opts));
812 core->cpu = NULL;
813 core->board = NULL;
814 core->debugger = NULL;
815 core->symbolTable = NULL;
816 core->init = _GBCoreInit;
817 core->deinit = _GBCoreDeinit;
818 core->platform = _GBCorePlatform;
819 core->setSync = _GBCoreSetSync;
820 core->loadConfig = _GBCoreLoadConfig;
821 core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
822 core->setVideoBuffer = _GBCoreSetVideoBuffer;
823 core->getPixels = _GBCoreGetPixels;
824 core->putPixels = _GBCorePutPixels;
825 core->getAudioChannel = _GBCoreGetAudioChannel;
826 core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
827 core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
828 core->setAVStream = _GBCoreSetAVStream;
829 core->addCoreCallbacks = _GBCoreAddCoreCallbacks;
830 core->clearCoreCallbacks = _GBCoreClearCoreCallbacks;
831 core->isROM = GBIsROM;
832 core->loadROM = _GBCoreLoadROM;
833 core->loadBIOS = _GBCoreLoadBIOS;
834 core->loadSave = _GBCoreLoadSave;
835 core->loadTemporarySave = _GBCoreLoadTemporarySave;
836 core->loadPatch = _GBCoreLoadPatch;
837 core->unloadROM = _GBCoreUnloadROM;
838 core->checksum = _GBCoreChecksum;
839 core->reset = _GBCoreReset;
840 core->runFrame = _GBCoreRunFrame;
841 core->runLoop = _GBCoreRunLoop;
842 core->step = _GBCoreStep;
843 core->stateSize = _GBCoreStateSize;
844 core->loadState = _GBCoreLoadState;
845 core->saveState = _GBCoreSaveState;
846 core->setKeys = _GBCoreSetKeys;
847 core->addKeys = _GBCoreAddKeys;
848 core->clearKeys = _GBCoreClearKeys;
849 core->frameCounter = _GBCoreFrameCounter;
850 core->frameCycles = _GBCoreFrameCycles;
851 core->frequency = _GBCoreFrequency;
852 core->getGameTitle = _GBCoreGetGameTitle;
853 core->getGameCode = _GBCoreGetGameCode;
854 core->setPeripheral = _GBCoreSetPeripheral;
855 core->busRead8 = _GBCoreBusRead8;
856 core->busRead16 = _GBCoreBusRead16;
857 core->busRead32 = _GBCoreBusRead32;
858 core->busWrite8 = _GBCoreBusWrite8;
859 core->busWrite16 = _GBCoreBusWrite16;
860 core->busWrite32 = _GBCoreBusWrite32;
861 core->rawRead8 = _GBCoreRawRead8;
862 core->rawRead16 = _GBCoreRawRead16;
863 core->rawRead32 = _GBCoreRawRead32;
864 core->rawWrite8 = _GBCoreRawWrite8;
865 core->rawWrite16 = _GBCoreRawWrite16;
866 core->rawWrite32 = _GBCoreRawWrite32;
867 core->listMemoryBlocks = _GBListMemoryBlocks;
868 core->getMemoryBlock = _GBGetMemoryBlock;
869#ifdef USE_DEBUGGERS
870 core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
871 core->debuggerPlatform = _GBCoreDebuggerPlatform;
872 core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
873 core->attachDebugger = _GBCoreAttachDebugger;
874 core->detachDebugger = _GBCoreDetachDebugger;
875 core->loadSymbols = _GBCoreLoadSymbols;
876#endif
877 core->cheatDevice = _GBCoreCheatDevice;
878 core->savedataClone = _GBCoreSavedataClone;
879 core->savedataRestore = _GBCoreSavedataRestore;
880 core->listVideoLayers = _GBCoreListVideoLayers;
881 core->listAudioChannels = _GBCoreListAudioChannels;
882 core->enableVideoLayer = _GBCoreEnableVideoLayer;
883 core->enableAudioChannel = _GBCoreEnableAudioChannel;
884#ifndef MINIMAL_CORE
885 core->startVideoLog = _GBCoreStartVideoLog;
886 core->endVideoLog = _GBCoreEndVideoLog;
887#endif
888 return core;
889}
890
891#ifndef MINIMAL_CORE
892static void _GBVLPStartFrameCallback(void *context) {
893 struct mCore* core = context;
894 struct GBCore* gbcore = (struct GBCore*) core;
895 struct GB* gb = core->board;
896
897 if (!mVideoLoggerRendererRun(gbcore->proxyRenderer.logger, true)) {
898 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
899 mVideoLogContextRewind(gbcore->logContext, core);
900 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
901 }
902}
903
904static bool _GBVLPInit(struct mCore* core) {
905 struct GBCore* gbcore = (struct GBCore*) core;
906 if (!_GBCoreInit(core)) {
907 return false;
908 }
909 gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
910 mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, true);
911 GBVideoProxyRendererCreate(&gbcore->proxyRenderer, NULL);
912 memset(&gbcore->logCallbacks, 0, sizeof(gbcore->logCallbacks));
913 gbcore->logCallbacks.videoFrameStarted = _GBVLPStartFrameCallback;
914 gbcore->logCallbacks.context = core;
915 core->addCoreCallbacks(core, &gbcore->logCallbacks);
916 return true;
917}
918
919static void _GBVLPDeinit(struct mCore* core) {
920 struct GBCore* gbcore = (struct GBCore*) core;
921 if (gbcore->logContext) {
922 mVideoLogContextDestroy(core, gbcore->logContext);
923 }
924 _GBCoreDeinit(core);
925}
926
927static void _GBVLPReset(struct mCore* core) {
928 struct GBCore* gbcore = (struct GBCore*) core;
929 struct GB* gb = (struct GB*) core->board;
930 if (gb->video.renderer == &gbcore->proxyRenderer.d) {
931 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
932 } else if (gbcore->renderer.outputBuffer) {
933 struct GBVideoRenderer* renderer = &gbcore->renderer.d;
934 GBVideoAssociateRenderer(&gb->video, renderer);
935 }
936
937 LR35902Reset(core->cpu);
938 mVideoLogContextRewind(gbcore->logContext, core);
939 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
940
941 // Make sure CPU loop never spins
942 GBHalt(gb->cpu);
943 gb->memory.ie = 0;
944 gb->memory.ime = false;
945}
946
947static bool _GBVLPLoadROM(struct mCore* core, struct VFile* vf) {
948 struct GBCore* gbcore = (struct GBCore*) core;
949 gbcore->logContext = mVideoLogContextCreate(NULL);
950 if (!mVideoLogContextLoad(gbcore->logContext, vf)) {
951 mVideoLogContextDestroy(core, gbcore->logContext);
952 gbcore->logContext = NULL;
953 return false;
954 }
955 mVideoLoggerAttachChannel(gbcore->proxyRenderer.logger, gbcore->logContext, 0);
956 return true;
957}
958
959static bool _GBVLPLoadState(struct mCore* core, const void* buffer) {
960 struct GB* gb = (struct GB*) core->board;
961 const struct GBSerializedState* state = buffer;
962
963 gb->timing.root = NULL;
964 gb->model = state->model;
965
966 gb->cpu->pc = GB_BASE_HRAM;
967 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
968
969 GBVideoDeserialize(&gb->video, state);
970 GBIODeserialize(gb, state);
971 GBAudioReset(&gb->audio);
972
973 // Make sure CPU loop never spins
974 GBHalt(gb->cpu);
975 gb->memory.ie = 0;
976 gb->memory.ime = false;
977
978 return true;
979}
980
981static bool _returnTrue(struct VFile* vf) {
982 UNUSED(vf);
983 return true;
984}
985
986struct mCore* GBVideoLogPlayerCreate(void) {
987 struct mCore* core = GBCoreCreate();
988 core->init = _GBVLPInit;
989 core->deinit = _GBVLPDeinit;
990 core->reset = _GBVLPReset;
991 core->loadROM = _GBVLPLoadROM;
992 core->loadState = _GBVLPLoadState;
993 core->isROM = _returnTrue;
994 return core;
995}
996#else
997struct mCore* GBVideoLogPlayerCreate(void) {
998 return false;
999}
1000#endif