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

  ViewVC Help
Powered by ViewVC 1.1.22