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}
290
291void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
292 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
293 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
294 } else {
295 switch (address) {
296 // Video
297 case REG_DISPSTAT:
298 value &= 0xFFF8;
299 GBAVideoWriteDISPSTAT(&gba->video, value);
300 return;
301
302 // Audio
303 case REG_SOUND1CNT_LO:
304 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
305 value &= 0x00FF;
306 break;
307 case REG_SOUND1CNT_HI:
308 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
309 break;
310 case REG_SOUND1CNT_X:
311 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
312 value &= 0x47FF;
313 break;
314 case REG_SOUND2CNT_LO:
315 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
316 break;
317 case REG_SOUND2CNT_HI:
318 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
319 value &= 0x47FF;
320 break;
321 case REG_SOUND3CNT_LO:
322 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
323 value &= 0x00E0;
324 break;
325 case REG_SOUND3CNT_HI:
326 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
327 value &= 0xE000;
328 break;
329 case REG_SOUND3CNT_X:
330 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
331 // TODO: The low bits need to not be readable, but still 8-bit writable
332 value &= 0x43FF;
333 break;
334 case REG_SOUND4CNT_LO:
335 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
336 value &= 0xFF00;
337 break;
338 case REG_SOUND4CNT_HI:
339 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
340 value &= 0x40FF;
341 break;
342 case REG_SOUNDCNT_LO:
343 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
344 break;
345 case REG_SOUNDCNT_HI:
346 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
347 break;
348 case REG_SOUNDCNT_X:
349 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
350 break;
351 case REG_SOUNDBIAS:
352 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
353 break;
354
355 case REG_WAVE_RAM0_LO:
356 case REG_WAVE_RAM1_LO:
357 case REG_WAVE_RAM2_LO:
358 case REG_WAVE_RAM3_LO:
359 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
360 break;
361
362 case REG_WAVE_RAM0_HI:
363 case REG_WAVE_RAM1_HI:
364 case REG_WAVE_RAM2_HI:
365 case REG_WAVE_RAM3_HI:
366 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
367 break;
368
369 case REG_FIFO_A_LO:
370 case REG_FIFO_B_LO:
371 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
372 break;
373
374 case REG_FIFO_A_HI:
375 case REG_FIFO_B_HI:
376 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
377 break;
378
379 // DMA
380 case REG_DMA0SAD_LO:
381 case REG_DMA0DAD_LO:
382 case REG_DMA1SAD_LO:
383 case REG_DMA1DAD_LO:
384 case REG_DMA2SAD_LO:
385 case REG_DMA2DAD_LO:
386 case REG_DMA3SAD_LO:
387 case REG_DMA3DAD_LO:
388 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
389 break;
390
391 case REG_DMA0SAD_HI:
392 case REG_DMA0DAD_HI:
393 case REG_DMA1SAD_HI:
394 case REG_DMA1DAD_HI:
395 case REG_DMA2SAD_HI:
396 case REG_DMA2DAD_HI:
397 case REG_DMA3SAD_HI:
398 case REG_DMA3DAD_HI:
399 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
400 break;
401
402 case REG_DMA0CNT_LO:
403 GBAMemoryWriteDMACNT_LO(gba, 0, value);
404 break;
405 case REG_DMA0CNT_HI:
406 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
407 break;
408 case REG_DMA1CNT_LO:
409 GBAMemoryWriteDMACNT_LO(gba, 1, value);
410 break;
411 case REG_DMA1CNT_HI:
412 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
413 break;
414 case REG_DMA2CNT_LO:
415 GBAMemoryWriteDMACNT_LO(gba, 2, value);
416 break;
417 case REG_DMA2CNT_HI:
418 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
419 break;
420 case REG_DMA3CNT_LO:
421 GBAMemoryWriteDMACNT_LO(gba, 3, value);
422 break;
423 case REG_DMA3CNT_HI:
424 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
425 break;
426
427 // Timers
428 case REG_TM0CNT_LO:
429 GBATimerWriteTMCNT_LO(gba, 0, value);
430 return;
431 case REG_TM1CNT_LO:
432 GBATimerWriteTMCNT_LO(gba, 1, value);
433 return;
434 case REG_TM2CNT_LO:
435 GBATimerWriteTMCNT_LO(gba, 2, value);
436 return;
437 case REG_TM3CNT_LO:
438 GBATimerWriteTMCNT_LO(gba, 3, value);
439 return;
440
441 case REG_TM0CNT_HI:
442 value &= 0x00C7;
443 GBATimerWriteTMCNT_HI(gba, 0, value);
444 break;
445 case REG_TM1CNT_HI:
446 value &= 0x00C7;
447 GBATimerWriteTMCNT_HI(gba, 1, value);
448 break;
449 case REG_TM2CNT_HI:
450 value &= 0x00C7;
451 GBATimerWriteTMCNT_HI(gba, 2, value);
452 break;
453 case REG_TM3CNT_HI:
454 value &= 0x00C7;
455 GBATimerWriteTMCNT_HI(gba, 3, value);
456 break;
457
458 // SIO
459 case REG_SIOCNT:
460 GBASIOWriteSIOCNT(&gba->sio, value);
461 break;
462 case REG_RCNT:
463 value &= 0xC1FF;
464 GBASIOWriteRCNT(&gba->sio, value);
465 break;
466 case REG_SIOMLT_SEND:
467 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
468 break;
469
470 // Interrupts and misc
471 case REG_WAITCNT:
472 GBAAdjustWaitstates(gba, value);
473 break;
474 case REG_IE:
475 GBAWriteIE(gba, value);
476 break;
477 case REG_IF:
478 value = gba->memory.io[REG_IF >> 1] & ~value;
479 break;
480 case REG_IME:
481 GBAWriteIME(gba, value);
482 break;
483 case REG_MAX:
484 // Some bad interrupt libraries will write to this
485 break;
486 default:
487 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
488 break;
489 }
490 }
491 gba->memory.io[address >> 1] = value;
492}
493
494void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
495 if (address == REG_HALTCNT) {
496 value &= 0x80;
497 if (!value) {
498 GBAHalt(gba);
499 } else {
500 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
501 }
502 return;
503 }
504 uint16_t value16 = value << (8 * (address & 1));
505 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
506 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
507}
508
509void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
510 switch (address) {
511 case REG_WAVE_RAM0_LO:
512 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
513 break;
514 case REG_WAVE_RAM1_LO:
515 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
516 break;
517 case REG_WAVE_RAM2_LO:
518 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
519 break;
520 case REG_WAVE_RAM3_LO:
521 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
522 break;
523 case REG_FIFO_A_LO:
524 case REG_FIFO_B_LO:
525 GBAAudioWriteFIFO(&gba->audio, address, value);
526 break;
527 case REG_DMA0SAD_LO:
528 GBAMemoryWriteDMASAD(gba, 0, value);
529 break;
530 case REG_DMA0DAD_LO:
531 GBAMemoryWriteDMADAD(gba, 0, value);
532 break;
533 case REG_DMA1SAD_LO:
534 GBAMemoryWriteDMASAD(gba, 1, value);
535 break;
536 case REG_DMA1DAD_LO:
537 GBAMemoryWriteDMADAD(gba, 1, value);
538 break;
539 case REG_DMA2SAD_LO:
540 GBAMemoryWriteDMASAD(gba, 2, value);
541 break;
542 case REG_DMA2DAD_LO:
543 GBAMemoryWriteDMADAD(gba, 2, value);
544 break;
545 case REG_DMA3SAD_LO:
546 GBAMemoryWriteDMASAD(gba, 3, value);
547 break;
548 case REG_DMA3DAD_LO:
549 GBAMemoryWriteDMADAD(gba, 3, value);
550 break;
551 default:
552 GBAIOWrite(gba, address, value & 0xFFFF);
553 GBAIOWrite(gba, address | 2, value >> 16);
554 return;
555 }
556 gba->memory.io[address >> 1] = value;
557 gba->memory.io[(address >> 1) + 1] = value >> 16;
558}
559
560uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
561 gba->haltPending = false; // IO reads need to invalidate detected idle loops
562 switch (address) {
563 case REG_TM0CNT_LO:
564 GBATimerUpdateRegister(gba, 0);
565 break;
566 case REG_TM1CNT_LO:
567 GBATimerUpdateRegister(gba, 1);
568 break;
569 case REG_TM2CNT_LO:
570 GBATimerUpdateRegister(gba, 2);
571 break;
572 case REG_TM3CNT_LO:
573 GBATimerUpdateRegister(gba, 3);
574 break;
575
576 case REG_KEYINPUT:
577 if (gba->rr && gba->rr->isPlaying(gba->rr)) {
578 return 0x3FF ^ gba->rr->queryInput(gba->rr);
579 } else if (gba->keySource) {
580 uint16_t input = *gba->keySource;
581 if (gba->rr && gba->rr->isRecording(gba->rr)) {
582 gba->rr->logInput(gba->rr, input);
583 }
584 return 0x3FF ^ input;
585 }
586 break;
587
588 case REG_SIOCNT:
589 return gba->sio.siocnt;
590 case REG_RCNT:
591 return gba->sio.rcnt;
592
593 case REG_DMA0CNT_LO:
594 case REG_DMA1CNT_LO:
595 case REG_DMA2CNT_LO:
596 case REG_DMA3CNT_LO:
597 // Write-only register
598 return 0;
599 case REG_DISPCNT:
600 case REG_DISPSTAT:
601 case REG_VCOUNT:
602 case REG_BG0CNT:
603 case REG_BG1CNT:
604 case REG_BG2CNT:
605 case REG_BG3CNT:
606 case REG_WININ:
607 case REG_WINOUT:
608 case REG_BLDCNT:
609 case REG_BLDALPHA:
610 case REG_SOUND1CNT_LO:
611 case REG_SOUND1CNT_HI:
612 case REG_SOUND1CNT_X:
613 case REG_SOUND2CNT_LO:
614 case REG_SOUND2CNT_HI:
615 case REG_SOUND3CNT_LO:
616 case REG_SOUND3CNT_HI:
617 case REG_SOUND3CNT_X:
618 case REG_SOUND4CNT_LO:
619 case REG_SOUND4CNT_HI:
620 case REG_SOUNDCNT_LO:
621 case REG_SOUNDCNT_HI:
622 case REG_DMA0CNT_HI:
623 case REG_DMA1CNT_HI:
624 case REG_DMA2CNT_HI:
625 case REG_DMA3CNT_HI:
626 case REG_SIOMULTI0:
627 case REG_SIOMULTI1:
628 case REG_SIOMULTI2:
629 case REG_SIOMULTI3:
630 case REG_SIOMLT_SEND:
631 case REG_IE:
632 case REG_IF:
633 case REG_WAITCNT:
634 case REG_IME:
635 // Handled transparently by registers
636 break;
637 case REG_MAX:
638 // Some bad interrupt libraries will read from this
639 break;
640 default:
641 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
642 break;
643 }
644 return gba->memory.io[address >> 1];
645}
646
647void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
648 int i;
649 for (i = 0; i < REG_MAX; i += 2) {
650 if (_isSpecialRegister[i >> 1]) {
651 state->io[i >> 1] = gba->memory.io[i >> 1];
652 } else if (_isValidRegister[i >> 1]) {
653 state->io[i >> 1] = GBAIORead(gba, i);
654 }
655 }
656
657 for (i = 0; i < 4; ++i) {
658 state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
659 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
660 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
661 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
662 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
663 }
664
665 memcpy(state->timers, gba->timers, sizeof(state->timers));
666 GBAHardwareSerialize(&gba->memory.hw, state);
667}
668
669void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
670 int i;
671 for (i = 0; i < REG_MAX; i += 2) {
672 if (_isSpecialRegister[i >> 1]) {
673 gba->memory.io[i >> 1] = state->io[i >> 1];
674 } else if (_isValidRegister[i >> 1]) {
675 GBAIOWrite(gba, i, state->io[i >> 1]);
676 }
677 }
678
679 gba->timersEnabled = 0;
680 memcpy(gba->timers, state->timers, sizeof(gba->timers));
681 for (i = 0; i < 4; ++i) {
682 gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
683 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
684 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
685 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
686 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
687 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
688 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
689 }
690
691 if (gba->timers[i].enable) {
692 gba->timersEnabled |= 1 << i;
693 }
694 }
695 GBAHardwareDeserialize(&gba->memory.hw, state);
696}