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