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/supervisor/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 &= 0x43FF;
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 // TODO: Confirm this behavior on real hardware
374 case REG_FIFO_A_LO:
375 case REG_FIFO_B_LO:
376 if (gba->performingDMA) {
377 GBAAudioWriteFIFO16(&gba->audio, address, value);
378 } else {
379 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
380 }
381 break;
382
383 case REG_FIFO_A_HI:
384 case REG_FIFO_B_HI:
385 if (gba->performingDMA) {
386 GBAAudioWriteFIFO16(&gba->audio, address, value);
387 } else {
388 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
389 }
390 break;
391
392 // DMA
393 case REG_DMA0SAD_LO:
394 case REG_DMA0DAD_LO:
395 case REG_DMA1SAD_LO:
396 case REG_DMA1DAD_LO:
397 case REG_DMA2SAD_LO:
398 case REG_DMA2DAD_LO:
399 case REG_DMA3SAD_LO:
400 case REG_DMA3DAD_LO:
401 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
402 break;
403
404 case REG_DMA0SAD_HI:
405 case REG_DMA0DAD_HI:
406 case REG_DMA1SAD_HI:
407 case REG_DMA1DAD_HI:
408 case REG_DMA2SAD_HI:
409 case REG_DMA2DAD_HI:
410 case REG_DMA3SAD_HI:
411 case REG_DMA3DAD_HI:
412 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
413 break;
414
415 case REG_DMA0CNT_LO:
416 GBAMemoryWriteDMACNT_LO(gba, 0, value);
417 break;
418 case REG_DMA0CNT_HI:
419 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
420 break;
421 case REG_DMA1CNT_LO:
422 GBAMemoryWriteDMACNT_LO(gba, 1, value);
423 break;
424 case REG_DMA1CNT_HI:
425 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
426 break;
427 case REG_DMA2CNT_LO:
428 GBAMemoryWriteDMACNT_LO(gba, 2, value);
429 break;
430 case REG_DMA2CNT_HI:
431 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
432 break;
433 case REG_DMA3CNT_LO:
434 GBAMemoryWriteDMACNT_LO(gba, 3, value);
435 break;
436 case REG_DMA3CNT_HI:
437 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
438 break;
439
440 // Timers
441 case REG_TM0CNT_LO:
442 GBATimerWriteTMCNT_LO(gba, 0, value);
443 return;
444 case REG_TM1CNT_LO:
445 GBATimerWriteTMCNT_LO(gba, 1, value);
446 return;
447 case REG_TM2CNT_LO:
448 GBATimerWriteTMCNT_LO(gba, 2, value);
449 return;
450 case REG_TM3CNT_LO:
451 GBATimerWriteTMCNT_LO(gba, 3, value);
452 return;
453
454 case REG_TM0CNT_HI:
455 value &= 0x00C7;
456 GBATimerWriteTMCNT_HI(gba, 0, value);
457 break;
458 case REG_TM1CNT_HI:
459 value &= 0x00C7;
460 GBATimerWriteTMCNT_HI(gba, 1, value);
461 break;
462 case REG_TM2CNT_HI:
463 value &= 0x00C7;
464 GBATimerWriteTMCNT_HI(gba, 2, value);
465 break;
466 case REG_TM3CNT_HI:
467 value &= 0x00C7;
468 GBATimerWriteTMCNT_HI(gba, 3, value);
469 break;
470
471 // SIO
472 case REG_SIOCNT:
473 GBASIOWriteSIOCNT(&gba->sio, value);
474 break;
475 case REG_RCNT:
476 value &= 0xC1FF;
477 GBASIOWriteRCNT(&gba->sio, value);
478 break;
479 case REG_SIOMLT_SEND:
480 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
481 break;
482
483 // Interrupts and misc
484 case REG_WAITCNT:
485 GBAAdjustWaitstates(gba, value);
486 break;
487 case REG_IE:
488 GBAWriteIE(gba, value);
489 break;
490 case REG_IF:
491 value = gba->memory.io[REG_IF >> 1] & ~value;
492 break;
493 case REG_IME:
494 GBAWriteIME(gba, value);
495 break;
496 case REG_MAX:
497 // Some bad interrupt libraries will write to this
498 break;
499 default:
500 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
501 break;
502 }
503 }
504 gba->memory.io[address >> 1] = value;
505}
506
507void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
508 if (address == REG_HALTCNT) {
509 value &= 0x80;
510 if (!value) {
511 GBAHalt(gba);
512 } else {
513 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
514 }
515 return;
516 }
517 uint16_t value16 = value << (8 * (address & 1));
518 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
519 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
520}
521
522void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
523 switch (address) {
524 case REG_WAVE_RAM0_LO:
525 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
526 break;
527 case REG_WAVE_RAM1_LO:
528 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
529 break;
530 case REG_WAVE_RAM2_LO:
531 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
532 break;
533 case REG_WAVE_RAM3_LO:
534 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
535 break;
536 case REG_FIFO_A_LO:
537 case REG_FIFO_B_LO:
538 GBAAudioWriteFIFO(&gba->audio, address, value);
539 break;
540 case REG_DMA0SAD_LO:
541 GBAMemoryWriteDMASAD(gba, 0, value);
542 break;
543 case REG_DMA0DAD_LO:
544 GBAMemoryWriteDMADAD(gba, 0, value);
545 break;
546 case REG_DMA1SAD_LO:
547 GBAMemoryWriteDMASAD(gba, 1, value);
548 break;
549 case REG_DMA1DAD_LO:
550 GBAMemoryWriteDMADAD(gba, 1, value);
551 break;
552 case REG_DMA2SAD_LO:
553 GBAMemoryWriteDMASAD(gba, 2, value);
554 break;
555 case REG_DMA2DAD_LO:
556 GBAMemoryWriteDMADAD(gba, 2, value);
557 break;
558 case REG_DMA3SAD_LO:
559 GBAMemoryWriteDMASAD(gba, 3, value);
560 break;
561 case REG_DMA3DAD_LO:
562 GBAMemoryWriteDMADAD(gba, 3, value);
563 break;
564 default:
565 GBAIOWrite(gba, address, value & 0xFFFF);
566 GBAIOWrite(gba, address | 2, value >> 16);
567 return;
568 }
569 gba->memory.io[address >> 1] = value;
570 gba->memory.io[(address >> 1) + 1] = value >> 16;
571}
572
573uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
574 gba->lastJump = -1; // IO reads need to invalidate detected idle loops
575 switch (address) {
576 case REG_TM0CNT_LO:
577 GBATimerUpdateRegister(gba, 0);
578 break;
579 case REG_TM1CNT_LO:
580 GBATimerUpdateRegister(gba, 1);
581 break;
582 case REG_TM2CNT_LO:
583 GBATimerUpdateRegister(gba, 2);
584 break;
585 case REG_TM3CNT_LO:
586 GBATimerUpdateRegister(gba, 3);
587 break;
588
589 case REG_KEYINPUT:
590 if (gba->rr && gba->rr->isPlaying(gba->rr)) {
591 return 0x3FF ^ gba->rr->queryInput(gba->rr);
592 } else if (gba->keySource) {
593 uint16_t input = *gba->keySource;
594 if (gba->rr && gba->rr->isRecording(gba->rr)) {
595 gba->rr->logInput(gba->rr, input);
596 }
597 return 0x3FF ^ input;
598 }
599 break;
600
601 case REG_SIOCNT:
602 return gba->sio.siocnt;
603 case REG_RCNT:
604 return gba->sio.rcnt;
605
606 case REG_DMA0CNT_LO:
607 case REG_DMA1CNT_LO:
608 case REG_DMA2CNT_LO:
609 case REG_DMA3CNT_LO:
610 // Write-only register
611 return 0;
612 case REG_DISPCNT:
613 case REG_DISPSTAT:
614 case REG_VCOUNT:
615 case REG_BG0CNT:
616 case REG_BG1CNT:
617 case REG_BG2CNT:
618 case REG_BG3CNT:
619 case REG_WININ:
620 case REG_WINOUT:
621 case REG_BLDCNT:
622 case REG_BLDALPHA:
623 case REG_SOUND1CNT_LO:
624 case REG_SOUND1CNT_HI:
625 case REG_SOUND1CNT_X:
626 case REG_SOUND2CNT_LO:
627 case REG_SOUND2CNT_HI:
628 case REG_SOUND3CNT_LO:
629 case REG_SOUND3CNT_HI:
630 case REG_SOUND3CNT_X:
631 case REG_SOUND4CNT_LO:
632 case REG_SOUND4CNT_HI:
633 case REG_SOUNDCNT_LO:
634 case REG_SOUNDCNT_HI:
635 case REG_DMA0CNT_HI:
636 case REG_DMA1CNT_HI:
637 case REG_DMA2CNT_HI:
638 case REG_DMA3CNT_HI:
639 case REG_SIOMULTI0:
640 case REG_SIOMULTI1:
641 case REG_SIOMULTI2:
642 case REG_SIOMULTI3:
643 case REG_SIOMLT_SEND:
644 case REG_IE:
645 case REG_IF:
646 case REG_WAITCNT:
647 case REG_IME:
648 // Handled transparently by registers
649 break;
650 case REG_MAX:
651 // Some bad interrupt libraries will read from this
652 break;
653 default:
654 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
655 break;
656 }
657 return gba->memory.io[address >> 1];
658}
659
660void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
661 int i;
662 for (i = 0; i < REG_MAX; i += 2) {
663 if (_isSpecialRegister[i >> 1]) {
664 state->io[i >> 1] = gba->memory.io[i >> 1];
665 } else if (_isValidRegister[i >> 1]) {
666 state->io[i >> 1] = GBAIORead(gba, i);
667 }
668 }
669
670 for (i = 0; i < 4; ++i) {
671 state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
672 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
673 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
674 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
675 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
676 }
677
678 memcpy(state->timers, gba->timers, sizeof(state->timers));
679 GBAHardwareSerialize(&gba->memory.hw, state);
680}
681
682void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
683 int i;
684 for (i = 0; i < REG_MAX; i += 2) {
685 if (_isSpecialRegister[i >> 1]) {
686 gba->memory.io[i >> 1] = state->io[i >> 1];
687 } else if (_isValidRegister[i >> 1]) {
688 GBAIOWrite(gba, i, state->io[i >> 1]);
689 }
690 }
691
692 gba->timersEnabled = 0;
693 memcpy(gba->timers, state->timers, sizeof(gba->timers));
694 for (i = 0; i < 4; ++i) {
695 gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
696 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
697 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
698 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
699 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
700 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
701 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
702 }
703
704 if (gba->timers[i].enable) {
705 gba->timersEnabled |= 1 << i;
706 }
707 }
708 GBAHardwareDeserialize(&gba->memory.hw, state);
709}