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 "util/crc32.h"
11#include "util/memory.h"
12#include "util/math.h"
13#include "util/patch.h"
14#include "util/vfs.h"
15
16const uint32_t DMG_LR35902_FREQUENCY = 0x400000;
17const uint32_t CGB_LR35902_FREQUENCY = 0x800000;
18const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E;
19
20const uint32_t GB_COMPONENT_MAGIC = 0x400000;
21
22static void GBInit(struct LR35902Core* cpu, struct LR35902Component* component);
23static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
24static void GBProcessEvents(struct LR35902Core* cpu);
25static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
26static void GBHitStub(struct LR35902Core* cpu);
27
28void GBCreate(struct GB* gb) {
29 gb->d.id = GB_COMPONENT_MAGIC;
30 gb->d.init = GBInit;
31 gb->d.deinit = 0;
32}
33
34static void GBInit(struct LR35902Core* cpu, struct LR35902Component* component) {
35 struct GB* gb = (struct GB*) component;
36 gb->cpu = cpu;
37
38 GBInterruptHandlerInit(&cpu->irqh);
39 GBMemoryInit(gb);
40 GBVideoInit(&gb->video);
41
42 gb->romVf = 0;
43
44 gb->pristineRom = 0;
45 gb->pristineRomSize = 0;
46 gb->yankedRomSize = 0;
47}
48
49bool GBLoadROM(struct GB* gb, struct VFile* vf, struct VFile* sav, const char* fname) {
50 GBUnloadROM(gb);
51 gb->romVf = vf;
52 gb->pristineRomSize = vf->size(vf);
53 vf->seek(vf, 0, SEEK_SET);
54#ifdef _3DS
55 gb->pristineRom = 0;
56 if (gb->pristineRomSize <= romBufferSize) {
57 gb->pristineRom = romBuffer;
58 vf->read(vf, romBuffer, gb->pristineRomSize);
59 }
60#else
61 gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ);
62#endif
63 if (!gb->pristineRom) {
64 return false;
65 }
66 gb->yankedRomSize = 0;
67 gb->memory.rom = gb->pristineRom;
68 gb->activeFile = fname;
69 gb->memory.romSize = gb->pristineRomSize;
70 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
71 return true;
72 // TODO: error check
73}
74
75void GBUnloadROM(struct GB* gb) {
76 // TODO: Share with GBAUnloadROM
77 if (gb->memory.rom && gb->pristineRom != gb->memory.rom) {
78 if (gb->yankedRomSize) {
79 gb->yankedRomSize = 0;
80 }
81 mappedMemoryFree(gb->memory.rom, 0x400000);
82 }
83 gb->memory.rom = 0;
84
85 if (gb->romVf) {
86#ifndef _3DS
87 gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize);
88#endif
89 gb->pristineRom = 0;
90 gb->romVf = 0;
91 }
92}
93
94void GBDestroy(struct GB* gb) {
95 GBUnloadROM(gb);
96
97 GBMemoryDeinit(gb);
98}
99
100void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
101 irqh->reset = GBReset;
102 irqh->processEvents = GBProcessEvents;
103 irqh->setInterrupts = GBSetInterrupts;
104 irqh->hitStub = GBHitStub;
105}
106
107void GBReset(struct LR35902Core* cpu) {
108 cpu->a = 1;
109 cpu->f.packed = 0xB0;
110 cpu->b = 0;
111 cpu->c = 0x13;
112 cpu->d = 0;
113 cpu->e = 0xD8;
114 cpu->h = 1;
115 cpu->l = 0x4D;
116 cpu->sp = 0xFFFE;
117 cpu->pc = 0x100;
118
119 struct GB* gb = (struct GB*) cpu->master;
120
121 if (gb->yankedRomSize) {
122 gb->memory.romSize = gb->yankedRomSize;
123 gb->yankedRomSize = 0;
124 }
125 GBMemoryReset(gb);
126
127 gb->video.p = gb;
128 GBVideoReset(&gb->video);
129}
130
131void GBUpdateIRQs(struct GB* gb) {
132 if (!gb->memory.ime) {
133 return;
134 }
135 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
136 if (!irqs) {
137 return;
138 }
139 if (irqs & (1 << GB_IRQ_VBLANK)) {
140 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
141 return;
142 }
143 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
144 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
145 return;
146 }
147 if (irqs & (1 << GB_IRQ_TIMER)) {
148 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
149 return;
150 }
151 if (irqs & (1 << GB_IRQ_SIO)) {
152 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
153 return;
154 }
155 if (irqs & (1 << GB_IRQ_KEYPAD)) {
156 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
157 }
158}
159
160void GBProcessEvents(struct LR35902Core* cpu) {
161 struct GB* gb = (struct GB*) cpu->master;
162 int32_t cycles = cpu->nextEvent;
163 int32_t nextEvent = INT_MAX;
164 int32_t testEvent;
165
166 testEvent = GBVideoProcessEvents(&gb->video, cycles);
167 if (testEvent < nextEvent) {
168 nextEvent = testEvent;
169 }
170
171 cpu->cycles -= cycles;
172 cpu->nextEvent = nextEvent;
173}
174
175void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
176 struct GB* gb = (struct GB*) cpu->master;
177 gb->memory.ime = enable;
178 GBUpdateIRQs(gb);
179}
180
181void GBHitStub(struct LR35902Core* cpu) {
182 // TODO
183 //printf("Hit stub at address %04X\n", cpu->pc);
184}