/[pcsx2_0.9.7]/trunk/pcsx2/IPU/IPUdma.cpp
ViewVC logotype

Contents of /trunk/pcsx2/IPU/IPUdma.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 6 months ago) by william
File size: 13041 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 #include "IPU.h"
19 #include "IPU/IPUdma.h"
20 #include "mpeg2lib/Mpeg.h"
21
22 #include "Vif.h"
23 #include "Gif.h"
24 #include "Vif_Dma.h"
25
26 static IPUStatus IPU1Status;
27 static tIPU_DMA g_nDMATransfer;
28
29 void ipuDmaReset()
30 {
31 IPU1Status.InProgress = false;
32 IPU1Status.DMAMode = DMA_MODE_NORMAL;
33 IPU1Status.DMAFinished = true;
34
35 g_nDMATransfer.reset();
36 }
37
38 void SaveStateBase::ipuDmaFreeze()
39 {
40 FreezeTag( "IPUdma" );
41 Freeze(g_nDMATransfer);
42 Freeze(IPU1Status);
43 }
44
45 static __fi void ipuDmacSrcChain()
46 {
47 switch (IPU1Status.ChainMode)
48 {
49 case TAG_REFE: // refe
50 //if(IPU1Status.InProgress == false) ipu1dma.tadr += 16;
51 IPU1Status.DMAFinished = true;
52 break;
53 case TAG_CNT: // cnt
54 // Set the taddr to the next tag
55 ipu1dma.tadr = ipu1dma.madr;
56 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;
57 break;
58
59 case TAG_NEXT: // next
60 ipu1dma.tadr = IPU1Status.NextMem;
61 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;
62 break;
63
64 case TAG_REF: // ref
65 //if(IPU1Status.InProgress == false)ipu1dma.tadr += 16;
66 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;
67 break;
68
69 case TAG_END: // end
70 //ipu1dma.tadr = ipu1dma.madr;
71 IPU1Status.DMAFinished = true;
72 break;
73 }
74 }
75
76 static __fi bool WaitGSPaths()
77 {
78 if(CHECK_IPUWAITHACK)
79 {
80 if(GSTransferStatus.PTH3 < STOPPED_MODE && GSTransferStatus.PTH3 != IDLE_MODE)
81 {
82 //GIF_LOG("Flushing gif chcr %x tadr %x madr %x qwc %x", gif->chcr._u32, gif->tadr, gif->madr, gif->qwc);
83 //DevCon.WriteLn("Waiting for GIF");
84 return false;
85 }
86
87 if(GSTransferStatus.PTH2 != STOPPED_MODE)
88 {
89 //DevCon.WriteLn("Waiting for VIF");
90 return false;
91 }
92 if(GSTransferStatus.PTH1 != STOPPED_MODE)
93 {
94 //DevCon.WriteLn("Waiting for VU");
95 return false;
96 }
97 }
98 return true;
99 }
100
101 static __fi int IPU1chain() {
102
103 int totalqwc = 0;
104
105 if (ipu1dma.qwc > 0 && IPU1Status.InProgress == true)
106 {
107 int qwc = ipu1dma.qwc;
108 u32 *pMem;
109
110 pMem = (u32*)dmaGetAddr(ipu1dma.madr, false);
111
112 if (pMem == NULL)
113 {
114 Console.Error("ipu1dma NULL!");
115 return totalqwc;
116 }
117
118 //Write our data to the fifo
119 qwc = ipu_fifo.in.write(pMem, qwc);
120 ipu1dma.madr += qwc << 4;
121 ipu1dma.qwc -= qwc;
122 totalqwc += qwc;
123 }
124
125 //Update TADR etc
126 if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain();
127
128 if( ipu1dma.qwc == 0)
129 IPU1Status.InProgress = false;
130
131 return totalqwc;
132 }
133
134 //static __fi bool WaitGSPaths()
135 //{
136 // //Wait for all GS paths to be clear
137 // if (GSTransferStatus._u32 != 0x2a)
138 // {
139 // if(GSTransferStatus.PTH3 != STOPPED_MODE && vif1Regs.mskpath3) return true;
140 // IPU_LOG("Waiting for GS transfers to finish %x", GSTransferStatus._u32);
141 // IPU_INT_TO(4);
142 // return false;
143 // }
144 // return true;
145 //}
146
147
148
149 int IPU1dma()
150 {
151 int ipu1cycles = 0;
152 int totalqwc = 0;
153
154 //We need to make sure GIF has flushed before sending IPU data, it seems to REALLY screw FFX videos
155 //if(!WaitGSPaths()) return totalqwc;
156
157 if(ipu1dma.chcr.STR == false || IPU1Status.DMAMode == 2)
158 {
159 //We MUST stop the IPU from trying to fill the FIFO with more data if the DMA has been suspended
160 //if we don't, we risk causing the data to go out of sync with the fifo and we end up losing some!
161 //This is true for Dragons Quest 8 and probably others which suspend the DMA.
162 DevCon.Warning("IPU1 running when IPU1 DMA disabled! CHCR %x QWC %x", ipu1dma.chcr._u32, ipu1dma.qwc);
163 return 0;
164 }
165
166 IPU_LOG("IPU1 DMA Called QWC %x Finished %d In Progress %d tadr %x", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma.tadr);
167
168 switch(IPU1Status.DMAMode)
169 {
170 case DMA_MODE_NORMAL:
171 {
172 if(!WaitGSPaths())
173 { // legacy WaitGSPaths() for now
174 IPU_INT_TO(32); //Give it a short wait.
175 return totalqwc;
176 }
177 IPU_LOG("Processing Normal QWC left %x Finished %d In Progress %d", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
178 if(IPU1Status.InProgress == true) totalqwc += IPU1chain();
179 }
180 break;
181
182 case DMA_MODE_CHAIN:
183 {
184 if(IPU1Status.InProgress == true) //No transfer is ready to go so we need to set one up
185 {
186 if(!WaitGSPaths())
187 { // legacy WaitGSPaths() for now
188 IPU_INT_TO(32); //Give it a short wait.
189 return totalqwc;
190 }
191 IPU_LOG("Processing Chain QWC left %x Finished %d In Progress %d", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
192 totalqwc += IPU1chain();
193 //Set the TADR forward
194 }
195
196
197 if(IPU1Status.InProgress == false && IPU1Status.DMAFinished == false) //No transfer is ready to go so we need to set one up
198 {
199 tDMA_TAG* ptag = dmaGetAddr(ipu1dma.tadr, false); //Set memory pointer to TADR
200
201 if (!ipu1dma.transfer("IPU1", ptag))
202 {
203 return totalqwc;
204 }
205
206 ipu1cycles += 1; // Add 1 cycles from the QW read for the tag
207 IPU1Status.ChainMode = ptag->ID;
208
209 if(ipu1dma.chcr.TTE) DevCon.Warning("TTE?");
210
211 switch (IPU1Status.ChainMode)
212 {
213 case TAG_REFE: // refe
214 // do not change tadr
215 //ipu1dma.tadr += 16;
216 ipu1dma.tadr += 16;
217 ipu1dma.madr = ptag[1]._u32;
218 IPU_LOG("Tag should end on %x", ipu1dma.tadr);
219
220 break;
221
222 case TAG_CNT: // cnt
223 ipu1dma.tadr += 16;
224 ipu1dma.madr = ipu1dma.tadr;
225 IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);
226 //ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16);
227 // Set the taddr to the next tag
228 //IPU1Status.DMAFinished = false;
229 break;
230
231 case TAG_NEXT: // next
232 ipu1dma.madr = ipu1dma.tadr + 16;
233 IPU1Status.NextMem = ptag[1]._u32;
234 IPU_LOG("Tag should end on %x", IPU1Status.NextMem);
235 //IPU1Status.DMAFinished = false;
236 break;
237
238 case TAG_REF: // ref
239 ipu1dma.madr = ptag[1]._u32;
240 ipu1dma.tadr += 16;
241 IPU_LOG("Tag should end on %x", ipu1dma.tadr);
242 //IPU1Status.DMAFinished = false;
243 break;
244
245 case TAG_END: // end
246 // do not change tadr
247 ipu1dma.madr = ipu1dma.tadr + 16;
248 //ipu1dma.tadr += 16;
249 IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);
250
251 break;
252
253 default:
254 Console.Error("IPU ERROR: different transfer mode!, Please report to PCSX2 Team");
255 break;
256 }
257
258 //if(ipu1dma.qwc == 0) Console.Warning("Blank QWC!");
259 if(ipu1dma.qwc > 0) IPU1Status.InProgress = true;
260 IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x",
261 ptag[1]._u32, ptag[0]._u32, ipu1dma.qwc, ipu1dma.madr, 8 - g_BP.IFC);
262
263 if (ipu1dma.chcr.TIE && ptag->IRQ) //Tag Interrupt is set, so schedule the end/interrupt
264 IPU1Status.DMAFinished = true;
265
266
267 if(!WaitGSPaths() && ipu1dma.qwc > 0)
268 { // legacy WaitGSPaths() for now
269 IPU_INT_TO(32); //Give it a short wait.
270 return totalqwc;
271 }
272 IPU_LOG("Processing Start Chain QWC left %x Finished %d In Progress %d", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);
273 totalqwc += IPU1chain();
274 //Set the TADR forward
275 }
276
277 }
278 break;
279 }
280
281 //Do this here to prevent double settings on Chain DMA's
282 if(totalqwc > 0 || ipu1dma.qwc == 0)
283 {
284 IPU_INT_TO(totalqwc * BIAS);
285 IPUProcessInterrupt();
286 }
287 else
288 {
289 cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048);
290 }
291
292 IPU_LOG("Completed Call IPU1 DMA QWC Remaining %x Finished %d In Progress %d tadr %x", ipu1dma.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma.tadr);
293 return totalqwc;
294 }
295
296 void IPU0dma()
297 {
298 if(!ipuRegs.ctrl.OFC)
299 {
300 IPU_INT_FROM( 64 );
301 IPUProcessInterrupt();
302 return;
303 }
304
305 int readsize;
306 tDMA_TAG* pMem;
307
308 if ((!(ipu0dma.chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0dma.qwc == 0))
309 {
310 DevCon.Warning("How??");
311 return;
312 }
313
314 pxAssert(!(ipu0dma.chcr.TTE));
315
316 IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc = %lx",
317 ipu0dma.chcr._u32, ipu0dma.madr, ipu0dma.qwc);
318
319 pxAssert(ipu0dma.chcr.MOD == NORMAL_MODE);
320
321 pMem = dmaGetAddr(ipu0dma.madr, true);
322
323 readsize = min(ipu0dma.qwc, (u16)ipuRegs.ctrl.OFC);
324 ipu_fifo.out.read(pMem, readsize);
325
326 ipu0dma.madr += readsize << 4;
327 ipu0dma.qwc -= readsize; // note: qwc is u16
328
329 if (ipu0dma.qwc == 0)
330 {
331 if (dmacRegs.ctrl.STS == STS_fromIPU) // STS == fromIPU
332 {
333 dmacRegs.stadr.ADDR = ipu0dma.madr;
334 switch (dmacRegs.ctrl.STD)
335 {
336 case NO_STD:
337 break;
338 case STD_GIF: // GIF
339 Console.Warning("GIFSTALL");
340 g_nDMATransfer.GIFSTALL = true;
341 break;
342 case STD_VIF1: // VIF
343 Console.Warning("VIFSTALL");
344 g_nDMATransfer.VIFSTALL = true;
345 break;
346 case STD_SIF1:
347 Console.Warning("SIFSTALL");
348 g_nDMATransfer.SIFSTALL = true;
349 break;
350 }
351 }
352 //Fixme ( voodoocycles ):
353 //This was IPU_INT_FROM(readsize*BIAS );
354 //This broke vids in Digital Devil Saga
355 //Note that interrupting based on totalsize is just guessing..
356 }
357 IPU_INT_FROM( readsize * BIAS );
358 if(ipuRegs.ctrl.IFC > 0) IPUProcessInterrupt();
359
360 //return readsize;
361 }
362
363 __fi void dmaIPU0() // fromIPU
364 {
365 if (ipu0dma.pad != 0)
366 {
367 // Note: pad is the padding right above qwc, so we're testing whether qwc
368 // has overflowed into pad.
369 DevCon.Warning(L"IPU0dma's upper 16 bits set to %x", ipu0dma.pad);
370 ipu0dma.qwc = ipu0dma.pad = 0;
371 //If we are going to clear down IPU0, we should end it too. Going to test this scenario on the PS2 mind - Refraction
372 ipu0dma.chcr.STR = false;
373 hwDmacIrq(DMAC_FROM_IPU);
374 }
375
376 IPU_INT_FROM( 64 );
377
378
379
380 }
381
382 __fi void dmaIPU1() // toIPU
383 {
384 IPU_LOG("IPU1DMAStart QWC %x, MADR %x, CHCR %x, TADR %x", ipu1dma.qwc, ipu1dma.madr, ipu1dma.chcr._u32, ipu1dma.tadr);
385
386 if (ipu1dma.pad != 0)
387 {
388 // Note: pad is the padding right above qwc, so we're testing whether qwc
389 // has overflowed into pad.
390 DevCon.Warning(L"IPU1dma's upper 16 bits set to %x\n", ipu1dma.pad);
391 ipu1dma.qwc = ipu1dma.pad = 0;
392 // If we are going to clear down IPU1, we should end it too.
393 // Going to test this scenario on the PS2 mind - Refraction
394 ipu1dma.chcr.STR = false;
395 hwDmacIrq(DMAC_TO_IPU);
396 }
397
398 if (ipu1dma.chcr.MOD == CHAIN_MODE) //Chain Mode
399 {
400 IPU_LOG("Setting up IPU1 Chain mode");
401 if(ipu1dma.qwc == 0)
402 {
403 IPU1Status.InProgress = false;
404 IPU1Status.DMAFinished = false;
405 }
406 else
407 { //Attempting to continue a previous chain
408 IPU_LOG("Resuming DMA TAG %x", (ipu1dma.chcr.TAG >> 12));
409 //We MUST check the CHCR for the tag it last knew, it can be manipulated!
410 IPU1Status.ChainMode = (ipu1dma.chcr.TAG >> 12) & 0x7;
411 IPU1Status.InProgress = true;
412 IPU1Status.DMAFinished = ((ipu1dma.chcr.TAG >> 15) && ipu1dma.chcr.TIE) ? true : false;
413 }
414
415 IPU1Status.DMAMode = DMA_MODE_CHAIN;
416 IPU1dma();
417 }
418 else //Normal Mode
419 {
420 if(ipu1dma.qwc == 0)
421 {
422 ipu1dma.chcr.STR = false;
423 // Hack to force stop IPU
424 ipuRegs.cmd.BUSY = 0;
425 ipuRegs.ctrl.BUSY = 0;
426 ipuRegs.topbusy = 0;
427 //
428 hwDmacIrq(DMAC_TO_IPU);
429 Console.Warning("IPU1 Normal error!");
430 }
431 else
432 {
433 IPU_LOG("Setting up IPU1 Normal mode");
434 IPU1Status.InProgress = true;
435 IPU1Status.DMAFinished = true;
436 IPU1Status.DMAMode = DMA_MODE_NORMAL;
437 IPU1dma();
438 }
439 }
440 }
441
442 extern void GIFdma();
443
444 void ipu0Interrupt()
445 {
446 IPU_LOG("ipu0Interrupt: %x", cpuRegs.cycle);
447
448 if(ipu0dma.qwc > 0)
449 {
450 IPU0dma();
451 return;
452 }
453 if (g_nDMATransfer.FIREINT0)
454 {
455 g_nDMATransfer.FIREINT0 = false;
456 hwIntcIrq(INTC_IPU);
457 }
458
459 if (g_nDMATransfer.GIFSTALL)
460 {
461 // gif
462 Console.Warning("IPU GIF Stall");
463 g_nDMATransfer.GIFSTALL = false;
464 //if (gif->chcr.STR) GIFdma();
465 }
466
467 if (g_nDMATransfer.VIFSTALL)
468 {
469 // vif
470 Console.Warning("IPU VIF Stall");
471 g_nDMATransfer.VIFSTALL = false;
472 //if (vif1ch.chcr.STR) dmaVIF1();
473 }
474
475 if (g_nDMATransfer.SIFSTALL)
476 {
477 // sif
478 Console.Warning("IPU SIF Stall");
479 g_nDMATransfer.SIFSTALL = false;
480
481 // Not totally sure whether this needs to be done or not, so I'm
482 // leaving it commented out for the moment.
483 //if (sif1dma.chcr.STR) SIF1Dma();
484 }
485
486 if (g_nDMATransfer.TIE0)
487 {
488 g_nDMATransfer.TIE0 = false;
489 }
490
491 ipu0dma.chcr.STR = false;
492 hwDmacIrq(DMAC_FROM_IPU);
493 }
494
495 IPU_FORCEINLINE void ipu1Interrupt()
496 {
497 IPU_LOG("ipu1Interrupt %x:", cpuRegs.cycle);
498
499 if(IPU1Status.DMAFinished == false || IPU1Status.InProgress == true) //Sanity Check
500 {
501 IPU1dma();
502 return;
503 }
504
505 IPU_LOG("ipu1 finish %x:", cpuRegs.cycle);
506 ipu1dma.chcr.STR = false;
507 IPU1Status.DMAMode = 2;
508 hwDmacIrq(DMAC_TO_IPU);
509 }

  ViewVC Help
Powered by ViewVC 1.1.22