all repos — mgba @ e5ee1aa07f0f7bffe86ddda36747b5480964e9fe

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
263		// Interrupts and misc
264		case REG_WAITCNT:
265			GBAAdjustWaitstates(&gba->memory, value);
266			break;
267		case REG_IE:
268			GBAWriteIE(gba, value);
269			break;
270		case REG_IF:
271			value = gba->memory.io[REG_IF >> 1] & ~value;
272			break;
273		case REG_IME:
274			GBAWriteIME(gba, value);
275			break;
276		case REG_MAX:
277			// Some bad interrupt libraries will write to this
278			break;
279		default:
280			GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address);
281			break;
282		}
283	}
284	gba->memory.io[address >> 1] = value;
285}
286
287void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
288	if (address == REG_HALTCNT) {
289		value &= 0x80;
290		if (!value) {
291			GBAHalt(gba);
292		} else {
293			GBALog(gba, GBA_LOG_STUB, "Stop unimplemented");
294		}
295		return;
296	}
297	uint16_t value16 = value << (8 * (address & 1));
298	value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
299	GBAIOWrite(gba, address & 0xFFFFFFFE, value16);
300}
301
302void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
303	switch (address) {
304	case REG_WAVE_RAM0_LO:
305		GBAAudioWriteWaveRAM(&gba->audio, 0, value);
306		break;
307	case REG_WAVE_RAM1_LO:
308		GBAAudioWriteWaveRAM(&gba->audio, 1, value);
309		break;
310	case REG_WAVE_RAM2_LO:
311		GBAAudioWriteWaveRAM(&gba->audio, 2, value);
312		break;
313	case REG_WAVE_RAM3_LO:
314		GBAAudioWriteWaveRAM(&gba->audio, 3, value);
315		break;
316	case REG_FIFO_A_LO:
317	case REG_FIFO_B_LO:
318		GBAAudioWriteFIFO(&gba->audio, address, value);
319		break;
320	case REG_DMA0SAD_LO:
321		GBAMemoryWriteDMASAD(&gba->memory, 0, value);
322		break;
323	case REG_DMA0DAD_LO:
324		GBAMemoryWriteDMADAD(&gba->memory, 0, value);
325		break;
326	case REG_DMA1SAD_LO:
327		GBAMemoryWriteDMASAD(&gba->memory, 1, value);
328		break;
329	case REG_DMA1DAD_LO:
330		GBAMemoryWriteDMADAD(&gba->memory, 1, value);
331		break;
332	case REG_DMA2SAD_LO:
333		GBAMemoryWriteDMASAD(&gba->memory, 2, value);
334		break;
335	case REG_DMA2DAD_LO:
336		GBAMemoryWriteDMADAD(&gba->memory, 2, value);
337		break;
338	case REG_DMA3SAD_LO:
339		GBAMemoryWriteDMASAD(&gba->memory, 3, value);
340		break;
341	case REG_DMA3DAD_LO:
342		GBAMemoryWriteDMADAD(&gba->memory, 3, value);
343		break;
344	default:
345		GBAIOWrite(gba, address, value & 0xFFFF);
346		GBAIOWrite(gba, address | 2, value >> 16);
347		return;
348	}
349	gba->memory.io[address >> 1] = value;
350	gba->memory.io[(address >> 1) + 1] = value >> 16;
351}
352
353uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
354	switch (address) {
355	case REG_DISPSTAT:
356		return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
357		break;
358
359	case REG_TM0CNT_LO:
360		GBATimerUpdateRegister(gba, 0);
361		break;
362	case REG_TM1CNT_LO:
363		GBATimerUpdateRegister(gba, 1);
364		break;
365	case REG_TM2CNT_LO:
366		GBATimerUpdateRegister(gba, 2);
367		break;
368	case REG_TM3CNT_LO:
369		GBATimerUpdateRegister(gba, 3);
370		break;
371
372	case REG_KEYINPUT:
373		if (gba->keySource) {
374			return 0x3FF ^ *gba->keySource;
375		}
376		break;
377
378	case REG_DMA0CNT_LO:
379	case REG_DMA1CNT_LO:
380	case REG_DMA2CNT_LO:
381	case REG_DMA3CNT_LO:
382		// Write-only register
383		return 0;
384	case REG_DISPCNT:
385	case REG_VCOUNT:
386	case REG_BG0CNT:
387	case REG_BG1CNT:
388	case REG_BG2CNT:
389	case REG_BG3CNT:
390	case REG_WININ:
391	case REG_WINOUT:
392	case REG_BLDCNT:
393	case REG_SOUND1CNT_LO:
394	case REG_SOUND1CNT_HI:
395	case REG_SOUND1CNT_X:
396	case REG_SOUND2CNT_LO:
397	case REG_SOUND2CNT_HI:
398	case REG_SOUND3CNT_LO:
399	case REG_SOUND3CNT_HI:
400	case REG_SOUND3CNT_X:
401	case REG_SOUND4CNT_LO:
402	case REG_SOUND4CNT_HI:
403	case REG_SOUNDCNT_LO:
404	case REG_SOUNDCNT_HI:
405	case REG_DMA0CNT_HI:
406	case REG_DMA1CNT_HI:
407	case REG_DMA2CNT_HI:
408	case REG_DMA3CNT_HI:
409	case REG_IE:
410	case REG_IF:
411	case REG_WAITCNT:
412	case REG_IME:
413		// Handled transparently by registers
414		break;
415	case REG_MAX:
416		// Some bad interrupt libraries will read from this
417		break;
418	default:
419		GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address);
420		break;
421	}
422	return gba->memory.io[address >> 1];
423}
424
425void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
426	int i;
427	for (i = 0; i < REG_MAX; i += 2) {
428		if (_isSpecialRegister[i >> 1]) {
429			state->io[i >> 1] = gba->memory.io[i >> 1];
430		} else if (_isValidRegister[i >> 1]) {
431			state->io[i >> 1] = GBAIORead(gba, i);
432		}
433	}
434
435	for (i = 0; i < 4; ++i) {
436		state->dma[i].nextSource = gba->memory.dma[i].nextSource;
437		state->dma[i].nextDest = gba->memory.dma[i].nextDest;
438		state->dma[i].nextCount = gba->memory.dma[i].nextCount;
439		state->dma[i].nextEvent = gba->memory.dma[i].nextEvent;
440	}
441
442	memcpy(state->timers, gba->timers, sizeof(state->timers));
443}
444
445void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
446	int i;
447	for (i = 0; i < REG_MAX; i += 2) {
448		if (_isSpecialRegister[i >> 1]) {
449			gba->memory.io[i >> 1] = state->io[i >> 1];
450		} else if (_isValidRegister[i >> 1]) {
451			GBAIOWrite(gba, i, state->io[i >> 1]);
452		}
453	}
454
455	for (i = 0; i < 4; ++i) {
456		gba->memory.dma[i].nextSource = state->dma[i].nextSource;
457		gba->memory.dma[i].nextDest = state->dma[i].nextDest;
458		gba->memory.dma[i].nextCount = state->dma[i].nextCount;
459		gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
460	}
461
462	memcpy(state->timers, gba->timers, sizeof(gba->timers));
463}