all repos — mgba @ 0a52f44fa822539200f5ae6aad1fe5f5a6a3ab0e

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 <mgba/internal/gba/io.h>
  7
  8#include <mgba/internal/arm/macros.h>
  9#include <mgba/internal/gba/dma.h>
 10#include <mgba/internal/gba/gba.h>
 11#include <mgba/internal/gba/serialize.h>
 12
 13mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io");
 14
 15const char* const GBAIORegisterNames[] = {
 16	// Video
 17	"DISPCNT",
 18	0,
 19	"DISPSTAT",
 20	"VCOUNT",
 21	"BG0CNT",
 22	"BG1CNT",
 23	"BG2CNT",
 24	"BG3CNT",
 25	"BG0HOFS",
 26	"BG0VOFS",
 27	"BG1HOFS",
 28	"BG1VOFS",
 29	"BG2HOFS",
 30	"BG2VOFS",
 31	"BG3HOFS",
 32	"BG3VOFS",
 33	"BG2PA",
 34	"BG2PB",
 35	"BG2PC",
 36	"BG2PD",
 37	"BG2X_LO",
 38	"BG2X_HI",
 39	"BG2Y_LO",
 40	"BG2Y_HI",
 41	"BG3PA",
 42	"BG3PB",
 43	"BG3PC",
 44	"BG3PD",
 45	"BG3X_LO",
 46	"BG3X_HI",
 47	"BG3Y_LO",
 48	"BG3Y_HI",
 49	"WIN0H",
 50	"WIN1H",
 51	"WIN0V",
 52	"WIN1V",
 53	"WININ",
 54	"WINOUT",
 55	"MOSAIC",
 56	0,
 57	"BLDCNT",
 58	"BLDALPHA",
 59	"BLDY",
 60	0,
 61	0,
 62	0,
 63	0,
 64	0,
 65
 66	// Sound
 67	"SOUND1CNT_LO",
 68	"SOUND1CNT_HI",
 69	"SOUND1CNT_X",
 70	0,
 71	"SOUND2CNT_LO",
 72	0,
 73	"SOUND2CNT_HI",
 74	0,
 75	"SOUND3CNT_LO",
 76	"SOUND3CNT_HI",
 77	"SOUND3CNT_X",
 78	0,
 79	"SOUND4CNT_LO",
 80	0,
 81	"SOUND4CNT_HI",
 82	0,
 83	"SOUNDCNT_LO",
 84	"SOUNDCNT_HI",
 85	"SOUNDCNT_X",
 86	0,
 87	"SOUNDBIAS",
 88	0,
 89	0,
 90	0,
 91	"WAVE_RAM0_LO",
 92	"WAVE_RAM0_HI",
 93	"WAVE_RAM1_LO",
 94	"WAVE_RAM1_HI",
 95	"WAVE_RAM2_LO",
 96	"WAVE_RAM2_HI",
 97	"WAVE_RAM3_LO",
 98	"WAVE_RAM3_HI",
 99	"FIFO_A_LO",
100	"FIFO_A_HI",
101	"FIFO_B_LO",
102	"FIFO_B_HI",
103	0,
104	0,
105	0,
106	0,
107
108	// DMA
109	"DMA0SAD_LO",
110	"DMA0SAD_HI",
111	"DMA0DAD_LO",
112	"DMA0DAD_HI",
113	"DMA0CNT_LO",
114	"DMA0CNT_HI",
115	"DMA1SAD_LO",
116	"DMA1SAD_HI",
117	"DMA1DAD_LO",
118	"DMA1DAD_HI",
119	"DMA1CNT_LO",
120	"DMA1CNT_HI",
121	"DMA2SAD_LO",
122	"DMA2SAD_HI",
123	"DMA2DAD_LO",
124	"DMA2DAD_HI",
125	"DMA2CNT_LO",
126	"DMA2CNT_HI",
127	"DMA3SAD_LO",
128	"DMA3SAD_HI",
129	"DMA3DAD_LO",
130	"DMA3DAD_HI",
131	"DMA3CNT_LO",
132	"DMA3CNT_HI",
133
134	0, 0, 0, 0, 0, 0, 0, 0,
135	0, 0, 0, 0, 0, 0, 0, 0,
136
137	// Timers
138	"TM0CNT_LO",
139	"TM0CNT_HI",
140	"TM1CNT_LO",
141	"TM1CNT_HI",
142	"TM2CNT_LO",
143	"TM2CNT_HI",
144	"TM3CNT_LO",
145	"TM3CNT_HI",
146
147	0, 0, 0, 0, 0, 0, 0, 0,
148
149	// SIO
150	"SIOMULTI0",
151	"SIOMULTI1",
152	"SIOMULTI2",
153	"SIOMULTI3",
154	"SIOCNT",
155	"SIOMLT_SEND",
156	0,
157	0,
158	"KEYINPUT",
159	"KEYCNT",
160	"RCNT",
161	0,
162	0,
163	0,
164	0,
165	0,
166	"JOYCNT",
167	0,
168	0,
169	0,
170	0,
171	0,
172	0,
173	0,
174	"JOY_RECV_LO",
175	"JOY_RECV_HI",
176	"JOY_TRANS_LO",
177	"JOY_TRANS_HI",
178	"JOYSTAT",
179	0,
180	0,
181	0,
182
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	0, 0, 0, 0, 0, 0, 0, 0,
192	0, 0, 0, 0, 0, 0, 0, 0,
193
194	// Interrupts, etc
195	"IE",
196	"IF",
197	"WAITCNT",
198	0,
199	"IME"
200};
201
202static const int _isValidRegister[REG_MAX >> 1] = {
203	// Video
204	1, 0, 1, 1, 1, 1, 1, 1,
205	1, 1, 1, 1, 1, 1, 1, 1,
206	1, 1, 1, 1, 1, 1, 1, 1,
207	1, 1, 1, 1, 1, 1, 1, 1,
208	1, 1, 1, 1, 1, 1, 1, 0,
209	1, 1, 1, 0, 0, 0, 0, 0,
210	// Audio
211	1, 1, 1, 0, 1, 0, 1, 0,
212	1, 1, 1, 0, 1, 0, 1, 0,
213	1, 1, 1, 0, 1, 0, 0, 0,
214	1, 1, 1, 1, 1, 1, 1, 1,
215	1, 1, 1, 1, 0, 0, 0, 0,
216	// DMA
217	1, 1, 1, 1, 1, 1, 1, 1,
218	1, 1, 1, 1, 1, 1, 1, 1,
219	1, 1, 1, 1, 1, 1, 1, 1,
220	0, 0, 0, 0, 0, 0, 0, 0,
221	0, 0, 0, 0, 0, 0, 0, 0,
222	// Timers
223	1, 1, 1, 1, 1, 1, 1, 1,
224	0, 0, 0, 0, 0, 0, 0, 0,
225	// SIO
226	1, 1, 1, 1, 1, 0, 0, 0,
227	1, 1, 1, 0, 0, 0, 0, 0,
228	1, 0, 0, 0, 0, 0, 0, 0,
229	1, 0, 1, 0, 1, 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	0, 0, 0, 0, 0, 0, 0, 0,
239	0, 0, 0, 0, 0, 0, 0, 0,
240	// Interrupts
241	1, 1, 1, 0, 1
242};
243
244static const int _isRSpecialRegister[REG_MAX >> 1] = {
245	// Video
246	0, 0, 1, 1, 0, 0, 0, 0,
247	1, 1, 1, 1, 1, 1, 1, 1,
248	1, 1, 1, 1, 1, 1, 1, 1,
249	1, 1, 1, 1, 1, 1, 1, 1,
250	1, 1, 1, 1, 1, 1, 1, 1,
251	1, 1, 1, 1, 1, 1, 1, 1,
252	// Audio
253	0, 0, 1, 0, 0, 0, 1, 0,
254	0, 0, 1, 0, 0, 0, 1, 0,
255	0, 0, 0, 0, 1, 0, 0, 0,
256	1, 1, 1, 1, 1, 1, 1, 1,
257	1, 1, 1, 1, 0, 0, 0, 0,
258	// DMA
259	1, 1, 1, 1, 1, 1, 1, 1,
260	1, 1, 1, 1, 1, 1, 1, 1,
261	1, 1, 1, 1, 1, 1, 1, 1,
262	0, 0, 0, 0, 0, 0, 0, 0,
263	0, 0, 0, 0, 0, 0, 0, 0,
264	// Timers
265	1, 1, 1, 1, 1, 1, 1, 1,
266	0, 0, 0, 0, 0, 0, 0, 0,
267	// SIO
268	1, 1, 1, 1, 1, 0, 0, 0,
269	1, 1, 1, 0, 0, 0, 0, 0,
270	1, 0, 0, 0, 0, 0, 0, 0,
271	1, 0, 1, 0, 1, 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	0, 0, 0, 0, 0, 0, 0, 0,
281	0, 0, 0, 0, 0, 0, 0, 0,
282	// Interrupts
283};
284
285static const int _isWSpecialRegister[REG_MAX >> 1] = {
286	// Video
287	0, 0, 1, 1, 0, 0, 0, 0,
288	0, 0, 0, 0, 0, 0, 0, 0,
289	0, 0, 0, 0, 0, 0, 0, 0,
290	0, 0, 0, 0, 0, 0, 0, 0,
291	0, 0, 0, 0, 0, 0, 0, 0,
292	0, 0, 0, 0, 0, 0, 0, 0,
293	// Audio
294	1, 1, 1, 0, 1, 0, 1, 0,
295	1, 0, 1, 0, 1, 0, 1, 0,
296	0, 0, 1, 0, 0, 0, 0, 0,
297	1, 1, 1, 1, 1, 1, 1, 1,
298	1, 1, 1, 1, 0, 0, 0, 0,
299	// DMA
300	0, 0, 0, 0, 0, 1, 0, 0,
301	0, 0, 0, 1, 0, 0, 0, 0,
302	0, 1, 0, 0, 0, 0, 0, 1,
303	0, 0, 0, 0, 0, 0, 0, 0,
304	0, 0, 0, 0, 0, 0, 0, 0,
305	// Timers
306	1, 1, 1, 1, 1, 1, 1, 1,
307	0, 0, 0, 0, 0, 0, 0, 0,
308	// SIO
309	1, 1, 1, 1, 1, 0, 0, 0,
310	1, 1, 1, 0, 0, 0, 0, 0,
311	1, 0, 0, 0, 0, 0, 0, 0,
312	1, 0, 1, 0, 1, 0, 0, 0,
313	0, 0, 0, 0, 0, 0, 0, 0,
314	0, 0, 0, 0, 0, 0, 0, 0,
315	0, 0, 0, 0, 0, 0, 0, 0,
316	0, 0, 0, 0, 0, 0, 0, 0,
317	0, 0, 0, 0, 0, 0, 0, 0,
318	0, 0, 0, 0, 0, 0, 0, 0,
319	0, 0, 0, 0, 0, 0, 0, 0,
320	0, 0, 0, 0, 0, 0, 0, 0,
321	0, 0, 0, 0, 0, 0, 0, 0,
322	0, 0, 0, 0, 0, 0, 0, 0,
323	// Interrupts
324	1, 1, 0, 0, 1
325};
326
327void GBAIOInit(struct GBA* gba) {
328	gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
329	gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL;
330	gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
331	gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200;
332	gba->memory.io[REG_BG2PA >> 1] = 0x100;
333	gba->memory.io[REG_BG2PD >> 1] = 0x100;
334	gba->memory.io[REG_BG3PA >> 1] = 0x100;
335	gba->memory.io[REG_BG3PD >> 1] = 0x100;
336
337	if (!gba->biosVf) {
338		gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
339		gba->memory.io[REG_POSTFLG >> 1] = 1;
340	}
341}
342
343void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
344	if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address == REG_DISPCNT)) {
345		value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
346	} else {
347		switch (address) {
348		// Video
349		case REG_DISPSTAT:
350			value &= 0xFFF8;
351			GBAVideoWriteDISPSTAT(&gba->video, value);
352			return;
353
354		case REG_VCOUNT:
355			mLOG(GBA_IO, GAME_ERROR, "Write to read-only I/O register: %03X", address);
356			return;
357
358		// Audio
359		case REG_SOUND1CNT_LO:
360			GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
361			value &= 0x007F;
362			break;
363		case REG_SOUND1CNT_HI:
364			GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
365			break;
366		case REG_SOUND1CNT_X:
367			GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
368			value &= 0x47FF;
369			break;
370		case REG_SOUND2CNT_LO:
371			GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
372			break;
373		case REG_SOUND2CNT_HI:
374			GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
375			value &= 0x47FF;
376			break;
377		case REG_SOUND3CNT_LO:
378			GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
379			value &= 0x00E0;
380			break;
381		case REG_SOUND3CNT_HI:
382			GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
383			value &= 0xE03F;
384			break;
385		case REG_SOUND3CNT_X:
386			GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
387			// TODO: The low bits need to not be readable, but still 8-bit writable
388			value &= 0x47FF;
389			break;
390		case REG_SOUND4CNT_LO:
391			GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
392			value &= 0xFF3F;
393			break;
394		case REG_SOUND4CNT_HI:
395			GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
396			value &= 0x40FF;
397			break;
398		case REG_SOUNDCNT_LO:
399			GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
400			value &= 0xFF77;
401			break;
402		case REG_SOUNDCNT_HI:
403			GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
404			value &= 0x770F;
405			break;
406		case REG_SOUNDCNT_X:
407			GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
408			value &= 0x0080;
409			value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF;
410			break;
411		case REG_SOUNDBIAS:
412			GBAAudioWriteSOUNDBIAS(&gba->audio, value);
413			break;
414
415		case REG_WAVE_RAM0_LO:
416		case REG_WAVE_RAM1_LO:
417		case REG_WAVE_RAM2_LO:
418		case REG_WAVE_RAM3_LO:
419			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
420			break;
421
422		case REG_WAVE_RAM0_HI:
423		case REG_WAVE_RAM1_HI:
424		case REG_WAVE_RAM2_HI:
425		case REG_WAVE_RAM3_HI:
426			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
427			break;
428
429		case REG_FIFO_A_LO:
430		case REG_FIFO_B_LO:
431			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
432			break;
433
434		case REG_FIFO_A_HI:
435		case REG_FIFO_B_HI:
436			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
437			break;
438
439		// DMA
440		case REG_DMA0SAD_LO:
441		case REG_DMA0DAD_LO:
442		case REG_DMA1SAD_LO:
443		case REG_DMA1DAD_LO:
444		case REG_DMA2SAD_LO:
445		case REG_DMA2DAD_LO:
446		case REG_DMA3SAD_LO:
447		case REG_DMA3DAD_LO:
448			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
449			break;
450
451		case REG_DMA0SAD_HI:
452		case REG_DMA0DAD_HI:
453		case REG_DMA1SAD_HI:
454		case REG_DMA1DAD_HI:
455		case REG_DMA2SAD_HI:
456		case REG_DMA2DAD_HI:
457		case REG_DMA3SAD_HI:
458		case REG_DMA3DAD_HI:
459			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
460			break;
461
462		case REG_DMA0CNT_LO:
463			GBADMAWriteCNT_LO(gba, 0, value & 0x3FFF);
464			break;
465		case REG_DMA0CNT_HI:
466			value = GBADMAWriteCNT_HI(gba, 0, value);
467			break;
468		case REG_DMA1CNT_LO:
469			GBADMAWriteCNT_LO(gba, 1, value & 0x3FFF);
470			break;
471		case REG_DMA1CNT_HI:
472			value = GBADMAWriteCNT_HI(gba, 1, value);
473			break;
474		case REG_DMA2CNT_LO:
475			GBADMAWriteCNT_LO(gba, 2, value & 0x3FFF);
476			break;
477		case REG_DMA2CNT_HI:
478			value = GBADMAWriteCNT_HI(gba, 2, value);
479			break;
480		case REG_DMA3CNT_LO:
481			GBADMAWriteCNT_LO(gba, 3, value);
482			break;
483		case REG_DMA3CNT_HI:
484			value = GBADMAWriteCNT_HI(gba, 3, value);
485			break;
486
487		// Timers
488		case REG_TM0CNT_LO:
489			GBATimerWriteTMCNT_LO(gba, 0, value);
490			return;
491		case REG_TM1CNT_LO:
492			GBATimerWriteTMCNT_LO(gba, 1, value);
493			return;
494		case REG_TM2CNT_LO:
495			GBATimerWriteTMCNT_LO(gba, 2, value);
496			return;
497		case REG_TM3CNT_LO:
498			GBATimerWriteTMCNT_LO(gba, 3, value);
499			return;
500
501		case REG_TM0CNT_HI:
502			value &= 0x00C7;
503			GBATimerWriteTMCNT_HI(gba, 0, value);
504			break;
505		case REG_TM1CNT_HI:
506			value &= 0x00C7;
507			GBATimerWriteTMCNT_HI(gba, 1, value);
508			break;
509		case REG_TM2CNT_HI:
510			value &= 0x00C7;
511			GBATimerWriteTMCNT_HI(gba, 2, value);
512			break;
513		case REG_TM3CNT_HI:
514			value &= 0x00C7;
515			GBATimerWriteTMCNT_HI(gba, 3, value);
516			break;
517
518		// SIO
519		case REG_SIOCNT:
520			GBASIOWriteSIOCNT(&gba->sio, value);
521			break;
522		case REG_RCNT:
523			value &= 0xC1FF;
524			GBASIOWriteRCNT(&gba->sio, value);
525			break;
526		case REG_JOY_TRANS_LO:
527		case REG_JOY_TRANS_HI:
528			gba->memory.io[REG_JOYSTAT >> 1] |= JOYSTAT_TRANS_BIT;
529			// Fall through
530		case REG_SIODATA32_LO:
531		case REG_SIODATA32_HI:
532		case REG_SIOMLT_SEND:
533		case REG_JOYCNT:
534		case REG_JOYSTAT:
535		case REG_JOY_RECV_LO:
536		case REG_JOY_RECV_HI:
537			value = GBASIOWriteRegister(&gba->sio, address, value);
538			break;
539
540		// Interrupts and misc
541		case REG_KEYCNT:
542			value &= 0xC3FF;
543			gba->memory.io[address >> 1] = value;
544			GBATestKeypadIRQ(gba);
545			return;
546		case REG_WAITCNT:
547			value &= 0x5FFF;
548			GBAAdjustWaitstates(gba, value);
549			break;
550		case REG_IE:
551			gba->memory.io[REG_IE >> 1] = value;
552			GBATestIRQ(gba, 1);
553			return;
554		case REG_IF:
555			value = gba->memory.io[REG_IF >> 1] & ~value;
556			gba->memory.io[REG_IF >> 1] = value;
557			GBATestIRQ(gba, 1);
558			return;
559		case REG_IME:
560			gba->memory.io[REG_IME >> 1] = value;
561			GBATestIRQ(gba, 1);
562			return;
563		case REG_MAX:
564			// Some bad interrupt libraries will write to this
565			break;
566		case REG_DEBUG_ENABLE:
567			gba->debug = value == 0xC0DE;
568			return;
569		case REG_DEBUG_FLAGS:
570			if (gba->debug) {
571				GBADebug(gba, value);
572				return;
573			}
574			// Fall through
575		default:
576			if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) {
577				STORE_16LE(value, address - REG_DEBUG_STRING, gba->debugString);
578				return;
579			}
580			mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address);
581			if (address >= REG_MAX) {
582				mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address);
583				return;
584			}
585			break;
586		}
587	}
588	gba->memory.io[address >> 1] = value;
589}
590
591void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
592	if (address == REG_HALTCNT) {
593		value &= 0x80;
594		if (!value) {
595			GBAHalt(gba);
596		} else {
597			GBAStop(gba);
598		}
599		return;
600	}
601	if (address == REG_POSTFLG) {
602		gba->memory.io[(address & (SIZE_IO - 1)) >> 1] = value;
603		return;
604	}
605	if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) {
606		gba->debugString[address - REG_DEBUG_STRING] = value;
607		return;
608	}
609	if (address > SIZE_IO) {
610		return;
611	}
612	uint16_t value16 = value << (8 * (address & 1));
613	value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
614	GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
615}
616
617void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
618	switch (address) {
619	case REG_WAVE_RAM0_LO:
620		GBAAudioWriteWaveRAM(&gba->audio, 0, value);
621		break;
622	case REG_WAVE_RAM1_LO:
623		GBAAudioWriteWaveRAM(&gba->audio, 1, value);
624		break;
625	case REG_WAVE_RAM2_LO:
626		GBAAudioWriteWaveRAM(&gba->audio, 2, value);
627		break;
628	case REG_WAVE_RAM3_LO:
629		GBAAudioWriteWaveRAM(&gba->audio, 3, value);
630		break;
631	case REG_FIFO_A_LO:
632	case REG_FIFO_B_LO:
633		GBAAudioWriteFIFO(&gba->audio, address, value);
634		break;
635	case REG_DMA0SAD_LO:
636		value = GBADMAWriteSAD(gba, 0, value);
637		break;
638	case REG_DMA0DAD_LO:
639		value = GBADMAWriteDAD(gba, 0, value);
640		break;
641	case REG_DMA1SAD_LO:
642		value = GBADMAWriteSAD(gba, 1, value);
643		break;
644	case REG_DMA1DAD_LO:
645		value = GBADMAWriteDAD(gba, 1, value);
646		break;
647	case REG_DMA2SAD_LO:
648		value = GBADMAWriteSAD(gba, 2, value);
649		break;
650	case REG_DMA2DAD_LO:
651		value = GBADMAWriteDAD(gba, 2, value);
652		break;
653	case REG_DMA3SAD_LO:
654		value = GBADMAWriteSAD(gba, 3, value);
655		break;
656	case REG_DMA3DAD_LO:
657		value = GBADMAWriteDAD(gba, 3, value);
658		break;
659	default:
660		if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) {
661			STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString);
662			return;
663		}
664		GBAIOWrite(gba, address, value & 0xFFFF);
665		GBAIOWrite(gba, address | 2, value >> 16);
666		return;
667	}
668	gba->memory.io[address >> 1] = value;
669	gba->memory.io[(address >> 1) + 1] = value >> 16;
670}
671
672bool GBAIOIsReadConstant(uint32_t address) {
673	switch (address) {
674	default:
675		return false;
676	case REG_BG0CNT:
677	case REG_BG1CNT:
678	case REG_BG2CNT:
679	case REG_BG3CNT:
680	case REG_WININ:
681	case REG_WINOUT:
682	case REG_BLDCNT:
683	case REG_BLDALPHA:
684	case REG_SOUND1CNT_LO:
685	case REG_SOUND1CNT_HI:
686	case REG_SOUND1CNT_X:
687	case REG_SOUND2CNT_LO:
688	case REG_SOUND2CNT_HI:
689	case REG_SOUND3CNT_LO:
690	case REG_SOUND3CNT_HI:
691	case REG_SOUND3CNT_X:
692	case REG_SOUND4CNT_LO:
693	case REG_SOUND4CNT_HI:
694	case REG_SOUNDCNT_LO:
695	case REG_SOUNDCNT_HI:
696	case REG_TM0CNT_HI:
697	case REG_TM1CNT_HI:
698	case REG_TM2CNT_HI:
699	case REG_TM3CNT_HI:
700	case REG_KEYINPUT:
701	case REG_KEYCNT:
702	case REG_IE:
703		return true;
704	}
705}
706
707uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
708	if (!GBAIOIsReadConstant(address)) {
709		// Most IO reads need to disable idle removal
710		gba->haltPending = false;
711	}
712
713	switch (address) {
714	// Reading this takes two cycles (1N+1I), so let's remove them preemptively
715	case REG_TM0CNT_LO:
716		GBATimerUpdateRegister(gba, 0, 2);
717		break;
718	case REG_TM1CNT_LO:
719		GBATimerUpdateRegister(gba, 1, 2);
720		break;
721	case REG_TM2CNT_LO:
722		GBATimerUpdateRegister(gba, 2, 2);
723		break;
724	case REG_TM3CNT_LO:
725		GBATimerUpdateRegister(gba, 3, 2);
726		break;
727
728	case REG_KEYINPUT: {
729			size_t c;
730			for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
731				struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
732				if (callbacks->keysRead) {
733					callbacks->keysRead(callbacks->context);
734				}
735			}
736			uint16_t input = 0;
737			if (gba->keyCallback) {
738				input = gba->keyCallback->readKeys(gba->keyCallback);
739				if (gba->keySource) {
740					*gba->keySource = input;
741				}
742			} else if (gba->keySource) {
743				input = *gba->keySource;
744				if (!gba->allowOpposingDirections) {
745					unsigned rl = input & 0x030;
746					unsigned ud = input & 0x0C0;
747					input &= 0x30F;
748					if (rl != 0x030) {
749						input |= rl;
750					}
751					if (ud != 0x0C0) {
752						input |= ud;
753					}
754				}
755			}
756			return 0x3FF ^ input;
757		}
758	case REG_SIOCNT:
759		return gba->sio.siocnt;
760	case REG_RCNT:
761		return gba->sio.rcnt;
762
763	case REG_BG0HOFS:
764	case REG_BG0VOFS:
765	case REG_BG1HOFS:
766	case REG_BG1VOFS:
767	case REG_BG2HOFS:
768	case REG_BG2VOFS:
769	case REG_BG3HOFS:
770	case REG_BG3VOFS:
771	case REG_BG2PA:
772	case REG_BG2PB:
773	case REG_BG2PC:
774	case REG_BG2PD:
775	case REG_BG2X_LO:
776	case REG_BG2X_HI:
777	case REG_BG2Y_LO:
778	case REG_BG2Y_HI:
779	case REG_BG3PA:
780	case REG_BG3PB:
781	case REG_BG3PC:
782	case REG_BG3PD:
783	case REG_BG3X_LO:
784	case REG_BG3X_HI:
785	case REG_BG3Y_LO:
786	case REG_BG3Y_HI:
787	case REG_WIN0H:
788	case REG_WIN1H:
789	case REG_WIN0V:
790	case REG_WIN1V:
791	case REG_MOSAIC:
792	case REG_BLDY:
793	case REG_FIFO_A_LO:
794	case REG_FIFO_A_HI:
795	case REG_FIFO_B_LO:
796	case REG_FIFO_B_HI:
797	case REG_DMA0SAD_LO:
798	case REG_DMA0SAD_HI:
799	case REG_DMA0DAD_LO:
800	case REG_DMA0DAD_HI:
801	case REG_DMA1SAD_LO:
802	case REG_DMA1SAD_HI:
803	case REG_DMA1DAD_LO:
804	case REG_DMA1DAD_HI:
805	case REG_DMA2SAD_LO:
806	case REG_DMA2SAD_HI:
807	case REG_DMA2DAD_LO:
808	case REG_DMA2DAD_HI:
809	case REG_DMA3SAD_LO:
810	case REG_DMA3SAD_HI:
811	case REG_DMA3DAD_LO:
812	case REG_DMA3DAD_HI:
813		// Write-only register
814		mLOG(GBA_IO, GAME_ERROR, "Read from write-only I/O register: %03X", address);
815		return GBALoadBad(gba->cpu);
816
817	case REG_DMA0CNT_LO:
818	case REG_DMA1CNT_LO:
819	case REG_DMA2CNT_LO:
820	case REG_DMA3CNT_LO:
821		// Many, many things read from the DMA register
822	case REG_MAX:
823		// Some bad interrupt libraries will read from this
824		// (Silent) write-only register
825		return 0;
826
827	case REG_JOY_RECV_LO:
828	case REG_JOY_RECV_HI:
829		gba->memory.io[REG_JOYSTAT >> 1] &= ~JOYSTAT_RECV_BIT;
830		break;
831
832	case REG_SOUNDBIAS:
833	case REG_POSTFLG:
834		mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address);
835		break;
836	case REG_SOUND1CNT_LO:
837	case REG_SOUND1CNT_HI:
838	case REG_SOUND1CNT_X:
839	case REG_SOUND2CNT_LO:
840	case REG_SOUND2CNT_HI:
841	case REG_SOUND3CNT_LO:
842	case REG_SOUND3CNT_HI:
843	case REG_SOUND3CNT_X:
844	case REG_SOUND4CNT_LO:
845	case REG_SOUND4CNT_HI:
846	case REG_SOUNDCNT_LO:
847		if (!GBAudioEnableIsEnable(gba->memory.io[REG_SOUNDCNT_X >> 1])) {
848			// TODO: Is writing allowed when the circuit is disabled?
849			return 0;
850		}
851		// Fall through
852	case REG_DISPCNT:
853	case REG_DISPSTAT:
854	case REG_VCOUNT:
855	case REG_BG0CNT:
856	case REG_BG1CNT:
857	case REG_BG2CNT:
858	case REG_BG3CNT:
859	case REG_WININ:
860	case REG_WINOUT:
861	case REG_BLDCNT:
862	case REG_BLDALPHA:
863	case REG_SOUNDCNT_HI:
864	case REG_SOUNDCNT_X:
865	case REG_WAVE_RAM0_LO:
866	case REG_WAVE_RAM0_HI:
867	case REG_WAVE_RAM1_LO:
868	case REG_WAVE_RAM1_HI:
869	case REG_WAVE_RAM2_LO:
870	case REG_WAVE_RAM2_HI:
871	case REG_WAVE_RAM3_LO:
872	case REG_WAVE_RAM3_HI:
873	case REG_DMA0CNT_HI:
874	case REG_DMA1CNT_HI:
875	case REG_DMA2CNT_HI:
876	case REG_DMA3CNT_HI:
877	case REG_TM0CNT_HI:
878	case REG_TM1CNT_HI:
879	case REG_TM2CNT_HI:
880	case REG_TM3CNT_HI:
881	case REG_KEYCNT:
882	case REG_SIOMULTI0:
883	case REG_SIOMULTI1:
884	case REG_SIOMULTI2:
885	case REG_SIOMULTI3:
886	case REG_SIOMLT_SEND:
887	case REG_JOYCNT:
888	case REG_JOY_TRANS_LO:
889	case REG_JOY_TRANS_HI:
890	case REG_JOYSTAT:
891	case REG_IE:
892	case REG_IF:
893	case REG_WAITCNT:
894	case REG_IME:
895		// Handled transparently by registers
896		break;
897	case 0x066:
898	case 0x06E:
899	case 0x076:
900	case 0x07A:
901	case 0x07E:
902	case 0x086:
903	case 0x08A:
904	case 0x136:
905	case 0x142:
906	case 0x15A:
907	case 0x206:
908		mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address);
909		return 0;
910	case REG_DEBUG_ENABLE:
911		if (gba->debug) {
912			return 0x1DEA;
913		}
914		// Fall through
915	default:
916		mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address);
917		return GBALoadBad(gba->cpu);
918	}
919	return gba->memory.io[address >> 1];
920}
921
922void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
923	int i;
924	for (i = 0; i < REG_MAX; i += 2) {
925		if (_isRSpecialRegister[i >> 1]) {
926			STORE_16(gba->memory.io[i >> 1], i, state->io);
927		} else if (_isValidRegister[i >> 1]) {
928			uint16_t reg = GBAIORead(gba, i);
929			STORE_16(reg, i, state->io);
930		}
931	}
932
933	for (i = 0; i < 4; ++i) {
934		STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io);
935		STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload);
936		STORE_32(gba->timers[i].lastEvent - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].lastEvent);
937		STORE_32(gba->timers[i].event.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextEvent);
938		STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags);
939		STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
940		STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
941		STORE_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
942		STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
943	}
944
945	STORE_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister);
946	STORE_32(gba->dmaPC, 0, &state->dmaBlockPC);
947
948	GBAHardwareSerialize(&gba->memory.hw, state);
949}
950
951void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
952	int i;
953	for (i = 0; i < REG_MAX; i += 2) {
954		if (_isWSpecialRegister[i >> 1]) {
955			LOAD_16(gba->memory.io[i >> 1], i, state->io);
956		} else if (_isValidRegister[i >> 1]) {
957			uint16_t reg;
958			LOAD_16(reg, i, state->io);
959			GBAIOWrite(gba, i, reg);
960		}
961	}
962
963	uint32_t when;
964	for (i = 0; i < 4; ++i) {
965		LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload);
966		LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags);
967		LOAD_32(when, 0, &state->timers[i].lastEvent);
968		gba->timers[i].lastEvent = when + mTimingCurrentTime(&gba->timing);
969		LOAD_32(when, 0, &state->timers[i].nextEvent);
970		if ((i < 1 || !GBATimerFlagsIsCountUp(gba->timers[i].flags)) && GBATimerFlagsIsEnable(gba->timers[i].flags)) {
971			mTimingSchedule(&gba->timing, &gba->timers[i].event, when);
972		} else {
973			gba->timers[i].event.when = when + mTimingCurrentTime(&gba->timing);
974		}
975
976		LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);
977		LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource);
978		LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);
979		LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
980		LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
981	}
982	GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
983	gba->sio.siocnt = gba->memory.io[REG_SIOCNT >> 1];
984	GBASIOWriteRCNT(&gba->sio, gba->memory.io[REG_RCNT >> 1]);
985
986	LOAD_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister);
987	LOAD_32(gba->dmaPC, 0, &state->dmaBlockPC);
988
989	GBADMAUpdate(gba);
990	GBAHardwareDeserialize(&gba->memory.hw, state);
991}