all repos — mgba @ 9bf6b571b121f78a6c1b0653ef0cb3267941e74f

mGBA Game Boy Advance Emulator

src/gba/gba.c (view raw)

  1#include "gba.h"
  2
  3#include "gba-bios.h"
  4#include "gba-io.h"
  5#include "gba-thread.h"
  6
  7#include "debugger.h"
  8
  9#include <limits.h>
 10#include <stdarg.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <string.h>
 14#include <sys/mman.h>
 15#include <sys/stat.h>
 16
 17enum {
 18	SP_BASE_SYSTEM = 0x03FFFF00,
 19	SP_BASE_IRQ = 0x03FFFFA0,
 20	SP_BASE_SUPERVISOR = 0x03FFFFE0
 21};
 22
 23static void GBAProcessEvents(struct ARMBoard* board);
 24static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);
 25static void GBAHitStub(struct ARMBoard* board, uint32_t opcode);
 26
 27void GBAInit(struct GBA* gba) {
 28	gba->errno = GBA_NO_ERROR;
 29	gba->errstr = 0;
 30
 31	ARMInit(&gba->cpu);
 32
 33	gba->memory.p = gba;
 34	GBAMemoryInit(&gba->memory);
 35	ARMAssociateMemory(&gba->cpu, &gba->memory.d);
 36
 37	gba->board.p = gba;
 38	GBABoardInit(&gba->board);
 39	ARMAssociateBoard(&gba->cpu, &gba->board.d);
 40
 41	gba->video.p = gba;
 42	GBAVideoInit(&gba->video);
 43
 44	gba->audio.p = gba;
 45	GBAAudioInit(&gba->audio);
 46
 47	GBAIOInit(gba);
 48
 49	memset(gba->timers, 0, sizeof(gba->timers));
 50
 51	gba->springIRQ = 0;
 52	gba->keySource = 0;
 53
 54	gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR;
 55
 56	ARMReset(&gba->cpu);
 57}
 58
 59void GBADeinit(struct GBA* gba) {
 60	GBAMemoryDeinit(&gba->memory);
 61	GBAVideoDeinit(&gba->video);
 62}
 63
 64void GBABoardInit(struct GBABoard* board) {
 65	board->d.reset = GBABoardReset;
 66	board->d.processEvents = GBAProcessEvents;
 67	board->d.swi16 = GBASwi16;
 68	board->d.swi32 = GBASwi32;
 69	board->d.hitStub = GBAHitStub;
 70}
 71
 72void GBABoardReset(struct ARMBoard* board) {
 73	struct ARMCore* cpu = board->cpu;
 74	ARMSetPrivilegeMode(cpu, MODE_IRQ);
 75	cpu->gprs[ARM_SP] = SP_BASE_IRQ;
 76	ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
 77	cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
 78	ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
 79	cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
 80}
 81
 82static void GBAProcessEvents(struct ARMBoard* board) {
 83	struct GBABoard* gbaBoard = (struct GBABoard*) board;
 84	int32_t cycles = board->cpu->cycles;
 85	int32_t nextEvent = INT_MAX;
 86	int32_t testEvent;
 87
 88	if (gbaBoard->p->springIRQ) {
 89		ARMRaiseIRQ(&gbaBoard->p->cpu);
 90		gbaBoard->p->springIRQ = 0;
 91	}
 92
 93	testEvent = GBAVideoProcessEvents(&gbaBoard->p->video, cycles);
 94	if (testEvent < nextEvent) {
 95		nextEvent = testEvent;
 96	}
 97
 98	testEvent = GBAMemoryProcessEvents(&gbaBoard->p->memory, cycles);
 99	if (testEvent < nextEvent) {
100		nextEvent = testEvent;
101	}
102
103	testEvent = GBATimersProcessEvents(gbaBoard->p, cycles);
104	if (testEvent < nextEvent) {
105		nextEvent = testEvent;
106	}
107
108	board->cpu->cycles = 0;
109	board->cpu->nextEvent = nextEvent;
110}
111
112static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
113	int32_t nextEvent = INT_MAX;
114	if (gba->timersEnabled) {
115		struct GBATimer* timer;
116		struct GBATimer* nextTimer;
117
118		timer = &gba->timers[0];
119		if (timer->enable) {
120			timer->nextEvent -= cycles;
121			timer->lastEvent -= cycles;
122			if (timer->nextEvent <= 0) {
123				timer->lastEvent = timer->nextEvent;
124				timer->nextEvent += timer->overflowInterval;
125				gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
126				timer->oldReload = timer->reload;
127
128				if (timer->doIrq) {
129					GBARaiseIRQ(gba, IRQ_TIMER0);
130				}
131
132				nextTimer = &gba->timers[1];
133				if (nextTimer->countUp) {
134					++gba->memory.io[REG_TM1CNT_LO >> 1];
135					if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
136						nextTimer->nextEvent = 0;
137					}
138				}
139			}
140			nextEvent = timer->nextEvent;
141		}
142
143		timer = &gba->timers[1];
144		if (timer->enable) {
145			timer->nextEvent -= cycles;
146			timer->lastEvent -= cycles;
147			if (timer->nextEvent <= 0) {
148				timer->lastEvent = timer->nextEvent;
149				timer->nextEvent += timer->overflowInterval;
150				gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
151				timer->oldReload = timer->reload;
152
153				if (timer->doIrq) {
154					GBARaiseIRQ(gba, IRQ_TIMER1);
155				}
156
157				if (timer->countUp) {
158					timer->nextEvent = INT_MAX;
159				}
160
161				nextTimer = &gba->timers[2];
162				if (nextTimer->countUp) {
163					++gba->memory.io[REG_TM2CNT_LO >> 1];
164					if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
165						nextTimer->nextEvent = 0;
166					}
167				}
168			}
169			if (timer->nextEvent < nextEvent) {
170				nextEvent = timer->nextEvent;
171			}
172		}
173
174		timer = &gba->timers[2];
175		if (timer->enable) {
176			timer->nextEvent -= cycles;
177			timer->lastEvent -= cycles;
178			nextEvent = timer->nextEvent;
179			if (timer->nextEvent <= 0) {
180				timer->lastEvent = timer->nextEvent;
181				timer->nextEvent += timer->overflowInterval;
182				gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
183				timer->oldReload = timer->reload;
184
185				if (timer->doIrq) {
186					GBARaiseIRQ(gba, IRQ_TIMER2);
187				}
188
189				if (timer->countUp) {
190					timer->nextEvent = INT_MAX;
191				}
192
193				nextTimer = &gba->timers[3];
194				if (nextTimer->countUp) {
195					++gba->memory.io[REG_TM3CNT_LO >> 1];
196					if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
197						nextTimer->nextEvent = 0;
198					}
199				}
200			}
201			if (timer->nextEvent < nextEvent) {
202				nextEvent = timer->nextEvent;
203			}
204		}
205
206		timer = &gba->timers[3];
207		if (timer->enable) {
208			timer->nextEvent -= cycles;
209			timer->lastEvent -= cycles;
210			nextEvent = timer->nextEvent;
211			if (timer->nextEvent <= 0) {
212				timer->lastEvent = timer->nextEvent;
213				timer->nextEvent += timer->overflowInterval;
214				gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
215				timer->oldReload = timer->reload;
216
217				if (timer->doIrq) {
218					GBARaiseIRQ(gba, IRQ_TIMER3);
219				}
220
221				if (timer->countUp) {
222					timer->nextEvent = INT_MAX;
223				}
224			}
225			if (timer->nextEvent < nextEvent) {
226				nextEvent = timer->nextEvent;
227			}
228		}
229	}
230	return nextEvent;
231}
232
233void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
234	ARMDebuggerInit(debugger, &gba->cpu);
235	gba->debugger = debugger;
236}
237
238void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
239	struct stat info;
240	gba->memory.rom = mmap(0, SIZE_CART0, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
241	gba->activeFile = fname;
242	fstat(fd, &info);
243	gba->memory.romSize = info.st_size;
244	// TODO: error check
245}
246
247void GBATimerUpdateRegister(struct GBA* gba, int timer) {
248	struct GBATimer* currentTimer = &gba->timers[timer];
249	if (currentTimer->enable && !currentTimer->countUp) {
250		gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> currentTimer->prescaleBits);
251	}
252}
253
254void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
255	gba->timers[timer].reload = reload;
256}
257
258void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
259	struct GBATimer* currentTimer = &gba->timers[timer];
260	GBATimerUpdateRegister(gba, timer);
261
262	int oldPrescale = currentTimer->prescaleBits;
263	switch (control & 0x0003) {
264	case 0x0000:
265		currentTimer->prescaleBits = 0;
266		break;
267	case 0x0001:
268		currentTimer->prescaleBits = 6;
269		break;
270	case 0x0002:
271		currentTimer->prescaleBits = 8;
272		break;
273	case 0x0003:
274		currentTimer->prescaleBits = 10;
275		break;
276	}
277	currentTimer->countUp = !!(control & 0x0004);
278	currentTimer->doIrq = !!(control & 0x0040);
279	currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
280	int wasEnabled = currentTimer->enable;
281	currentTimer->enable = !!(control & 0x0080);
282	if (!wasEnabled && currentTimer->enable) {
283		if (!currentTimer->countUp) {
284			currentTimer->nextEvent = gba->cpu.cycles + currentTimer->overflowInterval;
285		} else {
286			currentTimer->nextEvent = INT_MAX;
287		}
288		gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
289		currentTimer->oldReload = currentTimer->reload;
290		gba->timersEnabled |= 1 << timer;
291	} else if (wasEnabled && !currentTimer->enable) {
292		if (!currentTimer->countUp) {
293			gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> oldPrescale);
294		}
295		gba->timersEnabled &= ~(1 << timer);
296	} else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
297		// FIXME: this might be before present
298		currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
299	}
300
301	if (currentTimer->nextEvent < gba->cpu.nextEvent) {
302		gba->cpu.nextEvent = currentTimer->nextEvent;
303	}
304};
305
306void GBAWriteIE(struct GBA* gba, uint16_t value) {
307	if (value & (1 << IRQ_SIO)) {
308		GBALog(gba, GBA_LOG_STUB, "SIO interrupts not implemented");
309	}
310
311	if (value & (1 << IRQ_KEYPAD)) {
312		GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented");
313	}
314
315	if (value & (1 << IRQ_GAMEPAK)) {
316		GBALog(gba, GBA_LOG_STUB, "Gamepak interrupts not implemented");
317	}
318
319	if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
320		ARMRaiseIRQ(&gba->cpu);
321	}
322}
323
324void GBAWriteIME(struct GBA* gba, uint16_t value) {
325	if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
326		ARMRaiseIRQ(&gba->cpu);
327	}
328}
329
330void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
331	gba->memory.io[REG_IF >> 1] |= 1 << irq;
332
333	if (gba->memory.io[REG_IME >> 1] && (gba->memory.io[REG_IE >> 1] & 1 << irq)) {
334		ARMRaiseIRQ(&gba->cpu);
335	}
336}
337
338int GBATestIRQ(struct GBA* gba) {
339	if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
340		gba->springIRQ = 1;
341		gba->cpu.nextEvent = gba->cpu.cycles;
342		return 1;
343	}
344	return 0;
345}
346
347int GBAWaitForIRQ(struct GBA* gba) {
348	int irqs = gba->memory.io[REG_IF >> 1];
349	int newIRQs = 0;
350	gba->memory.io[REG_IF >> 1] = 0;
351	while (1) {
352		if (gba->cpu.nextEvent == INT_MAX) {
353			break;
354		} else {
355			gba->cpu.cycles = gba->cpu.nextEvent;
356			GBAProcessEvents(&gba->board.d);
357			if (gba->memory.io[REG_IF >> 1]) {
358				newIRQs = gba->memory.io[REG_IF >> 1];
359				break;
360			}
361		}
362	}
363	gba->memory.io[REG_IF >> 1] = newIRQs | irqs;
364	return newIRQs;
365}
366
367int GBAHalt(struct GBA* gba) {
368	return GBAWaitForIRQ(gba);
369}
370
371void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
372	if (!gba) {
373		struct GBAThread* threadContext = GBAThreadGetContext();
374		if (threadContext) {
375			gba = threadContext->gba;
376		}
377	}
378	if (gba && !(level & gba->logLevel)) {
379		return;
380	}
381	va_list args;
382	va_start(args, format);
383	vprintf(format, args);
384	va_end(args);
385	printf("\n");
386}
387
388void GBAHitStub(struct ARMBoard* board, uint32_t opcode) {
389	struct GBABoard* gbaBoard = (struct GBABoard*) board;
390	GBALog(gbaBoard->p, GBA_LOG_STUB, "Stub opcode: %08x", opcode);
391	if (!gbaBoard->p->debugger) {
392		abort();
393	} else {
394		ARMDebuggerEnter(gbaBoard->p->debugger);
395	}
396}