src/gba/io.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "io.h"
7
8#include "gba/rr/rr.h"
9#include "gba/serialize.h"
10#include "gba/sio.h"
11#include "gba/video.h"
12
13const char* GBAIORegisterNames[] = {
14 // Video
15 "DISPCNT",
16 0,
17 "DISPSTAT",
18 "VCOUNT",
19 "BG0CNT",
20 "BG1CNT",
21 "BG2CNT",
22 "BG3CNT",
23 "BG0HOFS",
24 "BG0VOFS",
25 "BG1HOFS",
26 "BG1VOFS",
27 "BG2HOFS",
28 "BG2VOFS",
29 "BG3HOFS",
30 "BG3VOFS",
31 "BG2PA",
32 "BG2PB",
33 "BG2PC",
34 "BG2PD",
35 "BG2X_LO",
36 "BG2X_HI",
37 "BG2Y_LO",
38 "BG2Y_HI",
39 "BG3PA",
40 "BG3PB",
41 "BG3PC",
42 "BG3PD",
43 "BG3X_LO",
44 "BG3X_HI",
45 "BG3Y_LO",
46 "BG3Y_HI",
47 "WIN0H",
48 "WIN1H",
49 "WIN0V",
50 "WIN1V",
51 "WININ",
52 "WINOUT",
53 "MOSAIC",
54 0,
55 "BLDCNT",
56 "BLDALPHA",
57 "BLDY",
58 0,
59 0,
60 0,
61 0,
62 0,
63
64 // Sound
65 "SOUND1CNT_LO",
66 "SOUND1CNT_HI",
67 "SOUND1CNT_X",
68 0,
69 "SOUND2CNT_LO",
70 0,
71 "SOUND2CNT_HI",
72 0,
73 "SOUND3CNT_LO",
74 "SOUND3CNT_HI",
75 "SOUND3CNT_X",
76 0,
77 "SOUND4CNT_LO",
78 0,
79 "SOUND4CNT_HI",
80 0,
81 "SOUNDCNT_LO",
82 "SOUNDCNT_HI",
83 "SOUNDCNT_X",
84 0,
85 "SOUNDBIAS",
86 0,
87 0,
88 0,
89 "WAVE_RAM0_LO",
90 "WAVE_RAM0_HI",
91 "WAVE_RAM1_LO",
92 "WAVE_RAM1_HI",
93 "WAVE_RAM2_LO",
94 "WAVE_RAM2_HI",
95 "WAVE_RAM3_LO",
96 "WAVE_RAM3_HI",
97 "FIFO_A_LO",
98 "FIFO_A_HI",
99 "FIFO_B_LO",
100 "FIFO_B_HI",
101 0,
102 0,
103 0,
104 0,
105
106 // DMA
107 "DMA0SAD_LO",
108 "DMA0SAD_HI",
109 "DMA0DAD_LO",
110 "DMA0DAD_HI",
111 "DMA0CNT_LO",
112 "DMA0CNT_HI",
113 "DMA1SAD_LO",
114 "DMA1SAD_HI",
115 "DMA1DAD_LO",
116 "DMA1DAD_HI",
117 "DMA1CNT_LO",
118 "DMA1CNT_HI",
119 "DMA2SAD_LO",
120 "DMA2SAD_HI",
121 "DMA2DAD_LO",
122 "DMA2DAD_HI",
123 "DMA2CNT_LO",
124 "DMA2CNT_HI",
125 "DMA3SAD_LO",
126 "DMA3SAD_HI",
127 "DMA3DAD_LO",
128 "DMA3DAD_HI",
129 "DMA3CNT_LO",
130 "DMA3CNT_HI",
131
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0,
134
135 // Timers
136 "TM0CNT_LO",
137 "TM0CNT_HI",
138 "TM1CNT_LO",
139 "TM1CNT_HI",
140 "TM2CNT_LO",
141 "TM2CNT_HI",
142 "TM3CNT_LO",
143 "TM3CNT_HI",
144
145 0, 0, 0, 0, 0, 0, 0, 0,
146
147 // SIO
148 "SIOMULTI0",
149 "SIOMULTI1",
150 "SIOMULTI2",
151 "SIOMULTI3",
152 "SIOCNT",
153 "SIOMLT_SEND",
154 0,
155 0,
156 "KEYINPUT",
157 "KEYCNT",
158 "RCNT",
159 0,
160 0,
161 0,
162 0,
163 0,
164 "JOYCNT",
165 0,
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 "JOY_RECV_LO",
173 "JOY_RECV_HI",
174 "JOY_TRANS_LO",
175 "JOY_TRANS_HI",
176 "JOYSTAT",
177 0,
178 0,
179 0,
180
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0, 0, 0, 0, 0, 0,
187 0, 0, 0, 0, 0, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 0,
189 0, 0, 0, 0, 0, 0, 0, 0,
190 0, 0, 0, 0, 0, 0, 0, 0,
191
192 // Interrupts, etc
193 "IE",
194 "IF",
195 "WAITCNT",
196 0,
197 "IME"
198};
199
200static const int _isValidRegister[REG_MAX >> 1] = {
201 // Video
202 1, 0, 1, 1, 1, 1, 1, 1,
203 1, 1, 1, 1, 1, 1, 1, 1,
204 1, 1, 1, 1, 1, 1, 1, 1,
205 1, 1, 1, 1, 1, 1, 1, 1,
206 1, 1, 1, 1, 1, 1, 1, 0,
207 1, 1, 1, 0, 0, 0, 0, 0,
208 // Audio
209 1, 1, 1, 0, 1, 0, 1, 0,
210 1, 1, 1, 0, 1, 0, 1, 0,
211 1, 1, 1, 0, 1, 0, 0, 0,
212 1, 1, 1, 1, 1, 1, 1, 1,
213 1, 1, 1, 1, 1, 0, 0, 0,
214 // DMA
215 1, 1, 1, 1, 1, 1, 1, 1,
216 1, 1, 1, 1, 1, 1, 1, 1,
217 1, 1, 1, 1, 1, 1, 1, 1,
218 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0,
220 // Timers
221 1, 1, 1, 1, 1, 1, 1, 1,
222 0, 0, 0, 0, 0, 0, 0, 0,
223 // SIO
224 1, 1, 1, 1, 1, 0, 0, 0,
225 1, 1, 1, 0, 0, 0, 0, 0,
226 1, 0, 0, 0, 0, 0, 0, 0,
227 1, 0, 1, 0, 1, 0, 0, 0,
228 0, 0, 0, 0, 0, 0, 0, 0,
229 0, 0, 0, 0, 0, 0, 0, 0,
230 0, 0, 0, 0, 0, 0, 0, 0,
231 0, 0, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0,
235 0, 0, 0, 0, 0, 0, 0, 0,
236 0, 0, 0, 0, 0, 0, 0, 0,
237 0, 0, 0, 0, 0, 0, 0, 0,
238 // Interrupts
239 1, 1, 1, 0, 1
240};
241
242static const int _isSpecialRegister[REG_MAX >> 1] = {
243 // Video
244 0, 0, 1, 1, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 0, 0, 0, 0, 0, 0, 0,
248 0, 0, 0, 0, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0,
250 // Audio
251 0, 0, 0, 0, 0, 0, 0, 0,
252 0, 0, 0, 0, 0, 0, 0, 0,
253 0, 0, 0, 0, 0, 0, 0, 0,
254 1, 1, 1, 1, 1, 1, 1, 1,
255 1, 1, 1, 1, 0, 0, 0, 0,
256 // DMA
257 0, 0, 0, 0, 0, 1, 0, 0,
258 0, 0, 0, 1, 0, 0, 0, 0,
259 0, 1, 0, 0, 0, 0, 0, 1,
260 0, 0, 0, 0, 0, 0, 0, 0,
261 0, 0, 0, 0, 0, 0, 0, 0,
262 // Timers
263 1, 1, 1, 1, 1, 1, 1, 1,
264 0, 0, 0, 0, 0, 0, 0, 0,
265 // SIO
266 1, 1, 1, 1, 1, 0, 0, 0,
267 1, 1, 1, 0, 0, 0, 0, 0,
268 1, 0, 0, 0, 0, 0, 0, 0,
269 1, 0, 1, 0, 1, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0,
272 0, 0, 0, 0, 0, 0, 0, 0,
273 0, 0, 0, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 0, 0, 0, 0,
275 0, 0, 0, 0, 0, 0, 0, 0,
276 0, 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 0, 0,
279 0, 0, 0, 0, 0, 0, 0, 0,
280 // Interrupts
281 1, 1, 0, 0, 1
282};
283
284void GBAIOInit(struct GBA* gba) {
285 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
286 gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
287 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
288 gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
289 gba->memory.io[REG_BG2PA >> 1] = 0x100;
290 gba->memory.io[REG_BG2PD >> 1] = 0x100;
291 gba->memory.io[REG_BG3PA >> 1] = 0x100;
292 gba->memory.io[REG_BG3PD >> 1] = 0x100;
293}
294
295void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
296 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
297 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
298 } else {
299 switch (address) {
300 // Video
301 case REG_DISPSTAT:
302 value &= 0xFFF8;
303 GBAVideoWriteDISPSTAT(&gba->video, value);
304 return;
305
306 // Audio
307 case REG_SOUND1CNT_LO:
308 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
309 value &= 0x00FF;
310 break;
311 case REG_SOUND1CNT_HI:
312 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
313 break;
314 case REG_SOUND1CNT_X:
315 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
316 value &= 0x47FF;
317 break;
318 case REG_SOUND2CNT_LO:
319 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
320 break;
321 case REG_SOUND2CNT_HI:
322 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
323 value &= 0x47FF;
324 break;
325 case REG_SOUND3CNT_LO:
326 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
327 value &= 0x00E0;
328 break;
329 case REG_SOUND3CNT_HI:
330 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
331 value &= 0xE000;
332 break;
333 case REG_SOUND3CNT_X:
334 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
335 // TODO: The low bits need to not be readable, but still 8-bit writable
336 value &= 0x47FF;
337 break;
338 case REG_SOUND4CNT_LO:
339 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
340 value &= 0xFF00;
341 break;
342 case REG_SOUND4CNT_HI:
343 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
344 value &= 0x40FF;
345 break;
346 case REG_SOUNDCNT_LO:
347 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
348 break;
349 case REG_SOUNDCNT_HI:
350 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
351 break;
352 case REG_SOUNDCNT_X:
353 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
354 break;
355 case REG_SOUNDBIAS:
356 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
357 break;
358
359 case REG_WAVE_RAM0_LO:
360 case REG_WAVE_RAM1_LO:
361 case REG_WAVE_RAM2_LO:
362 case REG_WAVE_RAM3_LO:
363 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
364 break;
365
366 case REG_WAVE_RAM0_HI:
367 case REG_WAVE_RAM1_HI:
368 case REG_WAVE_RAM2_HI:
369 case REG_WAVE_RAM3_HI:
370 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
371 break;
372
373 case REG_FIFO_A_LO:
374 case REG_FIFO_B_LO:
375 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
376 break;
377
378 case REG_FIFO_A_HI:
379 case REG_FIFO_B_HI:
380 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
381 break;
382
383 // DMA
384 case REG_DMA0SAD_LO:
385 case REG_DMA0DAD_LO:
386 case REG_DMA1SAD_LO:
387 case REG_DMA1DAD_LO:
388 case REG_DMA2SAD_LO:
389 case REG_DMA2DAD_LO:
390 case REG_DMA3SAD_LO:
391 case REG_DMA3DAD_LO:
392 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
393 break;
394
395 case REG_DMA0SAD_HI:
396 case REG_DMA0DAD_HI:
397 case REG_DMA1SAD_HI:
398 case REG_DMA1DAD_HI:
399 case REG_DMA2SAD_HI:
400 case REG_DMA2DAD_HI:
401 case REG_DMA3SAD_HI:
402 case REG_DMA3DAD_HI:
403 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
404 break;
405
406 case REG_DMA0CNT_LO:
407 GBAMemoryWriteDMACNT_LO(gba, 0, value);
408 break;
409 case REG_DMA0CNT_HI:
410 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
411 break;
412 case REG_DMA1CNT_LO:
413 GBAMemoryWriteDMACNT_LO(gba, 1, value);
414 break;
415 case REG_DMA1CNT_HI:
416 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
417 break;
418 case REG_DMA2CNT_LO:
419 GBAMemoryWriteDMACNT_LO(gba, 2, value);
420 break;
421 case REG_DMA2CNT_HI:
422 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
423 break;
424 case REG_DMA3CNT_LO:
425 GBAMemoryWriteDMACNT_LO(gba, 3, value);
426 break;
427 case REG_DMA3CNT_HI:
428 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
429 break;
430
431 // Timers
432 case REG_TM0CNT_LO:
433 GBATimerWriteTMCNT_LO(gba, 0, value);
434 return;
435 case REG_TM1CNT_LO:
436 GBATimerWriteTMCNT_LO(gba, 1, value);
437 return;
438 case REG_TM2CNT_LO:
439 GBATimerWriteTMCNT_LO(gba, 2, value);
440 return;
441 case REG_TM3CNT_LO:
442 GBATimerWriteTMCNT_LO(gba, 3, value);
443 return;
444
445 case REG_TM0CNT_HI:
446 value &= 0x00C7;
447 GBATimerWriteTMCNT_HI(gba, 0, value);
448 break;
449 case REG_TM1CNT_HI:
450 value &= 0x00C7;
451 GBATimerWriteTMCNT_HI(gba, 1, value);
452 break;
453 case REG_TM2CNT_HI:
454 value &= 0x00C7;
455 GBATimerWriteTMCNT_HI(gba, 2, value);
456 break;
457 case REG_TM3CNT_HI:
458 value &= 0x00C7;
459 GBATimerWriteTMCNT_HI(gba, 3, value);
460 break;
461
462 // SIO
463 case REG_SIOCNT:
464 GBASIOWriteSIOCNT(&gba->sio, value);
465 break;
466 case REG_RCNT:
467 value &= 0xC1FF;
468 GBASIOWriteRCNT(&gba->sio, value);
469 break;
470 case REG_SIOMLT_SEND:
471 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
472 break;
473
474 // Interrupts and misc
475 case REG_WAITCNT:
476 GBAAdjustWaitstates(gba, value);
477 break;
478 case REG_IE:
479 GBAWriteIE(gba, value);
480 break;
481 case REG_IF:
482 value = gba->memory.io[REG_IF >> 1] & ~value;
483 break;
484 case REG_IME:
485 GBAWriteIME(gba, value);
486 break;
487 case REG_MAX:
488 // Some bad interrupt libraries will write to this
489 break;
490 default:
491 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
492 if (address >= REG_MAX) {
493 GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address);
494 return;
495 }
496 break;
497 }
498 }
499 gba->memory.io[address >> 1] = value;
500}
501
502void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
503 if (address == REG_HALTCNT) {
504 value &= 0x80;
505 if (!value) {
506 GBAHalt(gba);
507 } else {
508 GBAStop(gba);
509 }
510 return;
511 }
512 uint16_t value16 = value << (8 * (address & 1));
513 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
514 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
515}
516
517void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
518 switch (address) {
519 case REG_WAVE_RAM0_LO:
520 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
521 break;
522 case REG_WAVE_RAM1_LO:
523 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
524 break;
525 case REG_WAVE_RAM2_LO:
526 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
527 break;
528 case REG_WAVE_RAM3_LO:
529 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
530 break;
531 case REG_FIFO_A_LO:
532 case REG_FIFO_B_LO:
533 GBAAudioWriteFIFO(&gba->audio, address, value);
534 break;
535 case REG_DMA0SAD_LO:
536 GBAMemoryWriteDMASAD(gba, 0, value);
537 break;
538 case REG_DMA0DAD_LO:
539 GBAMemoryWriteDMADAD(gba, 0, value);
540 break;
541 case REG_DMA1SAD_LO:
542 GBAMemoryWriteDMASAD(gba, 1, value);
543 break;
544 case REG_DMA1DAD_LO:
545 GBAMemoryWriteDMADAD(gba, 1, value);
546 break;
547 case REG_DMA2SAD_LO:
548 GBAMemoryWriteDMASAD(gba, 2, value);
549 break;
550 case REG_DMA2DAD_LO:
551 GBAMemoryWriteDMADAD(gba, 2, value);
552 break;
553 case REG_DMA3SAD_LO:
554 GBAMemoryWriteDMASAD(gba, 3, value);
555 break;
556 case REG_DMA3DAD_LO:
557 GBAMemoryWriteDMADAD(gba, 3, value);
558 break;
559 default:
560 GBAIOWrite(gba, address, value & 0xFFFF);
561 GBAIOWrite(gba, address | 2, value >> 16);
562 return;
563 }
564 gba->memory.io[address >> 1] = value;
565 gba->memory.io[(address >> 1) + 1] = value >> 16;
566}
567
568bool GBAIOIsReadConstant(uint32_t address) {
569 switch (address) {
570 default:
571 return false;
572 case REG_BG0CNT:
573 case REG_BG1CNT:
574 case REG_BG2CNT:
575 case REG_BG3CNT:
576 case REG_WININ:
577 case REG_WINOUT:
578 case REG_BLDCNT:
579 case REG_BLDALPHA:
580 case REG_DMA0CNT_LO:
581 case REG_DMA1CNT_LO:
582 case REG_DMA2CNT_LO:
583 case REG_DMA3CNT_LO:
584 case REG_KEYINPUT:
585 case REG_IE:
586 return true;
587 }
588}
589
590uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
591 if (!GBAIOIsReadConstant(address)) {
592 // Most IO reads need to disable idle removal
593 gba->haltPending = false;
594 }
595
596 switch (address) {
597 case REG_TM0CNT_LO:
598 GBATimerUpdateRegister(gba, 0);
599 break;
600 case REG_TM1CNT_LO:
601 GBATimerUpdateRegister(gba, 1);
602 break;
603 case REG_TM2CNT_LO:
604 GBATimerUpdateRegister(gba, 2);
605 break;
606 case REG_TM3CNT_LO:
607 GBATimerUpdateRegister(gba, 3);
608 break;
609
610 case REG_KEYINPUT:
611 if (gba->rr && gba->rr->isPlaying(gba->rr)) {
612 return 0x3FF ^ gba->rr->queryInput(gba->rr);
613 } else {
614 uint16_t input = 0x3FF;
615 if (gba->keyCallback) {
616 input = gba->keyCallback->readKeys(gba->keyCallback);
617 } else if (gba->keySource) {
618 input = *gba->keySource;
619 }
620 if (gba->rr && gba->rr->isRecording(gba->rr)) {
621 gba->rr->logInput(gba->rr, input);
622 }
623 return 0x3FF ^ input;
624 }
625
626 case REG_SIOCNT:
627 return gba->sio.siocnt;
628 case REG_RCNT:
629 return gba->sio.rcnt;
630
631 case REG_DMA0CNT_LO:
632 case REG_DMA1CNT_LO:
633 case REG_DMA2CNT_LO:
634 case REG_DMA3CNT_LO:
635 // Write-only register
636 return 0;
637 case REG_DISPCNT:
638 case REG_DISPSTAT:
639 case REG_VCOUNT:
640 case REG_BG0CNT:
641 case REG_BG1CNT:
642 case REG_BG2CNT:
643 case REG_BG3CNT:
644 case REG_WININ:
645 case REG_WINOUT:
646 case REG_BLDCNT:
647 case REG_BLDALPHA:
648 case REG_SOUND1CNT_LO:
649 case REG_SOUND1CNT_HI:
650 case REG_SOUND1CNT_X:
651 case REG_SOUND2CNT_LO:
652 case REG_SOUND2CNT_HI:
653 case REG_SOUND3CNT_LO:
654 case REG_SOUND3CNT_HI:
655 case REG_SOUND3CNT_X:
656 case REG_SOUND4CNT_LO:
657 case REG_SOUND4CNT_HI:
658 case REG_SOUNDCNT_LO:
659 case REG_SOUNDCNT_HI:
660 case REG_DMA0CNT_HI:
661 case REG_DMA1CNT_HI:
662 case REG_DMA2CNT_HI:
663 case REG_DMA3CNT_HI:
664 case REG_SIOMULTI0:
665 case REG_SIOMULTI1:
666 case REG_SIOMULTI2:
667 case REG_SIOMULTI3:
668 case REG_SIOMLT_SEND:
669 case REG_IE:
670 case REG_IF:
671 case REG_WAITCNT:
672 case REG_IME:
673 // Handled transparently by registers
674 break;
675 case REG_MAX:
676 // Some bad interrupt libraries will read from this
677 break;
678 default:
679 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
680 if (address >= REG_MAX) {
681 GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address);
682 return 0; // TODO: Reuse LOAD_BAD
683 }
684 break;
685 }
686 return gba->memory.io[address >> 1];
687}
688
689void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
690 int i;
691 for (i = 0; i < REG_MAX; i += 2) {
692 if (_isSpecialRegister[i >> 1]) {
693 state->io[i >> 1] = gba->memory.io[i >> 1];
694 } else if (_isValidRegister[i >> 1]) {
695 state->io[i >> 1] = GBAIORead(gba, i);
696 }
697 }
698
699 for (i = 0; i < 4; ++i) {
700 state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
701 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
702 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
703 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
704 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
705 }
706
707 memcpy(state->timers, gba->timers, sizeof(state->timers));
708 GBAHardwareSerialize(&gba->memory.hw, state);
709}
710
711void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
712 int i;
713 for (i = 0; i < REG_MAX; i += 2) {
714 if (_isSpecialRegister[i >> 1]) {
715 gba->memory.io[i >> 1] = state->io[i >> 1];
716 } else if (_isValidRegister[i >> 1]) {
717 GBAIOWrite(gba, i, state->io[i >> 1]);
718 }
719 }
720
721 gba->timersEnabled = 0;
722 memcpy(gba->timers, state->timers, sizeof(gba->timers));
723 for (i = 0; i < 4; ++i) {
724 gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
725 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
726 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
727 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
728 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
729 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
730 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
731 }
732
733 if (gba->timers[i].enable) {
734 gba->timersEnabled |= 1 << i;
735 }
736 }
737 GBAMemoryUpdateDMAs(gba, 0);
738 GBAHardwareDeserialize(&gba->memory.hw, state);
739}