src/gba/gba-io.c (view raw)
1#include "gba-io.h"
2
3#include "gba-rr.h"
4#include "gba-serialize.h"
5#include "gba-sio.h"
6#include "gba-video.h"
7
8const char* GBAIORegisterNames[] = {
9 // Video
10 "DISPCNT",
11 0,
12 "DISPSTAT",
13 "VCOUNT",
14 "BG0CNT",
15 "BG1CNT",
16 "BG2CNT",
17 "BG3CNT",
18 "BG0HOFS",
19 "BG0VOFS",
20 "BG1HOFS",
21 "BG1VOFS",
22 "BG2HOFS",
23 "BG2VOFS",
24 "BG3HOFS",
25 "BG3VOFS",
26 "BG2PA",
27 "BG2PB",
28 "BG2PC",
29 "BG2PD",
30 "BG2X_LO",
31 "BG2X_HI",
32 "BG2Y_LO",
33 "BG2Y_HI",
34 "BG3PA",
35 "BG3PB",
36 "BG3PC",
37 "BG3PD",
38 "BG3X_LO",
39 "BG3X_HI",
40 "BG3Y_LO",
41 "BG3Y_HI",
42 "WIN0H",
43 "WIN1H",
44 "WIN0V",
45 "WIN1V",
46 "WININ",
47 "WINOUT",
48 "MOSAIC",
49 0,
50 "BLDCNT",
51 "BLDALPHA",
52 "BLDY",
53 0,
54 0,
55 0,
56 0,
57 0,
58
59 // Sound
60 "SOUND1CNT_LO",
61 "SOUND1CNT_HI",
62 "SOUND1CNT_X",
63 0,
64 "SOUND2CNT_LO",
65 0,
66 "SOUND2CNT_HI",
67 0,
68 "SOUND3CNT_LO",
69 "SOUND3CNT_HI",
70 "SOUND3CNT_X",
71 0,
72 "SOUND4CNT_LO",
73 0,
74 "SOUND4CNT_HI",
75 0,
76 "SOUNDCNT_LO",
77 "SOUNDCNT_HI",
78 "SOUNDCNT_X",
79 0,
80 "SOUNDBIAS",
81 0,
82 0,
83 0,
84 "WAVE_RAM0_LO"
85 "WAVE_RAM0_HI",
86 "WAVE_RAM1_LO",
87 "WAVE_RAM1_HI",
88 "WAVE_RAM2_LO",
89 "WAVE_RAM2_HI",
90 "WAVE_RAM3_LO",
91 "WAVE_RAM3_HI",
92 "FIFO_A_LO",
93 "FIFO_A_HI",
94 "FIFO_B_LO",
95 "FIFO_B_HI",
96 0,
97 0,
98 0,
99 0,
100
101 // DMA
102 "DMA0SAD_LO",
103 "DMA0SAD_HI",
104 "DMA0DAD_LO",
105 "DMA0DAD_HI",
106 "DMA0CNT_LO",
107 "DMA0CNT_HI",
108 "DMA1SAD_LO",
109 "DMA1SAD_HI",
110 "DMA1DAD_LO",
111 "DMA1DAD_HI",
112 "DMA1CNT_LO",
113 "DMA1CNT_HI",
114 "DMA2SAD_LO",
115 "DMA2SAD_HI",
116 "DMA2DAD_LO",
117 "DMA2DAD_HI",
118 "DMA2CNT_LO",
119 "DMA2CNT_HI",
120 "DMA3SAD_LO",
121 "DMA3SAD_HI",
122 "DMA3DAD_LO",
123 "DMA3DAD_HI",
124 "DMA3CNT_LO",
125 "DMA3CNT_HI",
126
127 0, 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0, 0,
129
130 // Timers
131 "TM0CNT_LO",
132 "TM0CNT_HI",
133 "TM1CNT_LO",
134 "TM1CNT_HI",
135 "TM2CNT_LO",
136 "TM2CNT_HI",
137 "TM3CNT_LO",
138 "TM3CNT_HI",
139 0,
140
141 0, 0, 0, 0, 0, 0, 0, 0,
142
143 // SIO
144 "SIOMULTI0",
145 "SIOMULTI1",
146 "SIOMULTI2",
147 "SIOMULTI3",
148 "SIOCNT",
149 "SIOMLT_SEND",
150 0,
151 0,
152 "KEYINPUT",
153 "KEYCNT",
154 "RCNT",
155 0,
156 0,
157 0,
158 0,
159 0,
160 "JOYCNT",
161 0,
162 0,
163 0,
164 0,
165 0,
166 0,
167 0,
168 "JOY_RECV_LO",
169 "JOY_RECV_HI",
170 "JOY_TRANS_LO",
171 "JOY_RECV_HI",
172 "JOYSTAT",
173 0,
174 0,
175 0,
176
177 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0, 0, 0,
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
188 // Interrupts, etc
189 "IE",
190 "IF",
191 "WAITCNT",
192 0,
193 "IME"
194};
195
196static const int _isValidRegister[REG_MAX >> 1] = {
197 // Video
198 1, 0, 1, 1, 1, 1, 1, 1,
199 1, 1, 1, 1, 1, 1, 1, 1,
200 1, 1, 1, 1, 1, 1, 1, 1,
201 1, 1, 1, 1, 1, 1, 1, 1,
202 1, 1, 1, 1, 1, 1, 1, 0,
203 1, 1, 1, 0, 0, 0, 0, 0,
204 // Audio
205 1, 1, 1, 0, 1, 0, 1, 0,
206 1, 1, 1, 0, 1, 0, 1, 0,
207 1, 1, 1, 0, 1, 0, 0, 0,
208 1, 1, 1, 1, 1, 1, 1, 1,
209 1, 1, 1, 1, 1, 0, 0, 0,
210 // DMA
211 1, 1, 1, 1, 1, 1, 1, 1,
212 1, 1, 1, 1, 1, 1, 1, 1,
213 1, 1, 1, 1, 1, 1, 1, 1,
214 0, 0, 0, 0, 0, 0, 0, 0,
215 0, 0, 0, 0, 0, 0, 0, 0,
216 // Timers
217 1, 1, 1, 1, 1, 1, 1, 1,
218 0, 0, 0, 0, 0, 0, 0, 0,
219 // SIO
220 1, 1, 1, 1, 1, 0, 0, 0,
221 1, 1, 1, 0, 0, 0, 0, 0,
222 1, 0, 0, 0, 0, 0, 0, 0,
223 1, 0, 1, 0, 1, 0, 0, 0,
224 0, 0, 0, 0, 0, 0, 0, 0,
225 0, 0, 0, 0, 0, 0, 0, 0,
226 0, 0, 0, 0, 0, 0, 0, 0,
227 0, 0, 0, 0, 0, 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 // Interrupts
235 1, 1, 1, 0, 1
236};
237
238static const int _isSpecialRegister[REG_MAX >> 1] = {
239 // Video
240 0, 0, 0, 1, 0, 0, 0, 0,
241 0, 0, 0, 0, 0, 0, 0, 0,
242 0, 0, 0, 0, 0, 0, 0, 0,
243 0, 0, 0, 0, 0, 0, 0, 0,
244 0, 0, 0, 0, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 // Audio
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 1, 1, 1, 1, 1, 1, 1, 1,
251 1, 1, 1, 1, 0, 0, 0, 0,
252 // DMA
253 0, 0, 0, 0, 0, 1, 0, 0,
254 0, 0, 0, 1, 0, 0, 0, 0,
255 0, 1, 0, 0, 0, 0, 0, 1,
256 0, 0, 0, 0, 0, 0, 0, 0,
257 0, 0, 0, 0, 0, 0, 0, 0,
258 // Timers
259 1, 1, 1, 1, 1, 1, 1, 1,
260 0, 0, 0, 0, 0, 0, 0, 0,
261 // SIO
262 1, 1, 1, 1, 1, 0, 0, 0,
263 1, 1, 1, 0, 0, 0, 0, 0,
264 1, 0, 0, 0, 0, 0, 0, 0,
265 1, 0, 1, 0, 1, 0, 0, 0,
266 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0,
268 0, 0, 0, 0, 0, 0, 0, 0,
269 0, 0, 0, 0, 0, 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 // Interrupts
277 1, 1, 1, 0, 1
278};
279
280void GBAIOInit(struct GBA* gba) {
281 gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
282 gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
283 gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
284 gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
285}
286
287void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
288 if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
289 value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
290 } else {
291 switch (address) {
292 // Video
293 case REG_DISPSTAT:
294 value &= 0xFFF8;
295 GBAVideoWriteDISPSTAT(&gba->video, value);
296 break;
297
298 // Audio
299 case REG_SOUND1CNT_LO:
300 GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
301 value &= 0x00FF;
302 break;
303 case REG_SOUND1CNT_HI:
304 GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
305 break;
306 case REG_SOUND1CNT_X:
307 GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
308 value &= 0x47FF;
309 break;
310 case REG_SOUND2CNT_LO:
311 GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
312 break;
313 case REG_SOUND2CNT_HI:
314 GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
315 value &= 0x47FF;
316 break;
317 case REG_SOUND3CNT_LO:
318 GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
319 value &= 0x00E0;
320 break;
321 case REG_SOUND3CNT_HI:
322 GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
323 value &= 0xE000;
324 break;
325 case REG_SOUND3CNT_X:
326 GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
327 // TODO: The low bits need to not be readable, but still 8-bit writable
328 value &= 0x43FF;
329 break;
330 case REG_SOUND4CNT_LO:
331 GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
332 value &= 0xFF00;
333 break;
334 case REG_SOUND4CNT_HI:
335 GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
336 value &= 0x40FF;
337 break;
338 case REG_SOUNDCNT_LO:
339 GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
340 break;
341 case REG_SOUNDCNT_HI:
342 GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
343 break;
344 case REG_SOUNDCNT_X:
345 GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
346 break;
347 case REG_SOUNDBIAS:
348 GBAAudioWriteSOUNDBIAS(&gba->audio, value);
349 break;
350
351 case REG_WAVE_RAM0_LO:
352 case REG_WAVE_RAM1_LO:
353 case REG_WAVE_RAM2_LO:
354 case REG_WAVE_RAM3_LO:
355 case REG_FIFO_A_LO:
356 case REG_FIFO_B_LO:
357 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
358 break;
359
360 case REG_WAVE_RAM0_HI:
361 case REG_WAVE_RAM1_HI:
362 case REG_WAVE_RAM2_HI:
363 case REG_WAVE_RAM3_HI:
364 case REG_FIFO_A_HI:
365 case REG_FIFO_B_HI:
366 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
367 break;
368
369 // DMA
370 case REG_DMA0SAD_LO:
371 case REG_DMA0DAD_LO:
372 case REG_DMA1SAD_LO:
373 case REG_DMA1DAD_LO:
374 case REG_DMA2SAD_LO:
375 case REG_DMA2DAD_LO:
376 case REG_DMA3SAD_LO:
377 case REG_DMA3DAD_LO:
378 GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
379 break;
380
381 case REG_DMA0SAD_HI:
382 case REG_DMA0DAD_HI:
383 case REG_DMA1SAD_HI:
384 case REG_DMA1DAD_HI:
385 case REG_DMA2SAD_HI:
386 case REG_DMA2DAD_HI:
387 case REG_DMA3SAD_HI:
388 case REG_DMA3DAD_HI:
389 GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
390 break;
391
392 case REG_DMA0CNT_LO:
393 GBAMemoryWriteDMACNT_LO(gba, 0, value);
394 break;
395 case REG_DMA0CNT_HI:
396 value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
397 break;
398 case REG_DMA1CNT_LO:
399 GBAMemoryWriteDMACNT_LO(gba, 1, value);
400 break;
401 case REG_DMA1CNT_HI:
402 value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
403 break;
404 case REG_DMA2CNT_LO:
405 GBAMemoryWriteDMACNT_LO(gba, 2, value);
406 break;
407 case REG_DMA2CNT_HI:
408 value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
409 break;
410 case REG_DMA3CNT_LO:
411 GBAMemoryWriteDMACNT_LO(gba, 3, value);
412 break;
413 case REG_DMA3CNT_HI:
414 value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
415 break;
416
417 // Timers
418 case REG_TM0CNT_LO:
419 GBATimerWriteTMCNT_LO(gba, 0, value);
420 return;
421 case REG_TM1CNT_LO:
422 GBATimerWriteTMCNT_LO(gba, 1, value);
423 return;
424 case REG_TM2CNT_LO:
425 GBATimerWriteTMCNT_LO(gba, 2, value);
426 return;
427 case REG_TM3CNT_LO:
428 GBATimerWriteTMCNT_LO(gba, 3, value);
429 return;
430
431 case REG_TM0CNT_HI:
432 value &= 0x00C7;
433 GBATimerWriteTMCNT_HI(gba, 0, value);
434 break;
435 case REG_TM1CNT_HI:
436 value &= 0x00C7;
437 GBATimerWriteTMCNT_HI(gba, 1, value);
438 break;
439 case REG_TM2CNT_HI:
440 value &= 0x00C7;
441 GBATimerWriteTMCNT_HI(gba, 2, value);
442 break;
443 case REG_TM3CNT_HI:
444 value &= 0x00C7;
445 GBATimerWriteTMCNT_HI(gba, 3, value);
446 break;
447
448 // SIO
449 case REG_SIOCNT:
450 GBASIOWriteSIOCNT(&gba->sio, value);
451 break;
452 case REG_RCNT:
453 value &= 0xC1FF;
454 GBASIOWriteRCNT(&gba->sio, value);
455 break;
456 case REG_SIOMLT_SEND:
457 GBASIOWriteSIOMLT_SEND(&gba->sio, value);
458 break;
459
460 // Interrupts and misc
461 case REG_WAITCNT:
462 GBAAdjustWaitstates(gba, value);
463 break;
464 case REG_IE:
465 GBAWriteIE(gba, value);
466 break;
467 case REG_IF:
468 value = gba->memory.io[REG_IF >> 1] & ~value;
469 break;
470 case REG_IME:
471 GBAWriteIME(gba, value);
472 break;
473 case REG_MAX:
474 // Some bad interrupt libraries will write to this
475 break;
476 default:
477 GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
478 break;
479 }
480 }
481 gba->memory.io[address >> 1] = value;
482}
483
484void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
485 if (address == REG_HALTCNT) {
486 value &= 0x80;
487 if (!value) {
488 GBAHalt(gba);
489 } else {
490 GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
491 }
492 return;
493 }
494 uint16_t value16 = value << (8 * (address & 1));
495 value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
496 GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
497}
498
499void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
500 switch (address) {
501 case REG_WAVE_RAM0_LO:
502 GBAAudioWriteWaveRAM(&gba->audio, 0, value);
503 break;
504 case REG_WAVE_RAM1_LO:
505 GBAAudioWriteWaveRAM(&gba->audio, 1, value);
506 break;
507 case REG_WAVE_RAM2_LO:
508 GBAAudioWriteWaveRAM(&gba->audio, 2, value);
509 break;
510 case REG_WAVE_RAM3_LO:
511 GBAAudioWriteWaveRAM(&gba->audio, 3, value);
512 break;
513 case REG_FIFO_A_LO:
514 case REG_FIFO_B_LO:
515 GBAAudioWriteFIFO(&gba->audio, address, value);
516 break;
517 case REG_DMA0SAD_LO:
518 GBAMemoryWriteDMASAD(gba, 0, value);
519 break;
520 case REG_DMA0DAD_LO:
521 GBAMemoryWriteDMADAD(gba, 0, value);
522 break;
523 case REG_DMA1SAD_LO:
524 GBAMemoryWriteDMASAD(gba, 1, value);
525 break;
526 case REG_DMA1DAD_LO:
527 GBAMemoryWriteDMADAD(gba, 1, value);
528 break;
529 case REG_DMA2SAD_LO:
530 GBAMemoryWriteDMASAD(gba, 2, value);
531 break;
532 case REG_DMA2DAD_LO:
533 GBAMemoryWriteDMADAD(gba, 2, value);
534 break;
535 case REG_DMA3SAD_LO:
536 GBAMemoryWriteDMASAD(gba, 3, value);
537 break;
538 case REG_DMA3DAD_LO:
539 GBAMemoryWriteDMADAD(gba, 3, value);
540 break;
541 default:
542 GBAIOWrite(gba, address, value & 0xFFFF);
543 GBAIOWrite(gba, address | 2, value >> 16);
544 return;
545 }
546 gba->memory.io[address >> 1] = value;
547 gba->memory.io[(address >> 1) + 1] = value >> 16;
548}
549
550uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
551 switch (address) {
552 case REG_TM0CNT_LO:
553 GBATimerUpdateRegister(gba, 0);
554 break;
555 case REG_TM1CNT_LO:
556 GBATimerUpdateRegister(gba, 1);
557 break;
558 case REG_TM2CNT_LO:
559 GBATimerUpdateRegister(gba, 2);
560 break;
561 case REG_TM3CNT_LO:
562 GBATimerUpdateRegister(gba, 3);
563 break;
564
565 case REG_KEYINPUT:
566 if (GBARRIsPlaying(gba->rr)) {
567 return 0x3FF ^ GBARRQueryInput(gba->rr);
568 } else if (gba->keySource) {
569 uint16_t input = *gba->keySource;
570 if (GBARRIsRecording(gba->rr)) {
571 GBARRLogInput(gba->rr, input);
572 }
573 return 0x3FF ^ input;
574 }
575 break;
576
577 case REG_SIOCNT:
578 return gba->sio.siocnt;
579 case REG_RCNT:
580 return gba->sio.rcnt;
581
582 case REG_DMA0CNT_LO:
583 case REG_DMA1CNT_LO:
584 case REG_DMA2CNT_LO:
585 case REG_DMA3CNT_LO:
586 // Write-only register
587 return 0;
588 case REG_DISPCNT:
589 case REG_DISPSTAT:
590 case REG_VCOUNT:
591 case REG_BG0CNT:
592 case REG_BG1CNT:
593 case REG_BG2CNT:
594 case REG_BG3CNT:
595 case REG_WININ:
596 case REG_WINOUT:
597 case REG_BLDCNT:
598 case REG_BLDALPHA:
599 case REG_SOUND1CNT_LO:
600 case REG_SOUND1CNT_HI:
601 case REG_SOUND1CNT_X:
602 case REG_SOUND2CNT_LO:
603 case REG_SOUND2CNT_HI:
604 case REG_SOUND3CNT_LO:
605 case REG_SOUND3CNT_HI:
606 case REG_SOUND3CNT_X:
607 case REG_SOUND4CNT_LO:
608 case REG_SOUND4CNT_HI:
609 case REG_SOUNDCNT_LO:
610 case REG_SOUNDCNT_HI:
611 case REG_DMA0CNT_HI:
612 case REG_DMA1CNT_HI:
613 case REG_DMA2CNT_HI:
614 case REG_DMA3CNT_HI:
615 case REG_SIOMULTI0:
616 case REG_SIOMULTI1:
617 case REG_SIOMULTI2:
618 case REG_SIOMULTI3:
619 case REG_SIOMLT_SEND:
620 case REG_IE:
621 case REG_IF:
622 case REG_WAITCNT:
623 case REG_IME:
624 // Handled transparently by registers
625 break;
626 case REG_MAX:
627 // Some bad interrupt libraries will read from this
628 break;
629 default:
630 GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
631 break;
632 }
633 return gba->memory.io[address >> 1];
634}
635
636void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
637 int i;
638 for (i = 0; i < REG_MAX; i += 2) {
639 if (_isSpecialRegister[i >> 1]) {
640 state->io[i >> 1] = gba->memory.io[i >> 1];
641 } else if (_isValidRegister[i >> 1]) {
642 state->io[i >> 1] = GBAIORead(gba, i);
643 }
644 }
645
646 for (i = 0; i < 4; ++i) {
647 state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
648 state->dma[i].nextSource = gba->memory.dma[i].nextSource;
649 state->dma[i].nextDest = gba->memory.dma[i].nextDest;
650 state->dma[i].nextCount = gba->memory.dma[i].nextCount;
651 state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
652 }
653
654 memcpy(state->timers, gba->timers, sizeof(state->timers));
655 GBAGPIOSerialize(&gba->memory.gpio, state);
656}
657
658void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
659 int i;
660 for (i = 0; i < REG_MAX; i += 2) {
661 if (_isSpecialRegister[i >> 1]) {
662 gba->memory.io[i >> 1] = state->io[i >> 1];
663 } else if (_isValidRegister[i >> 1]) {
664 GBAIOWrite(gba, i, state->io[i >> 1]);
665 }
666 }
667
668 gba->timersEnabled = 0;
669 memcpy(gba->timers, state->timers, sizeof(gba->timers));
670 for (i = 0; i < 4; ++i) {
671 gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
672 gba->memory.dma[i].nextSource = state->dma[i].nextSource;
673 gba->memory.dma[i].nextDest = state->dma[i].nextDest;
674 gba->memory.dma[i].nextCount = state->dma[i].nextCount;
675 gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
676 if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
677 GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
678 }
679
680 if (gba->timers[i].enable) {
681 gba->timersEnabled |= 1 << i;
682 }
683 }
684 GBAGPIODeserialize(&gba->memory.gpio, state);
685}