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 "gb.h"
7
8#include "gb/io.h"
9
10#include "core/core.h"
11#include "core/cheats.h"
12#include "util/crc32.h"
13#include "util/memory.h"
14#include "util/math.h"
15#include "util/patch.h"
16#include "util/vfs.h"
17
18#define CLEANUP_THRESHOLD 15
19
20const uint32_t CGB_LR35902_FREQUENCY = 0x800000;
21const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E;
22
23const uint32_t GB_COMPONENT_MAGIC = 0x400000;
24
25mLOG_DEFINE_CATEGORY(GB, "GB");
26
27static void GBInit(void* cpu, struct mCPUComponent* component);
28static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
29static void GBProcessEvents(struct LR35902Core* cpu);
30static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
31static void GBIllegal(struct LR35902Core* cpu);
32static void GBStop(struct LR35902Core* cpu);
33
34#ifdef _3DS
35extern uint32_t* romBuffer;
36extern size_t romBufferSize;
37#endif
38
39void GBCreate(struct GB* gb) {
40 gb->d.id = GB_COMPONENT_MAGIC;
41 gb->d.init = GBInit;
42 gb->d.deinit = 0;
43}
44
45static void GBInit(void* cpu, struct mCPUComponent* component) {
46 struct GB* gb = (struct GB*) component;
47 gb->cpu = cpu;
48 gb->sync = NULL;
49
50 GBInterruptHandlerInit(&gb->cpu->irqh);
51 GBMemoryInit(gb);
52
53 gb->video.p = gb;
54 GBVideoInit(&gb->video);
55
56 gb->audio.p = gb;
57 GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant
58
59 gb->sio.p = gb;
60 GBSIOInit(&gb->sio);
61
62 gb->timer.p = gb;
63
64 gb->model = GB_MODEL_AUTODETECT;
65
66 gb->biosVf = 0;
67 gb->romVf = 0;
68 gb->sramVf = 0;
69
70 gb->pristineRom = 0;
71 gb->pristineRomSize = 0;
72 gb->yankedRomSize = 0;
73
74 gb->stream = NULL;
75}
76
77bool GBLoadROM(struct GB* gb, struct VFile* vf) {
78 GBUnloadROM(gb);
79 gb->romVf = vf;
80 gb->pristineRomSize = vf->size(vf);
81 vf->seek(vf, 0, SEEK_SET);
82#ifdef _3DS
83 gb->pristineRom = 0;
84 if (gb->pristineRomSize <= romBufferSize) {
85 gb->pristineRom = romBuffer;
86 vf->read(vf, romBuffer, gb->pristineRomSize);
87 }
88#else
89 gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ);
90#endif
91 if (!gb->pristineRom) {
92 return false;
93 }
94 gb->yankedRomSize = 0;
95 gb->memory.rom = gb->pristineRom;
96 gb->memory.romBase = gb->memory.rom;
97 gb->memory.romSize = gb->pristineRomSize;
98 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
99
100 // TODO: error check
101 return true;
102}
103
104bool GBLoadSave(struct GB* gb, struct VFile* vf) {
105 gb->sramVf = vf;
106 gb->sramRealVf = vf;
107 return vf;
108}
109
110static void GBSramDeinit(struct GB* gb) {
111 if (gb->sramVf) {
112 gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize);
113 gb->sramVf->close(gb->sramVf);
114 gb->sramVf = 0;
115 } else if (gb->memory.sram) {
116 mappedMemoryFree(gb->memory.sram, gb->sramSize);
117 }
118 gb->memory.sram = 0;
119}
120
121void GBResizeSram(struct GB* gb, size_t size) {
122 if (gb->memory.sram && size <= gb->sramSize) {
123 return;
124 }
125 mLOG(GB, INFO, "Resizing SRAM to %"PRIz"u bytes", size);
126 struct VFile* vf = gb->sramVf;
127 if (vf) {
128 if (vf == gb->sramRealVf) {
129 if (vf->size(vf) >= 0 && (size_t) vf->size(vf) < size) {
130 uint8_t extdataBuffer[0x100];
131 if (vf->size(vf) & 0xFF) {
132 // Copy over appended data, e.g. RTC data
133 memcpy(extdataBuffer, &gb->memory.sram[gb->sramSize - (vf->size(vf) & 0xFF)], vf->size(vf) & 0xFF);
134 }
135 if (gb->memory.sram) {
136 vf->unmap(vf, gb->memory.sram, gb->sramSize);
137 }
138 vf->truncate(vf, size);
139 gb->memory.sram = vf->map(vf, size, MAP_WRITE);
140 memset(&gb->memory.sram[gb->sramSize], 0xFF, size - gb->sramSize);
141 if (size & 0xFF) {
142 memcpy(&gb->memory.sram[gb->sramSize - (size & 0xFF)], extdataBuffer, size & 0xFF);
143 }
144 } else if (size > gb->sramSize || !gb->memory.sram) {
145 if (gb->memory.sram) {
146 vf->unmap(vf, gb->memory.sram, gb->sramSize);
147 }
148 gb->memory.sram = vf->map(vf, size, MAP_WRITE);
149 }
150 } else {
151 if (gb->memory.sram) {
152 vf->unmap(vf, gb->memory.sram, gb->sramSize);
153 }
154 gb->memory.sram = vf->map(vf, size, MAP_READ);
155 }
156 if (gb->memory.sram == (void*) -1) {
157 gb->memory.sram = NULL;
158 }
159 } else {
160 uint8_t* newSram = anonymousMemoryMap(size);
161 if (gb->memory.sram) {
162 if (size > gb->sramSize) {
163 memcpy(newSram, gb->memory.sram, gb->sramSize);
164 memset(&newSram[gb->sramSize], 0xFF, size - gb->sramSize);
165 } else {
166 memcpy(newSram, gb->memory.sram, size);
167 }
168 mappedMemoryFree(gb->memory.sram, gb->sramSize);
169 } else {
170 memset(newSram, 0xFF, size);
171 }
172 gb->memory.sram = newSram;
173 }
174 if (gb->sramSize < size) {
175 gb->sramSize = size;
176 }
177}
178
179void GBSramClean(struct GB* gb, uint32_t frameCount) {
180 // TODO: Share with GBASavedataClean
181 if (!gb->sramVf) {
182 return;
183 }
184 if (gb->sramDirty & GB_SRAM_DIRT_NEW) {
185 gb->sramDirtAge = frameCount;
186 gb->sramDirty &= ~GB_SRAM_DIRT_NEW;
187 if (!(gb->sramDirty & GB_SRAM_DIRT_SEEN)) {
188 gb->sramDirty |= GB_SRAM_DIRT_SEEN;
189 }
190 } else if ((gb->sramDirty & GB_SRAM_DIRT_SEEN) && frameCount - gb->sramDirtAge > CLEANUP_THRESHOLD) {
191 gb->sramDirty = 0;
192 if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
193 mLOG(GB_MEM, INFO, "Savedata synced");
194 } else {
195 mLOG(GB_MEM, INFO, "Savedata failed to sync!");
196 }
197 }
198}
199
200void GBSavedataMask(struct GB* gb, struct VFile* vf) {
201 GBSramDeinit(gb);
202 gb->sramVf = vf;
203 gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);
204}
205
206void GBSavedataUnmask(struct GB* gb) {
207 if (gb->sramVf == gb->sramRealVf) {
208 return;
209 }
210 GBSramDeinit(gb);
211 gb->sramVf = gb->sramRealVf;
212 gb->memory.sram = gb->sramVf->map(gb->sramVf, gb->sramSize, MAP_WRITE);
213}
214
215void GBUnloadROM(struct GB* gb) {
216 // TODO: Share with GBAUnloadROM
217 if (gb->memory.rom && gb->memory.romBase != gb->memory.rom) {
218 free(gb->memory.romBase);
219 }
220 if (gb->memory.rom && gb->pristineRom != gb->memory.rom) {
221 if (gb->yankedRomSize) {
222 gb->yankedRomSize = 0;
223 }
224 mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
225 }
226 gb->memory.rom = 0;
227
228 if (gb->romVf) {
229#ifndef _3DS
230 gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize);
231#endif
232 gb->romVf->close(gb->romVf);
233 gb->pristineRom = 0;
234 gb->romVf = 0;
235 }
236
237 GBSramDeinit(gb);
238}
239
240void GBLoadBIOS(struct GB* gb, struct VFile* vf) {
241 gb->biosVf = vf;
242}
243
244void GBApplyPatch(struct GB* gb, struct Patch* patch) {
245 size_t patchedSize = patch->outputSize(patch, gb->memory.romSize);
246 if (!patchedSize) {
247 return;
248 }
249 if (patchedSize > GB_SIZE_CART_MAX) {
250 patchedSize = GB_SIZE_CART_MAX;
251 }
252 gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX);
253 if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) {
254 mappedMemoryFree(gb->memory.rom, patchedSize);
255 gb->memory.rom = gb->pristineRom;
256 return;
257 }
258 gb->memory.romSize = patchedSize;
259 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
260}
261
262void GBDestroy(struct GB* gb) {
263 GBUnloadROM(gb);
264
265 if (gb->biosVf) {
266 gb->biosVf->close(gb->biosVf);
267 gb->biosVf = 0;
268 }
269
270 GBMemoryDeinit(gb);
271 GBVideoDeinit(&gb->video);
272 GBSIODeinit(&gb->sio);
273}
274
275void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
276 irqh->reset = GBReset;
277 irqh->processEvents = GBProcessEvents;
278 irqh->setInterrupts = GBSetInterrupts;
279 irqh->hitIllegal = GBIllegal;
280 irqh->stop = GBStop;
281 irqh->halt = GBHalt;
282}
283
284void GBReset(struct LR35902Core* cpu) {
285 struct GB* gb = (struct GB*) cpu->master;
286 GBDetectModel(gb);
287 if (gb->biosVf) {
288 gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
289 gb->memory.romBase = malloc(GB_SIZE_CART_BANK0);
290 ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0);
291 uint32_t biosCrc = doCrc32(gb->memory.romBase, size);
292 switch (biosCrc) {
293 case 0x59C8598E:
294 break;
295 case 0x41884E46:
296 break;
297 default:
298 gb->biosVf->close(gb->biosVf);
299 gb->biosVf = NULL;
300 free(gb->memory.romBase);
301 gb->memory.romBase = gb->memory.rom;
302 break;
303 }
304
305 if (gb->biosVf) {
306 memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
307 if (size > 0x100) {
308 memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge));
309 }
310
311 cpu->a = 0;
312 cpu->f.packed = 0;
313 cpu->c = 0;
314 cpu->e = 0;
315 cpu->h = 0;
316 cpu->l = 0;
317 cpu->sp = 0;
318 cpu->pc = 0;
319 }
320 }
321
322 cpu->b = 0;
323 cpu->d = 0;
324
325 if (!gb->biosVf) {
326 switch (gb->model) {
327 case GB_MODEL_DMG:
328 // TODO: SGB
329 case GB_MODEL_SGB:
330 case GB_MODEL_AUTODETECT: // Silence warnings
331 gb->model = GB_MODEL_DMG;
332 cpu->a = 1;
333 cpu->f.packed = 0xB0;
334 cpu->c = 0x13;
335 cpu->e = 0xD8;
336 cpu->h = 1;
337 cpu->l = 0x4D;
338 break;
339 case GB_MODEL_AGB:
340 cpu->b = 1;
341 // Fall through
342 case GB_MODEL_CGB:
343 cpu->a = 0x11;
344 cpu->f.packed = 0x80;
345 cpu->c = 0;
346 cpu->e = 0x08;
347 cpu->h = 0;
348 cpu->l = 0x7C;
349 break;
350 }
351
352 cpu->sp = 0xFFFE;
353 cpu->pc = 0x100;
354 }
355
356 gb->eiPending = INT_MAX;
357 gb->doubleSpeed = 0;
358
359 cpu->memory.setActiveRegion(cpu, cpu->pc);
360
361 if (gb->yankedRomSize) {
362 gb->memory.romSize = gb->yankedRomSize;
363 gb->yankedRomSize = 0;
364 }
365 GBMemoryReset(gb);
366 GBVideoReset(&gb->video);
367 GBTimerReset(&gb->timer);
368 GBIOReset(gb);
369 GBAudioReset(&gb->audio);
370 GBSIOReset(&gb->sio);
371
372 GBSavedataUnmask(gb);
373}
374
375void GBDetectModel(struct GB* gb) {
376 if (gb->model != GB_MODEL_AUTODETECT) {
377 return;
378 }
379 if (gb->biosVf) {
380 gb->biosVf->seek(gb->biosVf, 0, SEEK_SET);
381 void* bios = malloc(GB_SIZE_CART_BANK0);
382 ssize_t size = gb->biosVf->read(gb->biosVf, bios, GB_SIZE_CART_BANK0);
383 uint32_t biosCrc = doCrc32(gb->memory.romBase, size);
384 switch (biosCrc) {
385 case 0x59C8598E:
386 gb->model = GB_MODEL_DMG;
387 break;
388 case 0x41884E46:
389 gb->model = GB_MODEL_CGB;
390 break;
391 default:
392 gb->biosVf->close(gb->biosVf);
393 gb->biosVf = NULL;
394 }
395 free(bios);
396 }
397 if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) {
398 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
399 if (cart->cgb & 0x80) {
400 gb->model = GB_MODEL_CGB;
401 } else {
402 gb->model = GB_MODEL_DMG;
403 }
404 }
405
406 switch (gb->model) {
407 case GB_MODEL_DMG:
408 case GB_MODEL_SGB:
409 case GB_MODEL_AUTODETECT: //Silence warnings
410 gb->audio.style = GB_AUDIO_DMG;
411 break;
412 case GB_MODEL_AGB:
413 case GB_MODEL_CGB:
414 gb->audio.style = GB_AUDIO_CGB;
415 break;
416 }
417}
418
419void GBUpdateIRQs(struct GB* gb) {
420 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
421 if (!irqs) {
422 return;
423 }
424 gb->cpu->halted = false;
425
426 if (!gb->memory.ime || gb->cpu->irqPending) {
427 return;
428 }
429
430 if (irqs & (1 << GB_IRQ_VBLANK)) {
431 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
432 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
433 return;
434 }
435 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
436 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
437 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
438 return;
439 }
440 if (irqs & (1 << GB_IRQ_TIMER)) {
441 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
442 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
443 return;
444 }
445 if (irqs & (1 << GB_IRQ_SIO)) {
446 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
447 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
448 return;
449 }
450 if (irqs & (1 << GB_IRQ_KEYPAD)) {
451 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
452 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
453 }
454}
455
456void GBProcessEvents(struct LR35902Core* cpu) {
457 struct GB* gb = (struct GB*) cpu->master;
458 do {
459 int32_t cycles = cpu->nextEvent;
460 int32_t nextEvent = INT_MAX;
461 int32_t testEvent;
462
463 if (gb->eiPending != INT_MAX) {
464 gb->eiPending -= cycles;
465 if (gb->eiPending <= 0) {
466 gb->memory.ime = true;
467 GBUpdateIRQs(gb);
468 gb->eiPending = INT_MAX;
469 } else {
470 nextEvent = gb->eiPending;
471 }
472 }
473
474 testEvent = GBVideoProcessEvents(&gb->video, cycles >> gb->doubleSpeed);
475 if (testEvent != INT_MAX) {
476 testEvent <<= gb->doubleSpeed;
477 if (testEvent < nextEvent) {
478 nextEvent = testEvent;
479 }
480 }
481
482 testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed);
483 if (testEvent != INT_MAX) {
484 testEvent <<= gb->doubleSpeed;
485 if (testEvent < nextEvent) {
486 nextEvent = testEvent;
487 }
488 }
489
490 testEvent = GBTimerProcessEvents(&gb->timer, cycles);
491 if (testEvent < nextEvent) {
492 nextEvent = testEvent;
493 }
494
495 testEvent = GBSIOProcessEvents(&gb->sio, cycles);
496 if (testEvent < nextEvent) {
497 nextEvent = testEvent;
498 }
499
500 testEvent = GBMemoryProcessEvents(gb, cycles);
501 if (testEvent < nextEvent) {
502 nextEvent = testEvent;
503 }
504
505 cpu->cycles -= cycles;
506 cpu->nextEvent = nextEvent;
507
508 if (cpu->halted) {
509 cpu->cycles = cpu->nextEvent;
510 }
511 } while (cpu->cycles >= cpu->nextEvent);
512}
513
514void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
515 struct GB* gb = (struct GB*) cpu->master;
516 if (!enable) {
517 gb->memory.ime = enable;
518 gb->eiPending = INT_MAX;
519 GBUpdateIRQs(gb);
520 } else {
521 if (cpu->nextEvent > cpu->cycles + 4) {
522 cpu->nextEvent = cpu->cycles + 4;
523 }
524 gb->eiPending = cpu->cycles + 4;
525 }
526}
527
528void GBHalt(struct LR35902Core* cpu) {
529 if (!cpu->irqPending) {
530 cpu->cycles = cpu->nextEvent;
531 cpu->halted = true;
532 }
533}
534
535void GBStop(struct LR35902Core* cpu) {
536 struct GB* gb = (struct GB*) cpu->master;
537 if (cpu->bus) {
538 mLOG(GB, GAME_ERROR, "Hit illegal stop at address %04X:%02X\n", cpu->pc, cpu->bus);
539 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
540 struct mDebuggerEntryInfo info = {
541 .address = cpu->pc - 1,
542 .opcode = 0x1000 | cpu->bus
543 };
544 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
545 }
546 // Hang forever
547 gb->memory.ime = 0;
548 cpu->pc -= 2;
549 } else if (gb->memory.io[REG_KEY1] & 1) {
550 gb->doubleSpeed ^= 1;
551 gb->memory.io[REG_KEY1] &= 1;
552 gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
553 }
554 // TODO: Actually stop
555}
556
557void GBIllegal(struct LR35902Core* cpu) {
558 struct GB* gb = (struct GB*) cpu->master;
559 mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus);
560 if (cpu->components && cpu->components[CPU_COMPONENT_DEBUGGER]) {
561 struct mDebuggerEntryInfo info = {
562 .address = cpu->pc,
563 .opcode = cpu->bus
564 };
565 mDebuggerEnter((struct mDebugger*) cpu->components[CPU_COMPONENT_DEBUGGER], DEBUGGER_ENTER_ILLEGAL_OP, &info);
566 }
567 // Hang forever
568 gb->memory.ime = 0;
569 --cpu->pc;
570}
571
572bool GBIsROM(struct VFile* vf) {
573 vf->seek(vf, 0x104, SEEK_SET);
574 uint8_t header[4];
575 static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
576
577 if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
578 return false;
579 }
580 if (memcmp(header, knownHeader, sizeof(header))) {
581 return false;
582 }
583 return true;
584}
585
586void GBGetGameTitle(struct GB* gb, char* out) {
587 const struct GBCartridge* cart = NULL;
588 if (gb->memory.rom) {
589 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
590 }
591 if (gb->pristineRom) {
592 cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
593 }
594 if (!cart) {
595 return;
596 }
597 if (cart->oldLicensee != 0x33) {
598 memcpy(out, cart->titleLong, 16);
599 } else {
600 memcpy(out, cart->titleShort, 11);
601 }
602}
603
604void GBGetGameCode(struct GB* gb, char* out) {
605 memset(out, 0, 8);
606 const struct GBCartridge* cart = NULL;
607 if (gb->memory.rom) {
608 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
609 }
610 if (gb->pristineRom) {
611 cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
612 }
613 if (!cart) {
614 return;
615 }
616 if (cart->cgb == 0xC0) {
617 memcpy(out, "CGB-????", 8);
618 } else {
619 memcpy(out, "DMG-????", 8);
620 }
621 if (cart->oldLicensee == 0x33) {
622 memcpy(&out[4], cart->maker, 4);
623 }
624}
625
626void GBFrameEnded(struct GB* gb) {
627 GBSramClean(gb, gb->video.frameCounter);
628
629 if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
630 struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
631 size_t i;
632 for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
633 struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
634 mCheatRefresh(device, cheats);
635 }
636 }
637}