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}