all repos — mgba @ 97447ffa40d6f90ae5f1daf84987e6ff7688d0b8

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 &= 0x47FF;
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			if (address >= REG_MAX) {
493				GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address);
494				return;
495			}
496			break;
497		}
498	}
499	gba->memory.io[address >> 1] = value;
500}
501
502void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
503	if (address == REG_HALTCNT) {
504		value &= 0x80;
505		if (!value) {
506			GBAHalt(gba);
507		} else {
508			GBAStop(gba);
509		}
510		return;
511	}
512	uint16_t value16 = value << (8 * (address & 1));
513	value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
514	GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
515}
516
517void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
518	switch (address) {
519	case REG_WAVE_RAM0_LO:
520		GBAAudioWriteWaveRAM(&gba->audio, 0, value);
521		break;
522	case REG_WAVE_RAM1_LO:
523		GBAAudioWriteWaveRAM(&gba->audio, 1, value);
524		break;
525	case REG_WAVE_RAM2_LO:
526		GBAAudioWriteWaveRAM(&gba->audio, 2, value);
527		break;
528	case REG_WAVE_RAM3_LO:
529		GBAAudioWriteWaveRAM(&gba->audio, 3, value);
530		break;
531	case REG_FIFO_A_LO:
532	case REG_FIFO_B_LO:
533		GBAAudioWriteFIFO(&gba->audio, address, value);
534		break;
535	case REG_DMA0SAD_LO:
536		GBAMemoryWriteDMASAD(gba, 0, value);
537		break;
538	case REG_DMA0DAD_LO:
539		GBAMemoryWriteDMADAD(gba, 0, value);
540		break;
541	case REG_DMA1SAD_LO:
542		GBAMemoryWriteDMASAD(gba, 1, value);
543		break;
544	case REG_DMA1DAD_LO:
545		GBAMemoryWriteDMADAD(gba, 1, value);
546		break;
547	case REG_DMA2SAD_LO:
548		GBAMemoryWriteDMASAD(gba, 2, value);
549		break;
550	case REG_DMA2DAD_LO:
551		GBAMemoryWriteDMADAD(gba, 2, value);
552		break;
553	case REG_DMA3SAD_LO:
554		GBAMemoryWriteDMASAD(gba, 3, value);
555		break;
556	case REG_DMA3DAD_LO:
557		GBAMemoryWriteDMADAD(gba, 3, value);
558		break;
559	default:
560		GBAIOWrite(gba, address, value & 0xFFFF);
561		GBAIOWrite(gba, address | 2, value >> 16);
562		return;
563	}
564	gba->memory.io[address >> 1] = value;
565	gba->memory.io[(address >> 1) + 1] = value >> 16;
566}
567
568uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
569	gba->haltPending = false; // IO reads need to invalidate detected idle loops
570	switch (address) {
571	case REG_TM0CNT_LO:
572		GBATimerUpdateRegister(gba, 0);
573		break;
574	case REG_TM1CNT_LO:
575		GBATimerUpdateRegister(gba, 1);
576		break;
577	case REG_TM2CNT_LO:
578		GBATimerUpdateRegister(gba, 2);
579		break;
580	case REG_TM3CNT_LO:
581		GBATimerUpdateRegister(gba, 3);
582		break;
583
584	case REG_KEYINPUT:
585		if (gba->rr && gba->rr->isPlaying(gba->rr)) {
586			return 0x3FF ^ gba->rr->queryInput(gba->rr);
587		} else {
588			uint16_t input = 0x3FF;
589			if (gba->keyCallback) {
590				input = gba->keyCallback->readKeys(gba->keyCallback);
591			} else if (gba->keySource) {
592				input = *gba->keySource;
593			}
594			if (gba->rr && gba->rr->isRecording(gba->rr)) {
595				gba->rr->logInput(gba->rr, input);
596			}
597			return 0x3FF ^ input;
598		}
599
600	case REG_SIOCNT:
601		return gba->sio.siocnt;
602	case REG_RCNT:
603		return gba->sio.rcnt;
604
605	case REG_DMA0CNT_LO:
606	case REG_DMA1CNT_LO:
607	case REG_DMA2CNT_LO:
608	case REG_DMA3CNT_LO:
609		// Write-only register
610		return 0;
611	case REG_DISPCNT:
612	case REG_DISPSTAT:
613	case REG_VCOUNT:
614	case REG_BG0CNT:
615	case REG_BG1CNT:
616	case REG_BG2CNT:
617	case REG_BG3CNT:
618	case REG_WININ:
619	case REG_WINOUT:
620	case REG_BLDCNT:
621	case REG_BLDALPHA:
622	case REG_SOUND1CNT_LO:
623	case REG_SOUND1CNT_HI:
624	case REG_SOUND1CNT_X:
625	case REG_SOUND2CNT_LO:
626	case REG_SOUND2CNT_HI:
627	case REG_SOUND3CNT_LO:
628	case REG_SOUND3CNT_HI:
629	case REG_SOUND3CNT_X:
630	case REG_SOUND4CNT_LO:
631	case REG_SOUND4CNT_HI:
632	case REG_SOUNDCNT_LO:
633	case REG_SOUNDCNT_HI:
634	case REG_DMA0CNT_HI:
635	case REG_DMA1CNT_HI:
636	case REG_DMA2CNT_HI:
637	case REG_DMA3CNT_HI:
638	case REG_SIOMULTI0:
639	case REG_SIOMULTI1:
640	case REG_SIOMULTI2:
641	case REG_SIOMULTI3:
642	case REG_SIOMLT_SEND:
643	case REG_IE:
644	case REG_IF:
645	case REG_WAITCNT:
646	case REG_IME:
647		// Handled transparently by registers
648		break;
649	case REG_MAX:
650		// Some bad interrupt libraries will read from this
651		break;
652	default:
653		GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
654		if (address >= REG_MAX) {
655			GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address);
656			return 0; // TODO: Reuse LOAD_BAD
657		}
658		break;
659	}
660	return gba->memory.io[address >> 1];
661}
662
663void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
664	int i;
665	for (i = 0; i < REG_MAX; i += 2) {
666		if (_isSpecialRegister[i >> 1]) {
667			state->io[i >> 1] = gba->memory.io[i >> 1];
668		} else if (_isValidRegister[i >> 1]) {
669			state->io[i >> 1] = GBAIORead(gba, i);
670		}
671	}
672
673	for (i = 0; i < 4; ++i) {
674		state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
675		state->dma[i].nextSource = gba->memory.dma[i].nextSource;
676		state->dma[i].nextDest = gba->memory.dma[i].nextDest;
677		state->dma[i].nextCount = gba->memory.dma[i].nextCount;
678		state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
679	}
680
681	memcpy(state->timers, gba->timers, sizeof(state->timers));
682	GBAHardwareSerialize(&gba->memory.hw, state);
683}
684
685void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
686	int i;
687	for (i = 0; i < REG_MAX; i += 2) {
688		if (_isSpecialRegister[i >> 1]) {
689			gba->memory.io[i >> 1] = state->io[i >> 1];
690		} else if (_isValidRegister[i >> 1]) {
691			GBAIOWrite(gba, i, state->io[i >> 1]);
692		}
693	}
694
695	gba->timersEnabled = 0;
696	memcpy(gba->timers, state->timers, sizeof(gba->timers));
697	for (i = 0; i < 4; ++i) {
698		gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1];
699		gba->memory.dma[i].nextSource = state->dma[i].nextSource;
700		gba->memory.dma[i].nextDest = state->dma[i].nextDest;
701		gba->memory.dma[i].nextCount = state->dma[i].nextCount;
702		gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
703		if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
704			GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
705		}
706
707		if (gba->timers[i].enable) {
708			gba->timersEnabled |= 1 << i;
709		}
710	}
711	GBAMemoryUpdateDMAs(gba, 0);
712	GBAHardwareDeserialize(&gba->memory.hw, state);
713}