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