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

Annotation of /trunk/pcsx2/SPR.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 401 - (hide annotations) (download)
Fri Feb 25 17:31:09 2011 UTC (9 years, 10 months ago) by william
File size: 10942 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4358 local: v0.9.7.313-latest) in ./trunk
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 "SPR.h"
20     #include "VUmicro.h"
21    
22     extern void mfifoGIFtransfer(int);
23    
24     static bool spr0finished = false;
25     static bool spr1finished = false;
26    
27     static u32 mfifotransferred = 0;
28    
29     void sprInit()
30     {
31     }
32    
33     static void TestClearVUs(u32 madr, u32 size)
34     {
35     if (madr >= 0x11000000)
36     {
37     if (madr < 0x11004000)
38     {
39     DbgCon.Warning("scratch pad clearing vu0");
40     CpuVU0->Clear(madr&0xfff, size);
41     }
42     else if (madr >= 0x11008000 && madr < 0x1100c000)
43     {
44     DbgCon.Warning("scratch pad clearing vu1");
45     CpuVU1->Clear(madr&0x3fff, size);
46     }
47     }
48     }
49    
50     int _SPR0chain()
51     {
52     tDMA_TAG *pMem;
53 william 401 int partialqwc = 0;
54 william 62 if (spr0ch.qwc == 0) return 0;
55     pMem = SPRdmaGetAddr(spr0ch.madr, true);
56 william 31 if (pMem == NULL) return -1;
57    
58 william 62 switch (dmacRegs.ctrl.MFD)
59 william 31 {
60     case MFD_VIF1:
61     case MFD_GIF:
62 william 401 if(spr0ch.qwc > 1) partialqwc = spr0ch.qwc - 1;
63     else partialqwc = spr0ch.qwc;
64    
65 william 62 if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR)
66 william 31 Console.WriteLn("SPR MFIFO Write outside MFIFO area");
67     else
68 william 401 mfifotransferred += partialqwc;
69 william 31
70 william 401 hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), partialqwc);
71     spr0ch.madr += partialqwc << 4;
72 william 62 spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
73 william 401 spr0ch.sadr += partialqwc << 4;
74     spr0ch.qwc -= partialqwc;
75 william 31 break;
76    
77     case NO_MFD:
78     case MFD_RESERVED:
79 william 401
80     //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of
81     //the cycle delay out of the way before the end.
82     if(spr0ch.qwc > 1) partialqwc = spr0ch.qwc - 1;
83     else partialqwc = spr0ch.qwc;
84     memcpy_qwc(pMem, &psSu128(spr0ch.sadr), partialqwc);
85 william 31
86     // clear VU mem also!
87 william 401 TestClearVUs(spr0ch.madr, partialqwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes)
88    
89     spr0ch.madr += partialqwc << 4;
90     spr0ch.sadr += partialqwc << 4;
91     spr0ch.qwc -= partialqwc;
92    
93 william 31 break;
94     }
95    
96 william 401
97 william 31
98 william 401 return (partialqwc); // bus is 1/2 the ee speed
99 william 31 }
100    
101 william 62 __fi void SPR0chain()
102 william 31 {
103 william 280 CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS);
104 william 31 }
105    
106     void _SPR0interleave()
107     {
108 william 62 int qwc = spr0ch.qwc;
109     int sqwc = dmacRegs.sqwc.SQWC;
110     int tqwc = dmacRegs.sqwc.TQWC;
111 william 31 tDMA_TAG *pMem;
112    
113     if (tqwc == 0) tqwc = qwc;
114     //Console.WriteLn("dmaSPR0 interleave");
115     SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
116 william 62 spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr);
117 william 31
118 william 280 CPU_INT(DMAC_FROM_SPR, qwc * BIAS);
119 william 62
120 william 31 while (qwc > 0)
121     {
122 william 62 spr0ch.qwc = std::min(tqwc, qwc);
123     qwc -= spr0ch.qwc;
124     pMem = SPRdmaGetAddr(spr0ch.madr, true);
125 william 31
126 william 62 switch (dmacRegs.ctrl.MFD)
127 william 31 {
128     case MFD_VIF1:
129     case MFD_GIF:
130 william 62 hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), spr0ch.qwc);
131     mfifotransferred += spr0ch.qwc;
132 william 31 break;
133    
134     case NO_MFD:
135     case MFD_RESERVED:
136     // clear VU mem also!
137 william 62 TestClearVUs(spr0ch.madr, spr0ch.qwc << 2);
138     memcpy_qwc(pMem, &psSu128(spr0ch.sadr), spr0ch.qwc);
139 william 31 break;
140     }
141 william 62 spr0ch.sadr += spr0ch.qwc * 16;
142     spr0ch.madr += (sqwc + spr0ch.qwc) * 16;
143 william 31 }
144    
145 william 62 spr0ch.qwc = 0;
146 william 31 }
147    
148 william 62 static __fi void _dmaSPR0()
149 william 31 {
150 william 62 if (dmacRegs.ctrl.STS == STS_fromSPR)
151 william 31 {
152 william 62 Console.WriteLn("SPR0 stall %d", dmacRegs.ctrl.STS);
153 william 31 }
154    
155     // Transfer Dn_QWC from SPR to Dn_MADR
156 william 62 switch(spr0ch.chcr.MOD)
157 william 31 {
158     case NORMAL_MODE:
159     {
160     SPR0chain();
161     spr0finished = true;
162     return;
163     }
164     case CHAIN_MODE:
165     {
166     tDMA_TAG *ptag;
167 william 62 bool done = false;
168 william 31
169 william 62 if (spr0ch.qwc > 0)
170 william 31 {
171     SPR0chain();
172     return;
173     }
174     // Destination Chain Mode
175 william 62 ptag = (tDMA_TAG*)&psSu32(spr0ch.sadr);
176     spr0ch.sadr += 16;
177 william 31
178 william 62 spr0ch.unsafeTransfer(ptag);
179 william 31
180 william 62 spr0ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
181 william 31
182     SPR_LOG("spr0 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
183 william 62 ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr, spr0ch.sadr);
184 william 31
185 william 62 if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR
186 william 31 {
187     Console.WriteLn("SPR stall control");
188     }
189    
190     switch (ptag->ID)
191     {
192     case TAG_CNTS: // CNTS - Transfer QWC following the tag (Stall Control)
193 william 62 if (dmacRegs.ctrl.STS == STS_fromSPR) dmacRegs.stadr.ADDR = spr0ch.madr + (spr0ch.qwc * 16); //Copy MADR to DMAC_STADR stall addr register
194 william 31 break;
195    
196     case TAG_CNT: // CNT - Transfer QWC following the tag.
197     done = false;
198     break;
199    
200     case TAG_END: // End - Transfer QWC following the tag
201     done = true;
202     break;
203     }
204    
205     SPR0chain();
206    
207 william 62 if (spr0ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
208 william 31 {
209     //Console.WriteLn("SPR0 TIE");
210     done = true;
211     }
212    
213     spr0finished = done;
214     SPR_LOG("spr0 dmaChain complete %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
215 william 62 ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr);
216 william 31 break;
217     }
218     //case INTERLEAVE_MODE:
219     default:
220     {
221     _SPR0interleave();
222 william 62 spr0finished = true;
223 william 31 break;
224     }
225     }
226     }
227    
228     void SPRFROMinterrupt()
229     {
230 william 62
231     if (!spr0finished || spr0ch.qwc > 0)
232     {
233     _dmaSPR0();
234 william 31
235 william 62 if(mfifotransferred != 0)
236 william 31 {
237 william 62 switch (dmacRegs.ctrl.MFD)
238 william 31 {
239 william 62 case MFD_VIF1: // Most common case.
240     {
241     if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
242     spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
243     //Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr);
244     mfifoVIF1transfer(mfifotransferred);
245     mfifotransferred = 0;
246     break;
247     }
248     case MFD_GIF:
249     {
250     if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
251     spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
252     //Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
253     mfifoGIFtransfer(mfifotransferred);
254     mfifotransferred = 0;
255     break;
256     }
257     default:
258     break;
259 william 31 }
260     }
261 william 62 return;
262 william 31 }
263    
264    
265 william 62 spr0ch.chcr.STR = false;
266 william 31 hwDmacIrq(DMAC_FROM_SPR);
267 william 401 DMA_LOG("SPR0 DMA End");
268 william 31 }
269    
270     void dmaSPR0() // fromSPR
271     {
272     SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx",
273 william 62 spr0ch.chcr._u32, spr0ch.madr, spr0ch.qwc, spr0ch.sadr);
274 william 31
275 william 62
276     spr0finished = false; //Init
277    
278     if(spr0ch.chcr.MOD == CHAIN_MODE && spr0ch.qwc > 0)
279 william 31 {
280 william 62 //DevCon.Warning(L"SPR0 QWC on Chain " + spr0ch.chcr.desc());
281     if (spr0ch.chcr.tag().ID == TAG_END) // but not TAG_REFE?
282     {
283     spr0finished = true;
284     }
285 william 31 }
286 william 62
287     SPRFROMinterrupt();
288 william 31 }
289    
290 william 62 __fi static void SPR1transfer(const void* data, int qwc)
291 william 31 {
292 william 62 memcpy_qwc(&psSu128(spr1ch.sadr), data, qwc);
293     spr1ch.sadr += qwc * 16;
294 william 31 }
295    
296     int _SPR1chain()
297     {
298     tDMA_TAG *pMem;
299    
300 william 62 if (spr1ch.qwc == 0) return 0;
301 william 31
302 william 62 pMem = SPRdmaGetAddr(spr1ch.madr, false);
303 william 31 if (pMem == NULL) return -1;
304 william 401 int partialqwc = 0;
305     //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of
306     //the cycle delay out of the way before the end.
307     if(spr1ch.qwc > 1) partialqwc = spr1ch.qwc - 1;
308     else partialqwc = spr1ch.qwc;
309 william 31
310 william 401 SPR1transfer(pMem, partialqwc);
311     spr1ch.madr += partialqwc * 16;
312     spr1ch.qwc -= partialqwc;
313    
314 william 280 hwDmacSrcTadrInc(spr1ch);
315 william 31
316 william 401 return (partialqwc);
317 william 31 }
318    
319 william 62 __fi void SPR1chain()
320 william 31 {
321 william 401 if(!CHECK_IPUWAITHACK)
322     {
323     CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS);
324     }
325     else
326     {
327     _SPR1chain();
328     CPU_INT(DMAC_TO_SPR, 8);
329     }
330 william 31 }
331    
332     void _SPR1interleave()
333     {
334 william 62 int qwc = spr1ch.qwc;
335     int sqwc = dmacRegs.sqwc.SQWC;
336     int tqwc = dmacRegs.sqwc.TQWC;
337 william 31 tDMA_TAG *pMem;
338    
339     if (tqwc == 0) tqwc = qwc;
340     SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
341 william 62 spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr);
342 william 280 CPU_INT(DMAC_TO_SPR, qwc * BIAS);
343 william 31 while (qwc > 0)
344     {
345 william 62 spr1ch.qwc = std::min(tqwc, qwc);
346     qwc -= spr1ch.qwc;
347     pMem = SPRdmaGetAddr(spr1ch.madr, false);
348     memcpy_qwc(&psSu128(spr1ch.sadr), pMem, spr1ch.qwc);
349     spr1ch.sadr += spr1ch.qwc * 16;
350     spr1ch.madr += (sqwc + spr1ch.qwc) * 16;
351 william 31 }
352    
353 william 62 spr1ch.qwc = 0;
354 william 31 }
355    
356     void _dmaSPR1() // toSPR work function
357     {
358 william 62 switch(spr1ch.chcr.MOD)
359 william 31 {
360     case NORMAL_MODE:
361     {
362     //int cycles = 0;
363     // Transfer Dn_QWC from Dn_MADR to SPR1
364     SPR1chain();
365     spr1finished = true;
366     return;
367     }
368     case CHAIN_MODE:
369     {
370     tDMA_TAG *ptag;
371     bool done = false;
372    
373 william 62 if (spr1ch.qwc > 0)
374 william 31 {
375 william 62 SPR_LOG("spr1 Normal or in Progress size=%d, addr=%lx taddr=%lx saddr=%lx", spr1ch.qwc, spr1ch.madr, spr1ch.tadr, spr1ch.sadr);
376 william 31 // Transfer Dn_QWC from Dn_MADR to SPR1
377     SPR1chain();
378     return;
379     }
380     // Chain Mode
381    
382 william 62 ptag = SPRdmaGetAddr(spr1ch.tadr, false); //Set memory pointer to TADR
383 william 31
384 william 62 if (!spr1ch.transfer("SPR1 Tag", ptag))
385 william 31 {
386     done = true;
387     spr1finished = done;
388     }
389    
390 william 62 spr1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
391 william 31
392     // Transfer dma tag if tte is set
393 william 62 if (spr1ch.chcr.TTE)
394 william 31 {
395     SPR_LOG("SPR TTE: %x_%x\n", ptag[3]._u32, ptag[2]._u32);
396 william 62 SPR1transfer(ptag, 1); //Transfer Tag
397 william 31 }
398    
399 william 62 SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx taddr=%lx saddr=%lx",
400     ptag[1]._u32, ptag[0]._u32, spr1ch.qwc, ptag->ID, spr1ch.madr, spr1ch.tadr, spr1ch.sadr);
401 william 31
402 william 62 done = (hwDmacSrcChain(spr1ch, ptag->ID));
403 william 31 SPR1chain(); //Transfers the data set by the switch
404    
405 william 62 if (spr1ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
406 william 31 {
407     SPR_LOG("dmaIrq Set");
408    
409     //Console.WriteLn("SPR1 TIE");
410     done = true;
411     }
412    
413     spr1finished = done;
414     break;
415     }
416     //case INTERLEAVE_MODE:
417     default:
418     {
419     _SPR1interleave();
420 william 62 spr1finished = true;
421 william 31 break;
422     }
423     }
424     }
425    
426     void dmaSPR1() // toSPR
427     {
428     SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n"
429     " tadr = 0x%x, sadr = 0x%x",
430 william 62 spr1ch.chcr._u32, spr1ch.madr, spr1ch.qwc,
431     spr1ch.tadr, spr1ch.sadr);
432    
433     spr1finished = false; //Init
434    
435     if(spr1ch.chcr.MOD == CHAIN_MODE && spr1ch.qwc > 0)
436 william 31 {
437 william 62 //DevCon.Warning(L"SPR1 QWC on Chain " + spr1ch.chcr.desc());
438     if ((spr1ch.chcr.tag().ID == TAG_END) || (spr1ch.chcr.tag().ID == TAG_REFE))
439     {
440     spr1finished = true;
441     }
442 william 31 }
443 william 62
444     SPRTOinterrupt();
445 william 31 }
446    
447     void SPRTOinterrupt()
448     {
449 william 62 SPR_LOG("SPR1 Interrupt");
450     if (!spr1finished || spr1ch.qwc > 0)
451     {
452     _dmaSPR1();
453     return;
454     }
455 william 31
456 william 401 DMA_LOG("SPR1 DMA End");
457 william 62 spr1ch.chcr.STR = false;
458 william 31 hwDmacIrq(DMAC_TO_SPR);
459     }
460    
461     void SaveStateBase::sprFreeze()
462     {
463     FreezeTag("SPRdma");
464    
465     Freeze(spr0finished);
466     Freeze(spr1finished);
467     Freeze(mfifotransferred);
468     }

  ViewVC Help
Powered by ViewVC 1.1.22