1 |
/* PCSX2 - PS2 Emulator for PCs |
2 |
* Copyright (C) 2002-2010 PCSX2 Dev Team |
3 |
* |
4 |
* PCSX2 is free software: you can redistribute it and/or modify it under the terms |
5 |
* of the GNU Lesser General Public License as published by the Free Software Found- |
6 |
* ation, either version 3 of the License, or (at your option) any later version. |
7 |
* |
8 |
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
9 |
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
10 |
* PURPOSE. See the GNU General Public License for more details. |
11 |
* |
12 |
* You should have received a copy of the GNU General Public License along with PCSX2. |
13 |
* If not, see <http://www.gnu.org/licenses/>. |
14 |
*/ |
15 |
|
16 |
#include "PrecompiledHeader.h" |
17 |
#include "Common.h" |
18 |
#include "Vif_Dma.h" |
19 |
#include "GS.h" |
20 |
#include "Gif.h" |
21 |
#include "VUmicro.h" |
22 |
#include "newVif.h" |
23 |
|
24 |
__forceinline void vif1FLUSH() |
25 |
{ |
26 |
if (!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return; |
27 |
int _cycles = VU1.cycle; |
28 |
vu1Finish(); |
29 |
g_vifCycles += (VU1.cycle - _cycles) * BIAS; |
30 |
} |
31 |
|
32 |
void vif1TransferToMemory() |
33 |
{ |
34 |
u32 size; |
35 |
u64* pMem = (u64*)dmaGetAddr(vif1ch->madr, false); |
36 |
|
37 |
// VIF from gsMemory |
38 |
if (pMem == NULL) //Is vif0ptag empty? |
39 |
{ |
40 |
Console.WriteLn("Vif1 Tag BUSERR"); |
41 |
dmacRegs->stat.BEIS = true; //Bus Error |
42 |
vif1Regs->stat.FQC = 0; |
43 |
|
44 |
vif1ch->qwc = 0; |
45 |
vif1.done = true; |
46 |
CPU_INT(DMAC_VIF1, 0); |
47 |
return; //An error has occurred. |
48 |
} |
49 |
|
50 |
// MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading |
51 |
// stuff from the GS. The *only* way to handle this case safely is to flush the GS |
52 |
// completely and execute the transfer there-after. |
53 |
//Console.Warning("Real QWC %x", vif1ch->qwc); |
54 |
XMMRegisters::Freeze(); |
55 |
|
56 |
size = min((u32)vif1ch->qwc, vif1.GSLastDownloadSize); |
57 |
|
58 |
if (GSreadFIFO2 == NULL) |
59 |
{ |
60 |
for (;size > 0; --size) |
61 |
{ |
62 |
GetMTGS().WaitGS(); |
63 |
GSreadFIFO(&psHu64(VIF1_FIFO)); |
64 |
|
65 |
pMem[0] = psHu64(VIF1_FIFO); |
66 |
pMem[1] = psHu64(VIF1_FIFO + 8); |
67 |
pMem += 2; |
68 |
} |
69 |
if(vif1ch->qwc > vif1.GSLastDownloadSize) |
70 |
{ |
71 |
DevCon.Warning("GS Transfer < VIF QWC, Clearing end of space"); |
72 |
for (size = vif1ch->qwc - vif1.GSLastDownloadSize; size > 0; --size) |
73 |
{ |
74 |
psHu64(VIF1_FIFO) = 0; |
75 |
psHu64(VIF1_FIFO + 8) = 0; |
76 |
pMem[0] = psHu64(VIF1_FIFO); |
77 |
pMem[1] = psHu64(VIF1_FIFO + 8); |
78 |
pMem += 2; |
79 |
} |
80 |
} |
81 |
} |
82 |
else |
83 |
{ |
84 |
GetMTGS().WaitGS(); |
85 |
GSreadFIFO2(pMem, size); |
86 |
|
87 |
// set incase read |
88 |
psHu64(VIF1_FIFO) = pMem[2*size-2]; |
89 |
psHu64(VIF1_FIFO + 8) = pMem[2*size-1]; |
90 |
pMem += size * 2; |
91 |
if(vif1ch->qwc > vif1.GSLastDownloadSize) |
92 |
{ |
93 |
DevCon.Warning("GS Transfer < VIF QWC, Clearing end of space"); |
94 |
for (size = vif1ch->qwc - vif1.GSLastDownloadSize; size > 0; --size) |
95 |
{ |
96 |
psHu64(VIF1_FIFO) = 0; |
97 |
psHu64(VIF1_FIFO + 8) = 0; |
98 |
pMem[0] = psHu64(VIF1_FIFO); |
99 |
pMem[1] = psHu64(VIF1_FIFO + 8); |
100 |
pMem += 2; |
101 |
} |
102 |
} |
103 |
} |
104 |
|
105 |
|
106 |
XMMRegisters::Thaw(); |
107 |
|
108 |
g_vifCycles += vif1ch->qwc * 2; |
109 |
vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes |
110 |
if(vif1.GSLastDownloadSize >= vif1ch->qwc) |
111 |
{ |
112 |
vif1.GSLastDownloadSize -= vif1ch->qwc; |
113 |
vif1Regs->stat.FQC = min((u32)16, vif1.GSLastDownloadSize); |
114 |
} |
115 |
else |
116 |
{ |
117 |
vif1Regs->stat.FQC = 0; |
118 |
vif1.GSLastDownloadSize = 0; |
119 |
} |
120 |
|
121 |
vif1ch->qwc = 0; |
122 |
} |
123 |
|
124 |
bool _VIF1chain() |
125 |
{ |
126 |
u32 *pMem; |
127 |
|
128 |
if (vif1ch->qwc == 0) |
129 |
{ |
130 |
vif1.inprogress = 0; |
131 |
return true; |
132 |
} |
133 |
|
134 |
// Clarification - this is TO memory mode, for some reason i used the other way round >.< |
135 |
if (vif1.dmamode == VIF_NORMAL_TO_MEM_MODE) |
136 |
{ |
137 |
vif1TransferToMemory(); |
138 |
vif1.inprogress = 0; |
139 |
return true; |
140 |
} |
141 |
|
142 |
pMem = (u32*)dmaGetAddr(vif1ch->madr, !vif1ch->chcr.DIR); |
143 |
if (pMem == NULL) |
144 |
{ |
145 |
vif1.cmd = 0; |
146 |
vif1.tag.size = 0; |
147 |
vif1ch->qwc = 0; |
148 |
return true; |
149 |
} |
150 |
|
151 |
VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", |
152 |
vif1ch->qwc, vif1ch->madr, vif1ch->tadr); |
153 |
|
154 |
if (vif1.vifstalled) |
155 |
return VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false); |
156 |
else |
157 |
return VIF1transfer(pMem, vif1ch->qwc * 4, false); |
158 |
} |
159 |
|
160 |
__forceinline void vif1SetupTransfer() |
161 |
{ |
162 |
tDMA_TAG *ptag; |
163 |
|
164 |
switch (vif1.dmamode) |
165 |
{ |
166 |
case VIF_NORMAL_TO_MEM_MODE: |
167 |
case VIF_NORMAL_FROM_MEM_MODE: |
168 |
vif1.inprogress = 1; |
169 |
vif1.done = true; |
170 |
g_vifCycles = 2; |
171 |
break; |
172 |
|
173 |
case VIF_CHAIN_MODE: |
174 |
ptag = dmaGetAddr(vif1ch->tadr, false); //Set memory pointer to TADR |
175 |
|
176 |
if (!(vif1ch->transfer("Vif1 Tag", ptag))) return; |
177 |
|
178 |
vif1ch->madr = ptag[1]._u32; //MADR = ADDR field + SPR |
179 |
g_vifCycles += 1; // Add 1 g_vifCycles from the QW read for the tag |
180 |
|
181 |
// Transfer dma tag if tte is set |
182 |
|
183 |
VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", |
184 |
ptag[1]._u32, ptag[0]._u32, vif1ch->qwc, ptag->ID, vif1ch->madr, vif1ch->tadr); |
185 |
|
186 |
if (!vif1.done && ((dmacRegs->ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 |
187 |
{ |
188 |
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall |
189 |
if ((vif1ch->madr + vif1ch->qwc * 16) >= dmacRegs->stadr.ADDR) |
190 |
{ |
191 |
// stalled |
192 |
hwDmacIrq(DMAC_STALL_SIS); |
193 |
return; |
194 |
} |
195 |
} |
196 |
|
197 |
vif1.inprogress = 1; |
198 |
|
199 |
if (vif1ch->chcr.TTE) |
200 |
{ |
201 |
bool ret; |
202 |
|
203 |
if (vif1.vifstalled) |
204 |
ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on stall |
205 |
else |
206 |
ret = VIF1transfer((u32*)ptag + 2, 2, true); //Transfer Tag |
207 |
|
208 |
if ((ret == false) && vif1.irqoffset < 2) |
209 |
{ |
210 |
vif1.inprogress = 0; //Better clear this so it has to do it again (Jak 1) |
211 |
return; //There has been an error or an interrupt |
212 |
} |
213 |
} |
214 |
|
215 |
vif1.irqoffset = 0; |
216 |
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); |
217 |
|
218 |
//Check TIE bit of CHCR and IRQ bit of tag |
219 |
if (vif1ch->chcr.TIE && ptag->IRQ) |
220 |
{ |
221 |
VIF_LOG("dmaIrq Set"); |
222 |
|
223 |
//End Transfer |
224 |
vif1.done = true; |
225 |
return; |
226 |
} |
227 |
break; |
228 |
} |
229 |
} |
230 |
|
231 |
__forceinline void vif1Interrupt() |
232 |
{ |
233 |
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle); |
234 |
|
235 |
g_vifCycles = 0; |
236 |
|
237 |
//Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here. |
238 |
if (dmacRegs->ctrl.MFD == MFD_VIF1) // VIF MFIFO |
239 |
{ |
240 |
//Console.WriteLn("VIFMFIFO\n"); |
241 |
// Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw. |
242 |
if (vif1ch->chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch->chcr._u32); |
243 |
vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc); |
244 |
vifMFIFOInterrupt(); |
245 |
return; |
246 |
} |
247 |
|
248 |
//We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing) |
249 |
if (vif1ch->chcr.DIR)vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16); |
250 |
//Simulated GS transfer time done, clear the flags |
251 |
if(gifRegs->stat.APATH == GIF_APATH2 && (vif1.cmd & 0x70) != 0x50) |
252 |
{ |
253 |
gifRegs->stat.APATH = GIF_APATH_IDLE; |
254 |
} |
255 |
|
256 |
if (schedulepath3msk & 0x10) Vif1MskPath3(); |
257 |
|
258 |
if ((vif1Regs->stat.VGW)) |
259 |
{ |
260 |
if (GSTransferStatus.PTH3 < STOPPED_MODE || GSTransferStatus.PTH1 != STOPPED_MODE) |
261 |
{ |
262 |
CPU_INT(DMAC_VIF1, 4); |
263 |
return; |
264 |
} |
265 |
else |
266 |
{ |
267 |
vif1Regs->stat.VGW = false; |
268 |
} |
269 |
} |
270 |
|
271 |
if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32); |
272 |
|
273 |
if (vif1.irq && vif1.tag.size == 0) |
274 |
{ |
275 |
vif1Regs->stat.INT = true; |
276 |
hwIntcIrq(VIF1intc); |
277 |
--vif1.irq; |
278 |
if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) |
279 |
{ |
280 |
//vif1Regs->stat.FQC = 0; |
281 |
|
282 |
// One game doesn't like vif stalling at end, can't remember what. Spiderman isn't keen on it tho |
283 |
vif1ch->chcr.STR = false; |
284 |
return; |
285 |
} |
286 |
else if ((vif1ch->qwc > 0) || (vif1.irqoffset > 0)) |
287 |
{ |
288 |
if (vif1.stallontag) |
289 |
vif1SetupTransfer(); |
290 |
else |
291 |
_VIF1chain();//CPU_INT(DMAC_STALL_SIS, vif1ch->qwc * BIAS); |
292 |
} |
293 |
} |
294 |
|
295 |
if (vif1.inprogress & 0x1) |
296 |
{ |
297 |
_VIF1chain(); |
298 |
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation. |
299 |
// Timesplitters 2 depends on this beeing a bit higher than 128. |
300 |
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16); |
301 |
// Refraction - Removing voodoo timings for now, completely messes a lot of Path3 masked games. |
302 |
/*if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF1, 1024); |
303 |
else */CPU_INT(DMAC_VIF1, g_vifCycles /*VifCycleVoodoo*/); |
304 |
return; |
305 |
} |
306 |
|
307 |
if (!vif1.done) |
308 |
{ |
309 |
|
310 |
if (!(dmacRegs->ctrl.DMAE)) |
311 |
{ |
312 |
Console.WriteLn("vif1 dma masked"); |
313 |
return; |
314 |
} |
315 |
|
316 |
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); |
317 |
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16); |
318 |
CPU_INT(DMAC_VIF1, g_vifCycles); |
319 |
return; |
320 |
} |
321 |
|
322 |
if (vif1.vifstalled && vif1.irq) |
323 |
{ |
324 |
DevCon.WriteLn("VIF1 looping on stall\n"); |
325 |
CPU_INT(DMAC_VIF1, 0); |
326 |
return; //Dont want to end if vif is stalled. |
327 |
} |
328 |
#ifdef PCSX2_DEVBUILD |
329 |
if (vif1ch->qwc > 0) Console.WriteLn("VIF1 Ending with %x QWC left"); |
330 |
if (vif1.cmd != 0) Console.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size); |
331 |
#endif |
332 |
|
333 |
vif1Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands; |
334 |
if((vif1ch->chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16) |
335 |
{ //Reverse fifo has finished and nothing is left, so lets clear the outputting flag |
336 |
gifRegs->stat.OPH = false; |
337 |
} |
338 |
vif1ch->chcr.STR = false; |
339 |
g_vifCycles = 0; |
340 |
VIF_LOG("VIF1 End"); |
341 |
hwDmacIrq(DMAC_VIF1); |
342 |
|
343 |
} |
344 |
|
345 |
void dmaVIF1() |
346 |
{ |
347 |
VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" |
348 |
" tadr = %lx, asr0 = %lx, asr1 = %lx", |
349 |
vif1ch->chcr._u32, vif1ch->madr, vif1ch->qwc, |
350 |
vif1ch->tadr, vif1ch->asr0, vif1ch->asr1); |
351 |
|
352 |
vif1.done = false; |
353 |
g_vifCycles = 0; |
354 |
vif1.inprogress = 0; |
355 |
|
356 |
#ifdef PCSX2_DEVBUILD |
357 |
if (dmacRegs->ctrl.STD == STD_VIF1) |
358 |
{ |
359 |
//DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); |
360 |
} |
361 |
#endif |
362 |
|
363 |
if ((vif1ch->chcr.MOD == NORMAL_MODE) || vif1ch->qwc > 0) // Normal Mode |
364 |
{ |
365 |
|
366 |
if (dmacRegs->ctrl.STD == STD_VIF1) |
367 |
Console.WriteLn("DMA Stall Control on VIF1 normal"); |
368 |
|
369 |
if (vif1ch->chcr.DIR) // to Memory |
370 |
vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; |
371 |
else |
372 |
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; |
373 |
|
374 |
if(vif1ch->chcr.MOD == CHAIN_MODE && vif1ch->qwc > 0) DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch->chcr.desc()); |
375 |
} |
376 |
else |
377 |
{ |
378 |
vif1.dmamode = VIF_CHAIN_MODE; |
379 |
} |
380 |
|
381 |
if (vif1ch->chcr.DIR) vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc); |
382 |
|
383 |
// Chain Mode |
384 |
vif1Interrupt(); |
385 |
} |