/[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 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File size: 8724 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 "Vif.h"
19 #include "Gif.h"
20 #include "Vif_Dma.h"
21
22 VIFregisters *vifRegs;
23 vifStruct *vif;
24 u16 vifqwc = 0;
25 u32 g_vifCycles = 0;
26 u32 g_vu0Cycles = 0;
27 u32 g_vu1Cycles = 0;
28 u32 g_packetsizeonvu = 0;
29
30 __aligned16 VifMaskTypes g_vifmask;
31
32 extern u32 g_vifCycles;
33
34 static u32 qwctag(u32 mask)
35 {
36 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 u32 *src;
45 bool ret;
46
47 /* Check if the transfer should wrap around the ring buffer */
48 if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
49 {
50 int s1 = ((msize) - vif1ch.madr) >> 2;
51
52 SPR_LOG("Split MFIFO");
53
54 /* it does, so first copy 's1' bytes from 'addr' to 'data' */
55 src = (u32*)PSM(vif1ch.madr);
56 if (src == NULL) return false;
57
58 if (vif1.vifstalled)
59 ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset);
60 else
61 ret = VIF1transfer(src, s1);
62
63 vif1ch.madr = qwctag(vif1ch.madr);
64
65 if (ret)
66 {
67 /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
68 vif1ch.madr = maddr;
69
70 src = (u32*)PSM(maddr);
71 if (src == NULL) return false;
72 VIF1transfer(src, ((mfifoqwc << 2) - s1));
73 }
74 vif1ch.madr = qwctag(vif1ch.madr);
75
76 }
77 else
78 {
79 SPR_LOG("Direct MFIFO");
80
81 /* it doesn't, so just transfer 'qwc*4' words */
82 src = (u32*)PSM(vif1ch.madr);
83 if (src == NULL) return false;
84
85 if (vif1.vifstalled)
86 ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset);
87 else
88 ret = VIF1transfer(src, mfifoqwc << 2);
89
90 vif1ch.madr = qwctag(vif1ch.madr);
91
92 }
93 return ret;
94 }
95
96 static __fi void mfifo_VIF1chain()
97 {
98 /* Is QWC = 0? if so there is nothing to transfer */
99 if ((vif1ch.qwc == 0))
100 {
101 vif1.inprogress &= ~1;
102 return;
103 }
104
105 if (vif1ch.madr >= dmacRegs.rbor.ADDR &&
106 vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK))
107 {
108 //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 }
115 else
116 {
117 tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
118 SPR_LOG("Non-MFIFO Location");
119
120 //No need to exit on non-mfifo as it is indirect anyway, so it can be transferring this while spr refills the mfifo
121
122 if (pMem == NULL) return;
123
124 if (vif1.vifstalled)
125 VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset);
126 else
127 VIF1transfer((u32*)pMem, vif1ch.qwc << 2);
128 }
129 }
130
131
132
133 void mfifoVIF1transfer(int qwc)
134 {
135 tDMA_TAG *ptag;
136
137 g_vifCycles = 0;
138
139 if (qwc > 0)
140 {
141 vifqwc += qwc;
142 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 if (vif1.inprogress & 0x10)
144 {
145 if(vif1ch.chcr.STR == true)CPU_INT(DMAC_MFIFO_VIF, 4);
146
147 vif1Regs.stat.FQC = 0x10; // FQC=16
148 }
149 vif1.inprogress &= ~0x10;
150
151 return;
152 }
153
154 if (vif1ch.qwc == 0 && vifqwc > 0)
155 {
156 ptag = dmaGetAddr(vif1ch.tadr, false);
157
158 if (vif1ch.chcr.TTE)
159 {
160 bool ret;
161
162 if (vif1.vifstalled)
163 ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on Stall
164 else
165 ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
166
167 if ((ret == false) && vif1.irqoffset < 2)
168 {
169 return; //IRQ set by VIFTransfer
170
171 } //else vif1.vifstalled = false;
172 }
173
174 vif1.irqoffset = 0;
175
176 vif1ch.unsafeTransfer(ptag);
177
178 vif1ch.madr = ptag[1]._u32;
179 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 ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr);
183
184 switch (ptag->ID)
185 {
186 case TAG_REFE: // Refe - Transfer Packet According to ADDR field
187 vif1ch.tadr = qwctag(vif1ch.tadr + 16);
188 vif1.done = true; //End Transfer
189 break;
190
191 case TAG_CNT: // CNT - Transfer QWC following the tag.
192 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 vif1.done = false;
195 break;
196
197 case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
198 {
199 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 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 vif1ch.tadr = qwctag(vif1ch.tadr + 16); //Set TADR to next tag
210 vif1.done = false;
211 break;
212
213 case TAG_END: // End - Transfer QWC following the tag
214 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 vif1.done = true; //End Transfer
217 break;
218 }
219
220 if (vif1ch.chcr.TIE && ptag->IRQ)
221 {
222 VIF_LOG("dmaIrq Set");
223 vif1.done = true;
224 }
225
226 vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
227 vif1.inprogress |= 1;
228 }
229
230
231 SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr, vifqwc);
232 }
233
234 void vifMFIFOInterrupt()
235 {
236 g_vifCycles = 0;
237 VIF_LOG("vif mfifo interrupt");
238
239 if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2)
240 {
241 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 }
248
249 if (schedulepath3msk & 0x10) Vif1MskPath3();
250
251 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
254 //Simulated GS transfer time done, clear the flags
255
256 if (vif1.cmd)
257 {
258 if(vif1.done == true && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
259 }
260 else
261 {
262 vif1Regs.stat.VPS = VPS_IDLE;
263 }
264
265 if (vif1.irq && vif1.tag.size == 0)
266 {
267 vif1Regs.stat.INT = true;
268 hwIntcIrq(INTC_VIF1);
269 --vif1.irq;
270
271 if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
272 {
273 /*vif1Regs.stat.FQC = 0; // FQC=0
274 vif1ch.chcr.STR = false;*/
275 if(vif1ch.qwc > 0 || !vif1.done) return;
276 }
277 }
278
279 if (vif1.done == false || vif1ch.qwc)
280 {
281 switch(vif1.inprogress & 1)
282 {
283 case 0: //Set up transfer
284 if (vif1ch.tadr == spr0ch.madr)
285 {
286 // Console.WriteLn("Empty 1");
287 vifqwc = 0;
288 if((vif1.inprogress & 0x10) == 0)
289 {
290 hwDmacIrq(DMAC_MFIFO_EMPTY);
291 vif1.inprogress |= 0x10;
292 }
293 vif1Regs.stat.FQC = 0;
294 return;
295 }
296
297 mfifoVIF1transfer(0);
298 CPU_INT(DMAC_MFIFO_VIF, 4);
299 return;
300
301 case 1: //Transfer data
302 mfifo_VIF1chain();
303 //Sanity check! making sure we always have non-zero values
304 CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) );
305 return;
306 }
307 return;
308 }
309
310
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 {
315 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 vif1.done = 1;
324 g_vifCycles = 0;
325 vif1ch.chcr.STR = false;
326 hwDmacIrq(DMAC_VIF1);
327 VIF_LOG("vif mfifo dma end");
328
329 vif1Regs.stat.FQC = 0;
330 }

  ViewVC Help
Powered by ViewVC 1.1.22