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[GB_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 && gb->memory.rom) {
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 gb->model = GB_MODEL_DMG;
558 gb->memory.io[GB_REG_KEY1] = 0xFF;
559 gb->memory.io[GB_REG_BCPS] = 0x88; // Faked writing 4 BG palette entries
560 gb->memory.io[GB_REG_OCPS] = 0x90; // Faked writing 8 OBJ palette entries
561 gb->memory.io[GB_REG_SVBK] = 0xFF;
562 GBVideoDisableCGB(&gb->video);
563 }
564 nextDiv = 0xC;
565 break;
566 }
567
568 cpu->sp = 0xFFFE;
569 cpu->pc = 0x100;
570
571 gb->timer.nextDiv = GB_DMG_DIV_PERIOD * (16 - nextDiv);
572
573 mTimingDeschedule(&gb->timing, &gb->timer.event);
574 mTimingSchedule(&gb->timing, &gb->timer.event, gb->timer.nextDiv);
575
576 GBIOWrite(gb, GB_REG_LCDC, 0x91);
577 GBVideoSkipBIOS(&gb->video);
578
579 if (gb->biosVf) {
580 GBUnmapBIOS(gb);
581 }
582}
583
584void GBMapBIOS(struct GB* gb) {
585 gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
586 uint8_t* oldRomBase = gb->memory.romBase;
587 gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
588 ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
589 memcpy(&gb->memory.romBase[size], &oldRomBase[size], GB_SIZE_CART_BANK0 - size);
590 if (size > 0x100) {
591 memcpy(&gb->memory.romBase[0x100], &oldRomBase[0x100], sizeof(struct GBCartridge));
592 }
593}
594
595void GBUnmapBIOS(struct GB* gb) {
596 if (gb->memory.romBase < gb->memory.rom || gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
597 free(gb->memory.romBase);
598 if (gb->memory.mbcType == GB_MMM01) {
599 GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
600 } else {
601 GBMBCSwitchBank0(gb, 0);
602 }
603 }
604 // XXX: Force AGB registers for AGB-mode
605 if (gb->model == GB_MODEL_AGB && gb->cpu->pc == 0x100) {
606 gb->cpu->b = 1;
607 }
608}
609
610void GBDetectModel(struct GB* gb) {
611 if (gb->model != GB_MODEL_AUTODETECT) {
612 return;
613 }
614 if (gb->biosVf) {
615 switch (_GBBiosCRC32(gb->biosVf)) {
616 case DMG_BIOS_CHECKSUM:
617 case DMG_2_BIOS_CHECKSUM:
618 gb->model = GB_MODEL_DMG;
619 break;
620 case MGB_BIOS_CHECKSUM:
621 gb->model = GB_MODEL_MGB;
622 break;
623 case SGB_BIOS_CHECKSUM:
624 gb->model = GB_MODEL_SGB;
625 break;
626 case SGB2_BIOS_CHECKSUM:
627 gb->model = GB_MODEL_SGB2;
628 break;
629 case CGB_BIOS_CHECKSUM:
630 gb->model = GB_MODEL_CGB;
631 break;
632 default:
633 gb->biosVf->close(gb->biosVf);
634 gb->biosVf = NULL;
635 }
636 }
637 if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
638 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
639 if (cart->cgb & 0x80) {
640 gb->model = GB_MODEL_CGB;
641 } else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
642 gb->model = GB_MODEL_SGB;
643 } else {
644 gb->model = GB_MODEL_DMG;
645 }
646 }
647
648 switch (gb->model) {
649 case GB_MODEL_DMG:
650 case GB_MODEL_SGB:
651 case GB_MODEL_AUTODETECT: //Silence warnings
652 gb->audio.style = GB_AUDIO_DMG;
653 break;
654 case GB_MODEL_MGB:
655 case GB_MODEL_SGB2:
656 gb->audio.style = GB_AUDIO_MGB;
657 break;
658 case GB_MODEL_AGB:
659 case GB_MODEL_CGB:
660 gb->audio.style = GB_AUDIO_CGB;
661 break;
662 }
663}
664
665int GBValidModels(const uint8_t* bank0) {
666 const struct GBCartridge* cart = (const struct GBCartridge*) &bank0[0x100];
667 int models;
668 if (cart->cgb == 0x80) {
669 models = GB_MODEL_CGB | GB_MODEL_MGB;
670 } else if (cart->cgb == 0xC0) {
671 models = GB_MODEL_CGB;
672 } else {
673 models = GB_MODEL_MGB;
674 }
675 if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
676 models |= GB_MODEL_SGB;
677 }
678 return models;
679}
680
681void GBUpdateIRQs(struct GB* gb) {
682 int irqs = gb->memory.ie & gb->memory.io[GB_REG_IF] & 0x1F;
683 if (!irqs) {
684 gb->cpu->irqPending = false;
685 return;
686 }
687 gb->cpu->halted = false;
688
689 if (!gb->memory.ime) {
690 gb->cpu->irqPending = false;
691 return;
692 }
693 if (gb->cpu->irqPending) {
694 return;
695 }
696 SM83RaiseIRQ(gb->cpu);
697}
698
699void GBProcessEvents(struct SM83Core* cpu) {
700 struct GB* gb = (struct GB*) cpu->master;
701 do {
702 int32_t cycles = cpu->cycles;
703 int32_t nextEvent;
704
705 cpu->cycles = 0;
706#ifdef USE_DEBUGGERS
707 gb->timing.globalCycles += cycles;
708#endif
709 cpu->nextEvent = INT_MAX;
710
711 nextEvent = cycles;
712 do {
713 nextEvent = mTimingTick(&gb->timing, nextEvent);
714 } while (gb->cpuBlocked && !gb->earlyExit);
715 cpu->nextEvent = nextEvent;
716
717 if (cpu->halted) {
718 cpu->cycles = cpu->nextEvent;
719 if (!gb->memory.ie || !gb->memory.ime) {
720 break;
721 }
722 }
723 if (gb->earlyExit) {
724 break;
725 }
726 } while (cpu->cycles >= cpu->nextEvent);
727 gb->earlyExit = false;
728 if (gb->cpuBlocked) {
729 cpu->cycles = cpu->nextEvent;
730 }
731}
732
733void GBSetInterrupts(struct SM83Core* cpu, bool enable) {
734 struct GB* gb = (struct GB*) cpu->master;
735 mTimingDeschedule(&gb->timing, &gb->eiPending);
736 if (!enable) {
737 gb->memory.ime = false;
738 GBUpdateIRQs(gb);
739 } else {
740 mTimingSchedule(&gb->timing, &gb->eiPending, 4);
741 }
742}
743
744uint16_t GBIRQVector(struct SM83Core* cpu) {
745 struct GB* gb = (struct GB*) cpu->master;
746 int irqs = gb->memory.ie & gb->memory.io[GB_REG_IF];
747
748 if (irqs & (1 << GB_IRQ_VBLANK)) {
749 gb->memory.io[GB_REG_IF] &= ~(1 << GB_IRQ_VBLANK);
750 return GB_VECTOR_VBLANK;
751 }
752 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
753 gb->memory.io[GB_REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
754 return GB_VECTOR_LCDSTAT;
755 }
756 if (irqs & (1 << GB_IRQ_TIMER)) {
757 gb->memory.io[GB_REG_IF] &= ~(1 << GB_IRQ_TIMER);
758 return GB_VECTOR_TIMER;
759 }
760 if (irqs & (1 << GB_IRQ_SIO)) {
761 gb->memory.io[GB_REG_IF] &= ~(1 << GB_IRQ_SIO);
762 return GB_VECTOR_SIO;
763 }
764 if (irqs & (1 << GB_IRQ_KEYPAD)) {
765 gb->memory.io[GB_REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
766 return GB_VECTOR_KEYPAD;
767 }
768 return 0;
769}
770
771static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
772 UNUSED(timing);
773 UNUSED(cyclesLate);
774 struct GB* gb = user;
775 gb->memory.ime = true;
776 GBUpdateIRQs(gb);
777}
778
779void GBHalt(struct SM83Core* cpu) {
780 struct GB* gb = (struct GB*) cpu->master;
781 if (!(gb->memory.ie & gb->memory.io[GB_REG_IF] & 0x1F)) {
782 cpu->cycles = cpu->nextEvent;
783 cpu->halted = true;
784 } else if (!gb->memory.ime) {
785 mLOG(GB, GAME_ERROR, "HALT bug");
786 cpu->executionState = SM83_CORE_HALT_BUG;
787 }
788}
789
790void GBStop(struct SM83Core* cpu) {
791 struct GB* gb = (struct GB*) cpu->master;
792 if (gb->model >= GB_MODEL_CGB && gb->memory.io[GB_REG_KEY1] & 1) {
793 gb->doubleSpeed ^= 1;
794 gb->audio.timingFactor = gb->doubleSpeed + 1;
795 gb->memory.io[GB_REG_KEY1] = 0;
796 gb->memory.io[GB_REG_KEY1] |= gb->doubleSpeed << 7;
797 } else {
798 int sleep = ~(gb->memory.io[GB_REG_JOYP] & 0x30);
799 size_t c;
800 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
801 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
802 if (sleep && callbacks->sleep) {
803 callbacks->sleep(callbacks->context);
804 } else if (callbacks->shutdown) {
805 callbacks->shutdown(callbacks->context);
806 }
807 }
808 }
809}
810
811void GBIllegal(struct SM83Core* cpu) {
812 struct GB* gb = (struct GB*) cpu->master;
813 mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X", cpu->pc, cpu->bus);
814#ifdef USE_DEBUGGERS
815 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
816 struct mDebuggerEntryInfo info = {
817 .address = cpu->pc,
818 .type.bp.opcode = cpu->bus
819 };
820 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
821 }
822#endif
823 // Hang forever
824 gb->memory.ime = 0;
825 --cpu->pc;
826}
827
828bool GBIsROM(struct VFile* vf) {
829 if (!vf) {
830 return false;
831 }
832 vf->seek(vf, 0x104, SEEK_SET);
833 uint8_t header[4];
834
835 if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
836 return false;
837 }
838 if (memcmp(header, _knownHeader, sizeof(header))) {
839 return false;
840 }
841 return true;
842}
843
844void GBGetGameTitle(const struct GB* gb, char* out) {
845 const struct GBCartridge* cart = NULL;
846 if (gb->memory.rom) {
847 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
848 }
849 if (!cart) {
850 return;
851 }
852 if (cart->oldLicensee != 0x33) {
853 memcpy(out, cart->titleLong, 16);
854 } else {
855 memcpy(out, cart->titleShort, 11);
856 }
857}
858
859void GBGetGameCode(const struct GB* gb, char* out) {
860 memset(out, 0, 8);
861 const struct GBCartridge* cart = NULL;
862 if (gb->memory.rom) {
863 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
864 }
865 if (!cart) {
866 return;
867 }
868 if (cart->cgb == 0xC0) {
869 memcpy(out, "CGB-????", 8);
870 } else {
871 memcpy(out, "DMG-????", 8);
872 }
873 if (cart->oldLicensee == 0x33) {
874 memcpy(&out[4], cart->maker, 4);
875 }
876}
877
878void GBFrameStarted(struct GB* gb) {
879 GBTestKeypadIRQ(gb);
880
881 size_t c;
882 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
883 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
884 if (callbacks->videoFrameStarted) {
885 callbacks->videoFrameStarted(callbacks->context);
886 }
887 }
888}
889
890void GBFrameEnded(struct GB* gb) {
891 GBSramClean(gb, gb->video.frameCounter);
892
893 if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
894 struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
895 size_t i;
896 for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
897 struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
898 mCheatRefresh(device, cheats);
899 }
900 }
901
902 // TODO: Move to common code
903 if (gb->stream && gb->stream->postVideoFrame) {
904 const color_t* pixels;
905 size_t stride;
906 gb->video.renderer->getPixels(gb->video.renderer, &stride, (const void**) &pixels);
907 gb->stream->postVideoFrame(gb->stream, pixels, stride);
908 }
909
910 size_t c;
911 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
912 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
913 if (callbacks->videoFrameEnded) {
914 callbacks->videoFrameEnded(callbacks->context);
915 }
916 }
917}
918
919enum GBModel GBNameToModel(const char* model) {
920 if (strcasecmp(model, "DMG") == 0) {
921 return GB_MODEL_DMG;
922 } else if (strcasecmp(model, "CGB") == 0) {
923 return GB_MODEL_CGB;
924 } else if (strcasecmp(model, "AGB") == 0) {
925 return GB_MODEL_AGB;
926 } else if (strcasecmp(model, "SGB") == 0) {
927 return GB_MODEL_SGB;
928 } else if (strcasecmp(model, "MGB") == 0) {
929 return GB_MODEL_MGB;
930 } else if (strcasecmp(model, "SGB2") == 0) {
931 return GB_MODEL_SGB2;
932 }
933 return GB_MODEL_AUTODETECT;
934}
935
936const char* GBModelToName(enum GBModel model) {
937 switch (model) {
938 case GB_MODEL_DMG:
939 return "DMG";
940 case GB_MODEL_SGB:
941 return "SGB";
942 case GB_MODEL_MGB:
943 return "MGB";
944 case GB_MODEL_SGB2:
945 return "SGB2";
946 case GB_MODEL_CGB:
947 return "CGB";
948 case GB_MODEL_AGB:
949 return "AGB";
950 default:
951 case GB_MODEL_AUTODETECT:
952 return NULL;
953 }
954}