aboutsummaryrefslogtreecommitdiffstats
path: root/src/gba/interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gba/interrupts.c')
-rw-r--r--src/gba/interrupts.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/gba/interrupts.c b/src/gba/interrupts.c
new file mode 100644
index 0000000..3b11335
--- /dev/null
+++ b/src/gba/interrupts.c
@@ -0,0 +1,91 @@
1#include "gba.h"
2
3IrsFunc irs_table[] = {
4 [IRQ_VBLANK ] = NULL,
5 [IRQ_HBLANK ] = NULL,
6 [IRQ_VCOUNT ] = NULL,
7 [IRQ_TIMER_0] = NULL,
8 [IRQ_TIMER_1] = NULL,
9 [IRQ_TIMER_2] = NULL,
10 [IRQ_TIMER_3] = NULL,
11 [IRQ_SERIAL ] = NULL,
12 [IRQ_DMA_0 ] = NULL,
13 [IRQ_DMA_1 ] = NULL,
14 [IRQ_DMA_2 ] = NULL,
15 [IRQ_DMA_3 ] = NULL,
16 [IRQ_KEYPAD ] = NULL,
17 [IRQ_GAMEPAK] = NULL,
18};
19
20// External irs_main function, has to be written in ARM assembly.
21void irs_main(void);
22#define IRS_MAIN *(IrsFunc*)(0x03007FFC)
23
24void
25irq_enable(IrqIndex idx) {
26 switch (idx) {
27 case IRQ_VBLANK: { DISP_STATUS |= DISP_VBLANK_IRQ; } break;
28 case IRQ_HBLANK: { DISP_STATUS |= DISP_HBLANK_IRQ; } break;
29 case IRQ_VCOUNT: { DISP_STATUS |= DISP_VCOUNT_IRQ; } break;
30 case IRQ_TIMER_0: { TIMER_CTRL_0 |= TIMER_CTRL_IRQ; } break;
31 case IRQ_TIMER_1: { TIMER_CTRL_1 |= TIMER_CTRL_IRQ; } break;
32 case IRQ_TIMER_2: { TIMER_CTRL_2 |= TIMER_CTRL_IRQ; } break;
33 case IRQ_TIMER_3: { TIMER_CTRL_3 |= TIMER_CTRL_IRQ; } break;
34 case IRQ_SERIAL: { /* TODO: Set REG_SERIAL? */ } break;
35 case IRQ_DMA_0: { DMA_CTRL(0) |= DMA_IRQ; } break;
36 case IRQ_DMA_1: { DMA_CTRL(1) |= DMA_IRQ; } break;
37 case IRQ_DMA_2: { DMA_CTRL(2) |= DMA_IRQ; } break;
38 case IRQ_DMA_3: { DMA_CTRL(3) |= DMA_IRQ; } break;
39 case IRQ_KEYPAD: { KEY_CTRL |= KEY_IRQ; } break;
40 case IRQ_GAMEPAK: { /* Nothing to do here...*/ } break;
41 }
42 IRQ_ENABLE |= (1 << idx);
43}
44
45void
46irq_disable(IrqIndex idx) {
47 switch (idx) {
48 case IRQ_VBLANK: { DISP_STATUS &= ~DISP_VBLANK_IRQ; } break;
49 case IRQ_HBLANK: { DISP_STATUS &= ~DISP_HBLANK_IRQ; } break;
50 case IRQ_VCOUNT: { DISP_STATUS &= ~DISP_VCOUNT_IRQ; } break;
51 case IRQ_TIMER_0: { TIMER_CTRL_0 &= ~TIMER_CTRL_IRQ; } break;
52 case IRQ_TIMER_1: { TIMER_CTRL_1 &= ~TIMER_CTRL_IRQ; } break;
53 case IRQ_TIMER_2: { TIMER_CTRL_2 &= ~TIMER_CTRL_IRQ; } break;
54 case IRQ_TIMER_3: { TIMER_CTRL_3 &= ~TIMER_CTRL_IRQ; } break;
55 case IRQ_SERIAL: { /* TODO: Set REG_SERIAL? */ } break;
56 case IRQ_DMA_0: { DMA_CTRL(0) &= ~DMA_IRQ; } break;
57 case IRQ_DMA_1: { DMA_CTRL(1) &= ~DMA_IRQ; } break;
58 case IRQ_DMA_2: { DMA_CTRL(2) &= ~DMA_IRQ; } break;
59 case IRQ_DMA_3: { DMA_CTRL(3) &= ~DMA_IRQ; } break;
60 case IRQ_KEYPAD: { KEY_CTRL &= ~KEY_IRQ; } break;
61 case IRQ_GAMEPAK: { /* Nothing to do here...*/ } break;
62 }
63 IRQ_ENABLE &= ~(1 << idx);
64}
65
66void
67irs_set(IrqIndex idx, IrsFunc func) {
68 // Store IRQ_CTRL status and disable interrupts for now.
69 u16 irq_ctrl = IRQ_CTRL;
70 IRQ_CTRL = 0;
71
72 // Update the IRS table and enable/disable the given IRQ.
73 irs_table[idx] = func;
74 if (func == NULL) {
75 irq_disable(idx);
76 } else {
77 irq_enable(idx);
78 }
79
80 // Restore previous irq_ctrl.
81 IRQ_CTRL = irq_ctrl;
82}
83
84void
85irq_init(void) {
86 IRS_MAIN = irs_main;
87 IRQ_CTRL = 1;
88}
89
90void
91irs_stub(void) {}