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 nextTimer = &gba->timers[1];
140 if (nextTimer->countUp) {
141 ++gba->memory.io[REG_TM1CNT_LO >> 1];
142 if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
143 nextTimer->nextEvent = 0;
144 }
145 }
146 }
147 nextEvent = timer->nextEvent;
148 }
149
150 timer = &gba->timers[1];
151 if (timer->enable) {
152 timer->nextEvent -= cycles;
153 timer->lastEvent -= cycles;
154 if (timer->nextEvent <= 0) {
155 timer->lastEvent = timer->nextEvent;
156 timer->nextEvent += timer->overflowInterval;
157 gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
158 timer->oldReload = timer->reload;
159
160 if (timer->doIrq) {
161 GBARaiseIRQ(gba, IRQ_TIMER1);
162 }
163
164 if (timer->countUp) {
165 timer->nextEvent = INT_MAX;
166 }
167
168 nextTimer = &gba->timers[2];
169 if (nextTimer->countUp) {
170 ++gba->memory.io[REG_TM2CNT_LO >> 1];
171 if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
172 nextTimer->nextEvent = 0;
173 }
174 }
175 }
176 if (timer->nextEvent < nextEvent) {
177 nextEvent = timer->nextEvent;
178 }
179 }
180
181 timer = &gba->timers[2];
182 if (timer->enable) {
183 timer->nextEvent -= cycles;
184 timer->lastEvent -= cycles;
185 nextEvent = timer->nextEvent;
186 if (timer->nextEvent <= 0) {
187 timer->lastEvent = timer->nextEvent;
188 timer->nextEvent += timer->overflowInterval;
189 gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
190 timer->oldReload = timer->reload;
191
192 if (timer->doIrq) {
193 GBARaiseIRQ(gba, IRQ_TIMER2);
194 }
195
196 if (timer->countUp) {
197 timer->nextEvent = INT_MAX;
198 }
199
200 nextTimer = &gba->timers[3];
201 if (nextTimer->countUp) {
202 ++gba->memory.io[REG_TM3CNT_LO >> 1];
203 if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
204 nextTimer->nextEvent = 0;
205 }
206 }
207 }
208 if (timer->nextEvent < nextEvent) {
209 nextEvent = timer->nextEvent;
210 }
211 }
212
213 timer = &gba->timers[3];
214 if (timer->enable) {
215 timer->nextEvent -= cycles;
216 timer->lastEvent -= cycles;
217 nextEvent = timer->nextEvent;
218 if (timer->nextEvent <= 0) {
219 timer->lastEvent = timer->nextEvent;
220 timer->nextEvent += timer->overflowInterval;
221 gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
222 timer->oldReload = timer->reload;
223
224 if (timer->doIrq) {
225 GBARaiseIRQ(gba, IRQ_TIMER3);
226 }
227
228 if (timer->countUp) {
229 timer->nextEvent = INT_MAX;
230 }
231 }
232 if (timer->nextEvent < nextEvent) {
233 nextEvent = timer->nextEvent;
234 }
235 }
236 }
237 return nextEvent;
238}
239
240void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
241 ARMDebuggerInit(debugger, &gba->cpu);
242 gba->debugger = debugger;
243}
244
245void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
246 struct stat info;
247 gba->memory.rom = mmap(0, SIZE_CART0, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
248 gba->activeFile = fname;
249 fstat(fd, &info);
250 gba->memory.romSize = info.st_size;
251 // TODO: error check
252}
253
254void GBATimerUpdateRegister(struct GBA* gba, int timer) {
255 struct GBATimer* currentTimer = &gba->timers[timer];
256 if (currentTimer->enable && !currentTimer->countUp) {
257 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> currentTimer->prescaleBits);
258 }
259}
260
261void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
262 gba->timers[timer].reload = reload;
263}
264
265void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
266 struct GBATimer* currentTimer = &gba->timers[timer];
267 GBATimerUpdateRegister(gba, timer);
268
269 int oldPrescale = currentTimer->prescaleBits;
270 switch (control & 0x0003) {
271 case 0x0000:
272 currentTimer->prescaleBits = 0;
273 break;
274 case 0x0001:
275 currentTimer->prescaleBits = 6;
276 break;
277 case 0x0002:
278 currentTimer->prescaleBits = 8;
279 break;
280 case 0x0003:
281 currentTimer->prescaleBits = 10;
282 break;
283 }
284 currentTimer->countUp = !!(control & 0x0004);
285 currentTimer->doIrq = !!(control & 0x0040);
286 currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
287 int wasEnabled = currentTimer->enable;
288 currentTimer->enable = !!(control & 0x0080);
289 if (!wasEnabled && currentTimer->enable) {
290 if (!currentTimer->countUp) {
291 currentTimer->nextEvent = gba->cpu.cycles + currentTimer->overflowInterval;
292 } else {
293 currentTimer->nextEvent = INT_MAX;
294 }
295 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
296 currentTimer->oldReload = currentTimer->reload;
297 gba->timersEnabled |= 1 << timer;
298 } else if (wasEnabled && !currentTimer->enable) {
299 if (!currentTimer->countUp) {
300 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> oldPrescale);
301 }
302 gba->timersEnabled &= ~(1 << timer);
303 } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
304 // FIXME: this might be before present
305 currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
306 }
307
308 if (currentTimer->nextEvent < gba->cpu.nextEvent) {
309 gba->cpu.nextEvent = currentTimer->nextEvent;
310 }
311};
312
313void GBAWriteIE(struct GBA* gba, uint16_t value) {
314 if (value & (1 << IRQ_SIO)) {
315 GBALog(gba, GBA_LOG_STUB, "SIO interrupts not implemented");
316 }
317
318 if (value & (1 << IRQ_KEYPAD)) {
319 GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented");
320 }
321
322 if (value & (1 << IRQ_GAMEPAK)) {
323 GBALog(gba, GBA_LOG_STUB, "Gamepak interrupts not implemented");
324 }
325
326 if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
327 ARMRaiseIRQ(&gba->cpu);
328 }
329}
330
331void GBAWriteIME(struct GBA* gba, uint16_t value) {
332 if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
333 ARMRaiseIRQ(&gba->cpu);
334 }
335}
336
337void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
338 gba->memory.io[REG_IF >> 1] |= 1 << irq;
339
340 if (gba->memory.io[REG_IME >> 1] && (gba->memory.io[REG_IE >> 1] & 1 << irq)) {
341 ARMRaiseIRQ(&gba->cpu);
342 }
343}
344
345int GBATestIRQ(struct GBA* gba) {
346 if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
347 gba->springIRQ = 1;
348 gba->cpu.nextEvent = gba->cpu.cycles;
349 return 1;
350 }
351 return 0;
352}
353
354int GBAWaitForIRQ(struct GBA* gba) {
355 int irqs = gba->memory.io[REG_IF >> 1];
356 int newIRQs = 0;
357 gba->memory.io[REG_IF >> 1] = 0;
358 while (1) {
359 if (gba->cpu.nextEvent == INT_MAX) {
360 break;
361 } else {
362 gba->cpu.cycles = gba->cpu.nextEvent;
363 GBAProcessEvents(&gba->board.d);
364 if (gba->memory.io[REG_IF >> 1]) {
365 newIRQs = gba->memory.io[REG_IF >> 1];
366 break;
367 }
368 }
369 }
370 gba->memory.io[REG_IF >> 1] = newIRQs | irqs;
371 return newIRQs;
372}
373
374int GBAHalt(struct GBA* gba) {
375 return GBAWaitForIRQ(gba);
376}
377
378void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
379 if (!gba) {
380 struct GBAThread* threadContext = GBAThreadGetContext();
381 if (threadContext) {
382 gba = threadContext->gba;
383 }
384 }
385 if (gba && !(level & gba->logLevel)) {
386 return;
387 }
388 va_list args;
389 va_start(args, format);
390 vprintf(format, args);
391 va_end(args);
392 printf("\n");
393}
394
395void GBAHitStub(struct ARMBoard* board, uint32_t opcode) {
396 struct GBABoard* gbaBoard = (struct GBABoard*) board;
397 GBALog(gbaBoard->p, GBA_LOG_STUB, "Stub opcode: %08x", opcode);
398 if (!gbaBoard->p->debugger) {
399 abort();
400 } else {
401 ARMDebuggerEnter(gbaBoard->p->debugger);
402 }
403}