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

  ViewVC Help
Powered by ViewVC 1.1.22