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
32static const struct mCoreChannelInfo _GBVideoLayers[] = {
33 { 0, "bg", "Background", NULL },
34 { 1, "obj", "Objects", NULL },
35 { 2, "win", "Window", NULL },
36};
37
38static const struct mCoreChannelInfo _GBAudioChannels[] = {
39 { 0, "ch1", "Channel 1", "Square/Sweep" },
40 { 1, "ch2", "Channel 2", "Square" },
41 { 2, "ch3", "Channel 3", "PCM" },
42 { 3, "ch4", "Channel 4", "Noise" },
43};
44
45static const 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
51static const 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
59static const 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
70static const 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 if (stream && stream->videoFrameRateChanged) {
262 stream->videoFrameRateChanged(stream, core->frameCycles(core), core->frequency(core));
263 }
264}
265
266static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
267 return GBLoadROM(core->board, vf);
268}
269
270static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
271 UNUSED(type);
272 GBLoadBIOS(core->board, vf);
273 return true;
274}
275
276static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) {
277 return GBLoadSave(core->board, vf);
278}
279
280static bool _GBCoreLoadTemporarySave(struct mCore* core, struct VFile* vf) {
281 struct GB* gb = core->board;
282 GBSavedataMask(gb, vf, false);
283 return true; // TODO: Return a real value
284}
285
286static bool _GBCoreLoadPatch(struct mCore* core, struct VFile* vf) {
287 if (!vf) {
288 return false;
289 }
290 struct Patch patch;
291 if (!loadPatch(vf, &patch)) {
292 return false;
293 }
294 GBApplyPatch(core->board, &patch);
295 return true;
296}
297
298static void _GBCoreUnloadROM(struct mCore* core) {
299 struct GBCore* gbcore = (struct GBCore*) core;
300 struct LR35902Core* cpu = core->cpu;
301 if (gbcore->cheatDevice) {
302 LR35902HotplugDetach(cpu, CPU_COMPONENT_CHEAT_DEVICE);
303 cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = NULL;
304 mCheatDeviceDestroy(gbcore->cheatDevice);
305 gbcore->cheatDevice = NULL;
306 }
307 return GBUnloadROM(core->board);
308}
309
310static void _GBCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
311 struct GB* gb = (struct GB*) core->board;
312 switch (type) {
313 case CHECKSUM_CRC32:
314 memcpy(data, &gb->romCrc32, sizeof(gb->romCrc32));
315 break;
316 }
317 return;
318}
319
320static void _GBCoreReset(struct mCore* core) {
321 struct GBCore* gbcore = (struct GBCore*) core;
322 struct GB* gb = (struct GB*) core->board;
323 if (gbcore->renderer.outputBuffer) {
324 GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d);
325 }
326
327 if (gb->memory.rom) {
328 struct GBCartridgeOverride override;
329 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
330 override.headerCrc32 = doCrc32(cart, sizeof(*cart));
331 if (GBOverrideFind(gbcore->overrides, &override)) {
332 GBOverrideApply(gb, &override);
333 }
334 }
335
336#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
337 if (!gb->biosVf && core->opts.useBios) {
338 struct VFile* bios = NULL;
339 bool found = false;
340 if (core->opts.bios) {
341 bios = VFileOpen(core->opts.bios, O_RDONLY);
342 if (bios && GBIsBIOS(bios)) {
343 found = true;
344 } else if (bios) {
345 bios->close(bios);
346 bios = NULL;
347 }
348 }
349 if (!found) {
350 GBDetectModel(gb);
351 const char* configPath = NULL;
352
353 switch (gb->model) {
354 case GB_MODEL_DMG:
355 case GB_MODEL_SGB: // TODO
356 configPath = mCoreConfigGetValue(&core->config, "gb.bios");
357 break;
358 case GB_MODEL_CGB:
359 case GB_MODEL_AGB:
360 configPath = mCoreConfigGetValue(&core->config, "gbc.bios");
361 break;
362 default:
363 break;
364 };
365 if (configPath) {
366 bios = VFileOpen(configPath, O_RDONLY);
367 }
368 if (bios && GBIsBIOS(bios)) {
369 found = true;
370 } else if (bios) {
371 bios->close(bios);
372 bios = NULL;
373 }
374 }
375 if (!found) {
376 char path[PATH_MAX];
377 mCoreConfigDirectory(path, PATH_MAX);
378 switch (gb->model) {
379 case GB_MODEL_DMG:
380 case GB_MODEL_SGB: // TODO
381 strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path));
382 break;
383 case GB_MODEL_CGB:
384 case GB_MODEL_AGB:
385 strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path));
386 break;
387 default:
388 break;
389 };
390 bios = VFileOpen(path, O_RDONLY);
391 if (bios && GBIsBIOS(bios)) {
392 found = true;
393 } else if (bios) {
394 bios->close(bios);
395 bios = NULL;
396 }
397 }
398 if (bios) {
399 GBLoadBIOS(gb, bios);
400 }
401 }
402#endif
403
404 LR35902Reset(core->cpu);
405}
406
407static void _GBCoreRunFrame(struct mCore* core) {
408 struct GB* gb = core->board;
409 int32_t frameCounter = gb->video.frameCounter;
410 while (gb->video.frameCounter == frameCounter) {
411 LR35902Run(core->cpu);
412 }
413}
414
415static void _GBCoreRunLoop(struct mCore* core) {
416 LR35902Run(core->cpu);
417}
418
419static void _GBCoreStep(struct mCore* core) {
420 struct LR35902Core* cpu = core->cpu;
421 do {
422 LR35902Tick(cpu);
423 } while (cpu->executionState != LR35902_CORE_FETCH);
424}
425
426static size_t _GBCoreStateSize(struct mCore* core) {
427 UNUSED(core);
428 return sizeof(struct GBSerializedState);
429}
430
431static bool _GBCoreLoadState(struct mCore* core, const void* state) {
432 return GBDeserialize(core->board, state);
433}
434
435static bool _GBCoreSaveState(struct mCore* core, void* state) {
436 struct LR35902Core* cpu = core->cpu;
437 while (cpu->executionState != LR35902_CORE_FETCH) {
438 LR35902Tick(cpu);
439 }
440 GBSerialize(core->board, state);
441 return true;
442}
443
444static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) {
445 struct GBCore* gbcore = (struct GBCore*) core;
446 gbcore->keys = keys;
447 GBTestKeypadIRQ(core->board);
448}
449
450static void _GBCoreAddKeys(struct mCore* core, uint32_t keys) {
451 struct GBCore* gbcore = (struct GBCore*) core;
452 gbcore->keys |= keys;
453 GBTestKeypadIRQ(core->board);
454}
455
456static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) {
457 struct GBCore* gbcore = (struct GBCore*) core;
458 gbcore->keys &= ~keys;
459}
460
461static void _GBCoreSetCursorLocation(struct mCore* core, int x, int y) {
462 UNUSED(core);
463 UNUSED(x);
464 UNUSED(y);
465}
466
467static void _GBCoreSetCursorDown(struct mCore* core, bool down) {
468 UNUSED(core);
469 UNUSED(down);
470}
471
472static int32_t _GBCoreFrameCounter(const struct mCore* core) {
473 const struct GB* gb = core->board;
474 return gb->video.frameCounter;
475}
476
477static int32_t _GBCoreFrameCycles(const struct mCore* core) {
478 UNUSED(core);
479 return GB_VIDEO_TOTAL_LENGTH;
480}
481
482static int32_t _GBCoreFrequency(const struct mCore* core) {
483 UNUSED(core);
484 // TODO: GB differences
485 return DMG_LR35902_FREQUENCY;
486}
487
488static void _GBCoreGetGameTitle(const struct mCore* core, char* title) {
489 GBGetGameTitle(core->board, title);
490}
491
492static void _GBCoreGetGameCode(const struct mCore* core, char* title) {
493 GBGetGameCode(core->board, title);
494}
495
496static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
497 struct GB* gb = core->board;
498 switch (type) {
499 case mPERIPH_ROTATION:
500 gb->memory.rotation = periph;
501 break;
502 case mPERIPH_RUMBLE:
503 gb->memory.rumble = periph;
504 break;
505 default:
506 return;
507 }
508}
509
510static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) {
511 struct LR35902Core* cpu = core->cpu;
512 return cpu->memory.load8(cpu, address);
513}
514
515static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) {
516 struct LR35902Core* cpu = core->cpu;
517 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8);
518}
519
520static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) {
521 struct LR35902Core* cpu = core->cpu;
522 return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) |
523 (cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24);
524}
525
526static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) {
527 struct LR35902Core* cpu = core->cpu;
528 cpu->memory.store8(cpu, address, value);
529}
530
531static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) {
532 struct LR35902Core* cpu = core->cpu;
533 cpu->memory.store8(cpu, address, value);
534 cpu->memory.store8(cpu, address + 1, value >> 8);
535}
536
537static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) {
538 struct LR35902Core* cpu = core->cpu;
539 cpu->memory.store8(cpu, address, value);
540 cpu->memory.store8(cpu, address + 1, value >> 8);
541 cpu->memory.store8(cpu, address + 2, value >> 16);
542 cpu->memory.store8(cpu, address + 3, value >> 24);
543}
544
545static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address, int segment) {
546 struct LR35902Core* cpu = core->cpu;
547 return GBView8(cpu, address, segment);
548}
549
550static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address, int segment) {
551 struct LR35902Core* cpu = core->cpu;
552 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8);
553}
554
555static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address, int segment) {
556 struct LR35902Core* cpu = core->cpu;
557 return GBView8(cpu, address, segment) | (GBView8(cpu, address + 1, segment) << 8) |
558 (GBView8(cpu, address + 2, segment) << 16) | (GBView8(cpu, address + 3, segment) << 24);
559}
560
561static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, int segment, uint8_t value) {
562 struct LR35902Core* cpu = core->cpu;
563 GBPatch8(cpu, address, value, NULL, segment);
564}
565
566static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, int segment, uint16_t value) {
567 struct LR35902Core* cpu = core->cpu;
568 GBPatch8(cpu, address, value, NULL, segment);
569 GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
570}
571
572static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, int segment, uint32_t value) {
573 struct LR35902Core* cpu = core->cpu;
574 GBPatch8(cpu, address, value, NULL, segment);
575 GBPatch8(cpu, address + 1, value >> 8, NULL, segment);
576 GBPatch8(cpu, address + 2, value >> 16, NULL, segment);
577 GBPatch8(cpu, address + 3, value >> 24, NULL, segment);
578}
579
580size_t _GBListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) {
581 const struct GB* gb = core->board;
582 switch (gb->model) {
583 case GB_MODEL_DMG:
584 case GB_MODEL_SGB:
585 default:
586 *blocks = _GBMemoryBlocks;
587 return sizeof(_GBMemoryBlocks) / sizeof(*_GBMemoryBlocks);
588 case GB_MODEL_CGB:
589 case GB_MODEL_AGB:
590 *blocks = _GBCMemoryBlocks;
591 return sizeof(_GBCMemoryBlocks) / sizeof(*_GBCMemoryBlocks);
592 }
593}
594
595void* _GBGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) {
596 struct GB* gb = core->board;
597 bool isCgb = gb->model >= GB_MODEL_CGB;
598 switch (id) {
599 default:
600 return NULL;
601 case GB_REGION_CART_BANK0:
602 *sizeOut = gb->memory.romSize;
603 return gb->memory.rom;
604 case GB_REGION_VRAM:
605 *sizeOut = GB_SIZE_WORKING_RAM_BANK0 * (isCgb ? 1 : 2);
606 return gb->video.vram;
607 case GB_REGION_EXTERNAL_RAM:
608 *sizeOut = gb->sramSize;
609 return gb->memory.sram;
610 case GB_REGION_WORKING_RAM_BANK0:
611 *sizeOut = GB_SIZE_VRAM * (isCgb ? 8 : 2);
612 return gb->memory.wram;
613 case GB_BASE_OAM:
614 *sizeOut = GB_SIZE_OAM;
615 return gb->video.oam.raw;
616 case GB_BASE_HRAM:
617 *sizeOut = GB_SIZE_HRAM;
618 return gb->memory.hram;
619 }
620}
621
622#ifdef USE_DEBUGGERS
623static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
624 UNUSED(core);
625 switch (type) {
626 case DEBUGGER_CLI:
627 return true;
628 default:
629 return false;
630 }
631}
632
633static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) {
634 struct GBCore* gbcore = (struct GBCore*) core;
635 struct GB* gb = core->board;
636 if (!gbcore->debuggerPlatform) {
637 struct LR35902Debugger* platform = (struct LR35902Debugger*) LR35902DebuggerPlatformCreate();
638 if (gb->model >= GB_MODEL_CGB) {
639 platform->segments = _GBCSegments;
640 } else {
641 platform->segments = _GBSegments;
642 }
643 gbcore->debuggerPlatform = &platform->d;
644 }
645 return gbcore->debuggerPlatform;
646}
647
648static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) {
649 return GBCLIDebuggerCreate(core);
650}
651
652static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) {
653 struct LR35902Core* cpu = core->cpu;
654 if (core->debugger) {
655 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
656 }
657 cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
658 LR35902HotplugAttach(cpu, CPU_COMPONENT_DEBUGGER);
659 core->debugger = debugger;
660}
661
662static void _GBCoreDetachDebugger(struct mCore* core) {
663 struct LR35902Core* cpu = core->cpu;
664 if (core->debugger) {
665 LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER);
666 }
667 cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
668 core->debugger = NULL;
669}
670
671static void _GBCoreLoadSymbols(struct mCore* core, struct VFile* vf) {
672 core->symbolTable = mDebuggerSymbolTableCreate();
673#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
674 if (!vf) {
675 vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY);
676 }
677#endif
678 if (!vf) {
679 return;
680 }
681 GBLoadSymbols(core->symbolTable, vf);
682}
683#endif
684
685static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) {
686 struct GBCore* gbcore = (struct GBCore*) core;
687 if (!gbcore->cheatDevice) {
688 gbcore->cheatDevice = GBCheatDeviceCreate();
689 ((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d;
690 LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE);
691 gbcore->cheatDevice->p = core;
692 }
693 return gbcore->cheatDevice;
694}
695
696static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) {
697 struct GB* gb = core->board;
698 struct VFile* vf = gb->sramVf;
699 if (vf) {
700 *sram = malloc(vf->size(vf));
701 vf->seek(vf, 0, SEEK_SET);
702 return vf->read(vf, *sram, vf->size(vf));
703 }
704 *sram = malloc(gb->sramSize);
705 memcpy(*sram, gb->memory.sram, gb->sramSize);
706 return gb->sramSize;
707}
708
709static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t size, bool writeback) {
710 struct GB* gb = core->board;
711 if (!writeback) {
712 struct VFile* vf = VFileMemChunk(sram, size);
713 GBSavedataMask(gb, vf, true);
714 return true;
715 }
716 struct VFile* vf = gb->sramVf;
717 if (vf) {
718 vf->seek(vf, 0, SEEK_SET);
719 return vf->write(vf, sram, size) > 0;
720 }
721 if (size > 0x20000) {
722 size = 0x20000;
723 }
724 GBResizeSram(gb, size);
725 memcpy(gb->memory.sram, sram, size);
726 return true;
727}
728
729static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
730 UNUSED(core);
731 *info = _GBVideoLayers;
732 return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
733}
734
735static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
736 UNUSED(core);
737 *info = _GBAudioChannels;
738 return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
739}
740
741static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) {
742 struct GB* gb = core->board;
743 switch (id) {
744 case 0:
745 gb->video.renderer->disableBG = !enable;
746 break;
747 case 1:
748 gb->video.renderer->disableOBJ = !enable;
749 break;
750 case 2:
751 gb->video.renderer->disableWIN = !enable;
752 break;
753 default:
754 break;
755 }
756}
757
758static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) {
759 struct GB* gb = core->board;
760 switch (id) {
761 case 0:
762 case 1:
763 case 2:
764 case 3:
765 gb->audio.forceDisableCh[id] = !enable;
766 break;
767 default:
768 break;
769 }
770}
771
772static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
773 struct GBCore* gbcore = (struct GBCore*) core;
774 struct GB* gb = core->board;
775 gbcore->logContext = context;
776
777 int channelId = mVideoLoggerAddChannel(context);
778 gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
779 mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, false);
780 mVideoLoggerAttachChannel(gbcore->proxyRenderer.logger, context, channelId);
781 gbcore->proxyRenderer.logger->block = false;
782
783 GBVideoProxyRendererCreate(&gbcore->proxyRenderer, &gbcore->renderer.d);
784 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
785}
786
787static void _GBCoreEndVideoLog(struct mCore* core) {
788 struct GBCore* gbcore = (struct GBCore*) core;
789 struct GB* gb = core->board;
790 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
791 free(gbcore->proxyRenderer.logger);
792 gbcore->proxyRenderer.logger = NULL;
793}
794
795struct mCore* GBCoreCreate(void) {
796 struct GBCore* gbcore = malloc(sizeof(*gbcore));
797 struct mCore* core = &gbcore->d;
798 memset(&core->opts, 0, sizeof(core->opts));
799 core->cpu = NULL;
800 core->board = NULL;
801 core->debugger = NULL;
802 core->symbolTable = NULL;
803 core->init = _GBCoreInit;
804 core->deinit = _GBCoreDeinit;
805 core->platform = _GBCorePlatform;
806 core->setSync = _GBCoreSetSync;
807 core->loadConfig = _GBCoreLoadConfig;
808 core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
809 core->setVideoBuffer = _GBCoreSetVideoBuffer;
810 core->getPixels = _GBCoreGetPixels;
811 core->putPixels = _GBCorePutPixels;
812 core->getAudioChannel = _GBCoreGetAudioChannel;
813 core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
814 core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
815 core->setAVStream = _GBCoreSetAVStream;
816 core->addCoreCallbacks = _GBCoreAddCoreCallbacks;
817 core->clearCoreCallbacks = _GBCoreClearCoreCallbacks;
818 core->isROM = GBIsROM;
819 core->loadROM = _GBCoreLoadROM;
820 core->loadBIOS = _GBCoreLoadBIOS;
821 core->loadSave = _GBCoreLoadSave;
822 core->loadTemporarySave = _GBCoreLoadTemporarySave;
823 core->loadPatch = _GBCoreLoadPatch;
824 core->unloadROM = _GBCoreUnloadROM;
825 core->checksum = _GBCoreChecksum;
826 core->reset = _GBCoreReset;
827 core->runFrame = _GBCoreRunFrame;
828 core->runLoop = _GBCoreRunLoop;
829 core->step = _GBCoreStep;
830 core->stateSize = _GBCoreStateSize;
831 core->loadState = _GBCoreLoadState;
832 core->saveState = _GBCoreSaveState;
833 core->setKeys = _GBCoreSetKeys;
834 core->addKeys = _GBCoreAddKeys;
835 core->clearKeys = _GBCoreClearKeys;
836 core->setCursorLocation = _GBCoreSetCursorLocation;
837 core->setCursorDown = _GBCoreSetCursorDown;
838 core->frameCounter = _GBCoreFrameCounter;
839 core->frameCycles = _GBCoreFrameCycles;
840 core->frequency = _GBCoreFrequency;
841 core->getGameTitle = _GBCoreGetGameTitle;
842 core->getGameCode = _GBCoreGetGameCode;
843 core->setPeripheral = _GBCoreSetPeripheral;
844 core->busRead8 = _GBCoreBusRead8;
845 core->busRead16 = _GBCoreBusRead16;
846 core->busRead32 = _GBCoreBusRead32;
847 core->busWrite8 = _GBCoreBusWrite8;
848 core->busWrite16 = _GBCoreBusWrite16;
849 core->busWrite32 = _GBCoreBusWrite32;
850 core->rawRead8 = _GBCoreRawRead8;
851 core->rawRead16 = _GBCoreRawRead16;
852 core->rawRead32 = _GBCoreRawRead32;
853 core->rawWrite8 = _GBCoreRawWrite8;
854 core->rawWrite16 = _GBCoreRawWrite16;
855 core->rawWrite32 = _GBCoreRawWrite32;
856 core->listMemoryBlocks = _GBListMemoryBlocks;
857 core->getMemoryBlock = _GBGetMemoryBlock;
858#ifdef USE_DEBUGGERS
859 core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
860 core->debuggerPlatform = _GBCoreDebuggerPlatform;
861 core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
862 core->attachDebugger = _GBCoreAttachDebugger;
863 core->detachDebugger = _GBCoreDetachDebugger;
864 core->loadSymbols = _GBCoreLoadSymbols;
865#endif
866 core->cheatDevice = _GBCoreCheatDevice;
867 core->savedataClone = _GBCoreSavedataClone;
868 core->savedataRestore = _GBCoreSavedataRestore;
869 core->listVideoLayers = _GBCoreListVideoLayers;
870 core->listAudioChannels = _GBCoreListAudioChannels;
871 core->enableVideoLayer = _GBCoreEnableVideoLayer;
872 core->enableAudioChannel = _GBCoreEnableAudioChannel;
873#ifndef MINIMAL_CORE
874 core->startVideoLog = _GBCoreStartVideoLog;
875 core->endVideoLog = _GBCoreEndVideoLog;
876#endif
877 return core;
878}
879
880#ifndef MINIMAL_CORE
881static void _GBVLPStartFrameCallback(void *context) {
882 struct mCore* core = context;
883 struct GBCore* gbcore = (struct GBCore*) core;
884 struct GB* gb = core->board;
885
886 if (!mVideoLoggerRendererRun(gbcore->proxyRenderer.logger, true)) {
887 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
888 mVideoLogContextRewind(gbcore->logContext, core);
889 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
890 }
891}
892
893static bool _GBVLPInit(struct mCore* core) {
894 struct GBCore* gbcore = (struct GBCore*) core;
895 if (!_GBCoreInit(core)) {
896 return false;
897 }
898 gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
899 mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, true);
900 GBVideoProxyRendererCreate(&gbcore->proxyRenderer, NULL);
901 memset(&gbcore->logCallbacks, 0, sizeof(gbcore->logCallbacks));
902 gbcore->logCallbacks.videoFrameStarted = _GBVLPStartFrameCallback;
903 gbcore->logCallbacks.context = core;
904 core->addCoreCallbacks(core, &gbcore->logCallbacks);
905 return true;
906}
907
908static void _GBVLPDeinit(struct mCore* core) {
909 struct GBCore* gbcore = (struct GBCore*) core;
910 if (gbcore->logContext) {
911 mVideoLogContextDestroy(core, gbcore->logContext);
912 }
913 _GBCoreDeinit(core);
914}
915
916static void _GBVLPReset(struct mCore* core) {
917 struct GBCore* gbcore = (struct GBCore*) core;
918 struct GB* gb = (struct GB*) core->board;
919 if (gb->video.renderer == &gbcore->proxyRenderer.d) {
920 GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
921 } else if (gbcore->renderer.outputBuffer) {
922 struct GBVideoRenderer* renderer = &gbcore->renderer.d;
923 GBVideoAssociateRenderer(&gb->video, renderer);
924 }
925
926 LR35902Reset(core->cpu);
927 mVideoLogContextRewind(gbcore->logContext, core);
928 GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
929
930 // Make sure CPU loop never spins
931 GBHalt(gb->cpu);
932 gb->memory.ie = 0;
933 gb->memory.ime = false;
934}
935
936static bool _GBVLPLoadROM(struct mCore* core, struct VFile* vf) {
937 struct GBCore* gbcore = (struct GBCore*) core;
938 gbcore->logContext = mVideoLogContextCreate(NULL);
939 if (!mVideoLogContextLoad(gbcore->logContext, vf)) {
940 mVideoLogContextDestroy(core, gbcore->logContext);
941 gbcore->logContext = NULL;
942 return false;
943 }
944 mVideoLoggerAttachChannel(gbcore->proxyRenderer.logger, gbcore->logContext, 0);
945 return true;
946}
947
948static bool _GBVLPLoadState(struct mCore* core, const void* buffer) {
949 struct GB* gb = (struct GB*) core->board;
950 const struct GBSerializedState* state = buffer;
951
952 gb->timing.root = NULL;
953 gb->model = state->model;
954
955 gb->cpu->pc = GB_BASE_HRAM;
956 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
957
958 GBVideoDeserialize(&gb->video, state);
959 GBIODeserialize(gb, state);
960 GBAudioReset(&gb->audio);
961
962 // Make sure CPU loop never spins
963 GBHalt(gb->cpu);
964 gb->memory.ie = 0;
965 gb->memory.ime = false;
966
967 return true;
968}
969
970static bool _returnTrue(struct VFile* vf) {
971 UNUSED(vf);
972 return true;
973}
974
975struct mCore* GBVideoLogPlayerCreate(void) {
976 struct mCore* core = GBCoreCreate();
977 core->init = _GBVLPInit;
978 core->deinit = _GBVLPDeinit;
979 core->reset = _GBVLPReset;
980 core->loadROM = _GBVLPLoadROM;
981 core->loadState = _GBVLPLoadState;
982 core->isROM = _returnTrue;
983 return core;
984}
985#else
986struct mCore* GBVideoLogPlayerCreate(void) {
987 return false;
988}
989#endif