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