all repos — mgba @ c77ed8c11e03a2bb22bfb8111ac2d4fb8698d786

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