all repos — mgba @ 395f710805cf8f0ff4d8c3b44b670c411ad6debc

mGBA Game Boy Advance Emulator

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