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

Annotation of /trunk/pcsx2/Gif.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (hide annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 21063 byte(s)
re-commit (had local access denied errors when committing)
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    
19     #include "GS.h"
20     #include "Gif.h"
21     #include "Vif_Dma.h"
22    
23     #include "iR5900.h"
24    
25     using std::min;
26    
27     // A three-way toggle used to determine if the GIF is stalling (transferring) or done (finished).
28     // Should be a gifstate_t rather then int, but I don't feel like possibly interfering with savestates right now.
29     static int gifstate = GIF_STATE_READY;
30    
31     static bool gspath3done = false;
32    
33     static u32 gscycles = 0, prevcycles = 0, mfifocycles = 0;
34     static u32 gifqwc = 0;
35     static bool gifmfifoirq = false;
36    
37 william 62 //Just some temporary bits to store Path1 transfers if another is in progress.
38     __aligned16 u8 Path1Buffer[0x1000000];
39     u32 Path1WritePos = 0;
40     u32 Path1ReadPos = 0;
41    
42     static __fi void clearFIFOstuff(bool full)
43 william 31 {
44     if (full)
45 william 62 CSRreg.FIFO = CSR_FIFO_FULL;
46 william 31 else
47 william 62 CSRreg.FIFO = CSR_FIFO_EMPTY;
48 william 31 }
49 william 280 extern bool SIGNAL_IMR_Pending;
50 william 62 void gsPath1Interrupt()
51 william 31 {
52 william 62 //DevCon.Warning("Path1 flush W %x, R %x", Path1WritePos, Path1ReadPos);
53    
54    
55    
56 william 280 if((gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.IP3 == true && gifRegs.stat.APATH == GIF_APATH3)) && Path1WritePos > 0 && !gifRegs.stat.PSE && SIGNAL_IMR_Pending == false)
57 william 62 {
58     gifRegs.stat.P1Q = false;
59    
60     if (uint size = (Path1WritePos - Path1ReadPos))
61     {
62     GetMTGS().PrepDataPacket(GIF_PATH_1, size);
63     //DevCon.Warning("Flush Size = %x", size);
64 william 280 while(size > 0 && SIGNAL_IMR_Pending == false)
65 william 62 {
66     uint count = GIFPath_CopyTag(GIF_PATH_1, ((u128*)Path1Buffer) + Path1ReadPos, size);
67     Path1ReadPos += count;
68     size -= count;
69    
70     if(GSTransferStatus.PTH1 == STOPPED_MODE)
71     {
72     gifRegs.stat.OPH = false;
73     gifRegs.stat.APATH = GIF_APATH_IDLE;
74     }
75     }
76     GetMTGS().SendDataPacket();
77    
78     if(Path1ReadPos == Path1WritePos)
79     {
80     Path1WritePos = Path1ReadPos = 0;
81 william 280 }
82     else
83     {
84     //DevCon.Warning("Queue quitting early due to signal or EOP %x", size);
85     gifRegs.stat.P1Q = true;
86 william 62 }
87     }
88     }
89     else
90     {
91     if(gifRegs.stat.PSE) DevCon.Warning("Path1 paused by GIF_CTRL");
92 william 280 //DevCon.Warning("Looping??? IP3 %x APATH %x OPH %x", gifRegs.stat.IP3, gifRegs.stat.APATH, gifRegs.stat.OPH);
93 william 62 //if(!(cpuRegs.interrupt & (1<<28)) && Path1WritePos > 0)CPU_INT(28, 128);
94     }
95    
96     }
97    
98     extern bool SIGNAL_IMR_Pending;
99    
100     __fi void gsInterrupt()
101     {
102 william 31 GIF_LOG("gsInterrupt: %8.8x", cpuRegs.cycle);
103    
104 william 280 if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO
105     {
106     //Console.WriteLn("GIF MFIFO");
107     gifMFIFOInterrupt();
108     return;
109     }
110    
111 william 62 if(SIGNAL_IMR_Pending == true)
112 william 31 {
113 william 62 //DevCon.Warning("Path 3 Paused");
114     CPU_INT(DMAC_GIF, 128);
115 william 31 return;
116     }
117    
118 william 62 if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 )
119     {
120     gifRegs.stat.OPH = false;
121     GSTransferStatus.PTH3 = STOPPED_MODE;
122     gifRegs.stat.APATH = GIF_APATH_IDLE;
123     if(gifRegs.stat.P1Q) gsPath1Interrupt();
124     }
125    
126 william 31
127 william 62 if (!(gifch.chcr.STR))
128 william 31 {
129 william 62 //Console.WriteLn("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x", gifch.chcr._u32, gifch.qwc, done);
130     return;
131 william 31 }
132    
133 william 62
134     if ((gifch.qwc > 0) || (!gspath3done))
135 william 31 {
136 william 62 if (!dmacRegs.ctrl.DMAE)
137 william 31 {
138     Console.Warning("gs dma masked, re-scheduling...");
139     // re-raise the int shortly in the future
140     CPU_INT( DMAC_GIF, 64 );
141     return;
142     }
143    
144     GIFdma();
145     return;
146     }
147    
148     gspath3done = false;
149     gscycles = 0;
150 william 62 gifch.chcr.STR = false;
151 william 31
152 william 62 ////
153     /*gifRegs.stat.OPH = false;
154     GSTransferStatus.PTH3 = STOPPED_MODE;
155     gifRegs.stat.APATH = GIF_APATH_IDLE;*/
156     ////
157     gifRegs.stat.clear_flags(GIF_STAT_FQC);
158 william 31 clearFIFOstuff(false);
159     hwDmacIrq(DMAC_GIF);
160 william 62 //DevCon.Warning("GIF DMA end");
161 william 31 }
162    
163     static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
164     {
165 william 62 GetMTGS().PrepDataPacket(GIF_PATH_3, qwc);
166     uint size = GIFPath_CopyTag(GIF_PATH_3, (u128*)pMem, qwc );
167 william 31 GetMTGS().SendDataPacket();
168     return size;
169     }
170    
171     static u32 WRITERING_DMA(tDMA_TAG *pMem, u32 qwc)
172     {
173     return WRITERING_DMA((u32*)pMem, qwc);
174     }
175    
176     int _GIFchain()
177     {
178     tDMA_TAG *pMem;
179    
180 william 62 pMem = dmaGetAddr(gifch.madr, false);
181 william 31 if (pMem == NULL)
182     {
183     // reset path3, fixes dark cloud 2
184     GIFPath_Clear( GIF_PATH_3 );
185    
186     //must increment madr and clear qwc, else it loops
187 william 62 gifch.madr += gifch.qwc * 16;
188     gifch.qwc = 0;
189 william 31 Console.Warning( "Hackfix - NULL GIFchain" );
190     return -1;
191     }
192    
193 william 62 return WRITERING_DMA(pMem, gifch.qwc);
194 william 31 }
195    
196 william 62 static __fi void GIFchain()
197 william 31 {
198     // qwc check now done outside this function
199     // Voodoocycles
200     // >> 2 so Drakan and Tekken 5 don't mess up in some PATH3 transfer. Cycles to interrupt were getting huge..
201 william 62 /*if (gifch.qwc)*/ gscycles+= ( _GIFchain() * BIAS); /* guessing */
202 william 31 }
203    
204 william 62 static __fi bool checkTieBit(tDMA_TAG* &ptag)
205 william 31 {
206 william 62 if (gifch.chcr.TIE && ptag->IRQ)
207 william 31 {
208     GIF_LOG("dmaIrq Set");
209     gspath3done = true;
210     return true;
211     }
212    
213     return false;
214     }
215    
216 william 62 static __fi tDMA_TAG* ReadTag()
217 william 31 {
218 william 62 tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); //Set memory pointer to TADR
219 william 31
220 william 62 if (!(gifch.transfer("Gif", ptag))) return NULL;
221 william 31
222 william 62 gifch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
223 william 31 gscycles += 2; // Add 1 cycles from the QW read for the tag
224    
225 william 62 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
226 william 31 return ptag;
227     }
228    
229 william 62 static __fi tDMA_TAG* ReadTag2()
230 william 31 {
231 william 62 tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); //Set memory pointer to TADR
232 william 31
233 william 62 gifch.unsafeTransfer(ptag);
234     gifch.madr = ptag[1]._u32;
235 william 31
236 william 62 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
237 william 31 return ptag;
238     }
239    
240 william 62 bool CheckPaths(int Channel)
241     {
242     if(GSTransferStatus.PTH3 <= IMAGE_MODE && gifRegs.mode.IMT)
243     {
244     if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3))
245     {
246     if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true)
247     {
248 william 280 //DevCon.Warning("GIF Stall 1 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
249 william 62 gifRegs.stat.IP3 = true;
250     if(gifRegs.stat.P1Q) gsPath1Interrupt();
251     CPU_INT(DMAC_GIF, 16);
252     return false;
253     }
254     }
255     }
256     else if((GSTransferStatus.PTH3 == IDLE_MODE)|| (GSTransferStatus.PTH3 == STOPPED_MODE))
257     {
258     //This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed).
259     if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3))
260     {
261 william 280 //DevCon.Warning("GIF Stall 2 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
262 william 62 gifRegs.stat.IP3 = true;
263     CPU_INT(DMAC_GIF, 16);
264     return false;
265     }
266     }
267    
268     gifRegs.stat.IP3 = false;
269     return true;
270     }
271    
272 william 31 void GIFdma()
273     {
274     tDMA_TAG *ptag;
275    
276     gscycles = prevcycles;
277    
278 william 62 if (gifRegs.ctrl.PSE) // temporarily stop
279 william 31 {
280 william 62 Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)");
281     CPU_INT(DMAC_GIF, 16);
282 william 31 return;
283     }
284    
285 william 62 if ((dmacRegs.ctrl.STD == STD_GIF) && (prevcycles != 0))
286 william 31 {
287 william 62 //Console.WriteLn("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gifch.madr, psHu32(DMAC_STADR));
288 william 31
289 william 62 if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR)
290 william 31 {
291     CPU_INT(DMAC_GIF, 4);
292     gscycles = 0;
293     return;
294     }
295    
296     prevcycles = 0;
297 william 62 gifch.qwc = 0;
298 william 31 }
299    
300     clearFIFOstuff(true);
301 william 62 gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
302 william 31
303 william 62
304     if (vif1Regs.mskpath3 || gifRegs.mode.M3R)
305 william 31 {
306 william 62 if (gifch.qwc == 0)
307 william 31 {
308 william 62 if ((gifch.chcr.MOD == CHAIN_MODE) && gifch.chcr.STR)
309 william 31 {
310 william 62 //DevCon.Warning("GIF Reading Tag Masked MSK = %x", vif1Regs.mskpath3);
311 william 31 ptag = ReadTag();
312 william 62 gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
313 william 31 if (ptag == NULL) return;
314 william 62 GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr);
315 william 31
316     //Check TIE bit of CHCR and IRQ bit of tag
317     if (checkTieBit(ptag)) GIF_LOG("PATH3 MSK dmaIrq Set");
318     }
319     }
320 william 62
321 william 31
322 william 62 if (GSTransferStatus.PTH3 == IDLE_MODE)
323 william 31 {
324 william 62 GIF_LOG("PTH3 MASK Paused by VIF QWC %x", gifch.qwc);
325    
326     //DevCon.Warning("GIF Paused by Mask MSK = %x", vif1Regs.mskpath3);
327    
328     if(gifch.qwc == 0) gsInterrupt();
329     else gifRegs.stat.set_flags(GIF_STAT_P3Q);
330 william 31 return;
331     }
332 william 62
333    
334    
335     gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
336 william 31 //Check with Path3 masking games
337 william 62 if (gifch.qwc > 0) {
338     gifRegs.stat.set_flags(GIF_STAT_P3Q);
339     if(CheckPaths(DMAC_GIF) == false) return;
340     gifRegs.stat.clear_flags(GIF_STAT_P3Q);
341 william 31 GIF_LOG("PTH3 MASK Transferring");
342 william 62 GIFchain();
343     /*if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH_IDLE)
344     {
345     GSTransferStatus.PTH3 = STOPPED_MODE;
346     }*/
347 william 31 }//else DevCon.WriteLn("GIFdma() case 1, but qwc = 0!"); //Don't do 0 GIFchain and then return
348 william 62 CPU_INT(DMAC_GIF, gscycles);
349 william 31 return;
350    
351     }
352 william 62
353 william 31 // Transfer Dn_QWC from Dn_MADR to GIF
354 william 62 if ((gifch.chcr.MOD == NORMAL_MODE) || (gifch.qwc > 0)) // Normal Mode
355 william 31 {
356    
357 william 62 if ((dmacRegs.ctrl.STD == STD_GIF) && (gifch.chcr.MOD == NORMAL_MODE))
358 william 31 {
359 william 62 //Console.WriteLn("DMA Stall Control on GIF normal");
360 william 31 }
361 william 62 gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
362 william 31 //Check with Path3 masking games
363 william 62 //DevCon.Warning("GIF Transferring Normal/ChainQWC MSK = %x", vif1Regs.mskpath3);
364    
365    
366    
367     if (gifch.qwc > 0) {
368     gifRegs.stat.set_flags(GIF_STAT_P3Q);
369     if(CheckPaths(DMAC_GIF) == false) return;
370     gifRegs.stat.clear_flags(GIF_STAT_P3Q);
371 william 31 GIFchain(); //Transfers the data set by the switch
372 william 62 CPU_INT(DMAC_GIF, gscycles);
373 william 31 return;
374 william 62 } else DevCon.Warning("GIF Normalmode or QWC going to invalid case? CHCR %x", gifch.chcr._u32);
375 william 31
376     //else DevCon.WriteLn("GIFdma() case 2, but qwc = 0!"); //Don't do 0 GIFchain and then return, fixes Dual Hearts
377     }
378    
379 william 62 if ((gifch.chcr.MOD == CHAIN_MODE) && (!gspath3done)) // Chain Mode
380 william 31 {
381     ptag = ReadTag();
382     if (ptag == NULL) return;
383 william 62 //DevCon.Warning("GIF Reading Tag MSK = %x", vif1Regs.mskpath3);
384     GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr);
385     gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
386     if (dmacRegs.ctrl.STD == STD_GIF)
387 william 31 {
388 william 62 // there are still bugs, need to also check if gifch.madr +16*qwc >= stadr, if not, stall
389     if (!gspath3done && ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR) && (ptag->ID == TAG_REFS))
390 william 31 {
391     // stalled.
392     // We really need to test this. Pay attention to prevcycles, as it used to trigger GIFchains in the code above. (rama)
393 william 62 //Console.WriteLn("GS Stall Control start Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gifch.madr, psHu32(DMAC_STADR));
394 william 31 prevcycles = gscycles;
395 william 62 //gifch.tadr -= 16;
396     // Quake III revolution wants to see tadr move.
397     // Simple Media System (homebrew) as well.
398     // -16 also seems right (it shifts the bg image right if anything else).
399     gifch.tadr -= 16;
400     // Next line also needs to be here, according to ref
401     gifch.qwc = 0;
402 william 31 hwDmacIrq(DMAC_STALL_SIS);
403     CPU_INT(DMAC_GIF, gscycles);
404     gscycles = 0;
405     return;
406     }
407     }
408    
409     checkTieBit(ptag);
410 william 62 /*if(gifch.qwc == 0)
411     {
412     gsInterrupt();
413     return;
414     }*/
415 william 31 }
416    
417     prevcycles = 0;
418 william 62 CPU_INT(DMAC_GIF, gscycles);
419     gifRegs.stat.FQC = min((u16)0x10, gifch.qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
420 william 31 }
421    
422     void dmaGIF()
423     {
424     //We used to add wait time for the buffer to fill here, fixing some timing problems in path 3 masking
425     //It takes the time of 24 QW for the BUS to become ready - The Punisher And Streetball
426 william 62 //DevCon.Warning("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx", gifch.chcr._u32, gifch.madr, gifch.qwc, gifch.tadr, gifch.asr0, gifch.asr1);
427 william 31
428     gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
429    
430 william 62 gifRegs.stat.FQC |= 0x10; // hack ;)
431 william 31
432 william 62 if (gifch.chcr.MOD == NORMAL_MODE) { //Else it really is a normal transfer and we want to quit, else it gets confused with chains
433     gspath3done = true;
434     }
435 william 31 clearFIFOstuff(true);
436    
437 william 62 if(gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0)
438 william 31 {
439 william 62 //DevCon.Warning(L"GIF QWC on Chain " + gifch.chcr.desc());
440     if ((gifch.chcr.tag().ID == TAG_REFE) || (gifch.chcr.tag().ID == TAG_END))
441     {
442     gspath3done = true;
443     }
444 william 31 }
445    
446 william 280
447 william 31
448 william 280 gsInterrupt();
449 william 31 }
450    
451 william 280 static u16 QWCinGIFMFIFO(u32 DrainADDR)
452     {
453     u32 ret;
454    
455    
456     GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR);
457     //Calculate what we have in the fifo.
458     if(DrainADDR <= spr0ch.madr)
459     {
460     //Drain is below the tadr, calculate the difference between them
461     ret = (spr0ch.madr - DrainADDR) >> 4;
462     }
463     else
464     {
465     u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
466     //Drain is higher than SPR so it has looped round,
467     //calculate from base to the SPR tag addr and what is left in the top of the ring
468     ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4;
469     }
470     GIF_LOG("%x Available of the %x requested", ret, gifch.qwc);
471     if((s32)ret < 0) DevCon.Warning("GIF Returning %x!", ret);
472     return ret;
473     }
474    
475 william 31 // called from only one location, so forceinline it:
476 william 62 static __fi bool mfifoGIFrbTransfer()
477 william 31 {
478 william 280 u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc);
479 william 31 u32 *src;
480    
481 william 280 if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data
482    
483 william 62 GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc);
484    
485     // TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of
486     // its own internally now. We just need to groom a version of it that can wrap around MFIFO
487     // memory similarly to how it wraps VU1 memory on PATH1.
488 william 280 GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc);
489 william 31 /* Check if the transfer should wrap around the ring buffer */
490 william 280 if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
491 william 31 {
492 william 62 uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
493 william 31 uint s2 = (mfifoqwc - s1);
494 william 280 GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc);
495 william 31 /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */
496 william 62 /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
497 william 280
498     gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
499 william 62 src = (u32*)PSM(gifch.madr);
500 william 31 if (src == NULL) return false;
501 william 62 uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1);
502 william 31
503 william 62 if (copied == s1) // but only copy second if first didn't abort prematurely for some reason.
504 william 31 {
505 william 280 GIF_LOG("Transferring last %x QWC", s2);
506 william 62 src = (u32*)PSM(dmacRegs.rbor.ADDR);
507 william 280 gifch.madr = dmacRegs.rbor.ADDR;
508 william 31 if (src == NULL) return false;
509 william 62 copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2);
510 william 31 }
511    
512 william 62 mfifoqwc = copied;
513 william 280 GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc);
514 william 31 }
515     else
516     {
517 william 280 GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc);
518 william 62 /* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */
519 william 280
520     gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
521 william 62 src = (u32*)PSM(gifch.madr);
522 william 31 if (src == NULL) return false;
523 william 62 mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc);
524 william 280 GIF_LOG("%X QWC Copied direct %x QWC Left", mfifoqwc, gifch.qwc);
525 william 31 }
526    
527 william 62 GetMTGS().SendDataPacket();
528 william 280 //gifqwc -= mfifoqwc;
529     mfifocycles += (mfifoqwc) * 2; /* guessing */
530 william 31
531     return true;
532     }
533    
534     // called from only one location, so forceinline it:
535 william 62 static __fi bool mfifoGIFchain()
536 william 31 {
537     /* Is QWC = 0? if so there is nothing to transfer */
538 william 62 if (gifch.qwc == 0) return true;
539 william 31
540 william 62 if (gifch.madr >= dmacRegs.rbor.ADDR &&
541 william 280 gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
542 william 31 {
543 william 280 bool ret = true;
544     // if(gifch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge GIF");
545     if (!mfifoGIFrbTransfer()) ret = false;
546     if(QWCinGIFMFIFO(gifch.madr) == 0) gifstate |= GIF_STATE_EMPTY;
547     return ret;
548    
549 william 31 }
550     else
551     {
552     int mfifoqwc;
553 william 280 GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc);
554 william 62 tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false);
555 william 31 if (pMem == NULL) return false;
556    
557 william 62 mfifoqwc = WRITERING_DMA(pMem, gifch.qwc);
558 william 31 mfifocycles += (mfifoqwc) * 2; /* guessing */
559     }
560    
561     return true;
562     }
563    
564     static u32 qwctag(u32 mask)
565     {
566 william 62 return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
567 william 31 }
568    
569     void mfifoGIFtransfer(int qwc)
570     {
571     tDMA_TAG *ptag;
572    
573     mfifocycles = 0;
574     gifmfifoirq = false;
575    
576     if(qwc > 0 )
577     {
578 william 280 if ((gifstate & GIF_STATE_EMPTY) && !(cpuRegs.interrupt & (1<<DMAC_MFIFO_GIF)))
579     {
580     if(gifch.chcr.STR == true)CPU_INT(DMAC_MFIFO_GIF, 4);
581     gifstate &= ~GIF_STATE_EMPTY;
582     }
583     gifRegs.stat.FQC = 16;
584     return;
585 william 31 }
586    
587 william 62 if (gifRegs.ctrl.PSE) // temporarily stop
588     {
589     Console.WriteLn("Gif dma temp paused?");
590     CPU_INT(DMAC_MFIFO_GIF, 16);
591     return;
592     }
593 william 31
594 william 62 if (gifch.qwc == 0)
595 william 31 {
596 william 62 gifch.tadr = qwctag(gifch.tadr);
597 william 31
598 william 62 ptag = dmaGetAddr(gifch.tadr, false);
599     gifch.unsafeTransfer(ptag);
600     gifch.madr = ptag[1]._u32;
601 william 31
602     mfifocycles += 2;
603    
604     GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x",
605 william 62 ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gifqwc, spr0ch.madr);
606 william 31
607 william 280 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
608 william 31
609 william 280 if(gspath3done == true) gifstate = GIF_STATE_DONE;
610     else gifstate = GIF_STATE_READY;
611 william 31
612 william 62 if ((gifch.chcr.TIE) && (ptag->IRQ))
613 william 31 {
614     SPR_LOG("dmaIrq Set");
615     gifstate = GIF_STATE_DONE;
616     gifmfifoirq = true;
617     }
618 william 280 if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY;
619     }
620 william 31
621     if (!mfifoGIFchain())
622     {
623 william 62 Console.WriteLn("GIF dmaChain error size=%d, madr=%lx, tadr=%lx", gifch.qwc, gifch.madr, gifch.tadr);
624 william 31 gifstate = GIF_STATE_STALL;
625     }
626    
627 william 280 if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL;
628 william 62 CPU_INT(DMAC_MFIFO_GIF,mfifocycles);
629 william 31
630 william 62 SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr);
631 william 31 }
632    
633     void gifMFIFOInterrupt()
634     {
635 william 280 GIF_LOG("gifMFIFOInterrupt");
636 william 31 mfifocycles = 0;
637    
638 william 280 if (dmacRegs.ctrl.MFD != MFD_GIF)
639     {
640     DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO");
641     return;
642     }
643    
644 william 62 if(SIGNAL_IMR_Pending == true)
645 william 31 {
646 william 62 //DevCon.Warning("Path 3 Paused");
647     CPU_INT(DMAC_MFIFO_GIF, 128);
648     return;
649 william 31 }
650    
651 william 280 if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 )
652 william 31 {
653 william 62 gifRegs.stat.OPH = false;
654 william 280 GSTransferStatus.PTH3 = STOPPED_MODE;
655 william 62 gifRegs.stat.APATH = GIF_APATH_IDLE;
656     if(gifRegs.stat.P1Q) gsPath1Interrupt();
657 william 31 }
658    
659 william 280 if((gifstate & GIF_STATE_EMPTY))
660     {
661     FireMFIFOEmpty();
662     if(!(gifstate & GIF_STATE_STALL)) return;
663     }
664    
665 william 62 if(CheckPaths(11) == false) return;
666    
667     if (!(gifch.chcr.STR))
668 william 31 {
669     Console.WriteLn("WTF GIFMFIFO");
670     cpuRegs.interrupt &= ~(1 << 11);
671     return;
672     }
673    
674     if (!(gifstate & GIF_STATE_STALL))
675     {
676 william 280 if (QWCinGIFMFIFO(gifch.tadr) == 0)
677 william 31 {
678     gifstate |= GIF_STATE_EMPTY;
679 william 280 CPU_INT(DMAC_MFIFO_GIF, 4);
680 william 31 return;
681     }
682 william 280
683 william 31 mfifoGIFtransfer(0);
684     return;
685     }
686    
687     #ifdef PCSX2_DEVBUILD
688 william 62 if ((gifstate & GIF_STATE_READY) || (gifch.qwc > 0))
689 william 31 {
690     Console.Error("gifMFIFO Panic > Shouldn't go here!");
691     return;
692     }
693     #endif
694     //if(gifqwc > 0) Console.WriteLn("GIF MFIFO ending with stuff in it %x", gifqwc);
695     if (!gifmfifoirq) gifqwc = 0;
696    
697     gspath3done = false;
698     gscycles = 0;
699    
700 william 62 gifRegs.stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_P3Q | GIF_STAT_FQC); // APATH, P3Q, FQC = 0
701 william 31
702 william 62 vif1Regs.stat.VGW = false;
703     gifch.chcr.STR = false;
704 william 31 gifstate = GIF_STATE_READY;
705     hwDmacIrq(DMAC_GIF);
706 william 280 GIF_LOG("gifMFIFO End");
707 william 31 clearFIFOstuff(false);
708     }
709    
710     void SaveStateBase::gifFreeze()
711     {
712     FreezeTag( "GIFdma" );
713    
714     Freeze( gifstate );
715     Freeze( gifqwc );
716     Freeze( gspath3done );
717     Freeze( gscycles );
718     // Note: mfifocycles is not a persistent var, so no need to save it here.
719 william 62
720     int bufsize = Path1WritePos - Path1ReadPos;
721     Freeze(bufsize);
722    
723     if (IsSaving())
724     {
725     // We can just load the queued Path1 data into the front of the buffer, and
726     // reset the ReadPos and WritePos accordingly.
727     FreezeMem(Path1Buffer, bufsize);
728     Path1ReadPos = 0;
729     Path1WritePos = bufsize;
730     }
731     else
732     {
733     // Only want to save the actual Path1 data between readpos and writepos. The
734     // rest of the buffer is just unused-ness!
735     FreezeMem(&Path1Buffer[Path1ReadPos], bufsize);
736     }
737 william 31 }

  ViewVC Help
Powered by ViewVC 1.1.22