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