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#include "memory.h"
7
8#include "debugger.h"
9
10#include <limits.h>
11#include <stdarg.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.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
25struct GBACartridgeOverride {
26 uint32_t id;
27 enum SavedataType type;
28 int gpio;
29};
30
31static const struct GBACartridgeOverride _overrides[] = {
32 // Boktai: The Sun is in Your Hand
33 { 'EI3U', SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
34 { 'PI3U', SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
35
36 // Boktai 2: Solar Boy Django
37 { 'E23U', SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
38 { 'P23U', SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR },
39
40 // Drill Dozer
41 { 'J94V', SAVEDATA_SRAM, GPIO_RUMBLE },
42 { 'E94V', SAVEDATA_SRAM, GPIO_RUMBLE },
43
44 // Pokemon Ruby
45 { 'JVXA', SAVEDATA_FLASH1M, GPIO_RTC },
46 { 'EVXA', SAVEDATA_FLASH1M, GPIO_RTC },
47 { 'PVXA', SAVEDATA_FLASH1M, GPIO_RTC },
48 { 'IVXA', SAVEDATA_FLASH1M, GPIO_RTC },
49 { 'SVXA', SAVEDATA_FLASH1M, GPIO_RTC },
50 { 'DVXA', SAVEDATA_FLASH1M, GPIO_RTC },
51 { 'FVXA', SAVEDATA_FLASH1M, GPIO_RTC },
52
53 // Pokemon Sapphire
54 { 'JPXA', SAVEDATA_FLASH1M, GPIO_RTC },
55 { 'EPXA', SAVEDATA_FLASH1M, GPIO_RTC },
56 { 'PPXA', SAVEDATA_FLASH1M, GPIO_RTC },
57 { 'IPXA', SAVEDATA_FLASH1M, GPIO_RTC },
58 { 'SPXA', SAVEDATA_FLASH1M, GPIO_RTC },
59 { 'DPXA', SAVEDATA_FLASH1M, GPIO_RTC },
60 { 'FPXA', SAVEDATA_FLASH1M, GPIO_RTC },
61
62 // Pokemon Emerald
63 { 'JEPB', SAVEDATA_FLASH1M, GPIO_RTC },
64 { 'EEPB', SAVEDATA_FLASH1M, GPIO_RTC },
65 { 'PEPB', SAVEDATA_FLASH1M, GPIO_RTC },
66 { 'IEPB', SAVEDATA_FLASH1M, GPIO_RTC },
67 { 'SEPB', SAVEDATA_FLASH1M, GPIO_RTC },
68 { 'DEPB', SAVEDATA_FLASH1M, GPIO_RTC },
69 { 'FEPB', SAVEDATA_FLASH1M, GPIO_RTC },
70
71 // Pokemon FireRed
72 { 'JRPB', SAVEDATA_FLASH1M, GPIO_NONE },
73 { 'ERPB', SAVEDATA_FLASH1M, GPIO_NONE },
74 { 'PRPB', SAVEDATA_FLASH1M, GPIO_NONE },
75
76 // Pokemon LeafGreen
77 { 'JGPB', SAVEDATA_FLASH1M, GPIO_NONE },
78 { 'EGPB', SAVEDATA_FLASH1M, GPIO_NONE },
79 { 'PGPB', SAVEDATA_FLASH1M, GPIO_NONE },
80
81 // RockMan EXE 4.5 - Real Operation
82 { 'J4RB', SAVEDATA_FLASH512, GPIO_RTC },
83
84 // Super Mario Advance 4
85 { 'J4XA', SAVEDATA_FLASH1M, GPIO_NONE },
86 { 'E4XA', SAVEDATA_FLASH1M, GPIO_NONE },
87 { 'P4XA', SAVEDATA_FLASH1M, GPIO_NONE },
88
89 // Wario Ware Twisted
90 { 'JWZR', SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
91 { 'EWZR', SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
92 { 'PWZR', SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO },
93
94 { 0, 0, 0 }
95};
96
97static void GBAProcessEvents(struct ARMBoard* board);
98static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);
99static void GBAHitStub(struct ARMBoard* board, uint32_t opcode);
100static void GBAIllegal(struct ARMBoard* board, uint32_t opcode);
101
102static void _checkOverrides(struct GBA* gba, uint32_t code);
103
104void GBAInit(struct GBA* gba) {
105 gba->debugger = 0;
106 gba->savefile = 0;
107
108 ARMInit(&gba->cpu);
109
110 gba->memory.p = gba;
111 GBAMemoryInit(&gba->memory);
112 ARMAssociateMemory(&gba->cpu, &gba->memory.d);
113
114 gba->board.p = gba;
115 GBABoardInit(&gba->board);
116 ARMAssociateBoard(&gba->cpu, &gba->board.d);
117
118 gba->video.p = gba;
119 GBAVideoInit(&gba->video);
120
121 gba->audio.p = gba;
122 GBAAudioInit(&gba->audio);
123
124 GBAIOInit(gba);
125
126 gba->timersEnabled = 0;
127 memset(gba->timers, 0, sizeof(gba->timers));
128
129 gba->springIRQ = 0;
130 gba->keySource = 0;
131 gba->rotationSource = 0;
132 gba->rumble = 0;
133
134 gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR;
135
136 gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
137
138 ARMReset(&gba->cpu);
139}
140
141void GBADeinit(struct GBA* gba) {
142 GBAMemoryDeinit(&gba->memory);
143 GBAVideoDeinit(&gba->video);
144 GBAAudioDeinit(&gba->audio);
145}
146
147void GBABoardInit(struct GBABoard* board) {
148 board->d.reset = GBABoardReset;
149 board->d.processEvents = GBAProcessEvents;
150 board->d.swi16 = GBASwi16;
151 board->d.swi32 = GBASwi32;
152 board->d.hitIllegal = GBAIllegal;
153 board->d.readCPSR = GBATestIRQ;
154 board->d.hitStub = GBAHitStub;
155}
156
157void GBABoardReset(struct ARMBoard* board) {
158 struct ARMCore* cpu = board->cpu;
159 ARMSetPrivilegeMode(cpu, MODE_IRQ);
160 cpu->gprs[ARM_SP] = SP_BASE_IRQ;
161 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
162 cpu->gprs[ARM_SP] = SP_BASE_SUPERVISOR;
163 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
164 cpu->gprs[ARM_SP] = SP_BASE_SYSTEM;
165}
166
167static void GBAProcessEvents(struct ARMBoard* board) {
168 struct GBABoard* gbaBoard = (struct GBABoard*) board;
169 int32_t cycles = board->cpu->cycles;
170 int32_t nextEvent = INT_MAX;
171 int32_t testEvent;
172
173 if (gbaBoard->p->springIRQ) {
174 ARMRaiseIRQ(&gbaBoard->p->cpu);
175 gbaBoard->p->springIRQ = 0;
176 }
177
178 testEvent = GBAVideoProcessEvents(&gbaBoard->p->video, cycles);
179 if (testEvent < nextEvent) {
180 nextEvent = testEvent;
181 }
182
183 testEvent = GBAAudioProcessEvents(&gbaBoard->p->audio, cycles);
184 if (testEvent < nextEvent) {
185 nextEvent = testEvent;
186 }
187
188 testEvent = GBAMemoryProcessEvents(&gbaBoard->p->memory, cycles);
189 if (testEvent < nextEvent) {
190 nextEvent = testEvent;
191 }
192
193 testEvent = GBATimersProcessEvents(gbaBoard->p, cycles);
194 if (testEvent < nextEvent) {
195 nextEvent = testEvent;
196 }
197
198 board->cpu->cycles = 0;
199 board->cpu->nextEvent = nextEvent;
200}
201
202static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
203 int32_t nextEvent = INT_MAX;
204 if (gba->timersEnabled) {
205 struct GBATimer* timer;
206 struct GBATimer* nextTimer;
207
208 timer = &gba->timers[0];
209 if (timer->enable) {
210 timer->nextEvent -= cycles;
211 timer->lastEvent -= cycles;
212 if (timer->nextEvent <= 0) {
213 timer->lastEvent = timer->nextEvent;
214 timer->nextEvent += timer->overflowInterval;
215 gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
216 timer->oldReload = timer->reload;
217
218 if (timer->doIrq) {
219 GBARaiseIRQ(gba, IRQ_TIMER0);
220 }
221
222 if (gba->audio.enable) {
223 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 0) {
224 GBAAudioSampleFIFO(&gba->audio, 0);
225 }
226
227 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 0) {
228 GBAAudioSampleFIFO(&gba->audio, 1);
229 }
230 }
231
232 nextTimer = &gba->timers[1];
233 if (nextTimer->countUp) {
234 ++gba->memory.io[REG_TM1CNT_LO >> 1];
235 if (!gba->memory.io[REG_TM1CNT_LO >> 1]) {
236 nextTimer->nextEvent = 0;
237 }
238 }
239 }
240 nextEvent = timer->nextEvent;
241 }
242
243 timer = &gba->timers[1];
244 if (timer->enable) {
245 timer->nextEvent -= cycles;
246 timer->lastEvent -= cycles;
247 if (timer->nextEvent <= 0) {
248 timer->lastEvent = timer->nextEvent;
249 timer->nextEvent += timer->overflowInterval;
250 gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload;
251 timer->oldReload = timer->reload;
252
253 if (timer->doIrq) {
254 GBARaiseIRQ(gba, IRQ_TIMER1);
255 }
256
257 if (gba->audio.enable) {
258 if ((gba->audio.chALeft || gba->audio.chARight) && gba->audio.chATimer == 1) {
259 GBAAudioSampleFIFO(&gba->audio, 0);
260 }
261
262 if ((gba->audio.chBLeft || gba->audio.chBRight) && gba->audio.chBTimer == 1) {
263 GBAAudioSampleFIFO(&gba->audio, 1);
264 }
265 }
266
267 if (timer->countUp) {
268 timer->nextEvent = INT_MAX;
269 }
270
271 nextTimer = &gba->timers[2];
272 if (nextTimer->countUp) {
273 ++gba->memory.io[REG_TM2CNT_LO >> 1];
274 if (!gba->memory.io[REG_TM2CNT_LO >> 1]) {
275 nextTimer->nextEvent = 0;
276 }
277 }
278 }
279 if (timer->nextEvent < nextEvent) {
280 nextEvent = timer->nextEvent;
281 }
282 }
283
284 timer = &gba->timers[2];
285 if (timer->enable) {
286 timer->nextEvent -= cycles;
287 timer->lastEvent -= cycles;
288 nextEvent = timer->nextEvent;
289 if (timer->nextEvent <= 0) {
290 timer->lastEvent = timer->nextEvent;
291 timer->nextEvent += timer->overflowInterval;
292 gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload;
293 timer->oldReload = timer->reload;
294
295 if (timer->doIrq) {
296 GBARaiseIRQ(gba, IRQ_TIMER2);
297 }
298
299 if (timer->countUp) {
300 timer->nextEvent = INT_MAX;
301 }
302
303 nextTimer = &gba->timers[3];
304 if (nextTimer->countUp) {
305 ++gba->memory.io[REG_TM3CNT_LO >> 1];
306 if (!gba->memory.io[REG_TM3CNT_LO >> 1]) {
307 nextTimer->nextEvent = 0;
308 }
309 }
310 }
311 if (timer->nextEvent < nextEvent) {
312 nextEvent = timer->nextEvent;
313 }
314 }
315
316 timer = &gba->timers[3];
317 if (timer->enable) {
318 timer->nextEvent -= cycles;
319 timer->lastEvent -= cycles;
320 nextEvent = timer->nextEvent;
321 if (timer->nextEvent <= 0) {
322 timer->lastEvent = timer->nextEvent;
323 timer->nextEvent += timer->overflowInterval;
324 gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload;
325 timer->oldReload = timer->reload;
326
327 if (timer->doIrq) {
328 GBARaiseIRQ(gba, IRQ_TIMER3);
329 }
330
331 if (timer->countUp) {
332 timer->nextEvent = INT_MAX;
333 }
334 }
335 if (timer->nextEvent < nextEvent) {
336 nextEvent = timer->nextEvent;
337 }
338 }
339 }
340 return nextEvent;
341}
342
343#ifdef USE_DEBUGGER
344void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) {
345 ARMDebuggerInit(debugger, &gba->cpu);
346 gba->debugger = debugger;
347}
348#endif
349
350void GBALoadROM(struct GBA* gba, int fd, const char* fname) {
351 struct stat info;
352 gba->memory.rom = fileMemoryMap(fd, SIZE_CART0, MEMORY_READ);
353 gba->activeFile = fname;
354 fstat(fd, &info);
355 gba->memory.romSize = info.st_size;
356 if (gba->savefile) {
357 GBASavedataInit(&gba->memory.savedata, gba->savefile);
358 }
359 GBAGPIOInit(&gba->memory.gpio, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
360 _checkOverrides(gba, ((struct GBACartridge*) gba->memory.rom)->id);
361 // TODO: error check
362}
363
364void GBALoadBIOS(struct GBA* gba, int fd) {
365 gba->memory.bios = fileMemoryMap(fd, SIZE_BIOS, MEMORY_READ);
366 gba->memory.fullBios = 1;
367 uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
368 GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum);
369 if (checksum == GBA_BIOS_CHECKSUM) {
370 GBALog(gba, GBA_LOG_INFO, "Official GBA BIOS detected");
371 } else if (checksum == GBA_DS_BIOS_CHECKSUM) {
372 GBALog(gba, GBA_LOG_INFO, "Official GBA (DS) BIOS detected");
373 } else {
374 GBALog(gba, GBA_LOG_WARN, "BIOS checksum incorrect");
375 }
376 gba->biosChecksum = checksum;
377 if ((gba->cpu.gprs[ARM_PC] >> BASE_OFFSET) == BASE_BIOS) {
378 gba->memory.d.setActiveRegion(&gba->memory.d, gba->cpu.gprs[ARM_PC]);
379 }
380 // TODO: error check
381}
382
383void GBATimerUpdateRegister(struct GBA* gba, int timer) {
384 struct GBATimer* currentTimer = &gba->timers[timer];
385 if (currentTimer->enable && !currentTimer->countUp) {
386 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> currentTimer->prescaleBits);
387 }
388}
389
390void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) {
391 gba->timers[timer].reload = reload;
392}
393
394void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) {
395 struct GBATimer* currentTimer = &gba->timers[timer];
396 GBATimerUpdateRegister(gba, timer);
397
398 int oldPrescale = currentTimer->prescaleBits;
399 switch (control & 0x0003) {
400 case 0x0000:
401 currentTimer->prescaleBits = 0;
402 break;
403 case 0x0001:
404 currentTimer->prescaleBits = 6;
405 break;
406 case 0x0002:
407 currentTimer->prescaleBits = 8;
408 break;
409 case 0x0003:
410 currentTimer->prescaleBits = 10;
411 break;
412 }
413 currentTimer->countUp = !!(control & 0x0004);
414 currentTimer->doIrq = !!(control & 0x0040);
415 currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits;
416 int wasEnabled = currentTimer->enable;
417 currentTimer->enable = !!(control & 0x0080);
418 if (!wasEnabled && currentTimer->enable) {
419 if (!currentTimer->countUp) {
420 currentTimer->nextEvent = gba->cpu.cycles + currentTimer->overflowInterval;
421 } else {
422 currentTimer->nextEvent = INT_MAX;
423 }
424 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
425 currentTimer->oldReload = currentTimer->reload;
426 gba->timersEnabled |= 1 << timer;
427 } else if (wasEnabled && !currentTimer->enable) {
428 if (!currentTimer->countUp) {
429 gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu.cycles - currentTimer->lastEvent) >> oldPrescale);
430 }
431 gba->timersEnabled &= ~(1 << timer);
432 } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) {
433 // FIXME: this might be before present
434 currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval;
435 }
436
437 if (currentTimer->nextEvent < gba->cpu.nextEvent) {
438 gba->cpu.nextEvent = currentTimer->nextEvent;
439 }
440};
441
442void GBAWriteIE(struct GBA* gba, uint16_t value) {
443 if (value & (1 << IRQ_SIO)) {
444 GBALog(gba, GBA_LOG_STUB, "SIO interrupts not implemented");
445 }
446
447 if (value & (1 << IRQ_KEYPAD)) {
448 GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented");
449 }
450
451 if (value & (1 << IRQ_GAMEPAK)) {
452 GBALog(gba, GBA_LOG_STUB, "Gamepak interrupts not implemented");
453 }
454
455 if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
456 ARMRaiseIRQ(&gba->cpu);
457 }
458}
459
460void GBAWriteIME(struct GBA* gba, uint16_t value) {
461 if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
462 ARMRaiseIRQ(&gba->cpu);
463 }
464}
465
466void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) {
467 gba->memory.io[REG_IF >> 1] |= 1 << irq;
468
469 if (gba->memory.io[REG_IME >> 1] && (gba->memory.io[REG_IE >> 1] & 1 << irq)) {
470 ARMRaiseIRQ(&gba->cpu);
471 }
472}
473
474void GBATestIRQ(struct ARMBoard* board) {
475 struct GBABoard* gbaBoard = (struct GBABoard*) board;
476 struct GBA* gba = gbaBoard->p;
477 if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
478 gba->springIRQ = 1;
479 gba->cpu.nextEvent = 0;
480 }
481}
482
483int GBAWaitForIRQ(struct GBA* gba) {
484 int irqs = gba->memory.io[REG_IF >> 1];
485 int newIRQs = 0;
486 gba->memory.io[REG_IF >> 1] = 0;
487 while (1) {
488 if (gba->cpu.nextEvent == INT_MAX) {
489 break;
490 } else {
491 gba->cpu.cycles = gba->cpu.nextEvent;
492 GBAProcessEvents(&gba->board.d);
493 if (gba->memory.io[REG_IF >> 1]) {
494 newIRQs = gba->memory.io[REG_IF >> 1];
495 break;
496 }
497 }
498 }
499 gba->memory.io[REG_IF >> 1] = newIRQs | irqs;
500 return newIRQs;
501}
502
503int GBAHalt(struct GBA* gba) {
504 return GBAWaitForIRQ(gba);
505}
506
507void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) {
508 if (!gba) {
509 struct GBAThread* threadContext = GBAThreadGetContext();
510 if (threadContext) {
511 gba = threadContext->gba;
512 }
513 }
514 if (gba && !(level & gba->logLevel)) {
515 return;
516 }
517 va_list args;
518 va_start(args, format);
519 vprintf(format, args);
520 va_end(args);
521 printf("\n");
522}
523
524void GBAHitStub(struct ARMBoard* board, uint32_t opcode) {
525 struct GBABoard* gbaBoard = (struct GBABoard*) board;
526 GBALog(gbaBoard->p, GBA_LOG_STUB, "Stub opcode: %08x", opcode);
527#ifdef USE_DEBUGGER
528 if (!gbaBoard->p->debugger) {
529 abort();
530 } else {
531 ARMDebuggerEnter(gbaBoard->p->debugger);
532 }
533#else
534 abort();
535#endif
536}
537
538void GBAIllegal(struct ARMBoard* board, uint32_t opcode) {
539 struct GBABoard* gbaBoard = (struct GBABoard*) board;
540 GBALog(gbaBoard->p, GBA_LOG_WARN, "Illegal opcode: %08x", opcode);
541#ifdef USE_DEBUGGER
542 if (gbaBoard->p->debugger) {
543 ARMDebuggerEnter(gbaBoard->p->debugger);
544 }
545#endif
546}
547
548void _checkOverrides(struct GBA* gba, uint32_t id) {
549 int i;
550 for (i = 0; _overrides[i].id; ++i) {
551 if (_overrides[i].id == id) {
552 switch (_overrides[i].type) {
553 case SAVEDATA_FLASH512:
554 case SAVEDATA_FLASH1M:
555 gba->memory.savedata.type = _overrides[i].type;
556 GBASavedataInitFlash(&gba->memory.savedata);
557 break;
558 case SAVEDATA_EEPROM:
559 GBASavedataInitEEPROM(&gba->memory.savedata);
560 break;
561 case SAVEDATA_SRAM:
562 GBASavedataInitSRAM(&gba->memory.savedata);
563 break;
564 case SAVEDATA_NONE:
565 break;
566 }
567
568 if (_overrides[i].gpio & GPIO_RTC) {
569 GBAGPIOInitRTC(&gba->memory.gpio);
570 }
571
572 if (_overrides[i].gpio & GPIO_GYRO) {
573 GBAGPIOInitGyro(&gba->memory.gpio);
574 }
575
576 if (_overrides[i].gpio & GPIO_RUMBLE) {
577 GBAGPIOInitRumble(&gba->memory.gpio);
578 }
579 return;
580 }
581 }
582}