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