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