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 gba->memory.savedata.type = _overrides[i].type;
470 switch (_overrides[i].type) {
471 case SAVEDATA_FLASH512:
472 case SAVEDATA_FLASH1M:
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}