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