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