all repos — mgba @ 728f6481d62463360fd6f6841535733203b7dc8e

mGBA Game Boy Advance Emulator

src/gba/gba-io.c (view raw)

  1#include "gba-io.h"
  2
  3#include "gba-serialize.h"
  4#include "gba-video.h"
  5
  6static const int _isValidRegister[REG_MAX >> 1] = {
  7	// Video
  8	1, 0, 1, 1, 1, 1, 1, 1,
  9	1, 1, 1, 1, 1, 1, 1, 1,
 10	1, 1, 1, 1, 1, 1, 1, 1,
 11	1, 1, 1, 1, 1, 1, 1, 1,
 12	1, 1, 1, 1, 1, 1, 1, 0,
 13	1, 1, 1, 0, 0, 0, 0, 0,
 14	// Audio
 15	1, 1, 1, 0, 1, 0, 1, 0,
 16	1, 1, 1, 0, 1, 0, 1, 0,
 17	1, 1, 1, 0, 1, 0, 0, 0,
 18	1, 1, 1, 1, 1, 1, 1, 1,
 19	1, 1, 1, 1, 0, 0, 0, 0,
 20	// DMA
 21	1, 1, 1, 1, 1, 1, 1, 1,
 22	1, 1, 1, 1, 1, 1, 1, 1,
 23	1, 1, 1, 1, 1, 1, 1, 1,
 24	0, 0, 0, 0, 0, 0, 0, 0,
 25	0, 0, 0, 0, 0, 0, 0, 0,
 26	// Timers
 27	1, 1, 1, 1, 1, 1, 1, 1,
 28	0, 0, 0, 0, 0, 0, 0, 0,
 29	// SIO
 30	1, 1, 1, 1, 1, 0, 0, 0,
 31	1, 1, 1, 0, 0, 0, 0, 0,
 32	1, 0, 0, 0, 0, 0, 0, 0,
 33	1, 0, 1, 0, 1, 0, 0, 0,
 34	0, 0, 0, 0, 0, 0, 0, 0,
 35	0, 0, 0, 0, 0, 0, 0, 0,
 36	0, 0, 0, 0, 0, 0, 0, 0,
 37	0, 0, 0, 0, 0, 0, 0, 0,
 38	0, 0, 0, 0, 0, 0, 0, 0,
 39	0, 0, 0, 0, 0, 0, 0, 0,
 40	0, 0, 0, 0, 0, 0, 0, 0,
 41	0, 0, 0, 0, 0, 0, 0, 0,
 42	0, 0, 0, 0, 0, 0, 0, 0,
 43	0, 0, 0, 0, 0, 0, 0, 0,
 44	// Interrupts
 45	1, 1, 1, 0, 1
 46};
 47
 48static const int _isSpecialRegister[REG_MAX >> 1] = {
 49	// Video
 50	0, 0, 0, 1, 0, 0, 0, 0,
 51	0, 0, 0, 0, 0, 0, 0, 0,
 52	0, 0, 0, 0, 0, 0, 0, 0,
 53	0, 0, 0, 0, 0, 0, 0, 0,
 54	0, 0, 0, 0, 0, 0, 0, 0,
 55	0, 0, 0, 0, 0, 0, 0, 0,
 56	// Audio
 57	0, 0, 0, 0, 0, 0, 0, 0,
 58	0, 0, 0, 0, 0, 0, 0, 0,
 59	0, 0, 0, 0, 0, 0, 0, 0,
 60	1, 1, 1, 1, 1, 1, 1, 1,
 61	1, 1, 1, 1, 0, 0, 0, 0,
 62	// DMA
 63	1, 1, 1, 1, 1, 1, 1, 1,
 64	1, 1, 1, 1, 1, 1, 1, 1,
 65	1, 1, 1, 1, 1, 1, 1, 1,
 66	0, 0, 0, 0, 0, 0, 0, 0,
 67	0, 0, 0, 0, 0, 0, 0, 0,
 68	// Timers
 69	1, 1, 1, 1, 1, 1, 1, 1,
 70	0, 0, 0, 0, 0, 0, 0, 0,
 71	// SIO
 72	1, 1, 1, 1, 1, 0, 0, 0,
 73	1, 1, 1, 0, 0, 0, 0, 0,
 74	1, 0, 0, 0, 0, 0, 0, 0,
 75	1, 0, 1, 0, 1, 0, 0, 0,
 76	0, 0, 0, 0, 0, 0, 0, 0,
 77	0, 0, 0, 0, 0, 0, 0, 0,
 78	0, 0, 0, 0, 0, 0, 0, 0,
 79	0, 0, 0, 0, 0, 0, 0, 0,
 80	0, 0, 0, 0, 0, 0, 0, 0,
 81	0, 0, 0, 0, 0, 0, 0, 0,
 82	0, 0, 0, 0, 0, 0, 0, 0,
 83	0, 0, 0, 0, 0, 0, 0, 0,
 84	0, 0, 0, 0, 0, 0, 0, 0,
 85	0, 0, 0, 0, 0, 0, 0, 0,
 86	// Interrupts
 87	1, 1, 1, 0, 1
 88};
 89
 90void GBAIOInit(struct GBA* gba) {
 91	gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
 92	gba->memory.io[REG_RCNT >> 1] = 0x8000;
 93	gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
 94}
 95
 96void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
 97	if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
 98		value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
 99	} else {
100		switch (address) {
101		// Video
102		case REG_DISPSTAT:
103			value &= 0xFFF8;
104			GBAVideoWriteDISPSTAT(&gba->video, value);
105			break;
106
107		// Audio
108		case REG_SOUND1CNT_LO:
109			GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
110			value &= 0x00FF;
111			break;
112		case REG_SOUND1CNT_HI:
113			GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
114			break;
115		case REG_SOUND1CNT_X:
116			GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
117			value &= 0x47FF;
118			break;
119		case REG_SOUND2CNT_LO:
120			GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
121			break;
122		case REG_SOUND2CNT_HI:
123			GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
124			value &= 0x47FF;
125			break;
126		case REG_SOUND3CNT_LO:
127			GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
128			value &= 0x00E0;
129			break;
130		case REG_SOUND3CNT_HI:
131			GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
132			value &= 0xE000;
133			break;
134		case REG_SOUND3CNT_X:
135			GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
136			value &= 0x4000;
137			break;
138		case REG_SOUND4CNT_LO:
139			GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
140			value &= 0xFF00;
141			break;
142		case REG_SOUND4CNT_HI:
143			GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
144			value &= 0x40FF;
145			break;
146		case REG_SOUNDCNT_LO:
147			GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
148			break;
149		case REG_SOUNDCNT_HI:
150			GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
151			break;
152		case REG_SOUNDCNT_X:
153			GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
154			break;
155
156		case REG_WAVE_RAM0_LO:
157		case REG_WAVE_RAM1_LO:
158		case REG_WAVE_RAM2_LO:
159		case REG_WAVE_RAM3_LO:
160		case REG_FIFO_A_LO:
161		case REG_FIFO_B_LO:
162			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
163			break;
164
165		case REG_WAVE_RAM0_HI:
166		case REG_WAVE_RAM1_HI:
167		case REG_WAVE_RAM2_HI:
168		case REG_WAVE_RAM3_HI:
169		case REG_FIFO_A_HI:
170		case REG_FIFO_B_HI:
171			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
172			break;
173
174		// DMA
175		case REG_DMA0SAD_LO:
176		case REG_DMA0DAD_LO:
177		case REG_DMA1SAD_LO:
178		case REG_DMA1DAD_LO:
179		case REG_DMA2SAD_LO:
180		case REG_DMA2DAD_LO:
181		case REG_DMA3SAD_LO:
182		case REG_DMA3DAD_LO:
183			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
184			break;
185
186		case REG_DMA0SAD_HI:
187		case REG_DMA0DAD_HI:
188		case REG_DMA1SAD_HI:
189		case REG_DMA1DAD_HI:
190		case REG_DMA2SAD_HI:
191		case REG_DMA2DAD_HI:
192		case REG_DMA3SAD_HI:
193		case REG_DMA3DAD_HI:
194			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
195			break;
196
197		case REG_DMA0CNT_LO:
198			GBAMemoryWriteDMACNT_LO(&gba->memory, 0, value);
199			break;
200		case REG_DMA0CNT_HI:
201			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 0, value);
202			break;
203		case REG_DMA1CNT_LO:
204			GBAMemoryWriteDMACNT_LO(&gba->memory, 1, value);
205			break;
206		case REG_DMA1CNT_HI:
207			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 1, value);
208			break;
209		case REG_DMA2CNT_LO:
210			GBAMemoryWriteDMACNT_LO(&gba->memory, 2, value);
211			break;
212		case REG_DMA2CNT_HI:
213			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 2, value);
214			break;
215		case REG_DMA3CNT_LO:
216			GBAMemoryWriteDMACNT_LO(&gba->memory, 3, value);
217			break;
218		case REG_DMA3CNT_HI:
219			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 3, value);
220			break;
221
222		// Timers
223		case REG_TM0CNT_LO:
224			GBATimerWriteTMCNT_LO(gba, 0, value);
225			return;
226		case REG_TM1CNT_LO:
227			GBATimerWriteTMCNT_LO(gba, 1, value);
228			return;
229		case REG_TM2CNT_LO:
230			GBATimerWriteTMCNT_LO(gba, 2, value);
231			return;
232		case REG_TM3CNT_LO:
233			GBATimerWriteTMCNT_LO(gba, 3, value);
234			return;
235
236		case REG_TM0CNT_HI:
237			value &= 0x00C7;
238			GBATimerWriteTMCNT_HI(gba, 0, value);
239			break;
240		case REG_TM1CNT_HI:
241			value &= 0x00C7;
242			GBATimerWriteTMCNT_HI(gba, 1, value);
243			break;
244		case REG_TM2CNT_HI:
245			value &= 0x00C7;
246			GBATimerWriteTMCNT_HI(gba, 2, value);
247			break;
248		case REG_TM3CNT_HI:
249			value &= 0x00C7;
250			GBATimerWriteTMCNT_HI(gba, 3, value);
251			break;
252
253		// Interrupts and misc
254		case REG_WAITCNT:
255			GBAAdjustWaitstates(&gba->memory, value);
256			break;
257		case REG_IE:
258			GBAWriteIE(gba, value);
259			break;
260		case REG_IF:
261			value = gba->memory.io[REG_IF >> 1] & ~value;
262			break;
263		case REG_IME:
264			GBAWriteIME(gba, value);
265			break;
266		case 0x20A:
267			// Some bad interrupt libraries will write to this
268			break;
269		default:
270			GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
271			break;
272		}
273	}
274	gba->memory.io[address >> 1] = value;
275}
276
277void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
278	if (address == REG_HALTCNT) {
279		value &= 0x80;
280		if (!value) {
281			GBAHalt(gba);
282		} else {
283			GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
284		}
285		return;
286	}
287	uint16_t value16 = value << (8 * (address & 1));
288	value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
289	GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
290}
291
292void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
293	switch (address) {
294	case REG_WAVE_RAM0_LO:
295		GBAAudioWriteWaveRAM(&gba->audio, 0, value);
296		break;
297	case REG_WAVE_RAM1_LO:
298		GBAAudioWriteWaveRAM(&gba->audio, 1, value);
299		break;
300	case REG_WAVE_RAM2_LO:
301		GBAAudioWriteWaveRAM(&gba->audio, 2, value);
302		break;
303	case REG_WAVE_RAM3_LO:
304		GBAAudioWriteWaveRAM(&gba->audio, 3, value);
305		break;
306	case REG_FIFO_A_LO:
307	case REG_FIFO_B_LO:
308		GBAAudioWriteFIFO(&gba->audio, address, value);
309		break;
310	case REG_DMA0SAD_LO:
311		GBAMemoryWriteDMASAD(&gba->memory, 0, value);
312		break;
313	case REG_DMA0DAD_LO:
314		GBAMemoryWriteDMADAD(&gba->memory, 0, value);
315		break;
316	case REG_DMA1SAD_LO:
317		GBAMemoryWriteDMASAD(&gba->memory, 1, value);
318		break;
319	case REG_DMA1DAD_LO:
320		GBAMemoryWriteDMADAD(&gba->memory, 1, value);
321		break;
322	case REG_DMA2SAD_LO:
323		GBAMemoryWriteDMASAD(&gba->memory, 2, value);
324		break;
325	case REG_DMA2DAD_LO:
326		GBAMemoryWriteDMADAD(&gba->memory, 2, value);
327		break;
328	case REG_DMA3SAD_LO:
329		GBAMemoryWriteDMASAD(&gba->memory, 3, value);
330		break;
331	case REG_DMA3DAD_LO:
332		GBAMemoryWriteDMADAD(&gba->memory, 3, value);
333		break;
334	default:
335		GBAIOWrite(gba, address, value & 0xFFFF);
336		GBAIOWrite(gba, address | 2, value >> 16);
337		return;
338	}
339	gba->memory.io[address >> 1] = value;
340	gba->memory.io[(address >> 1) + 1] = value >> 16;
341}
342
343uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
344	switch (address) {
345	case REG_DISPSTAT:
346		return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
347		break;
348
349	case REG_TM0CNT_LO:
350		GBATimerUpdateRegister(gba, 0);
351		break;
352	case REG_TM1CNT_LO:
353		GBATimerUpdateRegister(gba, 1);
354		break;
355	case REG_TM2CNT_LO:
356		GBATimerUpdateRegister(gba, 2);
357		break;
358	case REG_TM3CNT_LO:
359		GBATimerUpdateRegister(gba, 3);
360		break;
361
362	case REG_KEYINPUT:
363		if (gba->keySource) {
364			return 0x3FF ^ *gba->keySource;
365		}
366		break;
367
368	case REG_DMA0CNT_LO:
369	case REG_DMA1CNT_LO:
370	case REG_DMA2CNT_LO:
371	case REG_DMA3CNT_LO:
372		// Write-only register
373		return 0;
374	case REG_DISPCNT:
375	case REG_VCOUNT:
376	case REG_BG0CNT:
377	case REG_BG1CNT:
378	case REG_BG2CNT:
379	case REG_BG3CNT:
380	case REG_WININ:
381	case REG_WINOUT:
382	case REG_BLDCNT:
383	case REG_SOUND1CNT_LO:
384	case REG_SOUND1CNT_HI:
385	case REG_SOUND1CNT_X:
386	case REG_SOUND2CNT_LO:
387	case REG_SOUND2CNT_HI:
388	case REG_SOUND3CNT_LO:
389	case REG_SOUND3CNT_HI:
390	case REG_SOUND3CNT_X:
391	case REG_SOUND4CNT_LO:
392	case REG_SOUND4CNT_HI:
393	case REG_SOUNDCNT_LO:
394	case REG_SOUNDCNT_HI:
395	case REG_DMA0CNT_HI:
396	case REG_DMA1CNT_HI:
397	case REG_DMA2CNT_HI:
398	case REG_DMA3CNT_HI:
399	case REG_IE:
400	case REG_IF:
401	case REG_WAITCNT:
402	case REG_IME:
403		// Handled transparently by registers
404		break;
405	case 0x20A:
406		// Some bad interrupt libraries will read from this
407		break;
408	default:
409		GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
410		break;
411	}
412	return gba->memory.io[address >> 1];
413}
414
415void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
416	int i;
417	for (i = 0; i < REG_MAX; i += 2) {
418		if (_isSpecialRegister[i >> 1]) {
419			state->io[i >> 1] = gba->memory.io[i >> 1];
420		} else if (_isValidRegister[i >> 1]) {
421			state->io[i >> 1] = GBAIORead(gba, i);
422		}
423	}
424}
425
426void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
427	// TODO: Actually fill this out
428	int i;
429	for (i = 0; i < REG_MAX; i += 2) {
430		if (_isSpecialRegister[i >> 1]) {
431			gba->memory.io[i >> 1] = state->io[i >> 1];
432		} else if (_isValidRegister[i >> 1]) {
433			GBAIOWrite(gba, i, state->io[i >> 1]);
434		}
435	}
436}