all repos — mgba @ 5a1a04a353c1b7a93791a7bf0dfc471d645efdaf

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