all repos — mgba @ 55ba676d7c7fcc665d4b454e80db82428f4adea1

mGBA Game Boy Advance Emulator

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}