all repos — mgba @ b66ce64c4704ab5053457715d296ce05ec9ce67e

mGBA Game Boy Advance Emulator

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}