src/gba/gba-io.c (view raw)
1#include "gba-io.h"
2
3#include "gba-serialize.h"
4#include "gba-video.h"
5
6static const int _isValidRegister[REG_MAX >> 1] = {
7 // Video
8 1, 0, 1, 1, 1, 1, 1, 1,
9 1, 1, 1, 1, 1, 1, 1, 1,
10 1, 1, 1, 1, 1, 1, 1, 1,
11 1, 1, 1, 1, 1, 1, 1, 1,
12 1, 1, 1, 1, 1, 1, 1, 0,
13 1, 1, 1, 0, 0, 0, 0, 0,
14 // Audio
15 1, 1, 1, 0, 1, 0, 1, 0,
16 1, 1, 1, 0, 1, 0, 1, 0,
17 1, 1, 1, 0, 1, 0, 0, 0,
18 1, 1, 1, 1, 1, 1, 1, 1,
19 1, 1, 1, 1, 1, 0, 0, 0,
20 // DMA
21 1, 1, 1, 1, 1, 1, 1, 1,
22 1, 1, 1, 1, 1, 1, 1, 1,
23 1, 1, 1, 1, 1, 1, 1, 1,
24 0, 0, 0, 0, 0, 0, 0, 0,
25 0, 0, 0, 0, 0, 0, 0, 0,
26 // Timers
27 1, 1, 1, 1, 1, 1, 1, 1,
28 0, 0, 0, 0, 0, 0, 0, 0,
29 // SIO
30 1, 1, 1, 1, 1, 0, 0, 0,
31 1, 1, 1, 0, 0, 0, 0, 0,
32 1, 0, 0, 0, 0, 0, 0, 0,
33 1, 0, 1, 0, 1, 0, 0, 0,
34 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0,
38 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0,
42 0, 0, 0, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0, 0, 0,
44 // Interrupts
45 1, 1, 1, 0, 1
46};
47
48static const int _isSpecialRegister[REG_MAX >> 1] = {
49 // Video
50 0, 0, 0, 1, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0,
56 // Audio
57 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0,
60 1, 1, 1, 1, 1, 1, 1, 1,
61 1, 1, 1, 1, 0, 0, 0, 0,
62 // DMA
63 1, 1, 1, 1, 1, 1, 1, 1,
64 1, 1, 1, 1, 1, 1, 1, 1,
65 1, 1, 1, 1, 1, 1, 1, 1,
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 // Timers
69 1, 1, 1, 1, 1, 1, 1, 1,
70 0, 0, 0, 0, 0, 0, 0, 0,
71 // SIO
72 1, 1, 1, 1, 1, 0, 0, 0,
73 1, 1, 1, 0, 0, 0, 0, 0,
74 1, 0, 0, 0, 0, 0, 0, 0,
75 1, 0, 1, 0, 1, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0,
82 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0,
86 // Interrupts
87 1, 1, 1, 0, 1
88};
89
90void GBAIOInit(struct GBA* gba) {
91 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
92 gba->memory.io[REG_RCNT >> 1] = 0x8000;
93 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
94 gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
95}
96
97void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
98 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
99 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
100 } else {
101 switch (address) {
102 // Video
103 case REG_DISPSTAT:
104 value &= 0xFFF8;
105 GBAVideoWriteDISPSTAT(&gba->video, value);
106 break;
107
108 // Audio
109 case REG_SOUND1CNT_LO:
110 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
111 value &= 0x00FF;
112 break;
113 case REG_SOUND1CNT_HI:
114 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
115 break;
116 case REG_SOUND1CNT_X:
117 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
118 value &= 0x47FF;
119 break;
120 case REG_SOUND2CNT_LO:
121 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
122 break;
123 case REG_SOUND2CNT_HI:
124 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
125 value &= 0x47FF;
126 break;
127 case REG_SOUND3CNT_LO:
128 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
129 value &= 0x00E0;
130 break;
131 case REG_SOUND3CNT_HI:
132 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
133 value &= 0xE000;
134 break;
135 case REG_SOUND3CNT_X:
136 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
137 value &= 0x4000;
138 break;
139 case REG_SOUND4CNT_LO:
140 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
141 value &= 0xFF00;
142 break;
143 case REG_SOUND4CNT_HI:
144 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
145 value &= 0x40FF;
146 break;
147 case REG_SOUNDCNT_LO:
148 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
149 break;
150 case REG_SOUNDCNT_HI:
151 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
152 break;
153 case REG_SOUNDCNT_X:
154 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
155 break;
156 case REG_SOUNDBIAS:
157 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
158 break;
159
160 case REG_WAVE_RAM0_LO:
161 case REG_WAVE_RAM1_LO:
162 case REG_WAVE_RAM2_LO:
163 case REG_WAVE_RAM3_LO:
164 case REG_FIFO_A_LO:
165 case REG_FIFO_B_LO:
166 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
167 break;
168
169 case REG_WAVE_RAM0_HI:
170 case REG_WAVE_RAM1_HI:
171 case REG_WAVE_RAM2_HI:
172 case REG_WAVE_RAM3_HI:
173 case REG_FIFO_A_HI:
174 case REG_FIFO_B_HI:
175 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
176 break;
177
178 // DMA
179 case REG_DMA0SAD_LO:
180 case REG_DMA0DAD_LO:
181 case REG_DMA1SAD_LO:
182 case REG_DMA1DAD_LO:
183 case REG_DMA2SAD_LO:
184 case REG_DMA2DAD_LO:
185 case REG_DMA3SAD_LO:
186 case REG_DMA3DAD_LO:
187 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
188 break;
189
190 case REG_DMA0SAD_HI:
191 case REG_DMA0DAD_HI:
192 case REG_DMA1SAD_HI:
193 case REG_DMA1DAD_HI:
194 case REG_DMA2SAD_HI:
195 case REG_DMA2DAD_HI:
196 case REG_DMA3SAD_HI:
197 case REG_DMA3DAD_HI:
198 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
199 break;
200
201 case REG_DMA0CNT_LO:
202 GBAMemoryWriteDMACNT_LO(&gba->memory, 0, value);
203 break;
204 case REG_DMA0CNT_HI:
205 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 0, value);
206 break;
207 case REG_DMA1CNT_LO:
208 GBAMemoryWriteDMACNT_LO(&gba->memory, 1, value);
209 break;
210 case REG_DMA1CNT_HI:
211 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 1, value);
212 break;
213 case REG_DMA2CNT_LO:
214 GBAMemoryWriteDMACNT_LO(&gba->memory, 2, value);
215 break;
216 case REG_DMA2CNT_HI:
217 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 2, value);
218 break;
219 case REG_DMA3CNT_LO:
220 GBAMemoryWriteDMACNT_LO(&gba->memory, 3, value);
221 break;
222 case REG_DMA3CNT_HI:
223 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 3, value);
224 break;
225
226 // Timers
227 case REG_TM0CNT_LO:
228 GBATimerWriteTMCNT_LO(gba, 0, value);
229 return;
230 case REG_TM1CNT_LO:
231 GBATimerWriteTMCNT_LO(gba, 1, value);
232 return;
233 case REG_TM2CNT_LO:
234 GBATimerWriteTMCNT_LO(gba, 2, value);
235 return;
236 case REG_TM3CNT_LO:
237 GBATimerWriteTMCNT_LO(gba, 3, value);
238 return;
239
240 case REG_TM0CNT_HI:
241 value &= 0x00C7;
242 GBATimerWriteTMCNT_HI(gba, 0, value);
243 break;
244 case REG_TM1CNT_HI:
245 value &= 0x00C7;
246 GBATimerWriteTMCNT_HI(gba, 1, value);
247 break;
248 case REG_TM2CNT_HI:
249 value &= 0x00C7;
250 GBATimerWriteTMCNT_HI(gba, 2, value);
251 break;
252 case REG_TM3CNT_HI:
253 value &= 0x00C7;
254 GBATimerWriteTMCNT_HI(gba, 3, value);
255 break;
256
257 // Interrupts and misc
258 case REG_WAITCNT:
259 GBAAdjustWaitstates(&gba->memory, value);
260 break;
261 case REG_IE:
262 GBAWriteIE(gba, value);
263 break;
264 case REG_IF:
265 value = gba->memory.io[REG_IF >> 1] & ~value;
266 break;
267 case REG_IME:
268 GBAWriteIME(gba, value);
269 break;
270 case REG_MAX:
271 // Some bad interrupt libraries will write to this
272 break;
273 default:
274 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
275 break;
276 }
277 }
278 gba->memory.io[address >> 1] = value;
279}
280
281void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
282 if (address == REG_HALTCNT) {
283 value &= 0x80;
284 if (!value) {
285 GBAHalt(gba);
286 } else {
287 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
288 }
289 return;
290 }
291 uint16_t value16 = value << (8 * (address & 1));
292 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
293 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
294}
295
296void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
297 switch (address) {
298 case REG_WAVE_RAM0_LO:
299 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
300 break;
301 case REG_WAVE_RAM1_LO:
302 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
303 break;
304 case REG_WAVE_RAM2_LO:
305 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
306 break;
307 case REG_WAVE_RAM3_LO:
308 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
309 break;
310 case REG_FIFO_A_LO:
311 case REG_FIFO_B_LO:
312 GBAAudioWriteFIFO(&gba->audio, address, value);
313 break;
314 case REG_DMA0SAD_LO:
315 GBAMemoryWriteDMASAD(&gba->memory, 0, value);
316 break;
317 case REG_DMA0DAD_LO:
318 GBAMemoryWriteDMADAD(&gba->memory, 0, value);
319 break;
320 case REG_DMA1SAD_LO:
321 GBAMemoryWriteDMASAD(&gba->memory, 1, value);
322 break;
323 case REG_DMA1DAD_LO:
324 GBAMemoryWriteDMADAD(&gba->memory, 1, value);
325 break;
326 case REG_DMA2SAD_LO:
327 GBAMemoryWriteDMASAD(&gba->memory, 2, value);
328 break;
329 case REG_DMA2DAD_LO:
330 GBAMemoryWriteDMADAD(&gba->memory, 2, value);
331 break;
332 case REG_DMA3SAD_LO:
333 GBAMemoryWriteDMASAD(&gba->memory, 3, value);
334 break;
335 case REG_DMA3DAD_LO:
336 GBAMemoryWriteDMADAD(&gba->memory, 3, value);
337 break;
338 default:
339 GBAIOWrite(gba, address, value & 0xFFFF);
340 GBAIOWrite(gba, address | 2, value >> 16);
341 return;
342 }
343 gba->memory.io[address >> 1] = value;
344 gba->memory.io[(address >> 1) + 1] = value >> 16;
345}
346
347uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
348 switch (address) {
349 case REG_DISPSTAT:
350 return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
351 break;
352
353 case REG_TM0CNT_LO:
354 GBATimerUpdateRegister(gba, 0);
355 break;
356 case REG_TM1CNT_LO:
357 GBATimerUpdateRegister(gba, 1);
358 break;
359 case REG_TM2CNT_LO:
360 GBATimerUpdateRegister(gba, 2);
361 break;
362 case REG_TM3CNT_LO:
363 GBATimerUpdateRegister(gba, 3);
364 break;
365
366 case REG_KEYINPUT:
367 if (gba->keySource) {
368 return 0x3FF ^ *gba->keySource;
369 }
370 break;
371
372 case REG_DMA0CNT_LO:
373 case REG_DMA1CNT_LO:
374 case REG_DMA2CNT_LO:
375 case REG_DMA3CNT_LO:
376 // Write-only register
377 return 0;
378 case REG_DISPCNT:
379 case REG_VCOUNT:
380 case REG_BG0CNT:
381 case REG_BG1CNT:
382 case REG_BG2CNT:
383 case REG_BG3CNT:
384 case REG_WININ:
385 case REG_WINOUT:
386 case REG_BLDCNT:
387 case REG_SOUND1CNT_LO:
388 case REG_SOUND1CNT_HI:
389 case REG_SOUND1CNT_X:
390 case REG_SOUND2CNT_LO:
391 case REG_SOUND2CNT_HI:
392 case REG_SOUND3CNT_LO:
393 case REG_SOUND3CNT_HI:
394 case REG_SOUND3CNT_X:
395 case REG_SOUND4CNT_LO:
396 case REG_SOUND4CNT_HI:
397 case REG_SOUNDCNT_LO:
398 case REG_SOUNDCNT_HI:
399 case REG_DMA0CNT_HI:
400 case REG_DMA1CNT_HI:
401 case REG_DMA2CNT_HI:
402 case REG_DMA3CNT_HI:
403 case REG_IE:
404 case REG_IF:
405 case REG_WAITCNT:
406 case REG_IME:
407 // Handled transparently by registers
408 break;
409 case REG_MAX:
410 // Some bad interrupt libraries will read from this
411 break;
412 default:
413 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
414 break;
415 }
416 return gba->memory.io[address >> 1];
417}
418
419void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
420 int i;
421 for (i = 0; i < REG_MAX; i += 2) {
422 if (_isSpecialRegister[i >> 1]) {
423 state->io[i >> 1] = gba->memory.io[i >> 1];
424 } else if (_isValidRegister[i >> 1]) {
425 state->io[i >> 1] = GBAIORead(gba, i);
426 }
427 }
428
429 for (i = 0; i < 4; ++i) {
430 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
431 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
432 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
433 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
434 }
435
436 memcpy(state->timers, gba->timers, sizeof(state->timers));
437}
438
439void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
440 int i;
441 for (i = 0; i < REG_MAX; i += 2) {
442 if (_isSpecialRegister[i >> 1]) {
443 gba->memory.io[i >> 1] = state->io[i >> 1];
444 } else if (_isValidRegister[i >> 1]) {
445 GBAIOWrite(gba, i, state->io[i >> 1]);
446 }
447 }
448
449 for (i = 0; i < 4; ++i) {
450 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
451 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
452 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
453 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
454 }
455
456 memcpy(state->timers, gba->timers, sizeof(gba->timers));
457}