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, 0, 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}
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
157 case REG_WAVE_RAM0_LO:
158 case REG_WAVE_RAM1_LO:
159 case REG_WAVE_RAM2_LO:
160 case REG_WAVE_RAM3_LO:
161 case REG_FIFO_A_LO:
162 case REG_FIFO_B_LO:
163 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
164 break;
165
166 case REG_WAVE_RAM0_HI:
167 case REG_WAVE_RAM1_HI:
168 case REG_WAVE_RAM2_HI:
169 case REG_WAVE_RAM3_HI:
170 case REG_FIFO_A_HI:
171 case REG_FIFO_B_HI:
172 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
173 break;
174
175 // DMA
176 case REG_DMA0SAD_LO:
177 case REG_DMA0DAD_LO:
178 case REG_DMA1SAD_LO:
179 case REG_DMA1DAD_LO:
180 case REG_DMA2SAD_LO:
181 case REG_DMA2DAD_LO:
182 case REG_DMA3SAD_LO:
183 case REG_DMA3DAD_LO:
184 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
185 break;
186
187 case REG_DMA0SAD_HI:
188 case REG_DMA0DAD_HI:
189 case REG_DMA1SAD_HI:
190 case REG_DMA1DAD_HI:
191 case REG_DMA2SAD_HI:
192 case REG_DMA2DAD_HI:
193 case REG_DMA3SAD_HI:
194 case REG_DMA3DAD_HI:
195 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
196 break;
197
198 case REG_DMA0CNT_LO:
199 GBAMemoryWriteDMACNT_LO(&gba->memory, 0, value);
200 break;
201 case REG_DMA0CNT_HI:
202 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 0, value);
203 break;
204 case REG_DMA1CNT_LO:
205 GBAMemoryWriteDMACNT_LO(&gba->memory, 1, value);
206 break;
207 case REG_DMA1CNT_HI:
208 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 1, value);
209 break;
210 case REG_DMA2CNT_LO:
211 GBAMemoryWriteDMACNT_LO(&gba->memory, 2, value);
212 break;
213 case REG_DMA2CNT_HI:
214 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 2, value);
215 break;
216 case REG_DMA3CNT_LO:
217 GBAMemoryWriteDMACNT_LO(&gba->memory, 3, value);
218 break;
219 case REG_DMA3CNT_HI:
220 value = GBAMemoryWriteDMACNT_HI(&gba->memory, 3, value);
221 break;
222
223 // Timers
224 case REG_TM0CNT_LO:
225 GBATimerWriteTMCNT_LO(gba, 0, value);
226 return;
227 case REG_TM1CNT_LO:
228 GBATimerWriteTMCNT_LO(gba, 1, value);
229 return;
230 case REG_TM2CNT_LO:
231 GBATimerWriteTMCNT_LO(gba, 2, value);
232 return;
233 case REG_TM3CNT_LO:
234 GBATimerWriteTMCNT_LO(gba, 3, value);
235 return;
236
237 case REG_TM0CNT_HI:
238 value &= 0x00C7;
239 GBATimerWriteTMCNT_HI(gba, 0, value);
240 break;
241 case REG_TM1CNT_HI:
242 value &= 0x00C7;
243 GBATimerWriteTMCNT_HI(gba, 1, value);
244 break;
245 case REG_TM2CNT_HI:
246 value &= 0x00C7;
247 GBATimerWriteTMCNT_HI(gba, 2, value);
248 break;
249 case REG_TM3CNT_HI:
250 value &= 0x00C7;
251 GBATimerWriteTMCNT_HI(gba, 3, value);
252 break;
253
254 // SIO
255 case REG_SIOCNT:
256 GBASIOWriteSIOCNT(&gba->sio, value);
257 break;
258 case REG_RCNT:
259 value &= 0xC1FF;
260 GBASIOWriteRCNT(&gba->sio, value);
261 break;
262
263 // Interrupts and misc
264 case REG_WAITCNT:
265 GBAAdjustWaitstates(&gba->memory, value);
266 break;
267 case REG_IE:
268 GBAWriteIE(gba, value);
269 break;
270 case REG_IF:
271 value = gba->memory.io[REG_IF >> 1] & ~value;
272 break;
273 case REG_IME:
274 GBAWriteIME(gba, value);
275 break;
276 case REG_MAX:
277 // Some bad interrupt libraries will write to this
278 break;
279 default:
280 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
281 break;
282 }
283 }
284 gba->memory.io[address >> 1] = value;
285}
286
287void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
288 if (address == REG_HALTCNT) {
289 value &= 0x80;
290 if (!value) {
291 GBAHalt(gba);
292 } else {
293 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
294 }
295 return;
296 }
297 uint16_t value16 = value << (8 * (address & 1));
298 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
299 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
300}
301
302void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
303 switch (address) {
304 case REG_WAVE_RAM0_LO:
305 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
306 break;
307 case REG_WAVE_RAM1_LO:
308 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
309 break;
310 case REG_WAVE_RAM2_LO:
311 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
312 break;
313 case REG_WAVE_RAM3_LO:
314 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
315 break;
316 case REG_FIFO_A_LO:
317 case REG_FIFO_B_LO:
318 GBAAudioWriteFIFO(&gba->audio, address, value);
319 break;
320 case REG_DMA0SAD_LO:
321 GBAMemoryWriteDMASAD(&gba->memory, 0, value);
322 break;
323 case REG_DMA0DAD_LO:
324 GBAMemoryWriteDMADAD(&gba->memory, 0, value);
325 break;
326 case REG_DMA1SAD_LO:
327 GBAMemoryWriteDMASAD(&gba->memory, 1, value);
328 break;
329 case REG_DMA1DAD_LO:
330 GBAMemoryWriteDMADAD(&gba->memory, 1, value);
331 break;
332 case REG_DMA2SAD_LO:
333 GBAMemoryWriteDMASAD(&gba->memory, 2, value);
334 break;
335 case REG_DMA2DAD_LO:
336 GBAMemoryWriteDMADAD(&gba->memory, 2, value);
337 break;
338 case REG_DMA3SAD_LO:
339 GBAMemoryWriteDMASAD(&gba->memory, 3, value);
340 break;
341 case REG_DMA3DAD_LO:
342 GBAMemoryWriteDMADAD(&gba->memory, 3, value);
343 break;
344 default:
345 GBAIOWrite(gba, address, value & 0xFFFF);
346 GBAIOWrite(gba, address | 2, value >> 16);
347 return;
348 }
349 gba->memory.io[address >> 1] = value;
350 gba->memory.io[(address >> 1) + 1] = value >> 16;
351}
352
353uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
354 switch (address) {
355 case REG_DISPSTAT:
356 return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
357 break;
358
359 case REG_TM0CNT_LO:
360 GBATimerUpdateRegister(gba, 0);
361 break;
362 case REG_TM1CNT_LO:
363 GBATimerUpdateRegister(gba, 1);
364 break;
365 case REG_TM2CNT_LO:
366 GBATimerUpdateRegister(gba, 2);
367 break;
368 case REG_TM3CNT_LO:
369 GBATimerUpdateRegister(gba, 3);
370 break;
371
372 case REG_KEYINPUT:
373 if (gba->keySource) {
374 return 0x3FF ^ *gba->keySource;
375 }
376 break;
377
378 case REG_DMA0CNT_LO:
379 case REG_DMA1CNT_LO:
380 case REG_DMA2CNT_LO:
381 case REG_DMA3CNT_LO:
382 // Write-only register
383 return 0;
384 case REG_DISPCNT:
385 case REG_VCOUNT:
386 case REG_BG0CNT:
387 case REG_BG1CNT:
388 case REG_BG2CNT:
389 case REG_BG3CNT:
390 case REG_WININ:
391 case REG_WINOUT:
392 case REG_BLDCNT:
393 case REG_SOUND1CNT_LO:
394 case REG_SOUND1CNT_HI:
395 case REG_SOUND1CNT_X:
396 case REG_SOUND2CNT_LO:
397 case REG_SOUND2CNT_HI:
398 case REG_SOUND3CNT_LO:
399 case REG_SOUND3CNT_HI:
400 case REG_SOUND3CNT_X:
401 case REG_SOUND4CNT_LO:
402 case REG_SOUND4CNT_HI:
403 case REG_SOUNDCNT_LO:
404 case REG_SOUNDCNT_HI:
405 case REG_DMA0CNT_HI:
406 case REG_DMA1CNT_HI:
407 case REG_DMA2CNT_HI:
408 case REG_DMA3CNT_HI:
409 case REG_IE:
410 case REG_IF:
411 case REG_WAITCNT:
412 case REG_IME:
413 // Handled transparently by registers
414 break;
415 case REG_MAX:
416 // Some bad interrupt libraries will read from this
417 break;
418 default:
419 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
420 break;
421 }
422 return gba->memory.io[address >> 1];
423}
424
425void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
426 int i;
427 for (i = 0; i < REG_MAX; i += 2) {
428 if (_isSpecialRegister[i >> 1]) {
429 state->io[i >> 1] = gba->memory.io[i >> 1];
430 } else if (_isValidRegister[i >> 1]) {
431 state->io[i >> 1] = GBAIORead(gba, i);
432 }
433 }
434
435 for (i = 0; i < 4; ++i) {
436 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
437 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
438 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
439 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
440 }
441
442 memcpy(state->timers, gba->timers, sizeof(state->timers));
443}
444
445void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
446 int i;
447 for (i = 0; i < REG_MAX; i += 2) {
448 if (_isSpecialRegister[i >> 1]) {
449 gba->memory.io[i >> 1] = state->io[i >> 1];
450 } else if (_isValidRegister[i >> 1]) {
451 GBAIOWrite(gba, i, state->io[i >> 1]);
452 }
453 }
454
455 for (i = 0; i < 4; ++i) {
456 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
457 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
458 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
459 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
460 }
461
462 memcpy(state->timers, gba->timers, sizeof(gba->timers));
463}