src/gb/gb.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/internal/gb/gb.h>
7
8#include <mgba/internal/gb/io.h>
9#include <mgba/internal/gb/mbc.h>
10#include <mgba/internal/sm83/sm83.h>
11
12#include <mgba/core/core.h>
13#include <mgba/core/cheats.h>
14#include <mgba-util/crc32.h>
15#include <mgba-util/memory.h>
16#include <mgba-util/math.h>
17#include <mgba-util/patch.h>
18#include <mgba-util/vfs.h>
19
20#define CLEANUP_THRESHOLD 15
21
22const uint32_t CGB_SM83_FREQUENCY = 0x800000;
23const uint32_t SGB_SM83_FREQUENCY = 0x418B1E;
24
25const uint32_t GB_COMPONENT_MAGIC = 0x400000;
26
27static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
28
29#define DMG_BIOS_CHECKSUM 0xC2F5CC97
30#define DMG_2_BIOS_CHECKSUM 0x59C8598E
31#define MGB_BIOS_CHECKSUM 0xE6920754
32#define SGB_BIOS_CHECKSUM 0xEC8A83B9
33#define SGB2_BIOS_CHECKSUM 0X53D0DD63
34#define CGB_BIOS_CHECKSUM 0x41884E46
35
36mLOG_DEFINE_CATEGORY(GB, "GB", "gb");
37
38static void GBInit(void* cpu, struct mCPUComponent* component);
39static void GBDeinit(struct mCPUComponent* component);
40static void GBInterruptHandlerInit(struct SM83InterruptHandler* irqh);
41static void GBProcessEvents(struct SM83Core* cpu);
42static void GBSetInterrupts(struct SM83Core* cpu, bool enable);
43static uint16_t GBIRQVector(struct SM83Core* cpu);
44static void GBIllegal(struct SM83Core* cpu);
45static void GBStop(struct SM83Core* cpu);
46
47static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate);
48
49void GBCreate(struct GB* gb) {
50 gb->d.id = GB_COMPONENT_MAGIC;
51 gb->d.init = GBInit;
52 gb->d.deinit = GBDeinit;
53}
54
55static void GBInit(void* cpu, struct mCPUComponent* component) {
56 struct GB* gb = (struct GB*) component;
57 gb->cpu = cpu;
58 gb->sync = NULL;
59
60 GBInterruptHandlerInit(&gb->cpu->irqh);
61 GBMemoryInit(gb);
62
63 gb->video.p = gb;
64 GBVideoInit(&gb->video);
65
66 gb->audio.p = gb;
67 GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant
68
69 gb->sio.p = gb;
70 GBSIOInit(&gb->sio);
71
72 gb->timer.p = gb;
73
74 gb->model = GB_MODEL_AUTODETECT;
75
76 gb->biosVf = NULL;
77 gb->romVf = NULL;
78 gb->sramVf = NULL;
79 gb->sramRealVf = NULL;
80
81 gb->isPristine = false;
82 gb->pristineRomSize = 0;
83 gb->yankedRomSize = 0;
84
85 mCoreCallbacksListInit(&gb->coreCallbacks, 0);
86 gb->stream = NULL;
87
88 mTimingInit(&gb->timing, &gb->cpu->cycles, &gb->cpu->nextEvent);
89 gb->audio.timing = &gb->timing;
90
91 gb->eiPending.name = "GB EI";
92 gb->eiPending.callback = _enableInterrupts;
93 gb->eiPending.context = gb;
94 gb->eiPending.priority = 0;
95}
96
97static void GBDeinit(struct mCPUComponent* component) {
98 struct GB* gb = (struct GB*) component;
99 mTimingDeinit(&gb->timing);
100}
101
102bool GBLoadROM(struct GB* gb, struct VFile* vf) {
103 if (!vf) {
104 return false;
105 }
106 GBUnloadROM(gb);
107 gb->romVf = vf;
108 gb->pristineRomSize = vf->size(vf);
109 vf->seek(vf, 0, SEEK_SET);
110 gb->isPristine = true;
111 gb->memory.rom = vf->map(vf, gb->pristineRomSize, MAP_READ);
112 if (!gb->memory.rom) {
113 return false;
114 }
115 gb->yankedRomSize = 0;
116 gb->memory.romBase = gb->memory.rom;
117 gb->memory.romSize = gb->pristineRomSize;
118 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
119 GBMBCInit(gb);
120
121 if (gb->cpu) {
122 struct SM83Core* cpu = gb->cpu;
123 cpu->memory.setActiveRegion(cpu, cpu->pc);
124 }
125
126 // TODO: error check
127 return true;
128}
129
130void GBYankROM(struct GB* gb) {
131 gb->yankedRomSize = gb->memory.romSize;
132 gb->yankedMbc = gb->memory.mbcType;
133 gb->memory.romSize = 0;
134 gb->memory.mbcType = GB_MBC_NONE;
135 gb->memory.sramAccess = false;
136
137 if (gb->cpu) {
138 struct SM83Core* cpu = gb->cpu;
139 cpu->memory.setActiveRegion(cpu, cpu->pc);
140 }
141}
142
143static void GBSramDeinit(struct GB* gb) {
144 if (gb->sramVf) {
145 gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize);
146 if (gb->memory.mbcType == GB_MBC3_RTC && gb->sramVf == gb->sramRealVf) {
147 GBMBCRTCWrite(gb);
148 }
149 gb->sramVf = NULL;
150 } else if (gb->memory.sram) {
151 mappedMemoryFree(gb->memory.sram, gb->sramSize);
152 }
153 gb->memory.sram = 0;
154}
155
156bool GBLoadSave(struct GB* gb, struct VFile* vf) {
157 GBSramDeinit(gb);
158 gb->sramVf = vf;
159 gb->sramRealVf = vf;
160 if (gb->sramSize) {
161 GBResizeSram(gb, gb->sramSize);
162 GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
163 }
164 return vf;
165}
166
167void GBResizeSram(struct GB* gb, size_t size) {
168 if (gb->memory.sram && size <= gb->sramSize) {
169 return;
170 }
171 struct VFile* vf = gb->sramVf;
172 if (vf) {
173 if (vf == gb->sramRealVf) {
174 ssize_t vfSize = vf->size(vf);
175 if (vfSize >= 0 && (size_t) vfSize < size) {
176 uint8_t extdataBuffer[0x100];
177 if (vfSize & 0xFF) {
178 vf->seek(vf, -(vfSize & 0xFF), SEEK_END);
179 vf->read(vf, extdataBuffer, vfSize & 0xFF);
180 }
181 if (gb->memory.sram) {
182 vf->unmap(vf, gb->memory.sram, gb->sramSize);
183 }
184 vf->truncate(vf, size + (vfSize & 0xFF));
185 if (vfSize & 0xFF) {
186 vf->seek(vf, size, SEEK_SET);
187 vf->write(vf, extdataBuffer, vfSize & 0xFF);
188 }
189 gb->memory.sram = vf->map(vf, size, MAP_WRITE);
190 memset(&gb->memory.sram[vfSize], 0xFF, size - vfSize);
191 } else if (size > gb->sramSize || !gb->memory.sram) {
192 if (gb->memory.sram) {
193 vf->unmap(vf, gb->memory.sram, gb->sramSize);
194 }
195 gb->memory.sram = vf->map(vf, size, MAP_WRITE);
196 }
197 } else {
198 if (gb->memory.sram) {
199 vf->unmap(vf, gb->memory.sram, gb->sramSize);
200 }
201 gb->memory.sram = vf->map(vf, size, MAP_READ);
202 }
203 if (gb->memory.sram == (void*) -1) {
204 gb->memory.sram = NULL;
205 }
206 } else if (size) {
207 uint8_t* newSram = anonymousMemoryMap(size);
208 if (gb->memory.sram) {
209 if (size > gb->sramSize) {
210 memcpy(newSram, gb->memory.sram, gb->sramSize);
211 memset(&newSram[gb->sramSize], 0xFF, size - gb->sramSize);
212 } else {
213 memcpy(newSram, gb->memory.sram, size);
214 }
215 mappedMemoryFree(gb->memory.sram, gb->sramSize);
216 } else {
217 memset(newSram, 0xFF, size);
218 }
219 gb->memory.sram = newSram;
220 }
221 if (gb->sramSize < size) {
222 gb->sramSize = size;
223 }
224}
225
226void GBSramClean(struct GB* gb, uint32_t frameCount) {
227 // TODO: Share with GBASavedataClean
228 if (!gb->sramVf) {
229 return;
230 }
231 if (gb->sramDirty & GB_SRAM_DIRT_NEW) {
232 gb->sramDirtAge = frameCount;
233 gb->sramDirty &= ~GB_SRAM_DIRT_NEW;
234 if (!(gb->sramDirty & GB_SRAM_DIRT_SEEN)) {
235 gb->sramDirty |= GB_SRAM_DIRT_SEEN;
236 }
237 } else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) {
238 if (gb->sramMaskWriteback) {
239 GBSavedataUnmask(gb);
240 }
241 if (gb->memory.mbcType == GB_MBC3_RTC) {
242 GBMBCRTCWrite(gb);
243 }
244 gb->sramDirty = 0;
245 if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
246 mLOG(GB_MEM, INFO, "Savedata synced");
247 } else {
248 mLOG(GB_MEM, INFO, "Savedata failed to sync!");
249 }
250
251 size_t c;
252 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
253 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
254 if (callbacks->savedataUpdated) {
255 callbacks->savedataUpdated(callbacks->context);
256 }
257 }
258 }
259}
260
261void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) {
262 struct VFile* oldVf = gb->sramVf;
263 GBSramDeinit(gb);
264 if (oldVf && oldVf != gb->sramRealVf) {
265 oldVf->close(oldVf);
266 }
267 gb->sramVf = vf;
268 gb->sramMaskWriteback = writeback;
269 gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);
270 GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
271}
272
273void GBSavedataUnmask(struct GB* gb) {
274 if (!gb->sramRealVf || gb->sramVf == gb->sramRealVf) {
275 return;
276 }
277 struct VFile* vf = gb->sramVf;
278 GBSramDeinit(gb);
279 gb->sramVf = gb->sramRealVf;
280 gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
281 if (gb->sramMaskWriteback) {
282 vf->seek(vf, 0, SEEK_SET);
283 vf->read(vf, gb->memory.sram, gb->sramSize);
284 gb->sramMaskWriteback = false;
285 }
286 GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
287 vf->close(vf);
288}
289
290void GBUnloadROM(struct GB* gb) {
291 // TODO: Share with GBAUnloadROM
292 if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && !gb->isPristine) {
293 free(gb->memory.romBase);
294 }
295 if (gb->memory.rom && !gb->isPristine) {
296 if (gb->yankedRomSize) {
297 gb->yankedRomSize = 0;
298 }
299 mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
300 }
301
302 if (gb->romVf) {
303#ifndef FIXED_ROM_BUFFER
304 gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
305#endif
306 gb->romVf->close(gb->romVf);
307 gb->romVf = NULL;
308 }
309 gb->memory.rom = NULL;
310 gb->memory.mbcType = GB_MBC_AUTODETECT;
311 gb->isPristine = false;
312
313 gb->sramMaskWriteback = false;
314 GBSramDeinit(gb);
315 if (gb->sramRealVf) {
316 gb->sramRealVf->close(gb->sramRealVf);
317 }
318 gb->sramRealVf = NULL;
319 gb->sramVf = NULL;
320 if (gb->memory.cam && gb->memory.cam->stopRequestImage) {
321 gb->memory.cam->stopRequestImage(gb->memory.cam);
322 }
323}
324
325void GBSynthesizeROM(struct VFile* vf) {
326 if (!vf) {
327 return;
328 }
329 const struct GBCartridge cart = {
330 .logo = { _knownHeader[0], _knownHeader[1], _knownHeader[2], _knownHeader[3]}
331 };
332
333 vf->seek(vf, 0x100, SEEK_SET);
334 vf->write(vf, &cart, sizeof(cart));
335}
336
337void GBLoadBIOS(struct GB* gb, struct VFile* vf) {
338 gb->biosVf = vf;
339}
340
341void GBApplyPatch(struct GB* gb, struct Patch* patch) {
342 size_t patchedSize = patch->outputSize(patch, gb->memory.romSize);
343 if (!patchedSize) {
344 return;
345 }
346 if (patchedSize > GB_SIZE_CART_MAX) {
347 patchedSize = GB_SIZE_CART_MAX;
348 }
349 void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX);
350 if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) {
351 mappedMemoryFree(newRom, GB_SIZE_CART_MAX);
352 return;
353 }
354 if (gb->romVf) {
355#ifndef FIXED_ROM_BUFFER
356 gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
357#endif
358 gb->romVf->close(gb->romVf);
359 gb->romVf = NULL;
360 }
361 gb->isPristine = false;
362 if (gb->memory.romBase == gb->memory.rom) {
363 gb->memory.romBase = newRom;
364 }
365 gb->memory.rom = newRom;
366 gb->memory.romSize = patchedSize;
367 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
368 gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
369}
370
371void GBDestroy(struct GB* gb) {
372 GBUnloadROM(gb);
373
374 if (gb->biosVf) {
375 gb->biosVf->close(gb->biosVf);
376 gb->biosVf = 0;
377 }
378
379 GBMemoryDeinit(gb);
380 GBAudioDeinit(&gb->audio);
381 GBVideoDeinit(&gb->video);
382 GBSIODeinit(&gb->sio);
383 mCoreCallbacksListDeinit(&gb->coreCallbacks);
384}
385
386void GBInterruptHandlerInit(struct SM83InterruptHandler* irqh) {
387 irqh->reset = GBReset;
388 irqh->processEvents = GBProcessEvents;
389 irqh->setInterrupts = GBSetInterrupts;
390 irqh->irqVector = GBIRQVector;
391 irqh->hitIllegal = GBIllegal;
392 irqh->stop = GBStop;
393 irqh->halt = GBHalt;
394}
395
396static uint32_t _GBBiosCRC32(struct VFile* vf) {
397 ssize_t size = vf->size(vf);
398 if (size <= 0 || size > GB_SIZE_CART_BANK0) {
399 return 0;
400 }
401 void* bios = vf->map(vf, size, MAP_READ);
402 uint32_t biosCrc = doCrc32(bios, size);
403 vf->unmap(vf, bios, size);
404 return biosCrc;
405}
406
407bool GBIsBIOS(struct VFile* vf) {
408 switch (_GBBiosCRC32(vf)) {
409 case DMG_BIOS_CHECKSUM:
410 case DMG_2_BIOS_CHECKSUM:
411 case MGB_BIOS_CHECKSUM:
412 case SGB_BIOS_CHECKSUM:
413 case SGB2_BIOS_CHECKSUM:
414 case CGB_BIOS_CHECKSUM:
415 return true;
416 default:
417 return false;
418 }
419}
420
421void GBReset(struct SM83Core* cpu) {
422 struct GB* gb = (struct GB*) cpu->master;
423 gb->memory.romBase = gb->memory.rom;
424 GBDetectModel(gb);
425
426 cpu->b = 0;
427 cpu->d = 0;
428
429 gb->timer.internalDiv = 0;
430
431 gb->cpuBlocked = false;
432 gb->earlyExit = false;
433 gb->doubleSpeed = 0;
434
435 if (gb->yankedRomSize) {
436 gb->memory.romSize = gb->yankedRomSize;
437 gb->memory.mbcType = gb->yankedMbc;
438 gb->yankedRomSize = 0;
439 }
440
441 gb->sgbBit = -1;
442 gb->sgbControllers = 0;
443 gb->sgbCurrentController = 0;
444 gb->currentSgbBits = 0;
445 gb->sgbIncrement = false;
446 memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
447
448 mTimingClear(&gb->timing);
449
450 GBMemoryReset(gb);
451
452 if (gb->biosVf) {
453 if (!GBIsBIOS(gb->biosVf)) {
454 gb->biosVf->close(gb->biosVf);
455 gb->biosVf = NULL;
456 } else {
457 GBMapBIOS(gb);
458 cpu->a = 0;
459 cpu->f.packed = 0;
460 cpu->c = 0;
461 cpu->e = 0;
462 cpu->h = 0;
463 cpu->l = 0;
464 cpu->sp = 0;
465 cpu->pc = 0;
466 }
467 }
468
469 GBVideoReset(&gb->video);
470 GBTimerReset(&gb->timer);
471 GBIOReset(gb);
472 if (!gb->biosVf) {
473 GBSkipBIOS(gb);
474 } else {
475 mTimingSchedule(&gb->timing, &gb->timer.event, 0);
476 }
477
478 GBAudioReset(&gb->audio);
479 GBSIOReset(&gb->sio);
480
481 cpu->memory.setActiveRegion(cpu, cpu->pc);
482
483 gb->sramMaskWriteback = false;
484 GBSavedataUnmask(gb);
485}
486
487void GBSkipBIOS(struct GB* gb) {
488 struct SM83Core* cpu = gb->cpu;
489 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
490 int nextDiv = 0;
491
492 switch (gb->model) {
493 case GB_MODEL_AUTODETECT: // Silence warnings
494 gb->model = GB_MODEL_DMG;
495 // Fall through
496 case GB_MODEL_DMG:
497 cpu->a = 1;
498 cpu->f.packed = 0xB0;
499 cpu->c = 0x13;
500 cpu->e = 0xD8;
501 cpu->h = 1;
502 cpu->l = 0x4D;
503 gb->timer.internalDiv = 0xABC;
504 nextDiv = 4;
505 break;
506 case GB_MODEL_SGB:
507 cpu->a = 1;
508 cpu->f.packed = 0x00;
509 cpu->c = 0x14;
510 cpu->e = 0x00;
511 cpu->h = 0xC0;
512 cpu->l = 0x60;
513 gb->timer.internalDiv = 0xD85;
514 nextDiv = 8;
515 break;
516 case GB_MODEL_MGB:
517 cpu->a = 0xFF;
518 cpu->f.packed = 0xB0;
519 cpu->c = 0x13;
520 cpu->e = 0xD8;
521 cpu->h = 1;
522 cpu->l = 0x4D;
523 gb->timer.internalDiv = 0xABC;
524 nextDiv = 4;
525 break;
526 case GB_MODEL_SGB2:
527 cpu->a = 0xFF;
528 cpu->f.packed = 0x00;
529 cpu->c = 0x14;
530 cpu->e = 0x00;
531 cpu->h = 0xC0;
532 cpu->l = 0x60;
533 gb->timer.internalDiv = 0xD84;
534 nextDiv = 8;
535 break;
536 case GB_MODEL_AGB:
537 cpu->b = 1;
538 // Fall through
539 case GB_MODEL_CGB:
540 cpu->a = 0x11;
541 if (gb->model == GB_MODEL_AGB) {
542 cpu->f.packed = 0x00;
543 } else {
544 cpu->f.packed = 0x80;
545 }
546 cpu->c = 0;
547 cpu->h = 0;
548 if (cart->cgb & 0x80) {
549 cpu->d = 0xFF;
550 cpu->e = 0x56;
551 cpu->l = 0x0D;
552 gb->timer.internalDiv = 0x2F0;
553 } else {
554 cpu->e = 0x08;
555 cpu->l = 0x7C;
556 gb->timer.internalDiv = 0x260;
557 }
558 nextDiv = 0xC;
559 break;
560 }
561
562 cpu->sp = 0xFFFE;
563 cpu->pc = 0x100;
564
565 gb->timer.nextDiv = GB_DMG_DIV_PERIOD * (16 - nextDiv);
566
567 mTimingDeschedule(&gb->timing, &gb->timer.event);
568 mTimingSchedule(&gb->timing, &gb->timer.event, gb->timer.nextDiv);
569
570 GBIOWrite(gb, REG_LCDC, 0x91);
571 GBVideoSkipBIOS(&gb->video);
572
573 if (gb->biosVf) {
574 GBUnmapBIOS(gb);
575 }
576}
577
578void GBMapBIOS(struct GB* gb) {
579 gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
580 uint8_t* oldRomBase = gb->memory.romBase;
581 gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
582 ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
583 memcpy(&gb->memory.romBase[size], &oldRomBase[size], GB_SIZE_CART_BANK0 - size);
584 if (size > 0x100) {
585 memcpy(&gb->memory.romBase[0x100], &oldRomBase[0x100], sizeof(struct GBCartridge));
586 }
587}
588
589void GBUnmapBIOS(struct GB* gb) {
590 if (gb->memory.romBase < gb->memory.rom || gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
591 free(gb->memory.romBase);
592 if (gb->memory.mbcType == GB_MMM01) {
593 GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
594 } else {
595 GBMBCSwitchBank0(gb, 0);
596 }
597 }
598 // XXX: Force AGB registers for AGB-mode
599 if (gb->model == GB_MODEL_AGB && gb->cpu->pc == 0x100) {
600 gb->cpu->b = 1;
601 }
602}
603
604void GBDetectModel(struct GB* gb) {
605 if (gb->model != GB_MODEL_AUTODETECT) {
606 return;
607 }
608 if (gb->biosVf) {
609 switch (_GBBiosCRC32(gb->biosVf)) {
610 case DMG_BIOS_CHECKSUM:
611 case DMG_2_BIOS_CHECKSUM:
612 gb->model = GB_MODEL_DMG;
613 break;
614 case MGB_BIOS_CHECKSUM:
615 gb->model = GB_MODEL_MGB;
616 break;
617 case SGB_BIOS_CHECKSUM:
618 gb->model = GB_MODEL_SGB;
619 break;
620 case SGB2_BIOS_CHECKSUM:
621 gb->model = GB_MODEL_SGB2;
622 break;
623 case CGB_BIOS_CHECKSUM:
624 gb->model = GB_MODEL_CGB;
625 break;
626 default:
627 gb->biosVf->close(gb->biosVf);
628 gb->biosVf = NULL;
629 }
630 }
631 if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
632 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
633 if (cart->cgb & 0x80) {
634 gb->model = GB_MODEL_CGB;
635 } else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
636 gb->model = GB_MODEL_SGB;
637 } else {
638 gb->model = GB_MODEL_DMG;
639 }
640 }
641
642 switch (gb->model) {
643 case GB_MODEL_DMG:
644 case GB_MODEL_SGB:
645 case GB_MODEL_AUTODETECT: //Silence warnings
646 gb->audio.style = GB_AUDIO_DMG;
647 break;
648 case GB_MODEL_MGB:
649 case GB_MODEL_SGB2:
650 gb->audio.style = GB_AUDIO_MGB;
651 break;
652 case GB_MODEL_AGB:
653 case GB_MODEL_CGB:
654 gb->audio.style = GB_AUDIO_CGB;
655 break;
656 }
657}
658
659int GBValidModels(const uint8_t* bank0) {
660 const struct GBCartridge* cart = (const struct GBCartridge*) &bank0[0x100];
661 int models;
662 if (cart->cgb == 0x80) {
663 models = GB_MODEL_CGB | GB_MODEL_MGB;
664 } else if (cart->cgb == 0xC0) {
665 models = GB_MODEL_CGB;
666 } else {
667 models = GB_MODEL_MGB;
668 }
669 if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
670 models |= GB_MODEL_SGB;
671 }
672 return models;
673}
674
675void GBUpdateIRQs(struct GB* gb) {
676 int irqs = gb->memory.ie & gb->memory.io[REG_IF] & 0x1F;
677 if (!irqs) {
678 gb->cpu->irqPending = false;
679 return;
680 }
681 gb->cpu->halted = false;
682
683 if (!gb->memory.ime) {
684 gb->cpu->irqPending = false;
685 return;
686 }
687 if (gb->cpu->irqPending) {
688 return;
689 }
690 SM83RaiseIRQ(gb->cpu);
691}
692
693void GBProcessEvents(struct SM83Core* cpu) {
694 struct GB* gb = (struct GB*) cpu->master;
695 do {
696 int32_t cycles = cpu->cycles;
697 int32_t nextEvent;
698
699 cpu->cycles = 0;
700#ifdef USE_DEBUGGERS
701 gb->timing.globalCycles += cycles;
702#endif
703 cpu->nextEvent = INT_MAX;
704
705 nextEvent = cycles;
706 do {
707 nextEvent = mTimingTick(&gb->timing, nextEvent);
708 } while (gb->cpuBlocked && !gb->earlyExit);
709 cpu->nextEvent = nextEvent;
710
711 if (cpu->halted) {
712 cpu->cycles = cpu->nextEvent;
713 if (!gb->memory.ie || !gb->memory.ime) {
714 break;
715 }
716 }
717 if (gb->earlyExit) {
718 break;
719 }
720 } while (cpu->cycles >= cpu->nextEvent);
721 gb->earlyExit = false;
722 if (gb->cpuBlocked) {
723 cpu->cycles = cpu->nextEvent;
724 }
725}
726
727void GBSetInterrupts(struct SM83Core* cpu, bool enable) {
728 struct GB* gb = (struct GB*) cpu->master;
729 mTimingDeschedule(&gb->timing, &gb->eiPending);
730 if (!enable) {
731 gb->memory.ime = false;
732 GBUpdateIRQs(gb);
733 } else {
734 mTimingSchedule(&gb->timing, &gb->eiPending, 4);
735 }
736}
737
738uint16_t GBIRQVector(struct SM83Core* cpu) {
739 struct GB* gb = (struct GB*) cpu->master;
740 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
741
742 if (irqs & (1 << GB_IRQ_VBLANK)) {
743 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
744 return GB_VECTOR_VBLANK;
745 }
746 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
747 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
748 return GB_VECTOR_LCDSTAT;
749 }
750 if (irqs & (1 << GB_IRQ_TIMER)) {
751 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
752 return GB_VECTOR_TIMER;
753 }
754 if (irqs & (1 << GB_IRQ_SIO)) {
755 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
756 return GB_VECTOR_SIO;
757 }
758 if (irqs & (1 << GB_IRQ_KEYPAD)) {
759 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
760 return GB_VECTOR_KEYPAD;
761 }
762 return 0;
763}
764
765static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
766 UNUSED(timing);
767 UNUSED(cyclesLate);
768 struct GB* gb = user;
769 gb->memory.ime = true;
770 GBUpdateIRQs(gb);
771}
772
773void GBHalt(struct SM83Core* cpu) {
774 struct GB* gb = (struct GB*) cpu->master;
775 if (!(gb->memory.ie & gb->memory.io[REG_IF] & 0x1F)) {
776 cpu->cycles = cpu->nextEvent;
777 cpu->halted = true;
778 } else if (!gb->memory.ime) {
779 mLOG(GB, GAME_ERROR, "HALT bug");
780 cpu->executionState = SM83_CORE_HALT_BUG;
781 }
782}
783
784void GBStop(struct SM83Core* cpu) {
785 struct GB* gb = (struct GB*) cpu->master;
786 if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_KEY1] & 1) {
787 gb->doubleSpeed ^= 1;
788 gb->audio.timingFactor = gb->doubleSpeed + 1;
789 gb->memory.io[REG_KEY1] = 0;
790 gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
791 } else {
792 int sleep = ~(gb->memory.io[REG_JOYP] & 0x30);
793 size_t c;
794 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
795 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
796 if (sleep && callbacks->sleep) {
797 callbacks->sleep(callbacks->context);
798 } else if (callbacks->shutdown) {
799 callbacks->shutdown(callbacks->context);
800 }
801 }
802 }
803}
804
805void GBIllegal(struct SM83Core* cpu) {
806 struct GB* gb = (struct GB*) cpu->master;
807 mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X", cpu->pc, cpu->bus);
808#ifdef USE_DEBUGGERS
809 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
810 struct mDebuggerEntryInfo info = {
811 .address = cpu->pc,
812 .type.bp.opcode = cpu->bus
813 };
814 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
815 }
816#endif
817 // Hang forever
818 gb->memory.ime = 0;
819 --cpu->pc;
820}
821
822bool GBIsROM(struct VFile* vf) {
823 if (!vf) {
824 return false;
825 }
826 vf->seek(vf, 0x104, SEEK_SET);
827 uint8_t header[4];
828
829 if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
830 return false;
831 }
832 if (memcmp(header, _knownHeader, sizeof(header))) {
833 return false;
834 }
835 return true;
836}
837
838void GBGetGameTitle(const struct GB* gb, char* out) {
839 const struct GBCartridge* cart = NULL;
840 if (gb->memory.rom) {
841 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
842 }
843 if (!cart) {
844 return;
845 }
846 if (cart->oldLicensee != 0x33) {
847 memcpy(out, cart->titleLong, 16);
848 } else {
849 memcpy(out, cart->titleShort, 11);
850 }
851}
852
853void GBGetGameCode(const struct GB* gb, char* out) {
854 memset(out, 0, 8);
855 const struct GBCartridge* cart = NULL;
856 if (gb->memory.rom) {
857 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
858 }
859 if (!cart) {
860 return;
861 }
862 if (cart->cgb == 0xC0) {
863 memcpy(out, "CGB-????", 8);
864 } else {
865 memcpy(out, "DMG-????", 8);
866 }
867 if (cart->oldLicensee == 0x33) {
868 memcpy(&out[4], cart->maker, 4);
869 }
870}
871
872void GBFrameStarted(struct GB* gb) {
873 GBTestKeypadIRQ(gb);
874
875 size_t c;
876 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
877 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
878 if (callbacks->videoFrameStarted) {
879 callbacks->videoFrameStarted(callbacks->context);
880 }
881 }
882}
883
884void GBFrameEnded(struct GB* gb) {
885 GBSramClean(gb, gb->video.frameCounter);
886
887 if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
888 struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
889 size_t i;
890 for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
891 struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
892 mCheatRefresh(device, cheats);
893 }
894 }
895
896 // TODO: Move to common code
897 if (gb->stream && gb->stream->postVideoFrame) {
898 const color_t* pixels;
899 size_t stride;
900 gb->video.renderer->getPixels(gb->video.renderer, &stride, (const void**) &pixels);
901 gb->stream->postVideoFrame(gb->stream, pixels, stride);
902 }
903
904 size_t c;
905 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
906 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
907 if (callbacks->videoFrameEnded) {
908 callbacks->videoFrameEnded(callbacks->context);
909 }
910 }
911}
912
913enum GBModel GBNameToModel(const char* model) {
914 if (strcasecmp(model, "DMG") == 0) {
915 return GB_MODEL_DMG;
916 } else if (strcasecmp(model, "CGB") == 0) {
917 return GB_MODEL_CGB;
918 } else if (strcasecmp(model, "AGB") == 0) {
919 return GB_MODEL_AGB;
920 } else if (strcasecmp(model, "SGB") == 0) {
921 return GB_MODEL_SGB;
922 } else if (strcasecmp(model, "MGB") == 0) {
923 return GB_MODEL_MGB;
924 } else if (strcasecmp(model, "SGB2") == 0) {
925 return GB_MODEL_SGB2;
926 }
927 return GB_MODEL_AUTODETECT;
928}
929
930const char* GBModelToName(enum GBModel model) {
931 switch (model) {
932 case GB_MODEL_DMG:
933 return "DMG";
934 case GB_MODEL_SGB:
935 return "SGB";
936 case GB_MODEL_MGB:
937 return "MGB";
938 case GB_MODEL_SGB2:
939 return "SGB2";
940 case GB_MODEL_CGB:
941 return "CGB";
942 case GB_MODEL_AGB:
943 return "AGB";
944 default:
945 case GB_MODEL_AUTODETECT:
946 return NULL;
947 }
948}