all repos — mgba @ a2b5edbbd5e1be8d70113215d45ce2368b286c94

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