all repos — mgba @ 7978a57128e32aa78245216fc0a173642685de1c

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