all repos — mgba @ 3d21ce1fd0751c7ebd00f8504f328b68ff780c8c

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		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}