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