1 /* Copyright (c) 2013-2015 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <mgba/internal/gba/dma.h>
7 
8 #include <mgba/internal/gba/gba.h>
9 #include <mgba/internal/gba/io.h>
10 
11 static void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate);
12 
13 static void GBADMAService(struct GBA* gba, int number, struct GBADMA* info);
14 
15 static const int DMA_OFFSET[] = { 1, -1, 0, 1 };
16 
GBADMAInit(struct GBA * gba)17 void GBADMAInit(struct GBA* gba) {
18 	gba->memory.dmaEvent.name = "GBA DMA";
19 	gba->memory.dmaEvent.callback = _dmaEvent;
20 	gba->memory.dmaEvent.context = gba;
21 	gba->memory.dmaEvent.priority = 0x40;
22 }
23 
GBADMAReset(struct GBA * gba)24 void GBADMAReset(struct GBA* gba) {
25 	memset(gba->memory.dma, 0, sizeof(gba->memory.dma));
26 	int i;
27 	for (i = 0; i < 4; ++i) {
28 		gba->memory.dma[i].count = 0x4000;
29 	}
30 	gba->memory.dma[3].count = 0x10000;
31 	gba->memory.activeDMA = -1;
32 }
_isValidDMASAD(int dma,uint32_t address)33 static bool _isValidDMASAD(int dma, uint32_t address) {
34 	if (dma == 0 && address >= BASE_CART0 && address < BASE_CART_SRAM) {
35 		return false;
36 	}
37 	return address >= BASE_WORKING_RAM;
38 }
39 
_isValidDMADAD(int dma,uint32_t address)40 static bool _isValidDMADAD(int dma, uint32_t address) {
41 	return dma == 3 || address < BASE_CART0;
42 }
43 
GBADMAWriteSAD(struct GBA * gba,int dma,uint32_t address)44 uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address) {
45 	struct GBAMemory* memory = &gba->memory;
46 	address &= 0x0FFFFFFE;
47 	if (_isValidDMASAD(dma, address)) {
48 		memory->dma[dma].source = address;
49 	} else {
50 		memory->dma[dma].source = 0;
51 	}
52 	return memory->dma[dma].source;
53 }
54 
GBADMAWriteDAD(struct GBA * gba,int dma,uint32_t address)55 uint32_t GBADMAWriteDAD(struct GBA* gba, int dma, uint32_t address) {
56 	struct GBAMemory* memory = &gba->memory;
57 	address &= 0x0FFFFFFE;
58 	if (_isValidDMADAD(dma, address)) {
59 		memory->dma[dma].dest = address;
60 	}
61 	return memory->dma[dma].dest;
62 }
63 
GBADMAWriteCNT_LO(struct GBA * gba,int dma,uint16_t count)64 void GBADMAWriteCNT_LO(struct GBA* gba, int dma, uint16_t count) {
65 	struct GBAMemory* memory = &gba->memory;
66 	memory->dma[dma].count = count ? count : (dma == 3 ? 0x10000 : 0x4000);
67 }
68 
GBADMAWriteCNT_HI(struct GBA * gba,int dma,uint16_t control)69 uint16_t GBADMAWriteCNT_HI(struct GBA* gba, int dma, uint16_t control) {
70 	struct GBAMemory* memory = &gba->memory;
71 	struct GBADMA* currentDma = &memory->dma[dma];
72 	int wasEnabled = GBADMARegisterIsEnable(currentDma->reg);
73 	if (dma < 3) {
74 		control &= 0xF7E0;
75 	} else {
76 		control &= 0xFFE0;
77 	}
78 	currentDma->reg = control;
79 
80 	if (GBADMARegisterIsDRQ(currentDma->reg)) {
81 		mLOG(GBA_MEM, STUB, "DRQ not implemented");
82 	}
83 
84 	if (!wasEnabled && GBADMARegisterIsEnable(currentDma->reg)) {
85 		currentDma->nextSource = currentDma->source;
86 		if (currentDma->nextSource >= BASE_CART0 && currentDma->nextSource < BASE_CART_SRAM && GBADMARegisterGetSrcControl(currentDma->reg) < 3) {
87 			currentDma->reg = GBADMARegisterClearSrcControl(currentDma->reg);
88 		}
89 		currentDma->nextDest = currentDma->dest;
90 
91 		uint32_t width = 2 << GBADMARegisterGetWidth(currentDma->reg);
92 		if (currentDma->nextSource & (width - 1)) {
93 			mLOG(GBA_MEM, GAME_ERROR, "Misaligned DMA source address: 0x%08X", currentDma->nextSource);
94 		}
95 		if (currentDma->nextDest & (width - 1)) {
96 			mLOG(GBA_MEM, GAME_ERROR, "Misaligned DMA destination address: 0x%08X", currentDma->nextDest);
97 		}
98 		currentDma->nextSource &= -width;
99 		currentDma->nextDest &= -width;
100 
101 		GBADMASchedule(gba, dma, currentDma);
102 	}
103 	// If the DMA has already occurred, this value might have changed since the function started
104 	return currentDma->reg;
105 };
106 
GBADMASchedule(struct GBA * gba,int number,struct GBADMA * info)107 void GBADMASchedule(struct GBA* gba, int number, struct GBADMA* info) {
108 	switch (GBADMARegisterGetTiming(info->reg)) {
109 	case GBA_DMA_TIMING_NOW:
110 		info->when = mTimingCurrentTime(&gba->timing) + 3; // DMAs take 3 cycles to start
111 		info->nextCount = info->count;
112 		break;
113 	case GBA_DMA_TIMING_HBLANK:
114 	case GBA_DMA_TIMING_VBLANK:
115 		// Handled implicitly
116 		return;
117 	case GBA_DMA_TIMING_CUSTOM:
118 		switch (number) {
119 		case 0:
120 			mLOG(GBA_MEM, WARN, "Discarding invalid DMA0 scheduling");
121 			return;
122 		case 1:
123 		case 2:
124 			GBAAudioScheduleFifoDma(&gba->audio, number, info);
125 			break;
126 		case 3:
127 			// Handled implicitly
128 			break;
129 		}
130 	}
131 	GBADMAUpdate(gba);
132 }
133 
GBADMARunHblank(struct GBA * gba,int32_t cycles)134 void GBADMARunHblank(struct GBA* gba, int32_t cycles) {
135 	struct GBAMemory* memory = &gba->memory;
136 	struct GBADMA* dma;
137 	int i;
138 	for (i = 0; i < 4; ++i) {
139 		dma = &memory->dma[i];
140 		if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_HBLANK && !dma->nextCount) {
141 			dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
142 			dma->nextCount = dma->count;
143 		}
144 	}
145 	GBADMAUpdate(gba);
146 }
147 
GBADMARunVblank(struct GBA * gba,int32_t cycles)148 void GBADMARunVblank(struct GBA* gba, int32_t cycles) {
149 	struct GBAMemory* memory = &gba->memory;
150 	struct GBADMA* dma;
151 	int i;
152 	for (i = 0; i < 4; ++i) {
153 		dma = &memory->dma[i];
154 		if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_VBLANK && !dma->nextCount) {
155 			dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
156 			dma->nextCount = dma->count;
157 		}
158 	}
159 	GBADMAUpdate(gba);
160 }
161 
GBADMARunDisplayStart(struct GBA * gba,int32_t cycles)162 void GBADMARunDisplayStart(struct GBA* gba, int32_t cycles) {
163 	struct GBAMemory* memory = &gba->memory;
164 	struct GBADMA* dma = &memory->dma[3];
165 	if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM && !dma->nextCount) {
166 		dma->when = mTimingCurrentTime(&gba->timing) + 3 + cycles;
167 		dma->nextCount = dma->count;
168 		GBADMAUpdate(gba);
169 	}
170 }
171 
_dmaEvent(struct mTiming * timing,void * context,uint32_t cyclesLate)172 void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
173 	UNUSED(timing);
174 	UNUSED(cyclesLate);
175 	struct GBA* gba = context;
176 	struct GBAMemory* memory = &gba->memory;
177 	struct GBADMA* dma = &memory->dma[memory->activeDMA];
178 	if (dma->nextCount == dma->count) {
179 		dma->when = mTimingCurrentTime(&gba->timing);
180 	}
181 	if (dma->nextCount & 0xFFFFF) {
182 		GBADMAService(gba, memory->activeDMA, dma);
183 	} else {
184 		dma->nextCount = 0;
185 		bool noRepeat = !GBADMARegisterIsRepeat(dma->reg);
186 		noRepeat |= GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_NOW;
187 		noRepeat |= memory->activeDMA == 3 && GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM && gba->video.vcount == GBA_VIDEO_VERTICAL_PIXELS + 1;
188 		if (noRepeat) {
189 			dma->reg = GBADMARegisterClearEnable(dma->reg);
190 
191 			// Clear the enable bit in memory
192 			memory->io[(REG_DMA0CNT_HI + memory->activeDMA * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
193 		}
194 		if (GBADMARegisterGetDestControl(dma->reg) == GBA_DMA_INCREMENT_RELOAD) {
195 			dma->nextDest = dma->dest;
196 		}
197 		if (GBADMARegisterIsDoIRQ(dma->reg)) {
198 			GBARaiseIRQ(gba, IRQ_DMA0 + memory->activeDMA, cyclesLate);
199 		}
200 		GBADMAUpdate(gba);
201 	}
202 }
203 
GBADMAUpdate(struct GBA * gba)204 void GBADMAUpdate(struct GBA* gba) {
205 	int i;
206 	struct GBAMemory* memory = &gba->memory;
207 	uint32_t currentTime = mTimingCurrentTime(&gba->timing);
208 	int32_t leastTime = INT_MAX;
209 	memory->activeDMA = -1;
210 	for (i = 0; i < 4; ++i) {
211 		struct GBADMA* dma = &memory->dma[i];
212 		if (GBADMARegisterIsEnable(dma->reg) && dma->nextCount) {
213 			int32_t time = dma->when - currentTime;
214 			if (memory->activeDMA == -1 || (dma->count == dma->nextCount && time < leastTime)) {
215 				leastTime = time;
216 				memory->activeDMA = i;
217 			}
218 		}
219 	}
220 
221 	if (memory->activeDMA >= 0) {
222 		mTimingDeschedule(&gba->timing, &memory->dmaEvent);
223 		mTimingSchedule(&gba->timing, &memory->dmaEvent, memory->dma[memory->activeDMA].when - currentTime);
224 	} else {
225 		gba->cpuBlocked = false;
226 	}
227 }
228 
GBADMAService(struct GBA * gba,int number,struct GBADMA * info)229 void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
230 	struct GBAMemory* memory = &gba->memory;
231 	struct ARMCore* cpu = gba->cpu;
232 	uint32_t width = 2 << GBADMARegisterGetWidth(info->reg);
233 	int32_t wordsRemaining = info->nextCount;
234 	uint32_t source = info->nextSource;
235 	uint32_t dest = info->nextDest;
236 	uint32_t sourceRegion = source >> BASE_OFFSET;
237 	uint32_t destRegion = dest >> BASE_OFFSET;
238 	int32_t cycles = 2;
239 
240 	gba->cpuBlocked = true;
241 	if (info->count == info->nextCount) {
242 		if (width == 4) {
243 			cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion];
244 		} else {
245 			cycles += memory->waitstatesNonseq16[sourceRegion] + memory->waitstatesNonseq16[destRegion];
246 		}
247 	} else {
248 		if (width == 4) {
249 			cycles += memory->waitstatesSeq32[sourceRegion] + memory->waitstatesSeq32[destRegion];
250 		} else {
251 			cycles += memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion];
252 		}
253 	}
254 	info->when += cycles;
255 
256 	gba->performingDMA = 1 | (number << 1);
257 	if (width == 4) {
258 		if (source) {
259 			memory->dmaTransferRegister = cpu->memory.load32(cpu, source, 0);
260 		}
261 		gba->bus = memory->dmaTransferRegister;
262 		cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0);
263 	} else {
264 		if (sourceRegion == REGION_CART2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) {
265 			memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata);
266 			memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
267 		} else if (source) {
268 			memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0);
269 			memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
270 		}
271 		if (destRegion == REGION_CART2_EX) {
272 			if (memory->savedata.type == SAVEDATA_AUTODETECT) {
273 				mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
274 				GBASavedataInitEEPROM(&memory->savedata);
275 			}
276 			if (memory->savedata.type == SAVEDATA_EEPROM512 || memory->savedata.type == SAVEDATA_EEPROM) {
277 				GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, wordsRemaining);
278 			}
279 		} else {
280 			cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0);
281 
282 		}
283 		gba->bus = memory->dmaTransferRegister;
284 	}
285 	int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
286 	int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
287 	if (source) {
288 		source += sourceOffset;
289 	}
290 	dest += destOffset;
291 	--wordsRemaining;
292 	gba->performingDMA = 0;
293 
294 	info->nextCount = wordsRemaining;
295 	info->nextSource = source;
296 	info->nextDest = dest;
297 	if (!wordsRemaining) {
298 		info->nextCount |= 0x80000000;
299 		if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) {
300 			info->when += 2;
301 		}
302 	}
303 	GBADMAUpdate(gba);
304 }
305