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 gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
423 gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
424 ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
425 memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
426 if (size > 0x100) {
427 memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge));
428 }
429
430 cpu->a = 0;
431 cpu->f.packed = 0;
432 cpu->c = 0;
433 cpu->e = 0;
434 cpu->h = 0;
435 cpu->l = 0;
436 cpu->sp = 0;
437 cpu->pc = 0;
438 }
439 }
440
441 cpu->b = 0;
442 cpu->d = 0;
443
444 gb->timer.internalDiv = 0;
445
446 gb->cpuBlocked = false;
447 gb->earlyExit = false;
448 gb->doubleSpeed = 0;
449
450 if (gb->yankedRomSize) {
451 gb->memory.romSize = gb->yankedRomSize;
452 gb->yankedRomSize = 0;
453 }
454
455 gb->sgbBit = -1;
456 gb->sgbControllers = 0;
457 gb->sgbCurrentController = 0;
458 gb->currentSgbBits = 0;
459 memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
460
461 mTimingClear(&gb->timing);
462
463 GBMemoryReset(gb);
464 GBVideoReset(&gb->video);
465 GBTimerReset(&gb->timer);
466 if (!gb->biosVf) {
467 GBSkipBIOS(gb);
468 } else {
469 mTimingSchedule(&gb->timing, &gb->timer.event, 0);
470 }
471
472 GBIOReset(gb);
473 GBAudioReset(&gb->audio);
474 GBSIOReset(&gb->sio);
475
476 cpu->memory.setActiveRegion(cpu, cpu->pc);
477
478 gb->sramMaskWriteback = false;
479 GBSavedataUnmask(gb);
480}
481
482void GBSkipBIOS(struct GB* gb) {
483 struct LR35902Core* cpu = gb->cpu;
484 int nextDiv = 0;
485
486 switch (gb->model) {
487 case GB_MODEL_AUTODETECT: // Silence warnings
488 gb->model = GB_MODEL_DMG;
489 // Fall through
490 case GB_MODEL_DMG:
491 cpu->a = 1;
492 cpu->f.packed = 0xB0;
493 cpu->c = 0x13;
494 cpu->e = 0xD8;
495 cpu->h = 1;
496 cpu->l = 0x4D;
497 gb->timer.internalDiv = 0xABC;
498 nextDiv = 4;
499 break;
500 case GB_MODEL_SGB:
501 cpu->a = 1;
502 cpu->f.packed = 0x00;
503 cpu->c = 0x14;
504 cpu->e = 0x00;
505 cpu->h = 0xC0;
506 cpu->l = 0x60;
507 gb->timer.internalDiv = 0xABC;
508 nextDiv = 4;
509 break;
510 case GB_MODEL_MGB:
511 cpu->a = 0xFF;
512 cpu->f.packed = 0xB0;
513 cpu->c = 0x13;
514 cpu->e = 0xD8;
515 cpu->h = 1;
516 cpu->l = 0x4D;
517 gb->timer.internalDiv = 0xABC;
518 nextDiv = 4;
519 break;
520 case GB_MODEL_SGB2:
521 cpu->a = 0xFF;
522 cpu->f.packed = 0x00;
523 cpu->c = 0x14;
524 cpu->e = 0x00;
525 cpu->h = 0xC0;
526 cpu->l = 0x60;
527 gb->timer.internalDiv = 0xABC;
528 nextDiv = 4;
529 break;
530 case GB_MODEL_AGB:
531 cpu->a = 0x11;
532 cpu->b = 1;
533 cpu->f.packed = 0x00;
534 cpu->c = 0;
535 cpu->e = 0x08;
536 cpu->h = 0;
537 cpu->l = 0x7C;
538 gb->timer.internalDiv = 0x1EA;
539 nextDiv = 0xC;
540 break;
541 case GB_MODEL_CGB:
542 cpu->a = 0x11;
543 cpu->f.packed = 0x80;
544 cpu->c = 0;
545 cpu->e = 0x08;
546 cpu->h = 0;
547 cpu->l = 0x7C;
548 gb->timer.internalDiv = 0x1EA;
549 nextDiv = 0xC;
550 break;
551 }
552
553 cpu->sp = 0xFFFE;
554 cpu->pc = 0x100;
555
556 mTimingDeschedule(&gb->timing, &gb->timer.event);
557 mTimingSchedule(&gb->timing, &gb->timer.event, 0);
558
559 GBIOWrite(gb, REG_LCDC, 0x91);
560
561 if (gb->biosVf) {
562 GBUnmapBIOS(gb);
563 }
564}
565
566void GBUnmapBIOS(struct GB* gb) {
567 if (gb->memory.romBase < gb->memory.rom || gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
568 free(gb->memory.romBase);
569 gb->memory.romBase = gb->memory.rom;
570 }
571 // XXX: Force AGB registers for AGB-mode
572 if (gb->model == GB_MODEL_AGB && gb->cpu->pc == 0x100) {
573 gb->cpu->b = 1;
574 }
575}
576
577void GBDetectModel(struct GB* gb) {
578 if (gb->model != GB_MODEL_AUTODETECT) {
579 return;
580 }
581 if (gb->biosVf) {
582 switch (_GBBiosCRC32(gb->biosVf)) {
583 case DMG_BIOS_CHECKSUM:
584 case DMG_2_BIOS_CHECKSUM:
585 gb->model = GB_MODEL_DMG;
586 break;
587 case MGB_BIOS_CHECKSUM:
588 gb->model = GB_MODEL_MGB;
589 break;
590 case SGB_BIOS_CHECKSUM:
591 gb->model = GB_MODEL_SGB;
592 break;
593 case SGB2_BIOS_CHECKSUM:
594 gb->model = GB_MODEL_SGB2;
595 break;
596 case CGB_BIOS_CHECKSUM:
597 gb->model = GB_MODEL_CGB;
598 break;
599 default:
600 gb->biosVf->close(gb->biosVf);
601 gb->biosVf = NULL;
602 }
603 }
604 if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
605 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
606 if (cart->cgb & 0x80) {
607 gb->model = GB_MODEL_CGB;
608 } else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
609 gb->model = GB_MODEL_SGB;
610 } else {
611 gb->model = GB_MODEL_DMG;
612 }
613 }
614
615 switch (gb->model) {
616 case GB_MODEL_DMG:
617 case GB_MODEL_SGB:
618 case GB_MODEL_AUTODETECT: //Silence warnings
619 gb->audio.style = GB_AUDIO_DMG;
620 break;
621 case GB_MODEL_MGB:
622 case GB_MODEL_SGB2:
623 gb->audio.style = GB_AUDIO_MGB;
624 break;
625 case GB_MODEL_AGB:
626 case GB_MODEL_CGB:
627 gb->audio.style = GB_AUDIO_CGB;
628 break;
629 }
630}
631
632void GBUpdateIRQs(struct GB* gb) {
633 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
634 if (!irqs) {
635 gb->cpu->irqPending = false;
636 return;
637 }
638 gb->cpu->halted = false;
639
640 if (!gb->memory.ime) {
641 gb->cpu->irqPending = false;
642 return;
643 }
644 if (gb->cpu->irqPending) {
645 return;
646 }
647 LR35902RaiseIRQ(gb->cpu);
648}
649
650void GBProcessEvents(struct LR35902Core* cpu) {
651 struct GB* gb = (struct GB*) cpu->master;
652 do {
653 int32_t cycles = cpu->cycles;
654 int32_t nextEvent;
655
656 cpu->cycles = 0;
657 cpu->nextEvent = INT_MAX;
658
659 nextEvent = cycles;
660 do {
661 nextEvent = mTimingTick(&gb->timing, nextEvent);
662 } while (gb->cpuBlocked);
663 cpu->nextEvent = nextEvent;
664
665 if (cpu->halted) {
666 cpu->cycles = cpu->nextEvent;
667 if (!gb->memory.ie || !gb->memory.ime) {
668 break;
669 }
670 }
671 if (gb->earlyExit) {
672 break;
673 }
674 } while (cpu->cycles >= cpu->nextEvent);
675 gb->earlyExit = false;
676}
677
678void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
679 struct GB* gb = (struct GB*) cpu->master;
680 mTimingDeschedule(&gb->timing, &gb->eiPending);
681 if (!enable) {
682 gb->memory.ime = false;
683 GBUpdateIRQs(gb);
684 } else {
685 mTimingSchedule(&gb->timing, &gb->eiPending, 4);
686 }
687}
688
689uint16_t GBIRQVector(struct LR35902Core* cpu) {
690 struct GB* gb = (struct GB*) cpu->master;
691 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
692
693 if (irqs & (1 << GB_IRQ_VBLANK)) {
694 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
695 return GB_VECTOR_VBLANK;
696 }
697 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
698 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
699 return GB_VECTOR_LCDSTAT;
700 }
701 if (irqs & (1 << GB_IRQ_TIMER)) {
702 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
703 return GB_VECTOR_TIMER;
704 }
705 if (irqs & (1 << GB_IRQ_SIO)) {
706 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
707 return GB_VECTOR_SIO;
708 }
709 if (irqs & (1 << GB_IRQ_KEYPAD)) {
710 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
711 return GB_VECTOR_KEYPAD;
712 }
713 return 0;
714}
715
716static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
717 UNUSED(timing);
718 UNUSED(cyclesLate);
719 struct GB* gb = user;
720 gb->memory.ime = true;
721 GBUpdateIRQs(gb);
722}
723
724void GBHalt(struct LR35902Core* cpu) {
725 struct GB* gb = (struct GB*) cpu->master;
726 if (!(gb->memory.ie & gb->memory.io[REG_IF])) {
727 cpu->cycles = cpu->nextEvent;
728 cpu->halted = true;
729 } else if (gb->model < GB_MODEL_CGB) {
730 mLOG(GB, STUB, "Unimplemented HALT bug");
731 }
732}
733
734void GBStop(struct LR35902Core* cpu) {
735 struct GB* gb = (struct GB*) cpu->master;
736 if (cpu->bus) {
737 mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X", cpu->pc, cpu->bus);
738 }
739 if (gb->memory.io[REG_KEY1] & 1) {
740 gb->doubleSpeed ^= 1;
741 gb->audio.timingFactor = gb->doubleSpeed + 1;
742 gb->memory.io[REG_KEY1] = 0;
743 gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
744 } else if (cpu->bus) {
745#ifdef USE_DEBUGGERS
746 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
747 struct mDebuggerEntryInfo info = {
748 .address = cpu->pc - 1,
749 .type.bp.opcode = 0x1000 | cpu->bus
750 };
751 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
752 }
753#endif
754 // Hang forever
755 gb->memory.ime = 0;
756 cpu->pc -= 2;
757 }
758 // TODO: Actually stop
759}
760
761void GBIllegal(struct LR35902Core* cpu) {
762 struct GB* gb = (struct GB*) cpu->master;
763 mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X", cpu->pc, cpu->bus);
764#ifdef USE_DEBUGGERS
765 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
766 struct mDebuggerEntryInfo info = {
767 .address = cpu->pc,
768 .type.bp.opcode = cpu->bus
769 };
770 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
771 }
772#endif
773 // Hang forever
774 gb->memory.ime = 0;
775 --cpu->pc;
776}
777
778bool GBIsROM(struct VFile* vf) {
779 if (!vf) {
780 return false;
781 }
782 vf->seek(vf, 0x104, SEEK_SET);
783 uint8_t header[4];
784
785 if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
786 return false;
787 }
788 if (memcmp(header, _knownHeader, sizeof(header))) {
789 return false;
790 }
791 return true;
792}
793
794void GBGetGameTitle(const struct GB* gb, char* out) {
795 const struct GBCartridge* cart = NULL;
796 if (gb->memory.rom) {
797 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
798 }
799 if (!cart) {
800 return;
801 }
802 if (cart->oldLicensee != 0x33) {
803 memcpy(out, cart->titleLong, 16);
804 } else {
805 memcpy(out, cart->titleShort, 11);
806 }
807}
808
809void GBGetGameCode(const struct GB* gb, char* out) {
810 memset(out, 0, 8);
811 const struct GBCartridge* cart = NULL;
812 if (gb->memory.rom) {
813 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
814 }
815 if (!cart) {
816 return;
817 }
818 if (cart->cgb == 0xC0) {
819 memcpy(out, "CGB-????", 8);
820 } else {
821 memcpy(out, "DMG-????", 8);
822 }
823 if (cart->oldLicensee == 0x33) {
824 memcpy(&out[4], cart->maker, 4);
825 }
826}
827
828void GBFrameStarted(struct GB* gb) {
829 GBTestKeypadIRQ(gb);
830
831 size_t c;
832 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
833 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
834 if (callbacks->videoFrameStarted) {
835 callbacks->videoFrameStarted(callbacks->context);
836 }
837 }
838}
839
840void GBFrameEnded(struct GB* gb) {
841 GBSramClean(gb, gb->video.frameCounter);
842
843 if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
844 struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
845 size_t i;
846 for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
847 struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
848 mCheatRefresh(device, cheats);
849 }
850 }
851
852 // TODO: Move to common code
853 if (gb->stream && gb->stream->postVideoFrame) {
854 const color_t* pixels;
855 size_t stride;
856 gb->video.renderer->getPixels(gb->video.renderer, &stride, (const void**) &pixels);
857 gb->stream->postVideoFrame(gb->stream, pixels, stride);
858 }
859
860 size_t c;
861 for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
862 struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
863 if (callbacks->videoFrameEnded) {
864 callbacks->videoFrameEnded(callbacks->context);
865 }
866 }
867}
868
869enum GBModel GBNameToModel(const char* model) {
870 if (strcasecmp(model, "DMG") == 0) {
871 return GB_MODEL_DMG;
872 } else if (strcasecmp(model, "CGB") == 0) {
873 return GB_MODEL_CGB;
874 } else if (strcasecmp(model, "AGB") == 0) {
875 return GB_MODEL_AGB;
876 } else if (strcasecmp(model, "SGB") == 0) {
877 return GB_MODEL_SGB;
878 } else if (strcasecmp(model, "MGB") == 0) {
879 return GB_MODEL_MGB;
880 } else if (strcasecmp(model, "SGB2") == 0) {
881 return GB_MODEL_SGB2;
882 }
883 return GB_MODEL_AUTODETECT;
884}
885
886const char* GBModelToName(enum GBModel model) {
887 switch (model) {
888 case GB_MODEL_DMG:
889 return "DMG";
890 case GB_MODEL_SGB:
891 return "SGB";
892 case GB_MODEL_MGB:
893 return "MGB";
894 case GB_MODEL_SGB2:
895 return "SGB2";
896 case GB_MODEL_CGB:
897 return "CGB";
898 case GB_MODEL_AGB:
899 return "AGB";
900 default:
901 case GB_MODEL_AUTODETECT:
902 return NULL;
903 }
904}