all repos — mgba @ 3ff3c248214f0f71591a0f9483e98ab37aa52d00

mGBA Game Boy Advance Emulator

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