all repos — mgba @ 02cb9c56c58e2c69846a90a15a8580e9c03439a9

mGBA Game Boy Advance Emulator

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

  1#include "gba-io.h"
  2
  3#include "gba-video.h"
  4
  5void GBAIOInit(struct GBA* gba) {
  6	gba->memory.io[REG_DISPCNT >> 1] = 0x0080;
  7	gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF;
  8}
  9
 10void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
 11	if (address < REG_SOUND1CNT_LO && address != REG_DISPSTAT) {
 12		gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
 13	} else {
 14		switch (address) {
 15		// Video
 16		case REG_DISPSTAT:
 17			GBAVideoWriteDISPSTAT(&gba->video, value);
 18			break;
 19
 20		// DMA
 21		case REG_DMA0SAD_LO:
 22		case REG_DMA0DAD_LO:
 23		case REG_DMA1SAD_LO:
 24		case REG_DMA1DAD_LO:
 25		case REG_DMA2SAD_LO:
 26		case REG_DMA2DAD_LO:
 27		case REG_DMA3SAD_LO:
 28		case REG_DMA3DAD_LO:
 29			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
 30			break;
 31
 32		case REG_DMA0SAD_HI:
 33		case REG_DMA0DAD_HI:
 34		case REG_DMA1SAD_HI:
 35		case REG_DMA1DAD_HI:
 36		case REG_DMA2SAD_HI:
 37		case REG_DMA2DAD_HI:
 38		case REG_DMA3SAD_HI:
 39		case REG_DMA3DAD_HI:
 40			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
 41			break;
 42
 43		case REG_DMA0CNT_LO:
 44			GBAMemoryWriteDMACNT_LO(&gba->memory, 0, value);
 45			break;
 46		case REG_DMA0CNT_HI:
 47			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 0, value);
 48			break;
 49		case REG_DMA1CNT_LO:
 50			GBAMemoryWriteDMACNT_LO(&gba->memory, 1, value);
 51			break;
 52		case REG_DMA1CNT_HI:
 53			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 1, value);
 54			break;
 55		case REG_DMA2CNT_LO:
 56			GBAMemoryWriteDMACNT_LO(&gba->memory, 2, value);
 57			break;
 58		case REG_DMA2CNT_HI:
 59			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 2, value);
 60			break;
 61		case REG_DMA3CNT_LO:
 62			GBAMemoryWriteDMACNT_LO(&gba->memory, 3, value);
 63			break;
 64		case REG_DMA3CNT_HI:
 65			value = GBAMemoryWriteDMACNT_HI(&gba->memory, 3, value);
 66			break;
 67
 68		// Timers
 69		case REG_TM0CNT_LO:
 70			GBATimerWriteTMCNT_LO(gba, 0, value);
 71			return;
 72		case REG_TM1CNT_LO:
 73			GBATimerWriteTMCNT_LO(gba, 1, value);
 74			return;
 75		case REG_TM2CNT_LO:
 76			GBATimerWriteTMCNT_LO(gba, 2, value);
 77			return;
 78		case REG_TM3CNT_LO:
 79			GBATimerWriteTMCNT_LO(gba, 3, value);
 80			return;
 81
 82		case REG_TM0CNT_HI:
 83			value &= 0x00C7;
 84			GBATimerWriteTMCNT_HI(gba, 0, value);
 85			break;
 86		case REG_TM1CNT_HI:
 87			value &= 0x00C7;
 88			GBATimerWriteTMCNT_HI(gba, 1, value);
 89			break;
 90		case REG_TM2CNT_HI:
 91			value &= 0x00C7;
 92			GBATimerWriteTMCNT_HI(gba, 2, value);
 93			break;
 94		case REG_TM3CNT_HI:
 95			value &= 0x00C7;
 96			GBATimerWriteTMCNT_HI(gba, 3, value);
 97			break;
 98
 99		// Interrupts and misc
