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