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