/[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 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 10992 byte(s)
committing r3113 initial commit again...
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    
54     if (spr0->qwc == 0) return 0;
55     pMem = SPRdmaGetAddr(spr0->madr, true);
56     if (pMem == NULL) return -1;
57    
58     switch (dmacRegs->ctrl.MFD)
59     {
60     case MFD_VIF1:
61     case MFD_GIF:
62     if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR)
63     Console.WriteLn("SPR MFIFO Write outside MFIFO area");
64     else
65     mfifotransferred += spr0->qwc;
66    
67     hwMFIFOWrite(spr0->madr, &psSu8(spr0->sadr), spr0->qwc << 4);
68     spr0->madr += spr0->qwc << 4;
69     spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
70     break;
71    
72     case NO_MFD:
73     case MFD_RESERVED:
74     memcpy_fast((u8*)pMem, &psSu8(spr0->sadr), spr0->qwc << 4);
75    
76     // clear VU mem also!
77     TestClearVUs(spr0->madr, spr0->qwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes)
78     spr0->madr += spr0->qwc << 4;
79     break;
80     }
81    
82     spr0->sadr += spr0->qwc << 4;
83    
84     return (spr0->qwc) * BIAS; // bus is 1/2 the ee speed
85     }
86    
87     __forceinline void SPR0chain()
88     {
89     _SPR0chain();
90     spr0->qwc = 0;
91     }
92    
93     void _SPR0interleave()
94     {
95     int qwc = spr0->qwc;
96     int sqwc = dmacRegs->sqwc.SQWC;
97     int tqwc = dmacRegs->sqwc.TQWC;
98     tDMA_TAG *pMem;
99    
100     if (tqwc == 0) tqwc = qwc;
101     //Console.WriteLn("dmaSPR0 interleave");
102     SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
103     spr0->qwc, tqwc, sqwc, spr0->madr, spr0->sadr);
104    
105     while (qwc > 0)
106     {
107     spr0->qwc = std::min(tqwc, qwc);
108     qwc -= spr0->qwc;
109     pMem = SPRdmaGetAddr(spr0->madr, true);
110    
111     switch (dmacRegs->ctrl.MFD)
112     {
113     case MFD_VIF1:
114     case MFD_GIF:
115     hwMFIFOWrite(spr0->madr, &psSu8(spr0->sadr), spr0->qwc << 4);
116     mfifotransferred += spr0->qwc;
117     break;
118    
119     case NO_MFD:
120     case MFD_RESERVED:
121     // clear VU mem also!
122     TestClearVUs(spr0->madr, spr0->qwc << 2);
123     memcpy_fast((u8*)pMem, &psSu8(spr0->sadr), spr0->qwc << 4);
124     break;
125     }
126     spr0->sadr += spr0->qwc * 16;
127     spr0->madr += (sqwc + spr0->qwc) * 16;
128     }
129    
130     spr0->qwc = 0;
131     spr0finished = true;
132     }
133    
134     static __forceinline void _dmaSPR0()
135     {
136     if (dmacRegs->ctrl.STS == STS_fromSPR)
137     {
138     Console.WriteLn("SPR0 stall %d", dmacRegs->ctrl.STS);
139     }
140    
141     // Transfer Dn_QWC from SPR to Dn_MADR
142     switch(spr0->chcr.MOD)
143     {
144     case NORMAL_MODE:
145     {
146     SPR0chain();
147     spr0finished = true;
148     return;
149     }
150     case CHAIN_MODE:
151     {
152     tDMA_TAG *ptag;
153     bool done = FALSE;
154    
155     if (spr0->qwc > 0)
156     {
157     SPR0chain();
158     spr0finished = true;
159     return;
160     }
161     // Destination Chain Mode
162     ptag = (tDMA_TAG*)&psSu32(spr0->sadr);
163     spr0->sadr += 16;
164    
165     spr0->unsafeTransfer(ptag);
166    
167     spr0->madr = ptag[1]._u32; //MADR = ADDR field + SPR
168    
169     SPR_LOG("spr0 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
170     ptag[1]._u32, ptag[0]._u32, spr0->qwc, ptag->ID, spr0->madr, spr0->sadr);
171    
172     if (dmacRegs->ctrl.STS == STS_fromSPR) // STS == fromSPR
173     {
174     Console.WriteLn("SPR stall control");
175     }
176    
177     switch (ptag->ID)
178     {
179     case TAG_CNTS: // CNTS - Transfer QWC following the tag (Stall Control)
180     if (dmacRegs->ctrl.STS == STS_fromSPR) dmacRegs->stadr.ADDR = spr0->madr + (spr0->qwc * 16); //Copy MADR to DMAC_STADR stall addr register
181     break;
182    
183     case TAG_CNT: // CNT - Transfer QWC following the tag.
184     done = false;
185     break;
186    
187     case TAG_END: // End - Transfer QWC following the tag
188     done = true;
189     break;
190     }
191    
192     SPR0chain();
193    
194     if (spr0->chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
195     {
196     //Console.WriteLn("SPR0 TIE");
197     done = true;
198     }
199    
200     spr0finished = done;
201    
202     if (!done)
203     {
204     ptag = (tDMA_TAG*)&psSu32(spr0->sadr); //Set memory pointer to SADR
205     CPU_INT(DMAC_FROM_SPR, /*ptag[0].QWC / BIAS*/ 4 ); // the lower 16bits of the tag / BIAS);
206     return;
207     }
208     SPR_LOG("spr0 dmaChain complete %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
209     ptag[1]._u32, ptag[0]._u32, spr0->qwc, ptag->ID, spr0->madr);
210     break;
211     }
212     //case INTERLEAVE_MODE:
213     default:
214     {
215     _SPR0interleave();
216     break;
217     }
218     }
219     }
220    
221     void SPRFROMinterrupt()
222     {
223     _dmaSPR0();
224    
225     if(mfifotransferred != 0)
226     {
227     switch (dmacRegs->ctrl.MFD)
228     {
229     case MFD_VIF1: // Most common case.
230     {
231     if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
232     spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
233     //Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr);
234     mfifoVIF1transfer(mfifotransferred);
235     mfifotransferred = 0;
236     if (vif1ch->chcr.STR) return;
237     break;
238     }
239     case MFD_GIF:
240     {
241     if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
242     spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
243     //Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
244     mfifoGIFtransfer(mfifotransferred);
245     mfifotransferred = 0;
246     if (gif->chcr.STR) return;
247     break;
248     }
249     default:
250     break;
251     }
252     }
253     if (!spr0finished) return;
254    
255    
256     spr0->chcr.STR = false;
257     hwDmacIrq(DMAC_FROM_SPR);
258     }
259    
260     void dmaSPR0() // fromSPR
261     {
262     SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx",
263     spr0->chcr._u32, spr0->madr, spr0->qwc, spr0->sadr);
264    
265     if ((spr0->chcr.MOD == CHAIN_MODE) && spr0->qwc == 0)
266     {
267     tDMA_TAG *ptag;
268     ptag = (tDMA_TAG*)&psSu32(spr0->sadr); //Set memory pointer to SADR
269     CPU_INT(DMAC_FROM_SPR, /*ptag[0].QWC / BIAS*/ 4 );
270     return;
271     }
272     if(spr0->chcr.MOD == CHAIN_MODE && spr0->qwc > 0) DevCon.Warning(L"SPR0 QWC on Chain " + spr0->chcr.desc());
273     // COMPLETE HACK!!! For now at least.. FFX Videos dont rely on interrupts or reading DMA values
274     // It merely assumes that the last one has finished then starts another one (broke with the DMA fix)
275     // This "shouldn't" cause any problems as SPR is generally faster than the other DMAS anyway. (Refraction)
276     CPU_INT(DMAC_FROM_SPR, /*spr0->qwc / BIAS*/ 4 );
277     }
278    
279     __forceinline static void SPR1transfer(u32 *data, int size)
280     {
281     memcpy_fast(&psSu8(spr1->sadr), (u8*)data, size << 2);
282    
283     spr1->sadr += size << 2;
284     }
285    
286     int _SPR1chain()
287     {
288     tDMA_TAG *pMem;
289    
290     if (spr1->qwc == 0) return 0;
291    
292     pMem = SPRdmaGetAddr(spr1->madr, false);
293     if (pMem == NULL) return -1;
294    
295     SPR1transfer((u32*)pMem, spr1->qwc << 2);
296     spr1->madr += spr1->qwc << 4;
297    
298     return (spr1->qwc) * BIAS;
299     }
300    
301     __forceinline void SPR1chain()
302     {
303     _SPR1chain();
304     spr1->qwc = 0;
305     }
306    
307     void _SPR1interleave()
308     {
309     int qwc = spr1->qwc;
310     int sqwc = dmacRegs->sqwc.SQWC;
311     int tqwc = dmacRegs->sqwc.TQWC;
312     tDMA_TAG *pMem;
313    
314     if (tqwc == 0) tqwc = qwc;
315     SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
316     spr1->qwc, tqwc, sqwc, spr1->madr, spr1->sadr);
317    
318     while (qwc > 0)
319     {
320     spr1->qwc = std::min(tqwc, qwc);
321     qwc -= spr1->qwc;
322     pMem = SPRdmaGetAddr(spr1->madr, false);
323     memcpy_fast(&psSu8(spr1->sadr), (u8*)pMem, spr1->qwc << 4);
324     spr1->sadr += spr1->qwc * 16;
325     spr1->madr += (sqwc + spr1->qwc) * 16;
326     }
327    
328     spr1->qwc = 0;
329     spr1finished = true;
330     }
331    
332     void _dmaSPR1() // toSPR work function
333     {
334     switch(spr1->chcr.MOD)
335     {
336     case NORMAL_MODE:
337     {
338     //int cycles = 0;
339     // Transfer Dn_QWC from Dn_MADR to SPR1
340     SPR1chain();
341     spr1finished = true;
342     return;
343     }
344     case CHAIN_MODE:
345     {
346     tDMA_TAG *ptag;
347     bool done = false;
348    
349     if (spr1->qwc > 0)
350     {
351     // Transfer Dn_QWC from Dn_MADR to SPR1
352     SPR1chain();
353     spr1finished = true;
354     return;
355     }
356     // Chain Mode
357    
358     ptag = SPRdmaGetAddr(spr1->tadr, false); //Set memory pointer to TADR
359    
360     if (!spr1->transfer("SPR1 Tag", ptag))
361     {
362     done = true;
363     spr1finished = done;
364     }
365    
366     spr1->madr = ptag[1]._u32; //MADR = ADDR field + SPR
367    
368     // Transfer dma tag if tte is set
369     if (spr1->chcr.TTE)
370     {
371     SPR_LOG("SPR TTE: %x_%x\n", ptag[3]._u32, ptag[2]._u32);
372     SPR1transfer((u32*)ptag, 4); //Transfer Tag
373     }
374    
375     SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx",
376     ptag[1]._u32, ptag[0]._u32, spr1->qwc, ptag->ID, spr1->madr);
377    
378     done = (hwDmacSrcChain(spr1, ptag->ID));
379     SPR1chain(); //Transfers the data set by the switch
380    
381     if (spr1->chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
382     {
383     SPR_LOG("dmaIrq Set");
384    
385     //Console.WriteLn("SPR1 TIE");
386     done = true;
387     }
388    
389     spr1finished = done;
390     if (!done)
391     {
392     ptag = SPRdmaGetAddr(spr1->tadr, false); //Set memory pointer to TADR
393     CPU_INT(DMAC_TO_SPR, /*(ptag[0].QWC / BIAS)*/ 4 );// the lower 16 bits of the tag / BIAS);
394     }
395     break;
396     }
397     //case INTERLEAVE_MODE:
398     default:
399     {
400     _SPR1interleave();
401     break;
402     }
403     }
404     }
405    
406     void dmaSPR1() // toSPR
407     {
408     SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n"
409     " tadr = 0x%x, sadr = 0x%x",
410     spr1->chcr._u32, spr1->madr, spr1->qwc,
411     spr1->tadr, spr1->sadr);
412    
413     if ((spr1->chcr.MOD == CHAIN_MODE) && (spr1->qwc == 0))
414     {
415     tDMA_TAG *ptag;
416     ptag = SPRdmaGetAddr(spr1->tadr, false); //Set memory pointer to TADR
417     CPU_INT(DMAC_TO_SPR, /*ptag[0].QWC / BIAS*/ 4 );
418     return;
419     }
420     if(spr1->chcr.MOD == CHAIN_MODE && spr1->qwc > 0) DevCon.Warning(L"SPR1 QWC on Chain " + spr1->chcr.desc());
421     // COMPLETE HACK!!! For now at least.. FFX Videos dont rely on interrupts or reading DMA values
422     // It merely assumes that the last one has finished then starts another one (broke with the DMA fix)
423     // This "shouldn't" cause any problems as SPR is generally faster than the other DMAS anyway. (Refraction)
424     CPU_INT(DMAC_TO_SPR, /*spr1->qwc / BIAS*/ 4 );
425     }
426    
427     void SPRTOinterrupt()
428     {
429     _dmaSPR1();
430     if (!spr1finished) return;
431    
432     spr1->chcr.STR = false;
433     hwDmacIrq(DMAC_TO_SPR);
434     }
435    
436     void SaveStateBase::sprFreeze()
437     {
438     FreezeTag("SPRdma");
439    
440     Freeze(spr0finished);
441     Freeze(spr1finished);
442     Freeze(mfifotransferred);
443     }

  ViewVC Help
Powered by ViewVC 1.1.22