all repos — mgba @ 565ee43bb26639078c70e194b859a9c98ed819c8

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