all repos — mgba @ 0458184a5e2ab6a852525c894a3a7d6a08595764

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