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}