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