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