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

  ViewVC Help
Powered by ViewVC 1.1.22