src/gba/gba-io.c (view raw)
1/* Copyright (c) 2013-2014 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 "gba-io.h"
7
8#include "gba-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 0,
145
146 0, 0, 0, 0, 0, 0, 0, 0,
147
148 // SIO
149 "SIOMULTI0",
150 "SIOMULTI1",
151 "SIOMULTI2",
152 "SIOMULTI3",
153 "SIOCNT",
154 "SIOMLT_SEND",
155 0,
156 0,
157 "KEYINPUT",
158 "KEYCNT",
159 "RCNT",
160 0,
161 0,
162 0,
163 0,
164 0,
165 "JOYCNT",
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 0,
173 "JOY_RECV_LO",
174 "JOY_RECV_HI",
175 "JOY_TRANS_LO",
176 "JOY_RECV_HI",
177 "JOYSTAT",
178 0,
179 0,
180 0,
181
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 0, 0, 0, 0, 0, 0, 0, 0,
192
193 // Interrupts, etc
194 "IE",
195 "IF",
196 "WAITCNT",
197 0,
198 "IME"
199};
200
201static const int _isValidRegister[REG_MAX >> 1] = {
202 // Video
203 1, 0, 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, 1,
207 1, 1, 1, 1, 1, 1, 1, 0,
208 1, 1, 1, 0, 0, 0, 0, 0,
209 // Audio
210 1, 1, 1, 0, 1, 0, 1, 0,
211 1, 1, 1, 0, 1, 0, 1, 0,
212 1, 1, 1, 0, 1, 0, 0, 0,
213 1, 1, 1, 1, 1, 1, 1, 1,
214 1, 1, 1, 1, 1, 0, 0, 0,
215 // DMA
216 1, 1, 1, 1, 1, 1, 1, 1,
217 1, 1, 1, 1, 1, 1, 1, 1,
218 1, 1, 1, 1, 1, 1, 1, 1,
219 0, 0, 0, 0, 0, 0, 0, 0,
220 0, 0, 0, 0, 0, 0, 0, 0,
221 // Timers
222 1, 1, 1, 1, 1, 1, 1, 1,
223 0, 0, 0, 0, 0, 0, 0, 0,
224 // SIO
225 1, 1, 1, 1, 1, 0, 0, 0,
226 1, 1, 1, 0, 0, 0, 0, 0,
227 1, 0, 0, 0, 0, 0, 0, 0,
228 1, 0, 1, 0, 1, 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 0, 0, 0, 0, 0, 0, 0, 0,
239 // Interrupts
240 1, 1, 1, 0, 1
241};
242
243static const int _isSpecialRegister[REG_MAX >> 1] = {
244 // Video
245 0, 0, 0, 1, 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 0, 0, 0, 0, 0, 0, 0, 0,
251 // Audio
252 0, 0, 0, 0, 0, 0, 0, 0,
253 0, 0, 0, 0, 0, 0, 0, 0,
254 0, 0, 0, 0, 0, 0, 0, 0,
255 1, 1, 1, 1, 1, 1, 1, 1,
256 1, 1, 1, 1, 0, 0, 0, 0,
257 // DMA
258 0, 0, 0, 0, 0, 1, 0, 0,
259 0, 0, 0, 1, 0, 0, 0, 0,
260 0, 1, 0, 0, 0, 0, 0, 1,
261 0, 0, 0, 0, 0, 0, 0, 0,
262 0, 0, 0, 0, 0, 0, 0, 0,
263 // Timers
264 1, 1, 1, 1, 1, 1, 1, 1,
265 0, 0, 0, 0, 0, 0, 0, 0,
266 // SIO
267 1, 1, 1, 1, 1, 0, 0, 0,
268 1, 1, 1, 0, 0, 0, 0, 0,
269 1, 0, 0, 0, 0, 0, 0, 0,
270 1, 0, 1, 0, 1, 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 0, 0, 0, 0, 0, 0, 0, 0,
281 // Interrupts
282 1, 1, 1, 0, 1
283};
284
285void GBAIOInit(struct GBA* gba) {
286 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
287 gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
288 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
289 gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
290}
291
292void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
293 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
294 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
295 } else {
296 switch (address) {
297 // Video
298 case REG_DISPSTAT:
299 value &= 0xFFF8;
300 GBAVideoWriteDISPSTAT(&gba->video, value);
301 break;
302
303 // Audio
304 case REG_SOUND1CNT_LO:
305 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
306 value &= 0x00FF;
307 break;
308 case REG_SOUND1CNT_HI:
309 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
310 break;
311 case REG_SOUND1CNT_X:
312 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
313 value &= 0x47FF;
314 break;
315 case REG_SOUND2CNT_LO:
316 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
317 break;
318 case REG_SOUND2CNT_HI:
319 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
320 value &= 0x47FF;
321 break;
322 case REG_SOUND3CNT_LO:
323 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
324 value &= 0x00E0;
325 break;
326 case REG_SOUND3CNT_HI:
327 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
328 value &= 0xE000;
329 break;
330 case REG_SOUND3CNT_X:
331 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
332 // TODO: The low bits need to not be readable, but still 8-bit writable
333 value &= 0x43FF;
334 break;
335 case REG_SOUND4CNT_LO:
336 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
337 value &= 0xFF00;
338 break;
339 case REG_SOUND4CNT_HI:
340 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
341 value &= 0x40FF;
342 break;
343 case REG_SOUNDCNT_LO:
344 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
345 break;
346 case REG_SOUNDCNT_HI:
347 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
348 break;
349 case REG_SOUNDCNT_X:
350 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
351 break;
352 case REG_SOUNDBIAS:
353 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
354 break;
355
356 case REG_WAVE_RAM0_LO:
357 case REG_WAVE_RAM1_LO:
358 case REG_WAVE_RAM2_LO:
359 case REG_WAVE_RAM3_LO:
360 case REG_FIFO_A_LO:
361 case REG_FIFO_B_LO:
362 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
363 break;
364
365 case REG_WAVE_RAM0_HI:
366 case REG_WAVE_RAM1_HI:
367 case REG_WAVE_RAM2_HI:
368 case REG_WAVE_RAM3_HI:
369 case REG_FIFO_A_HI:
370 case REG_FIFO_B_HI:
371 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
372 break;
373
374 // DMA
375 case REG_DMA0SAD_LO:
376 case REG_DMA0DAD_LO:
377 case REG_DMA1SAD_LO:
378 case REG_DMA1DAD_LO:
379 case REG_DMA2SAD_LO:
380 case REG_DMA2DAD_LO:
381 case REG_DMA3SAD_LO:
382 case REG_DMA3DAD_LO:
383 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
384 break;
385
386 case REG_DMA0SAD_HI:
387 case REG_DMA0DAD_HI:
388 case REG_DMA1SAD_HI:
389 case REG_DMA1DAD_HI:
390 case REG_DMA2SAD_HI:
391 case REG_DMA2DAD_HI:
392 case REG_DMA3SAD_HI:
393 case REG_DMA3DAD_HI:
394 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
395 break;
396
397 case REG_DMA0CNT_LO:
398 GBAMemoryWriteDMACNT_LO(gba, 0, value);
399 break;
400 case REG_DMA0CNT_HI:
401 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
402 break;
403 case REG_DMA1CNT_LO:
404 GBAMemoryWriteDMACNT_LO(gba, 1, value);
405 break;
406 case REG_DMA1CNT_HI:
407 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
408 break;
409 case REG_DMA2CNT_LO:
410 GBAMemoryWriteDMACNT_LO(gba, 2, value);
411 break;
412 case REG_DMA2CNT_HI:
413 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
414 break;
415 case REG_DMA3CNT_LO:
416 GBAMemoryWriteDMACNT_LO(gba, 3, value);
417 break;
418 case REG_DMA3CNT_HI:
419 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
420 break;
421
422 // Timers
423 case REG_TM0CNT_LO:
424 GBATimerWriteTMCNT_LO(gba, 0, value);
425 return;
426 case REG_TM1CNT_LO:
427 GBATimerWriteTMCNT_LO(gba, 1, value);
428 return;
429 case REG_TM2CNT_LO:
430 GBATimerWriteTMCNT_LO(gba, 2, value);
431 return;
432 case REG_TM3CNT_LO:
433 GBATimerWriteTMCNT_LO(gba, 3, value);
434 return;
435
436 case REG_TM0CNT_HI:
437 value &= 0x00C7;
438 GBATimerWriteTMCNT_HI(gba, 0, value);
439 break;
440 case REG_TM1CNT_HI:
441 value &= 0x00C7;
442 GBATimerWriteTMCNT_HI(gba, 1, value);
443 break;
444 case REG_TM2CNT_HI:
445 value &= 0x00C7;
446 GBATimerWriteTMCNT_HI(gba, 2, value);
447 break;
448 case REG_TM3CNT_HI:
449 value &= 0x00C7;
450 GBATimerWriteTMCNT_HI(gba, 3, value);
451 break;
452
453 // SIO
454 case REG_SIOCNT:
455 GBASIOWriteSIOCNT(&gba->sio, value);
456 break;
457 case REG_RCNT:
458 value &= 0xC1FF;
459 GBASIOWriteRCNT(&gba->sio, value);
460 break;
461 case REG_SIOMLT_SEND:
462 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
463 break;
464
465 // Interrupts and misc
466 case REG_WAITCNT:
467 GBAAdjustWaitstates(gba, value);
468 break;
469 case REG_IE:
470 GBAWriteIE(gba, value);
471 break;
472 case REG_IF:
473 value = gba->memory.io[REG_IF >> 1] & ~value;
474 break;
475 case REG_IME:
476 GBAWriteIME(gba, value);
477 break;
478 case REG_MAX:
479 // Some bad interrupt libraries will write to this
480 break;
481 default:
482 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
483 break;
484 }
485 }
486 gba->memory.io[address >> 1] = value;
487}
488
489void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
490 if (address == REG_HALTCNT) {
491 value &= 0x80;
492 if (!value) {
493 GBAHalt(gba);
494 } else {
495 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
496 }
497 return;
498 }
499 uint16_t value16 = value << (8 * (address & 1));
500 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
501 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
502}
503
504void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
505 switch (address) {
506 case REG_WAVE_RAM0_LO:
507 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
508 break;
509 case REG_WAVE_RAM1_LO:
510 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
511 break;
512 case REG_WAVE_RAM2_LO:
513 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
514 break;
515 case REG_WAVE_RAM3_LO:
516 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
517 break;
518 case REG_FIFO_A_LO:
519 case REG_FIFO_B_LO:
520 GBAAudioWriteFIFO(&gba->audio, address, value);
521 break;
522 case REG_DMA0SAD_LO:
523 GBAMemoryWriteDMASAD(gba, 0, value);
524 break;
525 case REG_DMA0DAD_LO:
526 GBAMemoryWriteDMADAD(gba, 0, value);
527 break;
528 case REG_DMA1SAD_LO:
529 GBAMemoryWriteDMASAD(gba, 1, value);
530 break;
531 case REG_DMA1DAD_LO:
532 GBAMemoryWriteDMADAD(gba, 1, value);
533 break;
534 case REG_DMA2SAD_LO:
535 GBAMemoryWriteDMASAD(gba, 2, value);
536 break;
537 case REG_DMA2DAD_LO:
538 GBAMemoryWriteDMADAD(gba, 2, value);
539 break;
540 case REG_DMA3SAD_LO:
541 GBAMemoryWriteDMASAD(gba, 3, value);
542 break;
543 case REG_DMA3DAD_LO:
544 GBAMemoryWriteDMADAD(gba, 3, value);
545 break;
546 default:
547 GBAIOWrite(gba, address, value & 0xFFFF);
548 GBAIOWrite(gba, address | 2, value >> 16);
549 return;
550 }
551 gba->memory.io[address >> 1] = value;
552 gba->memory.io[(address >> 1) + 1] = value >> 16;
553}
554
555uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
556 switch (address) {
557 case REG_TM0CNT_LO:
558 GBATimerUpdateRegister(gba, 0);
559 break;
560 case REG_TM1CNT_LO:
561 GBATimerUpdateRegister(gba, 1);
562 break;
563 case REG_TM2CNT_LO:
564 GBATimerUpdateRegister(gba, 2);
565 break;
566 case REG_TM3CNT_LO:
567 GBATimerUpdateRegister(gba, 3);
568 break;
569
570 case REG_KEYINPUT:
571 if (GBARRIsPlaying(gba->rr)) {
572 return 0x3FF ^ GBARRQueryInput(gba->rr);
573 } else if (gba->keySource) {
574 uint16_t input = *gba->keySource;
575 if (GBARRIsRecording(gba->rr)) {
576 GBARRLogInput(gba->rr, input);
577 }
578 return 0x3FF ^ input;
579 }
580 break;
581
582 case REG_SIOCNT:
583 return gba->sio.siocnt;
584 case REG_RCNT:
585 return gba->sio.rcnt;
586
587 case REG_DMA0CNT_LO:
588 case REG_DMA1CNT_LO:
589 case REG_DMA2CNT_LO:
590 case REG_DMA3CNT_LO:
591 // Write-only register
592 return 0;
593 case REG_DISPCNT:
594 case REG_DISPSTAT:
595 case REG_VCOUNT:
596 case REG_BG0CNT:
597 case REG_BG1CNT:
598 case REG_BG2CNT:
599 case REG_BG3CNT:
600 case REG_WININ:
601 case REG_WINOUT:
602 case REG_BLDCNT:
603 case REG_BLDALPHA:
604 case REG_SOUND1CNT_LO:
605 case REG_SOUND1CNT_HI:
606 case REG_SOUND1CNT_X:
607 case REG_SOUND2CNT_LO:
608 case REG_SOUND2CNT_HI:
609 case REG_SOUND3CNT_LO:
610 case REG_SOUND3CNT_HI:
611 case REG_SOUND3CNT_X:
612 case REG_SOUND4CNT_LO:
613 case REG_SOUND4CNT_HI:
614 case REG_SOUNDCNT_LO:
615 case REG_SOUNDCNT_HI:
616 case REG_DMA0CNT_HI:
617 case REG_DMA1CNT_HI:
618 case REG_DMA2CNT_HI:
619 case REG_DMA3CNT_HI:
620 case REG_SIOMULTI0:
621 case REG_SIOMULTI1:
622 case REG_SIOMULTI2:
623 case REG_SIOMULTI3:
624 case REG_SIOMLT_SEND:
625 case REG_IE:
626 case REG_IF:
627 case REG_WAITCNT:
628 case REG_IME:
629 // Handled transparently by registers
630 break;
631 case REG_MAX:
632 // Some bad interrupt libraries will read from this
633 break;
634 default:
635 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
636 break;
637 }
638 return gba->memory.io[address >> 1];
639}
640
641void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
642 int i;
643 for (i = 0; i < REG_MAX; i += 2) {
644 if (_isSpecialRegister[i >> 1]) {
645 state->io[i >> 1] = gba->memory.io[i >> 1];
646 } else if (_isValidRegister[i >> 1]) {
647 state->io[i >> 1] = GBAIORead(gba, i);
648 }
649 }
650
651 for (i = 0; i < 4; ++i) {
652 state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
653 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
654 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
655 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
656 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
657 }
658
659 memcpy(state->timers, gba->timers, sizeof(state->timers));
660 GBAGPIOSerialize(&gba->memory.gpio, state);
661}
662
663void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
664 int i;
665 for (i = 0; i < REG_MAX; i += 2) {
666 if (_isSpecialRegister[i >> 1]) {
667 gba->memory.io[i >> 1] = state->io[i >> 1];
668 } else if (_isValidRegister[i >> 1]) {
669 GBAIOWrite(gba, i, state->io[i >> 1]);
670 }
671 }
672
673 gba->timersEnabled = 0;
674 memcpy(gba->timers, state->timers, sizeof(gba->timers));
675 for (i = 0; i < 4; ++i) {
676 gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
677 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
678 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
679 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
680 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
681 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
682 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
683 }
684
685 if (gba->timers[i].enable) {
686 gba->timersEnabled |= 1 << i;
687 }
688 }
689 GBAGPIODeserialize(&gba->memory.gpio, state);
690}