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

Contents of /trunk/pcsx2/Gif.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years ago) by william
File size: 21063 byte(s)
re-commit (had local access denied errors when committing)
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
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 //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 {
44 if (full)
45 CSRreg.FIFO = CSR_FIFO_FULL;
46 else
47 CSRreg.FIFO = CSR_FIFO_EMPTY;
48 }
49 extern bool SIGNAL_IMR_Pending;
50 void gsPath1Interrupt()
51 {
52 //DevCon.Warning("Path1 flush W %x, R %x", Path1WritePos, Path1ReadPos);
53
54
55
56 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 {
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 while(size > 0 && SIGNAL_IMR_Pending == false)
65 {
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 }
82 else
83 {
84 //DevCon.Warning("Queue quitting early due to signal or EOP %x", size);
85 gifRegs.stat.P1Q = true;
86 }
87 }
88 }
89 else
90 {
91 if(gifRegs.stat.PSE) DevCon.Warning("Path1 paused by GIF_CTRL");
92 //DevCon.Warning("Looping??? IP3 %x APATH %x OPH %x", gifRegs.stat.IP3, gifRegs.stat.APATH, gifRegs.stat.OPH);
93 //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 GIF_LOG("gsInterrupt: %8.8x", cpuRegs.cycle);
103
104 if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO
105 {
106 //Console.WriteLn("GIF MFIFO");
107 gifMFIFOInterrupt();
108 return;
109 }
110
111 if(SIGNAL_IMR_Pending == true)
112 {
113 //DevCon.Warning("Path 3 Paused");
114 CPU_INT(DMAC_GIF, 128);
115 return;
116 }
117
118 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
127 if (!(gifch.chcr.STR))
128 {
129 //Console.WriteLn("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x", gifch.chcr._u32, gifch.qwc, done);
130 return;
131 }
132
133
134 if ((gifch.qwc > 0) || (!gspath3done))
135 {
136 if (!dmacRegs.ctrl.DMAE)
137 {
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 gifch.chcr.STR = false;
151
152 ////
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 clearFIFOstuff(false);
159 hwDmacIrq(DMAC_GIF);
160 //DevCon.Warning("GIF DMA end");
161 }
162
163 static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
164 {
165 GetMTGS().PrepDataPacket(GIF_PATH_3, qwc);
166 uint size = GIFPath_CopyTag(GIF_PATH_3, (u128*)pMem, qwc );
167 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 pMem = dmaGetAddr(gifch.madr, false);
181 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 gifch.madr += gifch.qwc * 16;
188 gifch.qwc = 0;
189 Console.Warning( "Hackfix - NULL GIFchain" );
190 return -1;
191 }
192
193 return WRITERING_DMA(pMem, gifch.qwc);
194 }
195
196 static __fi void GIFchain()
197 {
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 /*if (gifch.qwc)*/ gscycles+= ( _GIFchain() * BIAS); /* guessing */
202 }
203
204 static __fi bool checkTieBit(tDMA_TAG* &ptag)
205 {
206 if (gifch.chcr.TIE && ptag->IRQ)
207 {
208 GIF_LOG("dmaIrq Set");
209 gspath3done = true;
210 return true;
211 }
212
213 return false;
214 }
215
216 static __fi tDMA_TAG* ReadTag()
217 {
218 tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); //Set memory pointer to TADR
219
220 if (!(gifch.transfer("Gif", ptag))) return NULL;
221
222 gifch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
223 gscycles += 2; // Add 1 cycles from the QW read for the tag
224
225 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
226 return ptag;
227 }
228
229 static __fi tDMA_TAG* ReadTag2()
230 {
231 tDMA_TAG* ptag = dmaGetAddr(gifch.tadr, false); //Set memory pointer to TADR
232
233 gifch.unsafeTransfer(ptag);
234 gifch.madr = ptag[1]._u32;
235
236 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
237 return ptag;
238 }
239
240 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 //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 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 //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 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 void GIFdma()
273 {
274 tDMA_TAG *ptag;
275
276 gscycles = prevcycles;
277
278 if (gifRegs.ctrl.PSE) // temporarily stop
279 {
280 Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)");
281 CPU_INT(DMAC_GIF, 16);
282 return;
283 }
284
285 if ((dmacRegs.ctrl.STD == STD_GIF) && (prevcycles != 0))
286 {
287 //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
289 if ((gifch.madr + (gifch.qwc * 16)) > dmacRegs.stadr.ADDR)
290 {
291 CPU_INT(DMAC_GIF, 4);
292 gscycles = 0;
293 return;
294 }
295
296 prevcycles = 0;
297 gifch.qwc = 0;
298 }
299
300 clearFIFOstuff(true);
301 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
303
304 if (vif1Regs.mskpath3 || gifRegs.mode.M3R)
305 {
306 if (gifch.qwc == 0)
307 {
308 if ((gifch.chcr.MOD == CHAIN_MODE) && gifch.chcr.STR)
309 {
310 //DevCon.Warning("GIF Reading Tag Masked MSK = %x", vif1Regs.mskpath3);
311 ptag = ReadTag();
312 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 if (ptag == NULL) return;
314 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
316 //Check TIE bit of CHCR and IRQ bit of tag
317 if (checkTieBit(ptag)) GIF_LOG("PATH3 MSK dmaIrq Set");
318 }
319 }
320
321
322 if (GSTransferStatus.PTH3 == IDLE_MODE)
323 {
324 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 return;
331 }
332
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 //Check with Path3 masking games
337 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 GIF_LOG("PTH3 MASK Transferring");
342 GIFchain();
343 /*if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH_IDLE)
344 {
345 GSTransferStatus.PTH3 = STOPPED_MODE;
346 }*/
347 }//else DevCon.WriteLn("GIFdma() case 1, but qwc = 0!"); //Don't do 0 GIFchain and then return
348 CPU_INT(DMAC_GIF, gscycles);
349 return;
350
351 }
352
353 // Transfer Dn_QWC from Dn_MADR to GIF
354 if ((gifch.chcr.MOD == NORMAL_MODE) || (gifch.qwc > 0)) // Normal Mode
355 {
356
357 if ((dmacRegs.ctrl.STD == STD_GIF) && (gifch.chcr.MOD == NORMAL_MODE))
358 {
359 //Console.WriteLn("DMA Stall Control on GIF normal");
360 }
361 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 //Check with Path3 masking games
363 //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 GIFchain(); //Transfers the data set by the switch
372 CPU_INT(DMAC_GIF, gscycles);
373 return;
374 } else DevCon.Warning("GIF Normalmode or QWC going to invalid case? CHCR %x", gifch.chcr._u32);
375
376 //else DevCon.WriteLn("GIFdma() case 2, but qwc = 0!"); //Don't do 0 GIFchain and then return, fixes Dual Hearts
377 }
378
379 if ((gifch.chcr.MOD == CHAIN_MODE) && (!gspath3done)) // Chain Mode
380 {
381 ptag = ReadTag();
382 if (ptag == NULL) return;
383 //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 {
388 // 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 {
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 //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 prevcycles = gscycles;
395 //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 hwDmacIrq(DMAC_STALL_SIS);
403 CPU_INT(DMAC_GIF, gscycles);
404 gscycles = 0;
405 return;
406 }
407 }
408
409 checkTieBit(ptag);
410 /*if(gifch.qwc == 0)
411 {
412 gsInterrupt();
413 return;
414 }*/
415 }
416
417 prevcycles = 0;
418 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 }
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 //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
428 gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
429
430 gifRegs.stat.FQC |= 0x10; // hack ;)
431
432 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 clearFIFOstuff(true);
436
437 if(gifch.chcr.MOD == CHAIN_MODE && gifch.qwc > 0)
438 {
439 //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 }
445
446
447
448 gsInterrupt();
449 }
450
451 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 // called from only one location, so forceinline it:
476 static __fi bool mfifoGIFrbTransfer()
477 {
478 u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc);
479 u32 *src;
480
481 if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data
482
483 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 GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc);
489 /* Check if the transfer should wrap around the ring buffer */
490 if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
491 {
492 uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
493 uint s2 = (mfifoqwc - s1);
494 GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc);
495 /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */
496 /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
497
498 gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
499 src = (u32*)PSM(gifch.madr);
500 if (src == NULL) return false;
501 uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1);
502
503 if (copied == s1) // but only copy second if first didn't abort prematurely for some reason.
504 {
505 GIF_LOG("Transferring last %x QWC", s2);
506 src = (u32*)PSM(dmacRegs.rbor.ADDR);
507 gifch.madr = dmacRegs.rbor.ADDR;
508 if (src == NULL) return false;
509 copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2);
510 }
511
512 mfifoqwc = copied;
513 GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc);
514 }
515 else
516 {
517 GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc);
518 /* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */
519
520 gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK);
521 src = (u32*)PSM(gifch.madr);
522 if (src == NULL) return false;
523 mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc);
524 GIF_LOG("%X QWC Copied direct %x QWC Left", mfifoqwc, gifch.qwc);
525 }
526
527 GetMTGS().SendDataPacket();
528 //gifqwc -= mfifoqwc;
529 mfifocycles += (mfifoqwc) * 2; /* guessing */
530
531 return true;
532 }
533
534 // called from only one location, so forceinline it:
535 static __fi bool mfifoGIFchain()
536 {
537 /* Is QWC = 0? if so there is nothing to transfer */
538 if (gifch.qwc == 0) return true;
539
540 if (gifch.madr >= dmacRegs.rbor.ADDR &&
541 gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
542 {
543 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 }
550 else
551 {
552 int mfifoqwc;
553 GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc);
554 tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false);
555 if (pMem == NULL) return false;
556
557 mfifoqwc = WRITERING_DMA(pMem, gifch.qwc);
558 mfifocycles += (mfifoqwc) * 2; /* guessing */
559 }
560
561 return true;
562 }
563
564 static u32 qwctag(u32 mask)
565 {
566 return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
567 }
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 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 }
586
587 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
594 if (gifch.qwc == 0)
595 {
596 gifch.tadr = qwctag(gifch.tadr);
597
598 ptag = dmaGetAddr(gifch.tadr, false);
599 gifch.unsafeTransfer(ptag);
600 gifch.madr = ptag[1]._u32;
601
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 ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gifqwc, spr0ch.madr);
606
607 gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID);
608
609 if(gspath3done == true) gifstate = GIF_STATE_DONE;
610 else gifstate = GIF_STATE_READY;
611
612 if ((gifch.chcr.TIE) && (ptag->IRQ))
613 {
614 SPR_LOG("dmaIrq Set");
615 gifstate = GIF_STATE_DONE;
616 gifmfifoirq = true;
617 }
618 if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY;
619 }
620
621 if (!mfifoGIFchain())
622 {
623 Console.WriteLn("GIF dmaChain error size=%d, madr=%lx, tadr=%lx", gifch.qwc, gifch.madr, gifch.tadr);
624 gifstate = GIF_STATE_STALL;
625 }
626
627 if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL;
628 CPU_INT(DMAC_MFIFO_GIF,mfifocycles);
629
630 SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr);
631 }
632
633 void gifMFIFOInterrupt()
634 {
635 GIF_LOG("gifMFIFOInterrupt");
636 mfifocycles = 0;
637
638 if (dmacRegs.ctrl.MFD != MFD_GIF)
639 {
640 DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO");
641 return;
642 }
643
644 if(SIGNAL_IMR_Pending == true)
645 {
646 //DevCon.Warning("Path 3 Paused");
647 CPU_INT(DMAC_MFIFO_GIF, 128);
648 return;
649 }
650
651 if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 )
652 {
653 gifRegs.stat.OPH = false;
654 GSTransferStatus.PTH3 = STOPPED_MODE;
655 gifRegs.stat.APATH = GIF_APATH_IDLE;
656 if(gifRegs.stat.P1Q) gsPath1Interrupt();
657 }
658
659 if((gifstate & GIF_STATE_EMPTY))
660 {
661 FireMFIFOEmpty();
662 if(!(gifstate & GIF_STATE_STALL)) return;
663 }
664
665 if(CheckPaths(11) == false) return;
666
667 if (!(gifch.chcr.STR))
668 {
669 Console.WriteLn("WTF GIFMFIFO");
670 cpuRegs.interrupt &= ~(1 << 11);
671 return;
672 }
673
674 if (!(gifstate & GIF_STATE_STALL))
675 {
676 if (QWCinGIFMFIFO(gifch.tadr) == 0)
677 {
678 gifstate |= GIF_STATE_EMPTY;
679 CPU_INT(DMAC_MFIFO_GIF, 4);
680 return;
681 }
682
683 mfifoGIFtransfer(0);
684 return;
685 }
686
687 #ifdef PCSX2_DEVBUILD
688 if ((gifstate & GIF_STATE_READY) || (gifch.qwc > 0))
689 {
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 gifRegs.stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_P3Q | GIF_STAT_FQC); // APATH, P3Q, FQC = 0
701
702 vif1Regs.stat.VGW = false;
703 gifch.chcr.STR = false;
704 gifstate = GIF_STATE_READY;
705 hwDmacIrq(DMAC_GIF);
706 GIF_LOG("gifMFIFO End");
707 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
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 }

  ViewVC Help
Powered by ViewVC 1.1.22