all repos — mgba @ 618092a5f6b5ed1501e361b4c7c2f390f4967d66

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