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

Annotation of /trunk/pcsx2/Vif1_MFIFO.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 5 months ago) by william
File size: 8724 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug 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     #include "Vif.h"
19     #include "Gif.h"
20     #include "Vif_Dma.h"
21    
22     VIFregisters *vifRegs;
23     vifStruct *vif;
24     u16 vifqwc = 0;
25 william 62 u32 g_vifCycles = 0;
26     u32 g_vu0Cycles = 0;
27     u32 g_vu1Cycles = 0;
28     u32 g_packetsizeonvu = 0;
29 william 31
30     __aligned16 VifMaskTypes g_vifmask;
31    
32 william 62 extern u32 g_vifCycles;
33 william 31
34 william 62 static u32 qwctag(u32 mask)
35 william 31 {
36 william 62 return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
37     }
38    
39     static __fi bool mfifoVIF1rbTransfer()
40     {
41     u32 maddr = dmacRegs.rbor.ADDR;
42     u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
43     u16 mfifoqwc = std::min(vif1ch.qwc, vifqwc);
44 william 31 u32 *src;
45     bool ret;
46    
47     /* Check if the transfer should wrap around the ring buffer */
48 william 62 if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
49 william 31 {
50 william 62 int s1 = ((msize) - vif1ch.madr) >> 2;
51 william 31
52     SPR_LOG("Split MFIFO");
53    
54     /* it does, so first copy 's1' bytes from 'addr' to 'data' */
55 william 62 src = (u32*)PSM(vif1ch.madr);
56 william 31 if (src == NULL) return false;
57    
58     if (vif1.vifstalled)
59 william 62 ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset);
60 william 31 else
61 william 62 ret = VIF1transfer(src, s1);
62 william 31
63 william 62 vif1ch.madr = qwctag(vif1ch.madr);
64    
65 william 31 if (ret)
66     {
67     /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
68 william 62 vif1ch.madr = maddr;
69 william 31
70     src = (u32*)PSM(maddr);
71     if (src == NULL) return false;
72 william 62 VIF1transfer(src, ((mfifoqwc << 2) - s1));
73 william 31 }
74 william 62 vif1ch.madr = qwctag(vif1ch.madr);
75    
76 william 31 }
77     else
78     {
79     SPR_LOG("Direct MFIFO");
80    
81     /* it doesn't, so just transfer 'qwc*4' words */
82 william 62 src = (u32*)PSM(vif1ch.madr);
83 william 31 if (src == NULL) return false;
84    
85     if (vif1.vifstalled)
86 william 62 ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset);
87 william 31 else
88 william 62 ret = VIF1transfer(src, mfifoqwc << 2);
89    
90     vif1ch.madr = qwctag(vif1ch.madr);
91    
92 william 31 }
93     return ret;
94     }
95    
96 william 62 static __fi void mfifo_VIF1chain()
97 william 31 {
98     /* Is QWC = 0? if so there is nothing to transfer */
99 william 62 if ((vif1ch.qwc == 0))
100 william 31 {
101     vif1.inprogress &= ~1;
102 william 62 return;
103 william 31 }
104    
105 william 62 if (vif1ch.madr >= dmacRegs.rbor.ADDR &&
106     vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK))
107 william 31 {
108 william 62 //Need to exit on mfifo locations, if the madr is matching the madr of spr, we dont have any data left :(
109    
110     u16 startqwc = vif1ch.qwc;
111     mfifoVIF1rbTransfer();
112     vifqwc -= startqwc - vif1ch.qwc;
113    
114 william 31 }
115     else
116     {
117 william 62 tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
118 william 31 SPR_LOG("Non-MFIFO Location");
119    
120 william 62 //No need to exit on non-mfifo as it is indirect anyway, so it can be transferring this while spr refills the mfifo
121 william 31
122 william 62 if (pMem == NULL) return;
123    
124 william 31 if (vif1.vifstalled)
125 william 62 VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset);
126 william 31 else
127 william 62 VIF1transfer((u32*)pMem, vif1ch.qwc << 2);
128 william 31 }
129     }
130    
131    
132 william 62
133 william 31 void mfifoVIF1transfer(int qwc)
134     {
135     tDMA_TAG *ptag;
136    
137     g_vifCycles = 0;
138    
139     if (qwc > 0)
140     {
141     vifqwc += qwc;
142 william 62 SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done);
143 william 31 if (vif1.inprogress & 0x10)
144     {
145 william 62 if(vif1ch.chcr.STR == true)CPU_INT(DMAC_MFIFO_VIF, 4);
146 william 31
147 william 62 vif1Regs.stat.FQC = 0x10; // FQC=16
148 william 31 }
149     vif1.inprogress &= ~0x10;
150    
151     return;
152     }
153    
154 william 62 if (vif1ch.qwc == 0 && vifqwc > 0)
155 william 31 {
156 william 62 ptag = dmaGetAddr(vif1ch.tadr, false);
157 william 31
158 william 62 if (vif1ch.chcr.TTE)
159 william 31 {
160     bool ret;
161    
162 william 62 if (vif1.vifstalled)
163     ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on Stall
164 william 31 else
165 william 62 ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
166 william 31
167 william 62 if ((ret == false) && vif1.irqoffset < 2)
168 william 31 {
169     return; //IRQ set by VIFTransfer
170 william 62
171     } //else vif1.vifstalled = false;
172 william 31 }
173    
174 william 62 vif1.irqoffset = 0;
175 william 31
176 william 62 vif1ch.unsafeTransfer(ptag);
177    
178     vif1ch.madr = ptag[1]._u32;
179 william 31 vifqwc--;
180    
181     SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x",
182 william 62 ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr);
183 william 31
184     switch (ptag->ID)
185     {
186     case TAG_REFE: // Refe - Transfer Packet According to ADDR field
187 william 62 vif1ch.tadr = qwctag(vif1ch.tadr + 16);
188 william 31 vif1.done = true; //End Transfer
189     break;
190    
191     case TAG_CNT: // CNT - Transfer QWC following the tag.
192 william 62 vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW after Tag
193     vif1ch.tadr = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data
194 william 31 vif1.done = false;
195     break;
196    
197     case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
198     {
199 william 62 int temp = vif1ch.madr; //Temporarily Store ADDR
200     vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW following the tag
201     vif1ch.tadr = temp; //Copy temporarily stored ADDR to Tag
202     if ((temp & dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR));
203 william 31 vif1.done = false;
204     break;
205     }
206    
207     case TAG_REF: // Ref - Transfer QWC from ADDR field
208     case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
209 william 62 vif1ch.tadr = qwctag(vif1ch.tadr + 16); //Set TADR to next tag
210 william 31 vif1.done = false;
211     break;
212    
213     case TAG_END: // End - Transfer QWC following the tag
214 william 62 vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to data following the tag
215     vif1ch.tadr = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data
216 william 31 vif1.done = true; //End Transfer
217     break;
218     }
219    
220 william 62 if (vif1ch.chcr.TIE && ptag->IRQ)
221 william 31 {
222     VIF_LOG("dmaIrq Set");
223     vif1.done = true;
224     }
225 william 62
226     vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
227     vif1.inprogress |= 1;
228 william 31 }
229 william 62
230 william 31
231 william 62 SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr, vifqwc);
232 william 31 }
233    
234     void vifMFIFOInterrupt()
235     {
236     g_vifCycles = 0;
237     VIF_LOG("vif mfifo interrupt");
238    
239 william 62 if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2)
240 william 31 {
241 william 62 GSTransferStatus.PTH2 = STOPPED_MODE;
242     if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
243     gifRegs.stat.APATH = GIF_APATH_IDLE;
244     if(gifRegs.stat.P1Q) gsPath1Interrupt();
245     /*gifRegs.stat.APATH = GIF_APATH_IDLE;
246     if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;*/
247 william 31 }
248    
249 william 62 if (schedulepath3msk & 0x10) Vif1MskPath3();
250 william 31
251 william 62 if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) return;
252     //We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing)
253 william 31
254 william 62 //Simulated GS transfer time done, clear the flags
255    
256     if (vif1.cmd)
257 william 31 {
258 william 62 if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
259 william 31 }
260 william 62 else
261     {
262     vif1Regs.stat.VPS = VPS_IDLE;
263     }
264 william 31
265     if (vif1.irq && vif1.tag.size == 0)
266     {
267 william 62 vif1Regs.stat.INT = true;
268 william 31 hwIntcIrq(INTC_VIF1);
269     --vif1.irq;
270    
271 william 62 if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
272 william 31 {
273 william 62 /*vif1Regs.stat.FQC = 0; // FQC=0
274     vif1ch.chcr.STR = false;*/
275     if(vif1ch.qwc > 0 || !vif1.done) return;
276 william 31 }
277     }
278    
279 william 62 if (vif1.done == false || vif1ch.qwc)
280 william 31 {
281     switch(vif1.inprogress & 1)
282     {
283     case 0: //Set up transfer
284 william 62 if (vif1ch.tadr == spr0ch.madr)
285 william 31 {
286     // Console.WriteLn("Empty 1");
287     vifqwc = 0;
288 william 62 if((vif1.inprogress & 0x10) == 0)
289     {
290     hwDmacIrq(DMAC_MFIFO_EMPTY);
291     vif1.inprogress |= 0x10;
292     }
293     vif1Regs.stat.FQC = 0;
294 william 31 return;
295     }
296    
297     mfifoVIF1transfer(0);
298 william 62 CPU_INT(DMAC_MFIFO_VIF, 4);
299 william 31 return;
300    
301     case 1: //Transfer data
302     mfifo_VIF1chain();
303 william 62 //Sanity check! making sure we always have non-zero values
304     CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) );
305 william 31 return;
306     }
307     return;
308     }
309    
310 william 62
311     //FF7 Dirge of Cerberus seems to like the mfifo to tell it when it's empty, even if it's ending.
312     //Doesn't seem to care about the vif1 dma interrupting (possibly disabled the interrupt?)
313     if (vif1ch.tadr == spr0ch.madr)
314 william 31 {
315 william 62 vifqwc = 0;
316     if((vif1.inprogress & 0x10) == 0)
317     {
318     hwDmacIrq(DMAC_MFIFO_EMPTY);
319     vif1.inprogress |= 0x10;
320     }
321     }
322     vif1.vifstalled = false;
323 william 31 vif1.done = 1;
324     g_vifCycles = 0;
325 william 62 vif1ch.chcr.STR = false;
326 william 31 hwDmacIrq(DMAC_VIF1);
327     VIF_LOG("vif mfifo dma end");
328    
329 william 62 vif1Regs.stat.FQC = 0;
330 william 31 }

  ViewVC Help
Powered by ViewVC 1.1.22