all repos — mgba @ 9c92a29b28d1f81224ba28d5fc83a9481eccd5eb

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	0,
145
146	0, 0, 0, 0, 0, 0, 0, 0,
147
148	// SIO
149	"SIOMULTI0",
150	"SIOMULTI1",
151	"SIOMULTI2",
152	"SIOMULTI3",
153	"SIOCNT",
154	"SIOMLT_SEND",
155	0,
156	0,
157	"KEYINPUT",
158	"KEYCNT",
159	"RCNT",
160	0,
161	0,
162	0,
163	0,
164	0,
165	"JOYCNT",
166	0,
167	0,
168	0,
169	0,
170	0,
171	0,
172	0,
173	"JOY_RECV_LO",
174	"JOY_RECV_HI",
175	"JOY_TRANS_LO",
176	"JOY_RECV_HI",
177	"JOYSTAT",
178	0,
179	0,
180	0,
181
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	0, 0, 0, 0, 0, 0, 0, 0,
192
193	// Interrupts, etc
194	"IE",
195	"IF",
196	"WAITCNT",
197	0,
198	"IME"
199};
200
201static const int _isValidRegister[REG_MAX >> 1] = {
202	// Video
203	1, 0, 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, 1,
207	1, 1, 1, 1, 1, 1, 1, 0,
208	1, 1, 1, 0, 0, 0, 0, 0,
209	// Audio
210	1, 1, 1, 0, 1, 0, 1, 0,
211	1, 1, 1, 0, 1, 0, 1, 0,
212	1, 1, 1, 0, 1, 0, 0, 0,
213	1, 1, 1, 1, 1, 1, 1, 1,
214	1, 1, 1, 1, 1, 0, 0, 0,
215	// DMA
216	1, 1, 1, 1, 1, 1, 1, 1,
217	1, 1, 1, 1, 1, 1, 1, 1,
218	1, 1, 1, 1, 1, 1, 1, 1,
219	0, 0, 0, 0, 0, 0, 0, 0,
220	0, 0, 0, 0, 0, 0, 0, 0,
221	// Timers
222	1, 1, 1, 1, 1, 1, 1, 1,
223	0, 0, 0, 0, 0, 0, 0, 0,
224	// SIO
225	1, 1, 1, 1, 1, 0, 0, 0,
226	1, 1, 1, 0, 0, 0, 0, 0,
227	1, 0, 0, 0, 0, 0, 0, 0,
228	1, 0, 1, 0, 1, 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	0, 0, 0, 0, 0, 0, 0, 0,
239	// Interrupts
240	1, 1, 1, 0, 1
241};
242
243static const int _isSpecialRegister[REG_MAX >> 1] = {
244	// Video
245	0, 0, 0, 1, 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	0, 0, 0, 0, 0, 0, 0, 0,
251	// Audio
252	0, 0, 0, 0, 0, 0, 0, 0,
253	0, 0, 0, 0, 0, 0, 0, 0,
254	0, 0, 0, 0, 0, 0, 0, 0,
255	1, 1, 1, 1, 1, 1, 1, 1,
256	1, 1, 1, 1, 0, 0, 0, 0,
257	// DMA
258	0, 0, 0, 0, 0, 1, 0, 0,
259	0, 0, 0, 1, 0, 0, 0, 0,
260	0, 1, 0, 0, 0, 0, 0, 1,
261	0, 0, 0, 0, 0, 0, 0, 0,
262	0, 0, 0, 0, 0, 0, 0, 0,
263	// Timers
264	1, 1, 1, 1, 1, 1, 1, 1,
265	0, 0, 0, 0, 0, 0, 0, 0,
266	// SIO
267	1, 1, 1, 1, 1, 0, 0, 0,
268	1, 1, 1, 0, 0, 0, 0, 0,
269	1, 0, 0, 0, 0, 0, 0, 0,
270	1, 0, 1, 0, 1, 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	0, 0, 0, 0, 0, 0, 0, 0,
281	// Interrupts
282	1, 1, 1, 0, 1
283};
284
285void GBAIOInit(struct GBA* gba) {
286	gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
287	gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
288	gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
289	gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
290}
291
292void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
293	if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
294		value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
295	} else {
296		switch (address) {
297		// Video
298		case REG_DISPSTAT:
299			value &= 0xFFF8;
300			GBAVideoWriteDISPSTAT(&gba->video, value);
301			break;
302
303		// Audio
304		case REG_SOUND1CNT_LO:
305			GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
306			value &= 0x00FF;
307			break;
308		case REG_SOUND1CNT_HI:
309			GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
310			break;
311		case REG_SOUND1CNT_X:
312			GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
313			value &= 0x47FF;
314			break;
315		case REG_SOUND2CNT_LO:
316			GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
317			break;
318		case REG_SOUND2CNT_HI:
319			GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
320			value &= 0x47FF;
321			break;
322		case REG_SOUND3CNT_LO:
323			GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
324			value &= 0x00E0;
325			break;
326		case REG_SOUND3CNT_HI:
327			GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
328			value &= 0xE000;
329			break;
330		case REG_SOUND3CNT_X:
331			GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
332			// TODO: The low bits need to not be readable, but still 8-bit writable
333			value &= 0x43FF;
334			break;
335		case REG_SOUND4CNT_LO:
336			GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
337			value &= 0xFF00;
338			break;
339		case REG_SOUND4CNT_HI:
340			GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
341			value &= 0x40FF;
342			break;
343		case REG_SOUNDCNT_LO:
344			GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
345			break;
346		case REG_SOUNDCNT_HI:
347			GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
348			break;
349		case REG_SOUNDCNT_X:
350			GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
351			break;
352		case REG_SOUNDBIAS:
353			GBAAudioWriteSOUNDBIAS(&gba->audio, value);
354			break;
355
356		case REG_WAVE_RAM0_LO:
357		case REG_WAVE_RAM1_LO:
358		case REG_WAVE_RAM2_LO:
359		case REG_WAVE_RAM3_LO:
360		case REG_FIFO_A_LO:
361		case REG_FIFO_B_LO:
362			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
363			break;
364
365		case REG_WAVE_RAM0_HI:
366		case REG_WAVE_RAM1_HI:
367		case REG_WAVE_RAM2_HI:
368		case REG_WAVE_RAM3_HI:
369		case REG_FIFO_A_HI:
370		case REG_FIFO_B_HI:
371			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
372			break;
373
374		// DMA
375		case REG_DMA0SAD_LO:
376		case REG_DMA0DAD_LO:
377		case REG_DMA1SAD_LO:
378		case REG_DMA1DAD_LO:
379		case REG_DMA2SAD_LO:
380		case REG_DMA2DAD_LO:
381		case REG_DMA3SAD_LO:
382		case REG_DMA3DAD_LO:
383			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
384			break;
385
386		case REG_DMA0SAD_HI:
387		case REG_DMA0DAD_HI:
388		case REG_DMA1SAD_HI:
389		case REG_DMA1DAD_HI:
390		case REG_DMA2SAD_HI:
391		case REG_DMA2DAD_HI:
392		case REG_DMA3SAD_HI:
393		case REG_DMA3DAD_HI:
394			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
395			break;
396
397		case REG_DMA0CNT_LO:
398			GBAMemoryWriteDMACNT_LO(gba, 0, value);
399			break;
400		case REG_DMA0CNT_HI:
401			value = GBAMemoryWriteDMACNT_HI(gba, 0, value);
402			break;
403		case REG_DMA1CNT_LO:
404			GBAMemoryWriteDMACNT_LO(gba, 1, value);
405			break;
406		case REG_DMA1CNT_HI:
407			value = GBAMemoryWriteDMACNT_HI(gba, 1, value);
408			break;
409		case REG_DMA2CNT_LO:
410			GBAMemoryWriteDMACNT_LO(gba, 2, value);
411			break;
412		case REG_DMA2CNT_HI:
413			value = GBAMemoryWriteDMACNT_HI(gba, 2, value);
414			break;
415		case REG_DMA3CNT_LO:
416			GBAMemoryWriteDMACNT_LO(gba, 3, value);
417			break;
418		case REG_DMA3CNT_HI:
419			value = GBAMemoryWriteDMACNT_HI(gba, 3, value);
420			break;
421
422		// Timers
423		case REG_TM0CNT_LO:
424			GBATimerWriteTMCNT_LO(gba, 0, value);
425			return;
426		case REG_TM1CNT_LO:
427			GBATimerWriteTMCNT_LO(gba, 1, value);
428			return;
429		case REG_TM2CNT_LO:
430			GBATimerWriteTMCNT_LO(gba, 2, value);
431			return;
432		case REG_TM3CNT_LO:
433			GBATimerWriteTMCNT_LO(gba, 3, value);
434			return;
435
436		case REG_TM0CNT_HI:
437			value &= 0x00C7;
438			GBATimerWriteTMCNT_HI(gba, 0, value);
439			break;
440		case REG_TM1CNT_HI:
441			value &= 0x00C7;
442			GBATimerWriteTMCNT_HI(gba, 1, value);
443			break;
444		case REG_TM2CNT_HI:
445			value &= 0x00C7;
446			GBATimerWriteTMCNT_HI(gba, 2, value);
447			break;
448		case REG_TM3CNT_HI:
449			value &= 0x00C7;
450			GBATimerWriteTMCNT_HI(gba, 3, value);
451			break;
452
453		// SIO
454		case REG_SIOCNT:
455			GBASIOWriteSIOCNT(&gba->sio, value);
456			break;
457		case REG_RCNT:
458			value &= 0xC1FF;
459			GBASIOWriteRCNT(&gba->sio, value);
460			break;
461		case REG_SIOMLT_SEND:
462			GBASIOWriteSIOMLT_SEND(&gba->sio, value);
463			break;
464
465		// Interrupts and misc
466		case REG_WAITCNT:
467			GBAAdjustWaitstates(gba, value);
468			break;
469		case REG_IE:
470			GBAWriteIE(gba, value);
471			break;
472		case REG_IF:
473			value = gba->memory.io[REG_IF >> 1] & ~value;
474			break;
475		case REG_IME:
476			GBAWriteIME(gba, value);
477			break;
478		case REG_MAX:
479			// Some bad interrupt libraries will write to this
480			break;
481		default:
482			GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
483			break;
484		}
485	}
486	gba->memory.io[address >> 1] = value;
487}
488
489void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
490	if (address == REG_HALTCNT) {
491		value &= 0x80;
492		if (!value) {
493			GBAHalt(gba);
494		} else {
495			GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
496		}
497		return;
498	}
499	uint16_t value16 = value << (8 * (address & 1));
500	value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
501	GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
502}
503
504void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
505	switch (address) {
506	case REG_WAVE_RAM0_LO:
507		GBAAudioWriteWaveRAM(&gba->audio, 0, value);
508		break;
509	case REG_WAVE_RAM1_LO:
510		GBAAudioWriteWaveRAM(&gba->audio, 1, value);
511		break;
512	case REG_WAVE_RAM2_LO:
513		GBAAudioWriteWaveRAM(&gba->audio, 2, value);
514		break;
515	case REG_WAVE_RAM3_LO:
516		GBAAudioWriteWaveRAM(&gba->audio, 3, value);
517		break;
518	case REG_FIFO_A_LO:
519	case REG_FIFO_B_LO:
520		GBAAudioWriteFIFO(&gba->audio, address, value);
521		break;
522	case REG_DMA0SAD_LO:
523		GBAMemoryWriteDMASAD(gba, 0, value);
524		break;
525	case REG_DMA0DAD_LO:
526		GBAMemoryWriteDMADAD(gba, 0, value);
527		break;
528	case REG_DMA1SAD_LO:
529		GBAMemoryWriteDMASAD(gba, 1, value);
530		break;
531	case REG_DMA1DAD_LO:
532		GBAMemoryWriteDMADAD(gba, 1, value);
533		break;
534	case REG_DMA2SAD_LO:
535		GBAMemoryWriteDMASAD(gba, 2, value);
536		break;
537	case REG_DMA2DAD_LO:
538		GBAMemoryWriteDMADAD(gba, 2, value);
539		break;
540	case REG_DMA3SAD_LO:
541		GBAMemoryWriteDMASAD(gba, 3, value);
542		break;
543	case REG_DMA3DAD_LO:
544		GBAMemoryWriteDMADAD(gba, 3, value);
545		break;
546	default:
547		GBAIOWrite(gba, address, value & 0xFFFF);
548		GBAIOWrite(gba, address | 2, value >> 16);
549		return;
550	}
551	gba->memory.io[address >> 1] = value;
552	gba->memory.io[(address >> 1) + 1] = value >> 16;
553}
554
555uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
556	switch (address) {
557	case REG_TM0CNT_LO:
558		GBATimerUpdateRegister(gba, 0);
559		break;
560	case REG_TM1CNT_LO:
561		GBATimerUpdateRegister(gba, 1);
562		break;
563	case REG_TM2CNT_LO:
564		GBATimerUpdateRegister(gba, 2);
565		break;
566	case REG_TM3CNT_LO:
567		GBATimerUpdateRegister(gba, 3);
568		break;
569
570	case REG_KEYINPUT:
571		if (GBARRIsPlaying(gba->rr)) {
572			return 0x3FF ^ GBARRQueryInput(gba->rr);
573		} else if (gba->keySource) {
574			uint16_t input = *gba->keySource;
575			if (GBARRIsRecording(gba->rr)) {
576				GBARRLogInput(gba->rr, input);
577			}
578			return 0x3FF ^ input;
579		}
580		break;
581
582	case REG_SIOCNT:
583		return gba->sio.siocnt;
584	case REG_RCNT:
585		return gba->sio.rcnt;
586
587	case REG_DMA0CNT_LO:
588	case REG_DMA1CNT_LO:
589	case REG_DMA2CNT_LO:
590	case REG_DMA3CNT_LO:
591		// Write-only register
592		return 0;
593	case REG_DISPCNT:
594	case REG_DISPSTAT:
595	case REG_VCOUNT:
596	case REG_BG0CNT:
597	case REG_BG1CNT:
598	case REG_BG2CNT:
599	case REG_BG3CNT:
600	case REG_WININ:
601	case REG_WINOUT:
602	case REG_BLDCNT:
603	case REG_BLDALPHA:
604	case REG_SOUND1CNT_LO:
605	case REG_SOUND1CNT_HI:
606	case REG_SOUND1CNT_X:
607	case REG_SOUND2CNT_LO:
608	case REG_SOUND2CNT_HI:
609	case REG_SOUND3CNT_LO:
610	case REG_SOUND3CNT_HI:
611	case REG_SOUND3CNT_X:
612	case REG_SOUND4CNT_LO:
613	case REG_SOUND4CNT_HI:
614	case REG_SOUNDCNT_LO:
615	case REG_SOUNDCNT_HI:
616	case REG_DMA0CNT_HI:
617	case REG_DMA1CNT_HI:
618	case REG_DMA2CNT_HI:
619	case REG_DMA3CNT_HI:
620	case REG_SIOMULTI0:
621	case REG_SIOMULTI1:
622	case REG_SIOMULTI2:
623	case REG_SIOMULTI3:
624	case REG_SIOMLT_SEND:
625	case REG_IE:
626	case REG_IF:
627	case REG_WAITCNT:
628	case REG_IME:
629		// Handled transparently by registers
630		break;
631	case REG_MAX:
632		// Some bad interrupt libraries will read from this
633		break;
634	default:
635		GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
636		break;
637	}
638	return gba->memory.io[address >> 1];
639}
640
641void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
642	int i;
643	for (i = 0; i < REG_MAX; i += 2) {
644		if (_isSpecialRegister[i >> 1]) {
645			state->io[i >> 1] = gba->memory.io[i >> 1];
646		} else if (_isValidRegister[i >> 1]) {
647			state->io[i >> 1] = GBAIORead(gba, i);
648		}
649	}
650
651	for (i = 0; i < 4; ++i) {
652		state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
653		state->dma[i].nextSource = gba->memory.dma[i].nextSource;
654		state->dma[i].nextDest = gba->memory.dma[i].nextDest;
655		state->dma[i].nextCount = gba->memory.dma[i].nextCount;
656		state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
657	}
658
659	memcpy(state->timers, gba->timers, sizeof(state->timers));
660	GBAGPIOSerialize(&gba->memory.gpio, state);
661}
662
663void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
664	int i;
665	for (i = 0; i < REG_MAX; i += 2) {
666		if (_isSpecialRegister[i >> 1]) {
667			gba->memory.io[i >> 1] = state->io[i >> 1];
668		} else if (_isValidRegister[i >> 1]) {
669			GBAIOWrite(gba, i, state->io[i >> 1]);
670		}
671	}
672
673	gba->timersEnabled = 0;
674	memcpy(gba->timers, state->timers, sizeof(gba->timers));
675	for (i = 0; i < 4; ++i) {
676		gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
677		gba->memory.dma[i].nextSource = state->dma[i].nextSource;
678		gba->memory.dma[i].nextDest = state->dma[i].nextDest;
679		gba->memory.dma[i].nextCount = state->dma[i].nextCount;
680		gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
681		if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
682			GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
683		}
684
685		if (gba->timers[i].enable) {
686			gba->timersEnabled |= 1 << i;
687		}
688	}
689	GBAGPIODeserialize(&gba->memory.gpio, state);
690}