all repos — mgba @ 62d941a979255f695da2a073813ad05f70df2ec8

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