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

Contents of /trunk/pcsx2/Vif1_MFIFO.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years ago) by william
File size: 8756 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 "Vif.h"
19 #include "Gif.h"
20 #include "Vif_Dma.h"
21
22 u16 vifqwc = 0;
23 u32 g_vifCycles = 0;
24 u32 g_vu0Cycles = 0;
25 u32 g_vu1Cycles = 0;
26 u32 g_packetsizeonvu = 0;
27
28 extern u32 g_vifCycles;
29
30 static u32 qwctag(u32 mask)
31 {
32 return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK));
33 }
34
35 static u16 QWCinVIFMFIFO(u32 DrainADDR)
36 {
37 u32 ret;
38
39
40 SPR_LOG("VIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", vif1ch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR);
41 //Calculate what we have in the fifo.
42 if(DrainADDR <= spr0ch.madr)
43 {
44 //Drain is below the tadr, calculate the difference between them
45 ret = (spr0ch.madr - DrainADDR) >> 4;
46 }
47 else
48 {
49 u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
50 //Drain is higher than SPR so it has looped round,
51 //calculate from base to the SPR tag addr and what is left in the top of the ring
52 ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4;
53 }
54 SPR_LOG("%x Available of the %x requested", ret, vif1ch.qwc);
55
56 return ret;
57 }
58 static __fi bool mfifoVIF1rbTransfer()
59 {
60 u32 maddr = dmacRegs.rbor.ADDR;
61 u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
62 u16 mfifoqwc = min(QWCinVIFMFIFO(vif1ch.madr), vif1ch.qwc);
63 u32 *src;
64 bool ret;
65
66 if(mfifoqwc == 0) return true; //Cant do anything, lets forget it
67
68 /* Check if the transfer should wrap around the ring buffer */
69 if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
70 {
71 int s1 = ((msize) - vif1ch.madr) >> 2;
72
73 SPR_LOG("Split MFIFO");
74
75 /* it does, so first copy 's1' bytes from 'addr' to 'data' */
76 vif1ch.madr = qwctag(vif1ch.madr);
77
78 src = (u32*)PSM(vif1ch.madr);
79 if (src == NULL) return false;
80
81 if (vif1.vifstalled)
82 ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset);
83 else
84 ret = VIF1transfer(src, s1);
85
86 if (ret)
87 {
88 if(vif1.irqoffset != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset);
89 /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
90 vif1ch.madr = maddr;
91
92 src = (u32*)PSM(maddr);
93 if (src == NULL) return false;
94 VIF1transfer(src, ((mfifoqwc << 2) - s1));
95 }
96
97 }
98 else
99 {
100 SPR_LOG("Direct MFIFO");
101
102 /* it doesn't, so just transfer 'qwc*4' words */
103 src = (u32*)PSM(vif1ch.madr);
104 if (src == NULL) return false;
105
106 if (vif1.vifstalled)
107 ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset);
108 else
109 ret = VIF1transfer(src, mfifoqwc << 2);
110
111 }
112 return ret;
113 }
114
115 static __fi void mfifo_VIF1chain()
116 {
117 /* Is QWC = 0? if so there is nothing to transfer */
118 if ((vif1ch.qwc == 0))
119 {
120 vif1.inprogress &= ~1;
121 return;
122 }
123
124 if (vif1ch.madr >= dmacRegs.rbor.ADDR &&
125 vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
126 {
127 if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1");
128
129 vif1ch.madr = qwctag(vif1ch.madr);
130 mfifoVIF1rbTransfer();
131 vif1ch.tadr = qwctag(vif1ch.tadr);
132 vif1ch.madr = qwctag(vif1ch.madr);
133 if(QWCinVIFMFIFO(vif1ch.madr) == 0) vif1.inprogress |= 0x10;
134
135 //vifqwc -= startqwc - vif1ch.qwc;
136
137 }
138 else
139 {
140 tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
141 SPR_LOG("Non-MFIFO Location");
142
143 //No need to exit on non-mfifo as it is indirect anyway, so it can be transferring this while spr refills the mfifo
144
145 if (pMem == NULL) return;
146
147 if (vif1.vifstalled)
148 VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset);
149 else
150 VIF1transfer((u32*)pMem, vif1ch.qwc << 2);
151 }
152 }
153
154 void mfifoVIF1transfer(int qwc)
155 {
156 tDMA_TAG *ptag;
157
158 g_vifCycles = 0;
159
160 if (qwc > 0)
161 {
162 //vifqwc += qwc;
163 SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done);
164 if (vif1.inprogress & 0x10)
165 {
166 if(vif1ch.chcr.STR == true && !(cpuRegs.interrupt & (1<<DMAC_MFIFO_VIF)))
167 {
168 SPR_LOG("Data Added, Resuming");
169 CPU_INT(DMAC_MFIFO_VIF, 4);
170 }
171
172 vif1Regs.stat.FQC = 0x10; // FQC=16
173 }
174 vif1.inprogress &= ~0x10;
175
176 return;
177 }
178
179 if (vif1ch.qwc == 0)
180 {
181 vif1ch.tadr = qwctag(vif1ch.tadr);
182 ptag = dmaGetAddr(vif1ch.tadr, false);
183
184 if (vif1ch.chcr.TTE)
185 {
186 bool ret;
187
188 static __aligned16 u128 masked_tag;
189
190 masked_tag._u64[0] = 0;
191 masked_tag._u64[1] = *((u64*)ptag + 1);
192
193 VIF_LOG("\tVIF1 SrcChain TTE=1, data = 0x%08x.%08x", masked_tag._u32[3], masked_tag._u32[2]);
194
195 if (vif1.vifstalled)
196 {
197 ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset, 4 - vif1.irqoffset, true); //Transfer Tag on stall
198 //ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
199 }
200 else
201 {
202 vif1.irqoffset = 2;
203 ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
204 //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
205 }
206
207 if (!ret && vif1.irqoffset)
208 {
209 vif1.inprogress &= ~1;
210 return; //IRQ set by VIFTransfer
211
212 } //else vif1.vifstalled = false;
213 g_vifCycles += 2;
214 }
215
216 vif1.irqoffset = 0;
217
218 vif1ch.unsafeTransfer(ptag);
219
220 vif1ch.madr = ptag[1]._u32;
221
222 //vifqwc--;
223
224 SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x",
225 ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr);
226
227 vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID);
228
229 if (vif1ch.chcr.TIE && ptag->IRQ)
230 {
231 VIF_LOG("dmaIrq Set");
232 vif1.done = true;
233 }
234
235
236 if(vif1ch.qwc > 0) vif1.inprogress |= 1;
237
238 vif1ch.tadr = qwctag(vif1ch.tadr);
239
240 if(QWCinVIFMFIFO(vif1ch.tadr) == 0) vif1.inprogress |= 0x10;
241 }
242 else
243 {
244 DevCon.Warning("Vif MFIFO QWC not 0 on tag");
245 }
246
247
248 SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr, vifqwc);
249 }
250
251 void vifMFIFOInterrupt()
252 {
253 g_vifCycles = 0;
254 VIF_LOG("vif mfifo interrupt");
255
256
257 if (dmacRegs.ctrl.MFD != MFD_VIF1)
258 {
259 DevCon.Warning("Not in VIF MFIFO mode! Stopping VIF MFIFO");
260 return;
261 }
262
263 if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2)
264 {
265 GSTransferStatus.PTH2 = STOPPED_MODE;
266 if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
267 gifRegs.stat.APATH = GIF_APATH_IDLE;
268 if(gifRegs.stat.P1Q) gsPath1Interrupt();
269 /*gifRegs.stat.APATH = GIF_APATH_IDLE;
270 if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;*/
271 }
272
273 if (schedulepath3msk & 0x10) Vif1MskPath3();
274
275 if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false)
276 {
277 SPR_LOG("Waiting for PATH to be ready");
278 return;
279 }
280 //We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing)
281
282 //Simulated GS transfer time done, clear the flags
283
284 if (vif1.cmd)
285 {
286 if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
287 }
288 else
289 {
290 vif1Regs.stat.VPS = VPS_IDLE;
291 }
292
293
294 if (vif1.irq && vif1.tag.size == 0)
295 {
296 SPR_LOG("VIF MFIFO Code Interrupt detected");
297 vif1Regs.stat.INT = true;
298 hwIntcIrq(INTC_VIF1);
299 --vif1.irq;
300
301 if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
302 {
303 /*vif1Regs.stat.FQC = 0; // FQC=0
304 vif1ch.chcr.STR = false;*/
305 if((vif1ch.qwc > 0 || !vif1.done) && !(vif1.inprogress & 0x10)) return;
306 }
307 }
308
309 if(vif1.inprogress & 0x10)
310 {
311 FireMFIFOEmpty();
312 if(!(vif1.done && vif1ch.qwc == 0))return;
313 }
314
315 if (vif1.done == false || vif1ch.qwc)
316 {
317
318 switch(vif1.inprogress & 1)
319 {
320 case 0: //Set up transfer
321 if (QWCinVIFMFIFO(vif1ch.tadr) == 0)
322 {
323 vif1.inprogress |= 0x10;
324 CPU_INT(DMAC_MFIFO_VIF, 4 );
325 return;
326 }
327
328 mfifoVIF1transfer(0);
329
330 case 1: //Transfer data
331 mfifo_VIF1chain();
332 //Sanity check! making sure we always have non-zero values
333 CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) );
334 return;
335 }
336 return;
337 }
338
339 vif1.vifstalled = false;
340 vif1.done = 1;
341 g_vifCycles = 0;
342 vif1ch.chcr.STR = false;
343 hwDmacIrq(DMAC_VIF1);
344 VIF_LOG("vif mfifo dma end");
345
346 vif1Regs.stat.FQC = 0;
347 }

  ViewVC Help
Powered by ViewVC 1.1.22