/[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 401 - (show annotations) (download)
Fri Feb 25 17:31:09 2011 UTC (9 years, 10 months ago) by william
File size: 10942 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4358 local: v0.9.7.313-latest) 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
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 int partialqwc = 0;
54 if (spr0ch.qwc == 0) return 0;
55 pMem = SPRdmaGetAddr(spr0ch.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(spr0ch.qwc > 1) partialqwc = spr0ch.qwc - 1;
63 else partialqwc = spr0ch.qwc;
64
65 if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR)
66 Console.WriteLn("SPR MFIFO Write outside MFIFO area");
67 else
68 mfifotransferred += partialqwc;
69
70 hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), partialqwc);
71 spr0ch.madr += partialqwc << 4;
72 spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
73 spr0ch.sadr += partialqwc << 4;
74 spr0ch.qwc -= partialqwc;
75 break;
76
77 case NO_MFD:
78 case MFD_RESERVED:
79
80 //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of
81 //the cycle delay out of the way before the end.
82 if(spr0ch.qwc > 1) partialqwc = spr0ch.qwc - 1;
83 else partialqwc = spr0ch.qwc;
84 memcpy_qwc(pMem, &psSu128(spr0ch.sadr), partialqwc);
85
86 // clear VU mem also!
87 TestClearVUs(spr0ch.madr, partialqwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes)
88
89 spr0ch.madr += partialqwc << 4;
90 spr0ch.sadr += partialqwc << 4;
91 spr0ch.qwc -= partialqwc;
92
93 break;
94 }
95
96
97
98 return (partialqwc); // bus is 1/2 the ee speed
99 }
100
101 __fi void SPR0chain()
102 {
103 CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS);
104 }
105
106 void _SPR0interleave()
107 {
108 int qwc = spr0ch.qwc;
109 int sqwc = dmacRegs.sqwc.SQWC;
110 int tqwc = dmacRegs.sqwc.TQWC;
111 tDMA_TAG *pMem;
112
113 if (tqwc == 0) tqwc = qwc;
114 //Console.WriteLn("dmaSPR0 interleave");
115 SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
116 spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr);
117
118 CPU_INT(DMAC_FROM_SPR, qwc * BIAS);
119
120 while (qwc > 0)
121 {
122 spr0ch.qwc = std::min(tqwc, qwc);
123 qwc -= spr0ch.qwc;
124 pMem = SPRdmaGetAddr(spr0ch.madr, true);
125
126 switch (dmacRegs.ctrl.MFD)
127 {
128 case MFD_VIF1:
129 case MFD_GIF:
130 hwMFIFOWrite(spr0ch.madr, &psSu128(spr0ch.sadr), spr0ch.qwc);
131 mfifotransferred += spr0ch.qwc;
132 break;
133
134 case NO_MFD:
135 case MFD_RESERVED:
136 // clear VU mem also!
137 TestClearVUs(spr0ch.madr, spr0ch.qwc << 2);
138 memcpy_qwc(pMem, &psSu128(spr0ch.sadr), spr0ch.qwc);
139 break;
140 }
141 spr0ch.sadr += spr0ch.qwc * 16;
142 spr0ch.madr += (sqwc + spr0ch.qwc) * 16;
143 }
144
145 spr0ch.qwc = 0;
146 }
147
148 static __fi void _dmaSPR0()
149 {
150 if (dmacRegs.ctrl.STS == STS_fromSPR)
151 {
152 Console.WriteLn("SPR0 stall %d", dmacRegs.ctrl.STS);
153 }
154
155 // Transfer Dn_QWC from SPR to Dn_MADR
156 switch(spr0ch.chcr.MOD)
157 {
158 case NORMAL_MODE:
159 {
160 SPR0chain();
161 spr0finished = true;
162 return;
163 }
164 case CHAIN_MODE:
165 {
166 tDMA_TAG *ptag;
167 bool done = false;
168
169 if (spr0ch.qwc > 0)
170 {
171 SPR0chain();
172 return;
173 }
174 // Destination Chain Mode
175 ptag = (tDMA_TAG*)&psSu32(spr0ch.sadr);
176 spr0ch.sadr += 16;
177
178 spr0ch.unsafeTransfer(ptag);
179
180 spr0ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
181
182 SPR_LOG("spr0 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
183 ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr, spr0ch.sadr);
184
185 if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR
186 {
187 Console.WriteLn("SPR stall control");
188 }
189
190 switch (ptag->ID)
191 {
192 case TAG_CNTS: // CNTS - Transfer QWC following the tag (Stall Control)
193 if (dmacRegs.ctrl.STS == STS_fromSPR) dmacRegs.stadr.ADDR = spr0ch.madr + (spr0ch.qwc * 16); //Copy MADR to DMAC_STADR stall addr register
194 break;
195
196 case TAG_CNT: // CNT - Transfer QWC following the tag.
197 done = false;
198 break;
199
200 case TAG_END: // End - Transfer QWC following the tag
201 done = true;
202 break;
203 }
204
205 SPR0chain();
206
207 if (spr0ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
208 {
209 //Console.WriteLn("SPR0 TIE");
210 done = true;
211 }
212
213 spr0finished = done;
214 SPR_LOG("spr0 dmaChain complete %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
215 ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr);
216 break;
217 }
218 //case INTERLEAVE_MODE:
219 default:
220 {
221 _SPR0interleave();
222 spr0finished = true;
223 break;
224 }
225 }
226 }
227
228 void SPRFROMinterrupt()
229 {
230
231 if (!spr0finished || spr0ch.qwc > 0)
232 {
233 _dmaSPR0();
234
235 if(mfifotransferred != 0)
236 {
237 switch (dmacRegs.ctrl.MFD)
238 {
239 case MFD_VIF1: // Most common case.
240 {
241 if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
242 spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
243 //Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr);
244 mfifoVIF1transfer(mfifotransferred);
245 mfifotransferred = 0;
246 break;
247 }
248 case MFD_GIF:
249 {
250 if ((spr0ch.madr & ~dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
251 spr0ch.madr = dmacRegs.rbor.ADDR + (spr0ch.madr & dmacRegs.rbsr.RMSK);
252 //Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
253 mfifoGIFtransfer(mfifotransferred);
254 mfifotransferred = 0;
255 break;
256 }
257 default:
258 break;
259 }
260 }
261 return;
262 }
263
264
265 spr0ch.chcr.STR = false;
266 hwDmacIrq(DMAC_FROM_SPR);
267 DMA_LOG("SPR0 DMA End");
268 }
269
270 void dmaSPR0() // fromSPR
271 {
272 SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx",
273 spr0ch.chcr._u32, spr0ch.madr, spr0ch.qwc, spr0ch.sadr);
274
275
276 spr0finished = false; //Init
277
278 if(spr0ch.chcr.MOD == CHAIN_MODE && spr0ch.qwc > 0)
279 {
280 //DevCon.Warning(L"SPR0 QWC on Chain " + spr0ch.chcr.desc());
281 if (spr0ch.chcr.tag().ID == TAG_END) // but not TAG_REFE?
282 {
283 spr0finished = true;
284 }
285 }
286
287 SPRFROMinterrupt();
288 }
289
290 __fi static void SPR1transfer(const void* data, int qwc)
291 {
292 memcpy_qwc(&psSu128(spr1ch.sadr), data, qwc);
293 spr1ch.sadr += qwc * 16;
294 }
295
296 int _SPR1chain()
297 {
298 tDMA_TAG *pMem;
299
300 if (spr1ch.qwc == 0) return 0;
301
302 pMem = SPRdmaGetAddr(spr1ch.madr, false);
303 if (pMem == NULL) return -1;
304 int partialqwc = 0;
305 //Taking an arbitary small value for games which like to check the QWC/MADR instead of STR, so get most of
306 //the cycle delay out of the way before the end.
307 if(spr1ch.qwc > 1) partialqwc = spr1ch.qwc - 1;
308 else partialqwc = spr1ch.qwc;
309
310 SPR1transfer(pMem, partialqwc);
311 spr1ch.madr += partialqwc * 16;
312 spr1ch.qwc -= partialqwc;
313
314 hwDmacSrcTadrInc(spr1ch);
315
316 return (partialqwc);
317 }
318
319 __fi void SPR1chain()
320 {
321 if(!CHECK_IPUWAITHACK)
322 {
323 CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS);
324 }
325 else
326 {
327 _SPR1chain();
328 CPU_INT(DMAC_TO_SPR, 8);
329 }
330 }
331
332 void _SPR1interleave()
333 {
334 int qwc = spr1ch.qwc;
335 int sqwc = dmacRegs.sqwc.SQWC;
336 int tqwc = dmacRegs.sqwc.TQWC;
337 tDMA_TAG *pMem;
338
339 if (tqwc == 0) tqwc = qwc;
340 SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
341 spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr);
342 CPU_INT(DMAC_TO_SPR, qwc * BIAS);
343 while (qwc > 0)
344 {
345 spr1ch.qwc = std::min(tqwc, qwc);
346 qwc -= spr1ch.qwc;
347 pMem = SPRdmaGetAddr(spr1ch.madr, false);
348 memcpy_qwc(&psSu128(spr1ch.sadr), pMem, spr1ch.qwc);
349 spr1ch.sadr += spr1ch.qwc * 16;
350 spr1ch.madr += (sqwc + spr1ch.qwc) * 16;
351 }
352
353 spr1ch.qwc = 0;
354 }
355
356 void _dmaSPR1() // toSPR work function
357 {
358 switch(spr1ch.chcr.MOD)
359 {
360 case NORMAL_MODE:
361 {
362 //int cycles = 0;
363 // Transfer Dn_QWC from Dn_MADR to SPR1
364 SPR1chain();
365 spr1finished = true;
366 return;
367 }
368 case CHAIN_MODE:
369 {
370 tDMA_TAG *ptag;
371 bool done = false;
372
373 if (spr1ch.qwc > 0)
374 {
375 SPR_LOG("spr1 Normal or in Progress size=%d, addr=%lx taddr=%lx saddr=%lx", spr1ch.qwc, spr1ch.madr, spr1ch.tadr, spr1ch.sadr);
376 // Transfer Dn_QWC from Dn_MADR to SPR1
377 SPR1chain();
378 return;
379 }
380 // Chain Mode
381
382 ptag = SPRdmaGetAddr(spr1ch.tadr, false); //Set memory pointer to TADR
383
384 if (!spr1ch.transfer("SPR1 Tag", ptag))
385 {
386 done = true;
387 spr1finished = done;
388 }
389
390 spr1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
391
392 // Transfer dma tag if tte is set
393 if (spr1ch.chcr.TTE)
394 {
395 SPR_LOG("SPR TTE: %x_%x\n", ptag[3]._u32, ptag[2]._u32);
396 SPR1transfer(ptag, 1); //Transfer Tag
397 }
398
399 SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx taddr=%lx saddr=%lx",
400 ptag[1]._u32, ptag[0]._u32, spr1ch.qwc, ptag->ID, spr1ch.madr, spr1ch.tadr, spr1ch.sadr);
401
402 done = (hwDmacSrcChain(spr1ch, ptag->ID));
403 SPR1chain(); //Transfers the data set by the switch
404
405 if (spr1ch.chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
406 {
407 SPR_LOG("dmaIrq Set");
408
409 //Console.WriteLn("SPR1 TIE");
410 done = true;
411 }
412
413 spr1finished = done;
414 break;
415 }
416 //case INTERLEAVE_MODE:
417 default:
418 {
419 _SPR1interleave();
420 spr1finished = true;
421 break;
422 }
423 }
424 }
425
426 void dmaSPR1() // toSPR
427 {
428 SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n"
429 " tadr = 0x%x, sadr = 0x%x",
430 spr1ch.chcr._u32, spr1ch.madr, spr1ch.qwc,
431 spr1ch.tadr, spr1ch.sadr);
432
433 spr1finished = false; //Init
434
435 if(spr1ch.chcr.MOD == CHAIN_MODE && spr1ch.qwc > 0)
436 {
437 //DevCon.Warning(L"SPR1 QWC on Chain " + spr1ch.chcr.desc());
438 if ((spr1ch.chcr.tag().ID == TAG_END) || (spr1ch.chcr.tag().ID == TAG_REFE))
439 {
440 spr1finished = true;
441 }
442 }
443
444 SPRTOinterrupt();
445 }
446
447 void SPRTOinterrupt()
448 {
449 SPR_LOG("SPR1 Interrupt");
450 if (!spr1finished || spr1ch.qwc > 0)
451 {
452 _dmaSPR1();
453 return;
454 }
455
456 DMA_LOG("SPR1 DMA End");
457 spr1ch.chcr.STR = false;
458 hwDmacIrq(DMAC_TO_SPR);
459 }
460
461 void SaveStateBase::sprFreeze()
462 {
463 FreezeTag("SPRdma");
464
465 Freeze(spr0finished);
466 Freeze(spr1finished);
467 Freeze(mfifotransferred);
468 }

  ViewVC Help
Powered by ViewVC 1.1.22