all repos — mgba @ 6906df95e28cd08dac54def70704ac4775c5dbcb

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