all repos — mgba @ c5ed4cb9af4ab9166d93cc40259c70445266a49e

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/rr/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			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
568bool GBAIOIsReadConstant(uint32_t address) {
569	switch (address) {
570	default:
571		return false;
572	case REG_BG0CNT:
573	case REG_BG1CNT:
574	case REG_BG2CNT:
575	case REG_BG3CNT:
576	case REG_WININ:
577	case REG_WINOUT:
578	case REG_BLDCNT:
579	case REG_BLDALPHA:
580	case REG_DMA0CNT_LO:
581	case REG_DMA1CNT_LO:
582	case REG_DMA2CNT_LO:
583	case REG_DMA3CNT_LO:
584	case REG_KEYINPUT:
585	case REG_IE:
586		return true;
587	}
588}
589
590uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
591	if (!GBAIOIsReadConstant(address)) {
592		// Most IO reads need to disable idle removal
593		gba->haltPending = false;
594	}
595
596	switch (address) {
597	case REG_TM0CNT_LO:
598		GBATimerUpdateRegister(gba, 0);
599		break;
600	case REG_TM1CNT_LO:
601		GBATimerUpdateRegister(gba, 1);
602		break;
603	case REG_TM2CNT_LO:
604		GBATimerUpdateRegister(gba, 2);
605		break;
606	case REG_TM3CNT_LO:
607		GBATimerUpdateRegister(gba, 3);
608		break;
609
610	case REG_KEYINPUT:
611		if (gba->rr && gba->rr->isPlaying(gba->rr)) {
612			return 0x3FF ^ gba->rr->queryInput(gba->rr);
613		} else {
614			uint16_t input = 0x3FF;
615			if (gba->keyCallback) {
616				input = gba->keyCallback->readKeys(gba->keyCallback);
617			} else if (gba->keySource) {
618				input = *gba->keySource;
619			}
620			if (gba->rr && gba->rr->isRecording(gba->rr)) {
621				gba->rr->logInput(gba->rr, input);
622			}
623			return 0x3FF ^ input;
624		}
625
626	case REG_SIOCNT:
627		return gba->sio.siocnt;
628	case REG_RCNT:
629		return gba->sio.rcnt;
630
631	case REG_DMA0CNT_LO:
632	case REG_DMA1CNT_LO:
633	case REG_DMA2CNT_LO:
634	case REG_DMA3CNT_LO:
635		// Write-only register
636		return 0;
637	case REG_DISPCNT:
638	case REG_DISPSTAT:
639	case REG_VCOUNT:
640	case REG_BG0CNT:
641	case REG_BG1CNT:
642	case REG_BG2CNT:
643	case REG_BG3CNT:
644	case REG_WININ:
645	case REG_WINOUT:
646	case REG_BLDCNT:
647	case REG_BLDALPHA:
648	case REG_SOUND1CNT_LO:
649	case REG_SOUND1CNT_HI:
650	case REG_SOUND1CNT_X:
651	case REG_SOUND2CNT_LO:
652	case REG_SOUND2CNT_HI:
653	case REG_SOUND3CNT_LO:
654	case REG_SOUND3CNT_HI:
655	case REG_SOUND3CNT_X:
656	case REG_SOUND4CNT_LO:
657	case REG_SOUND4CNT_HI:
658	case REG_SOUNDCNT_LO:
659	case REG_SOUNDCNT_HI:
660	case REG_DMA0CNT_HI:
661	case REG_DMA1CNT_HI:
662	case REG_DMA2CNT_HI:
663	case REG_DMA3CNT_HI:
664	case REG_SIOMULTI0:
665	case REG_SIOMULTI1:
666	case REG_SIOMULTI2:
667	case REG_SIOMULTI3:
668	case REG_SIOMLT_SEND:
669	case REG_IE:
670	case REG_IF:
671	case REG_WAITCNT:
672	case REG_IME:
673		// Handled transparently by registers
674		break;
675	case REG_MAX:
676		// Some bad interrupt libraries will read from this
677		break;
678	default:
679		GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
680		if (address >= REG_MAX) {
681			GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address);
682			return 0; // TODO: Reuse LOAD_BAD
683		}
684		break;
685	}
686	return gba->memory.io[address >> 1];
687}
688
689void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
690	int i;
691	for (i = 0; i < REG_MAX; i += 2) {
692		if (_isSpecialRegister[i >> 1]) {
693			state->io[i >> 1] = gba->memory.io[i >> 1];
694		} else if (_isValidRegister[i >> 1]) {
695			state->io[i >> 1] = GBAIORead(gba, i);
696		}
697	}
698
699	for (i = 0; i < 4; ++i) {
700		state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1];
701		state->dma[i].nextSource = gba->memory.dma[i].nextSource;
702		state->dma[i].nextDest = gba->memory.dma[i].nextDest;
703		state->dma[i].nextCount = gba->memory.dma[i].nextCount;
704		state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
705	}
706
707	memcpy(state->timers, gba->timers, sizeof(state->timers));
708	GBAHardwareSerialize(&gba->memory.hw, state);
709}
710
711void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
712	int i;
713	for (i = 0; i < REG_MAX; i += 2) {
714		if (_isSpecialRegister[i >> 1]) {
715			LOAD_16(gba->memory.io[i >> 1], i, state->io);
716		} else if (_isValidRegister[i >> 1]) {
717			uint16_t reg;
718			LOAD_16(reg, i, state->io);
719			GBAIOWrite(gba, i, reg);
720		}
721	}
722
723	gba->timersEnabled = 0;
724	for (i = 0; i < 4; ++i) {
725		LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload);
726		LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload);
727		LOAD_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent);
728		LOAD_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent);
729		LOAD_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval);
730		LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags);
731		LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);
732		LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
733		LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
734		LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
735		LOAD_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent);
736		if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
737			GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
738		}
739
740		if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
741			gba->timersEnabled |= 1 << i;
742		}
743	}
744	GBAMemoryUpdateDMAs(gba, 0);
745	GBAHardwareDeserialize(&gba->memory.hw, state);
746}