/[pcsx2_0.9.7]/trunk/pcsx2/Vif1_Dma.cpp
ViewVC logotype

Contents of /trunk/pcsx2/Vif1_Dma.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22