100		case REG_WAITCNT:
101			GBAAdjustWaitstates(&gba->memory, value);
102			break;
103		case REG_IE:
104			GBAWriteIE(gba, value);
105			break;
106		case REG_IF:
107			value = gba->memory.io[REG_IF >> 1] & ~value;
108			break;
109		case REG_IME:
110			GBAWriteIME(gba, value);
111			break;
112		default:
113			GBALog(GBA_LOG_STUB, "Stub I/O register write: %03x", address);
114			break;
115		}
116	}
117	gba->memory.io[address >> 1] = value;
118}
119
120void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) {
121	if (address == REG_HALTCNT) {
122		value &= 0x80;
123		if (!value) {
124			GBAHalt(gba);
125		} else {
126			GBALog(GBA_LOG_STUB, "Stop unimplemented");
127		}
128		return;
129	}
130	value <<= 8 * (address & 1);
131	value |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1)));
132	GBAIOWrite(gba, address, value);
133}
134
135void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {
136	switch (address) {
137	case REG_DMA0SAD_LO:
138		GBAMemoryWriteDMASAD(&gba->memory, 0, value);
139		break;
140	case REG_DMA0DAD_LO:
141		GBAMemoryWriteDMADAD(&gba->memory, 0, value);
142		break;
143	case REG_DMA1SAD_LO:
144		GBAMemoryWriteDMASAD(&gba->memory, 1, value);
145		break;
146	case REG_DMA1DAD_LO:
147		GBAMemoryWriteDMADAD(&gba->memory, 1, value);
148		break;
149	case REG_DMA2SAD_LO:
150		GBAMemoryWriteDMASAD(&gba->memory, 2, value);
151		break;
152	case REG_DMA2DAD_LO:
153		GBAMemoryWriteDMADAD(&gba->memory, 2, value);
154		break;
155	case REG_DMA3SAD_LO:
156		GBAMemoryWriteDMASAD(&gba->memory, 3, value);
157		break;
158	case REG_DMA3DAD_LO:
159		GBAMemoryWriteDMADAD(&gba->memory, 3, value);
160		break;
161	default:
162		GBAIOWrite(gba, address, value & 0xFFFF);
163		GBAIOWrite(gba, address | 2, value >> 16);
164		return;
165	}
166	gba->memory.io[address >> 1] = value;
167	gba->memory.io[(address >> 1) + 1] = value >> 16;
168}
169
170uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
171	switch (address) {
172	case REG_DISPSTAT:
173		return gba->memory.io[REG_DISPSTAT >> 1] | GBAVideoReadDISPSTAT(&gba->video);
174		break;
175
176	case REG_TM0CNT_LO:
177		GBATimerUpdateRegister(gba, 0);
178		break;
179	case REG_TM1CNT_LO:
180		GBATimerUpdateRegister(gba, 1);
181		break;
182	case REG_TM2CNT_LO:
183		GBATimerUpdateRegister(gba, 2);
184		break;
185	case REG_TM3CNT_LO:
186		GBATimerUpdateRegister(gba, 3);
187		break;
188
189	case REG_KEYINPUT:
190		if (gba->keySource) {
191			return 0x3FF ^ *gba->keySource;
192		}
193		break;
194
195	case REG_DMA0CNT_LO:
196	case REG_DMA1CNT_LO:
197	case REG_DMA2CNT_LO:
198	case REG_DMA3CNT_LO:
199		// Write-only register
200		return 0;
201	case REG_VCOUNT:
202	case REG_DMA0CNT_HI:
203	case REG_DMA1CNT_HI:
204	case REG_DMA2CNT_HI:
205	case REG_DMA3CNT_HI:
206	case REG_IE:
207	case REG_IF:
208	case REG_WAITCNT:
209	case REG_IME:
210		// Handled transparently by registers
211		break;
212	default:
213		GBALog(GBA_LOG_STUB, "Stub I/O register read: %03x", address);
214		break;
215	}
216	return gba->memory.io[address >> 1];
217}