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

Contents of /trunk/pcsx2/SPR.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show 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 /* 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