1 |
william |
31 |
/* 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 |
william |
62 |
|
25 |
|
|
__fi void vif1FLUSH() |
26 |
william |
31 |
{ |
27 |
william |
62 |
if(g_packetsizeonvu > vif1.vifpacketsize && g_vu1Cycles > 0) |
28 |
|
|
{ |
29 |
|
|
//DevCon.Warning("Adding on same packet"); |
30 |
|
|
if( ((g_packetsizeonvu - vif1.vifpacketsize) >> 1) > g_vu1Cycles) |
31 |
|
|
g_vu1Cycles -= (g_packetsizeonvu - vif1.vifpacketsize) >> 1; |
32 |
|
|
else g_vu1Cycles = 0; |
33 |
|
|
} |
34 |
|
|
if(g_vu1Cycles > 0) |
35 |
|
|
{ |
36 |
|
|
//DevCon.Warning("Adding %x cycles to VIF1", g_vu1Cycles * BIAS); |
37 |
|
|
g_vifCycles += g_vu1Cycles; |
38 |
|
|
g_vu1Cycles = 0; |
39 |
|
|
|
40 |
|
|
} |
41 |
|
|
g_vu1Cycles = 0;//else DevCon.Warning("VIF1 Different Packet, how can i work this out :/"); |
42 |
|
|
if (VU0.VI[REG_VPU_STAT].UL & 0x100) |
43 |
|
|
{ |
44 |
|
|
int _cycles = VU1.cycle; |
45 |
|
|
vu1Finish(); |
46 |
|
|
//DevCon.Warning("VIF1 adding %x cycles", (VU1.cycle - _cycles) * BIAS); |
47 |
|
|
g_vifCycles += (VU1.cycle - _cycles) * BIAS; |
48 |
|
|
} |
49 |
|
|
if(gifRegs.stat.P1Q && ((vif1.cmd & 0x7f) != 0x14) && ((vif1.cmd & 0x7f) != 0x17)) |
50 |
|
|
{ |
51 |
|
|
vif1.vifstalled = true; |
52 |
|
|
vif1Regs.stat.VGW = true; |
53 |
|
|
vif1.GifWaitState = 2; |
54 |
|
|
} |
55 |
|
|
|
56 |
william |
31 |
} |
57 |
|
|
|
58 |
|
|
void vif1TransferToMemory() |
59 |
|
|
{ |
60 |
|
|
u32 size; |
61 |
william |
87 |
u128* pMem = (u128*)dmaGetAddr(vif1ch.madr, false); |
62 |
william |
31 |
|
63 |
|
|
// VIF from gsMemory |
64 |
|
|
if (pMem == NULL) //Is vif0ptag empty? |
65 |
|
|
{ |
66 |
|
|
Console.WriteLn("Vif1 Tag BUSERR"); |
67 |
william |
62 |
dmacRegs.stat.BEIS = true; //Bus Error |
68 |
|
|
vif1Regs.stat.FQC = 0; |
69 |
william |
31 |
|
70 |
william |
62 |
vif1ch.qwc = 0; |
71 |
william |
31 |
vif1.done = true; |
72 |
|
|
CPU_INT(DMAC_VIF1, 0); |
73 |
|
|
return; //An error has occurred. |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
// MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading |
77 |
|
|
// stuff from the GS. The *only* way to handle this case safely is to flush the GS |
78 |
|
|
// completely and execute the transfer there-after. |
79 |
william |
62 |
//Console.Warning("Real QWC %x", vif1ch.qwc); |
80 |
|
|
size = min((u32)vif1ch.qwc, vif1.GSLastDownloadSize); |
81 |
william |
87 |
const u128* pMemEnd = pMem + vif1.GSLastDownloadSize; |
82 |
william |
31 |
|
83 |
|
|
if (GSreadFIFO2 == NULL) |
84 |
|
|
{ |
85 |
|
|
for (;size > 0; --size) |
86 |
|
|
{ |
87 |
|
|
GetMTGS().WaitGS(); |
88 |
william |
87 |
GSreadFIFO((u64*)pMem); |
89 |
|
|
++pMem; |
90 |
william |
31 |
} |
91 |
|
|
} |
92 |
|
|
else |
93 |
|
|
{ |
94 |
|
|
GetMTGS().WaitGS(); |
95 |
william |
87 |
GSreadFIFO2((u64*)pMem, size); |
96 |
|
|
pMem += size; |
97 |
|
|
} |
98 |
william |
31 |
|
99 |
william |
87 |
if(pMem < pMemEnd) |
100 |
|
|
{ |
101 |
|
|
DevCon.Warning("GS Transfer < VIF QWC, Clearing end of space"); |
102 |
|
|
|
103 |
|
|
__m128 zeroreg = _mm_setzero_ps(); |
104 |
|
|
do { |
105 |
|
|
_mm_store_ps((float*)pMem, zeroreg); |
106 |
|
|
++pMem; |
107 |
|
|
} while (pMem < pMemEnd); |
108 |
william |
31 |
} |
109 |
|
|
|
110 |
william |
62 |
g_vifCycles += vif1ch.qwc * 2; |
111 |
|
|
vif1ch.madr += vif1ch.qwc * 16; // mgs3 scene changes |
112 |
|
|
if(vif1.GSLastDownloadSize >= vif1ch.qwc) |
113 |
william |
31 |
{ |
114 |
william |
62 |
vif1.GSLastDownloadSize -= vif1ch.qwc; |
115 |
|
|
vif1Regs.stat.FQC = min((u32)16, vif1.GSLastDownloadSize); |
116 |
william |
31 |
} |
117 |
|
|
else |
118 |
|
|
{ |
119 |
william |
62 |
vif1Regs.stat.FQC = 0; |
120 |
william |
31 |
vif1.GSLastDownloadSize = 0; |
121 |
|
|
} |
122 |
|
|
|
123 |
william |
62 |
vif1ch.qwc = 0; |
124 |
william |
31 |
} |
125 |
|
|
|
126 |
|
|
bool _VIF1chain() |
127 |
|
|
{ |
128 |
|
|
u32 *pMem; |
129 |
|
|
|
130 |
william |
62 |
if (vif1ch.qwc == 0) |
131 |
william |
31 |
{ |
132 |
william |
62 |
vif1.inprogress &= ~1; |
133 |
|
|
vif1.irqoffset = 0; |
134 |
william |
31 |
return true; |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
// Clarification - this is TO memory mode, for some reason i used the other way round >.< |
138 |
|
|
if (vif1.dmamode == VIF_NORMAL_TO_MEM_MODE) |
139 |
|
|
{ |
140 |
|
|
vif1TransferToMemory(); |
141 |
william |
62 |
vif1.inprogress &= ~1; |
142 |
william |
31 |
return true; |
143 |
|
|
} |
144 |
|
|
|
145 |
william |
62 |
pMem = (u32*)dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR); |
146 |
william |
31 |
if (pMem == NULL) |
147 |
|
|
{ |
148 |
|
|
vif1.cmd = 0; |
149 |
|
|
vif1.tag.size = 0; |
150 |
william |
62 |
vif1ch.qwc = 0; |
151 |
william |
31 |
return true; |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", |
155 |
william |
62 |
vif1ch.qwc, vif1ch.madr, vif1ch.tadr); |
156 |
william |
31 |
|
157 |
|
|
if (vif1.vifstalled) |
158 |
william |
280 |
return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset, false); |
159 |
william |
31 |
else |
160 |
william |
280 |
return VIF1transfer(pMem, vif1ch.qwc * 4, false); |
161 |
william |
31 |
} |
162 |
|
|
|
163 |
william |
62 |
__fi void vif1SetupTransfer() |
164 |
william |
31 |
{ |
165 |
|
|
tDMA_TAG *ptag; |
166 |
william |
62 |
|
167 |
william |
31 |
switch (vif1.dmamode) |
168 |
|
|
{ |
169 |
|
|
case VIF_NORMAL_TO_MEM_MODE: |
170 |
|
|
case VIF_NORMAL_FROM_MEM_MODE: |
171 |
william |
62 |
vif1.inprogress |= 1; |
172 |
william |
31 |
vif1.done = true; |
173 |
|
|
g_vifCycles = 2; |
174 |
william |
62 |
break; |
175 |
william |
31 |
|
176 |
|
|
case VIF_CHAIN_MODE: |
177 |
william |
62 |
ptag = dmaGetAddr(vif1ch.tadr, false); //Set memory pointer to TADR |
178 |
william |
31 |
|
179 |
william |
62 |
if (!(vif1ch.transfer("Vif1 Tag", ptag))) return; |
180 |
william |
31 |
|
181 |
william |
62 |
vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR |
182 |
william |
31 |
g_vifCycles += 1; // Add 1 g_vifCycles from the QW read for the tag |
183 |
|
|
|
184 |
william |
62 |
VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", |
185 |
|
|
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr); |
186 |
william |
31 |
|
187 |
william |
62 |
if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 |
188 |
william |
31 |
{ |
189 |
|
|
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall |
190 |
william |
62 |
if ((vif1ch.madr + vif1ch.qwc * 16) >= dmacRegs.stadr.ADDR) |
191 |
william |
31 |
{ |
192 |
|
|
// stalled |
193 |
|
|
hwDmacIrq(DMAC_STALL_SIS); |
194 |
|
|
return; |
195 |
|
|
} |
196 |
|
|
} |
197 |
|
|
|
198 |
william |
62 |
|
199 |
|
|
vif1.inprogress &= ~1; |
200 |
william |
31 |
|
201 |
william |
62 |
if (vif1ch.chcr.TTE) |
202 |
william |
31 |
{ |
203 |
william |
62 |
// Transfer dma tag if tte is set |
204 |
|
|
|
205 |
william |
31 |
bool ret; |
206 |
|
|
|
207 |
william |
273 |
static __aligned16 u128 masked_tag; |
208 |
|
|
|
209 |
|
|
masked_tag._u64[0] = 0; |
210 |
|
|
masked_tag._u64[1] = *((u64*)ptag + 1); |
211 |
|
|
|
212 |
|
|
VIF_LOG("\tVIF1 SrcChain TTE=1, data = 0x%08x.%08x", masked_tag._u32[3], masked_tag._u32[2]); |
213 |
|
|
|
214 |
william |
31 |
if (vif1.vifstalled) |
215 |
william |
62 |
{ |
216 |
william |
273 |
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset, 4 - vif1.irqoffset, true); //Transfer Tag on stall |
217 |
|
|
//ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall |
218 |
william |
62 |
} |
219 |
william |
31 |
else |
220 |
william |
273 |
{ |
221 |
|
|
//Some games (like killzone) do Tags mid unpack, the nops will just write blank data |
222 |
|
|
//to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words |
223 |
|
|
vif1.irqoffset = 2; |
224 |
|
|
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag |
225 |
|
|
//ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag |
226 |
|
|
} |
227 |
william |
62 |
|
228 |
william |
273 |
if (!ret && vif1.irqoffset) |
229 |
william |
31 |
{ |
230 |
william |
62 |
vif1.inprogress &= ~1; //Better clear this so it has to do it again (Jak 1) |
231 |
|
|
return; //IRQ set by VIFTransfer |
232 |
william |
273 |
} |
233 |
william |
31 |
} |
234 |
william |
62 |
vif1.irqoffset = 0; |
235 |
william |
31 |
|
236 |
|
|
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); |
237 |
|
|
|
238 |
william |
62 |
if(vif1ch.qwc > 0) vif1.inprogress |= 1; |
239 |
|
|
|
240 |
william |
31 |
//Check TIE bit of CHCR and IRQ bit of tag |
241 |
william |
62 |
if (vif1ch.chcr.TIE && ptag->IRQ) |
242 |
william |
31 |
{ |
243 |
|
|
VIF_LOG("dmaIrq Set"); |
244 |
|
|
|
245 |
|
|
//End Transfer |
246 |
|
|
vif1.done = true; |
247 |
|
|
return; |
248 |
|
|
} |
249 |
william |
62 |
break; |
250 |
william |
31 |
} |
251 |
|
|
} |
252 |
|
|
|
253 |
william |
62 |
extern bool SIGNAL_IMR_Pending; |
254 |
|
|
|
255 |
|
|
bool CheckPath2GIF(EE_EventType channel) |
256 |
william |
31 |
{ |
257 |
william |
62 |
if ((vif1Regs.stat.VGW)) |
258 |
|
|
{ |
259 |
|
|
if( vif1.GifWaitState == 0 ) //DIRECT/HL Check |
260 |
|
|
{ |
261 |
william |
401 |
if(GSTransferStatus.PTH3 < STOPPED_MODE || gifRegs.stat.P1Q) |
262 |
william |
62 |
{ |
263 |
|
|
if(gifRegs.stat.IMT && GSTransferStatus.PTH3 <= IMAGE_MODE && (vif1.cmd & 0x7f) == 0x50 && gifRegs.stat.P1Q == false) |
264 |
|
|
{ |
265 |
|
|
vif1Regs.stat.VGW = false; |
266 |
|
|
} |
267 |
|
|
else |
268 |
|
|
{ |
269 |
|
|
//DevCon.Warning("VIF1-0 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); |
270 |
|
|
CPU_INT(channel, 128); |
271 |
|
|
return false; |
272 |
|
|
} |
273 |
|
|
} |
274 |
|
|
else |
275 |
|
|
{ |
276 |
|
|
vif1Regs.stat.VGW = false; |
277 |
|
|
} |
278 |
|
|
} |
279 |
|
|
else if( vif1.GifWaitState == 1 ) // Else we're flushing path3 :), but of course waiting for the microprogram to finish |
280 |
|
|
{ |
281 |
|
|
if (gifRegs.stat.P1Q) |
282 |
|
|
{ |
283 |
|
|
//DevCon.Warning("VIF1-1 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); |
284 |
|
|
CPU_INT(channel, 128); |
285 |
|
|
return false; |
286 |
|
|
} |
287 |
|
|
|
288 |
william |
401 |
if (GSTransferStatus.PTH3 < STOPPED_MODE) |
289 |
william |
62 |
{ |
290 |
william |
401 |
//DevCon.Warning("VIF1-11 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); |
291 |
william |
62 |
//DevCon.Warning("PTH3 %x P1Q %x P3Q %x IP3 %x", GSTransferStatus.PTH3, gifRegs.stat.P1Q, gifRegs.stat.P3Q, gifRegs.stat.IP3 ); |
292 |
william |
401 |
CPU_INT(channel, 128); |
293 |
william |
62 |
return false; |
294 |
|
|
} |
295 |
william |
401 |
|
296 |
|
|
vif1Regs.stat.VGW = false; |
297 |
|
|
|
298 |
william |
62 |
} |
299 |
william |
401 |
else if( vif1.GifWaitState == 3 ) // Any futher GIF transfers are paused. |
300 |
william |
62 |
{ |
301 |
|
|
if (gifRegs.ctrl.PSE) |
302 |
|
|
{ |
303 |
|
|
//DevCon.Warning("VIF1-1 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); |
304 |
|
|
CPU_INT(channel, 128); |
305 |
|
|
return false; |
306 |
|
|
} |
307 |
william |
401 |
|
308 |
|
|
vif1Regs.stat.VGW = false; |
309 |
|
|
|
310 |
william |
62 |
} |
311 |
|
|
else //Normal Flush |
312 |
|
|
{ |
313 |
|
|
if (gifRegs.stat.P1Q) |
314 |
|
|
{ |
315 |
|
|
//DevCon.Warning("VIF1-2 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); |
316 |
|
|
CPU_INT(channel, 128); |
317 |
|
|
return false; |
318 |
|
|
} |
319 |
william |
401 |
|
320 |
|
|
vif1Regs.stat.VGW = false; |
321 |
william |
62 |
} |
322 |
|
|
} |
323 |
william |
401 |
|
324 |
william |
62 |
if(SIGNAL_IMR_Pending == true && (vif1.cmd & 0x7e) == 0x50) |
325 |
|
|
{ |
326 |
|
|
//DevCon.Warning("Path 2 Paused"); |
327 |
|
|
CPU_INT(channel, 128); |
328 |
|
|
return false; |
329 |
|
|
} |
330 |
william |
401 |
|
331 |
william |
62 |
return true; |
332 |
|
|
} |
333 |
|
|
__fi void vif1Interrupt() |
334 |
|
|
{ |
335 |
william |
31 |
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle); |
336 |
|
|
|
337 |
|
|
g_vifCycles = 0; |
338 |
|
|
|
339 |
william |
401 |
if (schedulepath3msk & 0x10) |
340 |
william |
62 |
{ |
341 |
william |
401 |
MSKPATH3_LOG("Scheduled Path3 Mask Firing"); |
342 |
|
|
Vif1MskPath3(); |
343 |
william |
62 |
} |
344 |
|
|
|
345 |
william |
401 |
if(GSTransferStatus.PTH2 == PENDINGSTOP_MODE) |
346 |
william |
62 |
{ |
347 |
william |
401 |
GSTransferStatus.PTH2 = STOPPED_MODE; |
348 |
|
|
|
349 |
|
|
if(gifRegs.stat.APATH == GIF_APATH2) |
350 |
|
|
{ |
351 |
|
|
if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false; |
352 |
|
|
gifRegs.stat.APATH = GIF_APATH_IDLE; |
353 |
|
|
if(gifRegs.stat.P1Q) gsPath1Interrupt(); |
354 |
|
|
} |
355 |
william |
62 |
} |
356 |
william |
401 |
|
357 |
william |
31 |
//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. |
358 |
william |
62 |
if (dmacRegs.ctrl.MFD == MFD_VIF1) |
359 |
william |
31 |
{ |
360 |
|
|
//Console.WriteLn("VIFMFIFO\n"); |
361 |
|
|
// Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw. |
362 |
william |
62 |
if (vif1ch.chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32); |
363 |
|
|
vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); |
364 |
william |
31 |
vifMFIFOInterrupt(); |
365 |
|
|
return; |
366 |
|
|
} |
367 |
|
|
|
368 |
william |
62 |
//We need to check the direction, if it is downloading from the GS, we handle that separately (KH2 for testing) |
369 |
|
|
if (vif1ch.chcr.DIR) |
370 |
william |
31 |
{ |
371 |
william |
62 |
if (!CheckPath2GIF(DMAC_VIF1)) return; |
372 |
|
|
|
373 |
|
|
vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); |
374 |
|
|
//Simulated GS transfer time done, clear the flags |
375 |
william |
31 |
} |
376 |
william |
62 |
|
377 |
|
|
if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32); |
378 |
william |
31 |
|
379 |
|
|
if (vif1.irq && vif1.tag.size == 0) |
380 |
|
|
{ |
381 |
william |
401 |
VIF_LOG("VIF IRQ Firing"); |
382 |
william |
62 |
vif1Regs.stat.INT = true; |
383 |
william |
31 |
hwIntcIrq(VIF1intc); |
384 |
|
|
--vif1.irq; |
385 |
william |
62 |
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) |
386 |
william |
31 |
{ |
387 |
william |
62 |
//vif1Regs.stat.FQC = 0; |
388 |
william |
31 |
|
389 |
william |
62 |
//NFSHPS stalls when the whole packet has gone across (it stalls in the last 32bit cmd) |
390 |
|
|
//In this case VIF will end |
391 |
william |
401 |
vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); |
392 |
|
|
if(vif1ch.qwc > 0 || !vif1.done) |
393 |
|
|
{ |
394 |
|
|
VIF_LOG("VIF1 Stalled"); |
395 |
|
|
return; |
396 |
|
|
} |
397 |
william |
31 |
} |
398 |
|
|
} |
399 |
|
|
|
400 |
william |
401 |
//Mirroring change to VIF0 |
401 |
|
|
if (vif1.cmd) |
402 |
|
|
{ |
403 |
|
|
if (vif1.done && (vif1ch.qwc == 0)) vif1Regs.stat.VPS = VPS_WAITING; |
404 |
|
|
} |
405 |
|
|
else |
406 |
|
|
{ |
407 |
|
|
vif1Regs.stat.VPS = VPS_IDLE; |
408 |
|
|
} |
409 |
|
|
|
410 |
william |
31 |
if (vif1.inprogress & 0x1) |
411 |
|
|
{ |
412 |
|
|
_VIF1chain(); |
413 |
|
|
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation. |
414 |
|
|
// Timesplitters 2 depends on this beeing a bit higher than 128. |
415 |
william |
62 |
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); |
416 |
william |
31 |
// Refraction - Removing voodoo timings for now, completely messes a lot of Path3 masked games. |
417 |
|
|
/*if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF1, 1024); |
418 |
|
|
else */CPU_INT(DMAC_VIF1, g_vifCycles /*VifCycleVoodoo*/); |
419 |
|
|
return; |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
if (!vif1.done) |
423 |
|
|
{ |
424 |
|
|
|
425 |
william |
62 |
if (!(dmacRegs.ctrl.DMAE)) |
426 |
william |
31 |
{ |
427 |
|
|
Console.WriteLn("vif1 dma masked"); |
428 |
|
|
return; |
429 |
|
|
} |
430 |
|
|
|
431 |
|
|
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); |
432 |
william |
62 |
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); |
433 |
william |
31 |
CPU_INT(DMAC_VIF1, g_vifCycles); |
434 |
|
|
return; |
435 |
|
|
} |
436 |
|
|
|
437 |
|
|
if (vif1.vifstalled && vif1.irq) |
438 |
|
|
{ |
439 |
|
|
DevCon.WriteLn("VIF1 looping on stall\n"); |
440 |
|
|
CPU_INT(DMAC_VIF1, 0); |
441 |
|
|
return; //Dont want to end if vif is stalled. |
442 |
|
|
} |
443 |
|
|
#ifdef PCSX2_DEVBUILD |
444 |
william |
62 |
if (vif1ch.qwc > 0) Console.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc); |
445 |
william |
31 |
if (vif1.cmd != 0) Console.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size); |
446 |
|
|
#endif |
447 |
|
|
|
448 |
william |
62 |
if((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16) |
449 |
|
|
{ |
450 |
|
|
//Reverse fifo has finished and nothing is left, so lets clear the outputting flag |
451 |
|
|
gifRegs.stat.OPH = false; |
452 |
william |
31 |
} |
453 |
william |
62 |
|
454 |
william |
401 |
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); |
455 |
|
|
|
456 |
william |
62 |
vif1ch.chcr.STR = false; |
457 |
|
|
vif1.vifstalled = false; |
458 |
william |
31 |
g_vifCycles = 0; |
459 |
william |
62 |
g_vu1Cycles = 0; |
460 |
william |
401 |
DMA_LOG("VIF1 DMA End"); |
461 |
william |
31 |
hwDmacIrq(DMAC_VIF1); |
462 |
|
|
|
463 |
|
|
} |
464 |
|
|
|
465 |
|
|
void dmaVIF1() |
466 |
|
|
{ |
467 |
|
|
VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" |
468 |
|
|
" tadr = %lx, asr0 = %lx, asr1 = %lx", |
469 |
william |
62 |
vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc, |
470 |
|
|
vif1ch.tadr, vif1ch.asr0, vif1ch.asr1); |
471 |
william |
31 |
|
472 |
william |
62 |
// vif1.done = false; |
473 |
|
|
|
474 |
|
|
//if(vif1.irqoffset != 0 && vif1.vifstalled == true) DevCon.Warning("Offset on VIF1 start! offset %x, Progress %x", vif1.irqoffset, vif1.vifstalled); |
475 |
|
|
/*vif1.irqoffset = 0; |
476 |
|
|
vif1.vifstalled = false; |
477 |
|
|
vif1.inprogress = 0;*/ |
478 |
william |
31 |
g_vifCycles = 0; |
479 |
william |
62 |
g_vu1Cycles = 0; |
480 |
william |
31 |
|
481 |
|
|
#ifdef PCSX2_DEVBUILD |
482 |
william |
62 |
if (dmacRegs.ctrl.STD == STD_VIF1) |
483 |
william |
31 |
{ |
484 |
|
|
//DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); |
485 |
|
|
} |
486 |
|
|
#endif |
487 |
|
|
|
488 |
william |
62 |
if ((vif1ch.chcr.MOD == NORMAL_MODE) || vif1ch.qwc > 0) // Normal Mode |
489 |
william |
31 |
{ |
490 |
|
|
|
491 |
william |
62 |
if (dmacRegs.ctrl.STD == STD_VIF1) |
492 |
william |
31 |
Console.WriteLn("DMA Stall Control on VIF1 normal"); |
493 |
|
|
|
494 |
william |
62 |
if (vif1ch.chcr.DIR) // to Memory |
495 |
william |
31 |
vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; |
496 |
|
|
else |
497 |
|
|
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; |
498 |
|
|
|
499 |
william |
62 |
vif1.done = false; |
500 |
|
|
|
501 |
|
|
// ignore tag if it's a GS download (Def Jam Fight for NY) |
502 |
|
|
if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_MODE) |
503 |
|
|
{ |
504 |
|
|
vif1.dmamode = VIF_CHAIN_MODE; |
505 |
william |
280 |
//DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); |
506 |
william |
62 |
|
507 |
|
|
if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END)) |
508 |
|
|
{ |
509 |
|
|
vif1.done = true; |
510 |
|
|
} |
511 |
|
|
} |
512 |
william |
31 |
} |
513 |
|
|
else |
514 |
|
|
{ |
515 |
|
|
vif1.dmamode = VIF_CHAIN_MODE; |
516 |
william |
62 |
vif1.done = false; |
517 |
william |
280 |
vif1.inprogress = 0; |
518 |
william |
31 |
} |
519 |
|
|
|
520 |
william |
62 |
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); |
521 |
william |
31 |
|
522 |
|
|
// Chain Mode |
523 |
william |
62 |
CPU_INT(DMAC_VIF1, 4); |
524 |
william |
31 |
} |