all repos — mgba @ 290b64b171be380c131898fdaad5106caffb90c7

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