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