all repos — mgba @ eb5580f719aac6d7f08186bf2a079c446e05c92f

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