src/gba/gba-io.c (view raw)
1#include "gba-io.h"
2
3#include "gba-video.h"
4
5void GBAIOInit(struct GBA* gba) {
6 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
7 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
8}
9
10void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
11 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
12 gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
13 } else {
14 switch (address) {
15 // Video
16 case REG_DISPSTAT:
17 GBAVideoWriteDISPSTAT(&gba->video, value);
18 break;
19
20 // DMA
21 case REG_DMA0SAD_LO:
22 case REG_DMA0DAD_LO:
23 case REG_DMA1SAD_LO:
24 case REG_DMA1DAD_LO:
25 case REG_DMA2SAD_LO:
26 case REG_DMA2DAD_LO:
27 case REG_DMA3SAD_LO:
28 case REG_DMA3DAD_LO:
29 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
30 break;
31
32 case REG_DMA0SAD_HI:
33 case REG_DMA0DAD_HI:
34 case REG_DMA1SAD_HI:
35 case REG_DMA1DAD_HI:
36 case REG_DMA2SAD_HI:
37 case REG_DMA2DAD_HI:
38 case REG_DMA3SAD_HI:
39 case REG_DMA3DAD_HI:
40 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
41 break;
42
43 case REG_DMA0CNT_LO:
44 GBAMemoryWriteDMACNT_LO(&gba->memory, 0, value);
45 break;
46 case REG_DMA0CNT_HI:
47 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 0, value);
48 break;
49 case REG_DMA1CNT_LO:
50 GBAMemoryWriteDMACNT_LO(&gba->memory, 1, value);
51 break;
52 case REG_DMA1CNT_HI:
53 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 1, value);
54 break;
55 case REG_DMA2CNT_LO:
56 GBAMemoryWriteDMACNT_LO(&gba->memory, 2, value);
57 break;
58 case REG_DMA2CNT_HI:
59 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 2, value);
60 break;
61 case REG_DMA3CNT_LO:
62 GBAMemoryWriteDMACNT_LO(&gba->memory, 3, value);
63 break;
64 case REG_DMA3CNT_HI:
65 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 3, value);
66 break;
67
68 // Timers
69 case REG_TM0CNT_LO:
70 GBATimerWriteTMCNT_LO(gba, 0, value);
71 return;
72 case REG_TM1CNT_LO:
73 GBATimerWriteTMCNT_LO(gba, 1, value);
74 return;
75 case REG_TM2CNT_LO:
76 GBATimerWriteTMCNT_LO(gba, 2, value);
77 return;
78 case REG_TM3CNT_LO:
79 GBATimerWriteTMCNT_LO(gba, 3, value);
80 return;
81
82 case REG_TM0CNT_HI:
83 value &= 0x00C7;
84 GBATimerWriteTMCNT_HI(gba, 0, value);
85 break;
86 case REG_TM1CNT_HI:
87 value &= 0x00C7;
88 GBATimerWriteTMCNT_HI(gba, 1, value);
89 break;
90 case REG_TM2CNT_HI:
91 value &= 0x00C7;
92 GBATimerWriteTMCNT_HI(gba, 2, value);
93 break;
94 case REG_TM3CNT_HI:
95 value &= 0x00C7;
96 GBATimerWriteTMCNT_HI(gba, 3, value);
97 break;
98
99 // Interrupts and misc
100 case REG_WAITCNT:
101 GBAAdjustWaitstates(&gba->memory, value);
102 break;
103 case REG_IE:
104 GBAWriteIE(gba, value);
105 break;
106 case REG_IF:
107 value = gba->memory.io[REG_IF >> 1] & ~value;
108 break;
109 case REG_IME:
110 GBAWriteIME(gba, value);
111 break;
112 case 0x20A:
113 // Some bad interrupt libraries will write to this
114 break;
115 default:
116 GBALog(GBA_LOG_STUB, "Stub I/O register write: %03x", address);
117 break;
118 }
119 }
120 gba->memory.io[address >> 1] = value;
121}
122
123void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
124 if (address == REG_HALTCNT) {
125 value &= 0x80;
126 if (!value) {
127 GBAHalt(gba);
128 } else {
129 GBALog(GBA_LOG_STUB, "Stop unimplemented");
130 }
131 return;
132 }
133 value <<= 8 * (address & 1);
134 value |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
135 GBAIOWrite(gba, address, value);
136}
137
138void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
139 switch (address) {
140 case REG_DMA0SAD_LO:
141 GBAMemoryWriteDMASAD(&gba->memory, 0, value);
142 break;
143 case REG_DMA0DAD_LO:
144 GBAMemoryWriteDMADAD(&gba->memory, 0, value);
145 break;
146 case REG_DMA1SAD_LO:
147 GBAMemoryWriteDMASAD(&gba->memory, 1, value);
148 break;
149 case REG_DMA1DAD_LO:
150 GBAMemoryWriteDMADAD(&gba->memory, 1, value);
151 break;
152 case REG_DMA2SAD_LO:
153 GBAMemoryWriteDMASAD(&gba->memory, 2, value);
154 break;
155 case REG_DMA2DAD_LO:
156 GBAMemoryWriteDMADAD(&gba->memory, 2, value);
157 break;
158 case REG_DMA3SAD_LO:
159 GBAMemoryWriteDMASAD(&gba->memory, 3, value);
160 break;
161 case REG_DMA3DAD_LO:
162 GBAMemoryWriteDMADAD(&gba->memory, 3, value);
163 break;
164 default:
165 GBAIOWrite(gba, address, value & 0xFFFF);
166 GBAIOWrite(gba, address | 2, value >> 16);
167 return;
168 }
169 gba->memory.io[address >> 1] = value;
170 gba->memory.io[(address >> 1) + 1] = value >> 16;
171}
172
173uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
174 switch (address) {
175 case REG_DISPSTAT:
176 return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
177 break;
178
179 case REG_TM0CNT_LO:
180 GBATimerUpdateRegister(gba, 0);
181 break;
182 case REG_TM1CNT_LO:
183 GBATimerUpdateRegister(gba, 1);
184 break;
185 case REG_TM2CNT_LO:
186 GBATimerUpdateRegister(gba, 2);
187 break;
188 case REG_TM3CNT_LO:
189 GBATimerUpdateRegister(gba, 3);
190 break;
191
192 case REG_KEYINPUT:
193 if (gba->keySource) {
194 return 0x3FF ^ *gba->keySource;
195 }
196 break;
197
198 case REG_DMA0CNT_LO:
199 case REG_DMA1CNT_LO:
200 case REG_DMA2CNT_LO:
201 case REG_DMA3CNT_LO:
202 // Write-only register
203 return 0;
204 case REG_VCOUNT:
205 case REG_DMA0CNT_HI:
206 case REG_DMA1CNT_HI:
207 case REG_DMA2CNT_HI:
208 case REG_DMA3CNT_HI:
209 case REG_IE:
210 case REG_IF:
211 case REG_WAITCNT:
212 case REG_IME:
213 // Handled transparently by registers
214 break;
215 case 0x20A:
216 // Some bad interrupt libraries will read from this
217 break;
218 default:
219 GBALog(GBA_LOG_STUB, "Stub I/O register read: %03x", address);
220 break;
221 }
222 return gba->memory.io[address >> 1];
223}