all repos — mgba @ ec32efd8e40c716b0d7908dfe25815262eb52b2f

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