all repos — mgba @ ddc1034d42a2eba9cc367ecddc331012a206bc6c

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