all repos — mgba @ e112e8671512c3ab716a343bb28e361e21db7b28

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