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->timer.p = gb;
58
59 gb->romVf = 0;
60 gb->sramVf = 0;
61
62 gb->pristineRom = 0;
63 gb->pristineRomSize = 0;
64 gb->yankedRomSize = 0;
65
66 gb->stream = NULL;
67
68 gb->eiPending = false;
69 gb->doubleSpeed = 0;
70}
71
72bool GBLoadROM(struct GB* gb, struct VFile* vf) {
73 GBUnloadROM(gb);
74 gb->romVf = vf;
75 gb->pristineRomSize = vf->size(vf);
76 vf->seek(vf, 0, SEEK_SET);
77#ifdef _3DS
78 gb->pristineRom = 0;
79 if (gb->pristineRomSize <= romBufferSize) {
80 gb->pristineRom = romBuffer;
81 vf->read(vf, romBuffer, gb->pristineRomSize);
82 }
83#else
84 gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ);
85#endif
86 if (!gb->pristineRom) {
87 return false;
88 }
89 gb->yankedRomSize = 0;
90 gb->memory.rom = gb->pristineRom;
91 gb->memory.romSize = gb->pristineRomSize;
92 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
93
94 // TODO: error check
95 return true;
96}
97
98bool GBLoadSave(struct GB* gb, struct VFile* vf) {
99 gb->sramVf = vf;
100 if (vf) {
101 // TODO: Do this in bank-switching code
102 if (vf->size(vf) < 0x20000) {
103 vf->truncate(vf, 0x20000);
104 }
105 gb->memory.sram = vf->map(vf, 0x20000, MAP_WRITE);
106 }
107 return gb->memory.sram;
108}
109
110void GBUnloadROM(struct GB* gb) {
111 // TODO: Share with GBAUnloadROM
112 if (gb->memory.rom && gb->pristineRom != gb->memory.rom) {
113 if (gb->yankedRomSize) {
114 gb->yankedRomSize = 0;
115 }
116 mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
117 }
118 gb->memory.rom = 0;
119
120 if (gb->romVf) {
121#ifndef _3DS
122 gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize);
123#endif
124 gb->romVf->close(gb->romVf);
125 gb->pristineRom = 0;
126 gb->romVf = 0;
127 }
128
129 if (gb->sramVf) {
130 gb->sramVf->unmap(gb->sramVf, gb->memory.sram, 0x8000);
131 gb->sramVf = 0;
132 } else if (gb->memory.sram) {
133 mappedMemoryFree(gb->memory.sram, 0x8000);
134 }
135 gb->memory.sram = 0;
136}
137
138void GBApplyPatch(struct GB* gb, struct Patch* patch) {
139 size_t patchedSize = patch->outputSize(patch, gb->memory.romSize);
140 if (!patchedSize) {
141 return;
142 }
143 if (patchedSize > GB_SIZE_CART_MAX) {
144 patchedSize = GB_SIZE_CART_MAX;
145 }
146 gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX);
147 if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) {
148 mappedMemoryFree(gb->memory.rom, patchedSize);
149 gb->memory.rom = gb->pristineRom;
150 return;
151 }
152 gb->memory.romSize = patchedSize;
153 gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
154}
155
156void GBDestroy(struct GB* gb) {
157 GBUnloadROM(gb);
158
159 GBMemoryDeinit(gb);
160}
161
162void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
163 irqh->reset = GBReset;
164 irqh->processEvents = GBProcessEvents;
165 irqh->setInterrupts = GBSetInterrupts;
166 irqh->hitIllegal = GBIllegal;
167 irqh->stop = GBStop;
168 irqh->halt = GBHalt;
169}
170
171void GBReset(struct LR35902Core* cpu) {
172 struct GB* gb = (struct GB*) cpu->master;
173
174 const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
175 if (cart->cgb & 0x80) {
176 gb->model = GB_MODEL_CGB;
177 gb->audio.style = GB_AUDIO_CGB;
178 cpu->a = 0x11;
179 cpu->f.packed = 0x80;
180 cpu->c = 0;
181 cpu->e = 0x08;
182 cpu->h = 0;
183 cpu->l = 0x7C;
184 } else {
185 // TODO: SGB
186 gb->model = GB_MODEL_DMG;
187 gb->audio.style = GB_AUDIO_DMG;
188 cpu->a = 1;
189 cpu->f.packed = 0xB0;
190 cpu->c = 0x13;
191 cpu->e = 0xD8;
192 cpu->h = 1;
193 cpu->l = 0x4D;
194 }
195 cpu->b = 0;
196 cpu->d = 0;
197 cpu->sp = 0xFFFE;
198 cpu->pc = 0x100;
199 cpu->memory.setActiveRegion(cpu, cpu->pc);
200
201 if (gb->yankedRomSize) {
202 gb->memory.romSize = gb->yankedRomSize;
203 gb->yankedRomSize = 0;
204 }
205 GBMemoryReset(gb);
206 GBVideoReset(&gb->video);
207 GBTimerReset(&gb->timer);
208 GBIOReset(gb);
209 GBAudioReset(&gb->audio);
210}
211
212void GBUpdateIRQs(struct GB* gb) {
213 int irqs = gb->memory.ie & gb->memory.io[REG_IF];
214 if (!irqs) {
215 return;
216 }
217 gb->cpu->halted = false;
218
219 if (!gb->memory.ime) {
220 return;
221 }
222
223 if (irqs & (1 << GB_IRQ_VBLANK)) {
224 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
225 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
226 return;
227 }
228 if (irqs & (1 << GB_IRQ_LCDSTAT)) {
229 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
230 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
231 return;
232 }
233 if (irqs & (1 << GB_IRQ_TIMER)) {
234 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
235 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
236 return;
237 }
238 if (irqs & (1 << GB_IRQ_SIO)) {
239 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
240 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
241 return;
242 }
243 if (irqs & (1 << GB_IRQ_KEYPAD)) {
244 LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
245 gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
246 }
247}
248
249void GBProcessEvents(struct LR35902Core* cpu) {
250 struct GB* gb = (struct GB*) cpu->master;
251 do {
252 int32_t cycles = cpu->nextEvent;
253 int32_t nextEvent = INT_MAX;
254 int32_t testEvent;
255
256 if (gb->eiPending) {
257 gb->eiPending -= cycles;
258 if (gb->eiPending <= 0) {
259 gb->memory.ime = true;
260 GBUpdateIRQs(gb);
261 gb->eiPending = 0;
262 }
263 }
264
265 testEvent = GBVideoProcessEvents(&gb->video, cycles >> gb->doubleSpeed);
266 if (testEvent != INT_MAX) {
267 testEvent <<= gb->doubleSpeed;
268 if (testEvent < nextEvent) {
269 nextEvent = testEvent;
270 }
271 }
272
273 testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed);
274 if (testEvent != INT_MAX) {
275 testEvent <<= gb->doubleSpeed;
276 if (testEvent < nextEvent) {
277 nextEvent = testEvent;
278 }
279 }
280
281 testEvent = GBTimerProcessEvents(&gb->timer, cycles);
282 if (testEvent < nextEvent) {
283 nextEvent = testEvent;
284 }
285
286 testEvent = GBMemoryProcessEvents(gb, cycles);
287 if (testEvent < nextEvent) {
288 nextEvent = testEvent;
289 }
290
291 cpu->cycles -= cycles;
292 cpu->nextEvent = nextEvent;
293
294 if (cpu->halted) {
295 cpu->cycles = cpu->nextEvent;
296 }
297 } while (cpu->cycles >= cpu->nextEvent);
298}
299
300void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
301 struct GB* gb = (struct GB*) cpu->master;
302 if (!enable) {
303 gb->memory.ime = enable;
304 gb->eiPending = 0;
305 GBUpdateIRQs(gb);
306 } else {
307 if (cpu->nextEvent > cpu->cycles + 4) {
308 cpu->nextEvent = cpu->cycles + 4;
309 }
310 gb->eiPending = cpu->cycles + 4;
311 }
312}
313
314void GBHalt(struct LR35902Core* cpu) {
315 cpu->cycles = cpu->nextEvent;
316 cpu->halted = true;
317}
318
319void GBStop(struct LR35902Core* cpu) {
320 struct GB* gb = (struct GB*) cpu->master;
321 if (gb->memory.io[REG_KEY1] & 1) {
322 gb->doubleSpeed ^= 1;
323 gb->memory.io[REG_KEY1] &= 1;
324 gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7;
325 }
326 // TODO: Actually stop
327}
328
329void GBIllegal(struct LR35902Core* cpu) {
330 // TODO
331 mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus);
332}
333
334bool GBIsROM(struct VFile* vf) {
335 vf->seek(vf, 0x104, SEEK_SET);
336 uint8_t header[4];
337 static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
338
339 if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) {
340 return false;
341 }
342 if (memcmp(header, knownHeader, sizeof(header))) {
343 return false;
344 }
345 return true;
346}
347
348void GBGetGameTitle(struct GB* gb, char* out) {
349 const struct GBCartridge* cart = NULL;
350 if (gb->memory.rom) {
351 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
352 }
353 if (gb->pristineRom) {
354 cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
355 }
356 if (!cart) {
357 return;
358 }
359 if (cart->oldLicensee != 0x33) {
360 memcpy(out, cart->titleLong, 16);
361 } else {
362 memcpy(out, cart->titleShort, 11);
363 }
364}
365
366void GBGetGameCode(struct GB* gb, char* out) {
367 memset(out, 0, 8);
368 const struct GBCartridge* cart = NULL;
369 if (gb->memory.rom) {
370 cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
371 }
372 if (gb->pristineRom) {
373 cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
374 }
375 if (!cart) {
376 return;
377 }
378 if (cart->cgb == 0xC0) {
379 memcpy(out, "CGB-????", 8);
380 } else {
381 memcpy(out, "DMG-????", 8);
382 }
383 if (cart->oldLicensee == 0x33) {
384 memcpy(&out[4], cart->maker, 4);
385 }
386}
387
388void GBFrameEnded(struct GB* gb) {
389 if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) {
390 struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE];
391 size_t i;
392 for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
393 struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i);
394 mCheatRefresh(device, cheats);
395 }
396 }
397}