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

Annotation of /trunk/pcsx2/Sif1.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (hide annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 6 months ago) by william
File size: 8169 byte(s)
re-commit (had local access denied errors when committing)
1 william 31 /* 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    
18     #define _PC_ // disables MIPS opcode macros.
19    
20     #include "IopCommon.h"
21     #include "Sif.h"
22    
23     _sif sif1;
24    
25     static bool done = false;
26    
27 william 62 static __fi void Sif1Init()
28 william 31 {
29     SIF_LOG("SIF1 DMA start...");
30     done = false;
31     sif1.ee.cycles = 0;
32     sif1.iop.cycles = 0;
33     }
34    
35     // Write from the EE to Fifo.
36 william 62 static __fi bool WriteEEtoFifo()
37 william 31 {
38     // There's some data ready to transfer into the fifo..
39    
40     SIF_LOG("Sif 1: Write EE to Fifo");
41 william 62 const int writeSize = min((s32)sif1dma.qwc, sif1.fifo.free() >> 2);
42 william 31
43     tDMA_TAG *ptag;
44    
45 william 62 ptag = sif1dma.getAddr(sif1dma.madr, DMAC_SIF1, false);
46 william 31 if (ptag == NULL)
47     {
48     DevCon.Warning("Write EE to Fifo: ptag == NULL");
49     return false;
50     }
51    
52     sif1.fifo.write((u32*)ptag, writeSize << 2);
53    
54 william 62 sif1dma.madr += writeSize << 4;
55 william 280 hwDmacSrcTadrInc(sif1dma);
56 william 31 sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above
57 william 62 sif1dma.qwc -= writeSize;
58 william 31
59     return true;
60     }
61    
62     // Read from the fifo and write to IOP
63 william 62 static __fi bool WriteFifoToIOP()
64 william 31 {
65     // If we're reading something, continue to do so.
66    
67     SIF_LOG("Sif1: Write Fifo to IOP");
68     const int readSize = min (sif1.iop.counter, sif1.fifo.size);
69    
70     SIF_LOG("Sif 1 IOP doing transfer %04X to %08X", readSize, HW_DMA10_MADR);
71    
72 william 273 sif1.fifo.read((u32*)iopPhysMem(hw_dma10.madr), readSize);
73     psxCpu->Clear(hw_dma10.madr, readSize);
74     hw_dma10.madr += readSize << 2;
75 william 31 sif1.iop.cycles += readSize >> 2; // fixme: should be >> 4
76     sif1.iop.counter -= readSize;
77    
78     return true;
79     }
80    
81     // Get a tag and process it.
82 william 62 static __fi bool ProcessEETag()
83 william 31 {
84     // Chain mode
85     tDMA_TAG *ptag;
86     SIF_LOG("Sif1: ProcessEETag");
87    
88 william 62 // Process DMA tag at sif1dma.tadr
89     ptag = sif1dma.DMAtransfer(sif1dma.tadr, DMAC_SIF1);
90 william 31 if (ptag == NULL)
91     {
92     Console.WriteLn("Sif1 ProcessEETag: ptag = NULL");
93     return false;
94     }
95    
96 william 62 if (sif1dma.chcr.TTE)
97 william 31 {
98     Console.WriteLn("SIF1 TTE");
99     sif1.fifo.write((u32*)ptag + 2, 2);
100     }
101    
102 william 62 if (sif1dma.chcr.TIE && ptag->IRQ)
103 william 31 {
104     Console.WriteLn("SIF1 TIE");
105     sif1.ee.end = true;
106     }
107    
108     SIF_LOG(wxString(ptag->tag_to_str()).To8BitData());
109     switch (ptag->ID)
110     {
111     case TAG_REFE:
112     sif1.ee.end = true;
113 william 62 sif1dma.madr = ptag[1]._u32;
114     sif1dma.tadr += 16;
115 william 31 break;
116    
117     case TAG_CNT:
118 william 280 sif1dma.tadr += 16;
119     sif1dma.madr = sif1dma.tadr;
120 william 31 break;
121    
122     case TAG_NEXT:
123 william 62 sif1dma.madr = sif1dma.tadr + 16;
124     sif1dma.tadr = ptag[1]._u32;
125 william 31 break;
126    
127     case TAG_REF:
128     case TAG_REFS:
129 william 62 sif1dma.madr = ptag[1]._u32;
130     sif1dma.tadr += 16;
131 william 31 break;
132    
133     case TAG_END:
134     sif1.ee.end = true;
135 william 62 sif1dma.madr = sif1dma.tadr + 16;
136 william 280 //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4);
137 william 31 break;
138    
139     default:
140     Console.WriteLn("Bad addr1 source chain");
141     }
142     return true;
143     }
144    
145     // Write fifo to data, and put it in IOP.
146 william 62 static __fi bool SIFIOPReadTag()
147 william 31 {
148     // Read a tag.
149     sif1.fifo.read((u32*)&sif1.iop.data, 4);
150     //sif1words = (sif1words + 3) & 0xfffffffc; // Round up to nearest 4.
151     SIF_LOG("SIF 1 IOP: dest chain tag madr:%08X wc:%04X id:%X irq:%d",
152     sif1data & 0xffffff, sif1words, sif1tag.ID, sif1tag.IRQ);
153    
154     // Only use the first 24 bits.
155 william 273 hw_dma10.madr = sif1data & 0xffffff;
156 william 31
157     sif1.iop.counter = sif1words;
158     if (sif1tag.IRQ || (sif1tag.ID & 4)) sif1.iop.end = true;
159    
160     return true;
161     }
162    
163     // Stop processing EE, and signal an interrupt.
164 william 62 static __fi void EndEE()
165 william 31 {
166     sif1.ee.end = false;
167     sif1.ee.busy = false;
168     SIF_LOG("Sif 1: End EE");
169    
170     // Voodoocycles : Okami wants around 100 cycles when booting up
171     // Other games reach like 50k cycles here, but the EE will long have given up by then and just retry.
172     // (Cause of double interrupts on the EE)
173     if (sif1.ee.cycles == 0)
174     {
175     SIF_LOG("SIF1 EE: cycles = 0");
176     sif1.ee.cycles = 1;
177     }
178    
179    
180 william 62 CPU_INT(DMAC_SIF1, /*min((int)(*/sif1.ee.cycles*BIAS/*), 384)*/);
181 william 31 }
182    
183     // Stop processing IOP, and signal an interrupt.
184 william 62 static __fi void EndIOP()
185 william 31 {
186     sif1data = 0;
187     sif1.iop.end = false;
188     sif1.iop.busy = false;
189     SIF_LOG("Sif 1: End IOP");
190    
191     //Fixme ( voodoocycles ):
192     //The *24 are needed for ecco the dolphin (CDVD hangs) and silver surfer (Pad not detected)
193     //Greater than *35 break rebooting when trying to play Tekken5 arcade history
194     //Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3...
195     if (sif1.iop.cycles == 0)
196     {
197     DevCon.Warning("SIF1 IOP: cycles = 0");
198     sif1.iop.cycles = 1;
199     }
200     // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords)
201 william 62 PSX_INT(IopEvt_SIF1, /*min((*/sif1.iop.cycles/* * 26*//*), 1024)*/);
202 william 31 }
203    
204     // Handle the EE transfer.
205 william 62 static __fi void HandleEETransfer()
206 william 31 {
207 william 62 if(sif1dma.chcr.STR == false)
208 william 31 {
209     DevCon.Warning("Replacement for irq prevention hack EE SIF1");
210     sif1.ee.end = false;
211     sif1.ee.busy = false;
212     return;
213     }
214 william 62 if (dmacRegs.ctrl.STD == STD_SIF1)
215 william 31 {
216     DevCon.Warning("SIF1 stall control"); // STD == fromSIF1
217     }
218    
219 william 62 /*if (sif1dma.qwc == 0)
220     if (sif1dma.chcr.MOD == NORMAL_MODE)
221 william 31 if (!sif1.ee.end){
222 william 62 DevCon.Warning("sif1 irq prevented CHCR %x QWC %x", sif1dma.chcr, sif1dma.qwc);
223 william 31 done = true;
224     return;
225     }*/
226    
227     // If there's no more to transfer.
228 william 62 if (sif1dma.qwc <= 0)
229 william 31 {
230     // If NORMAL mode or end of CHAIN then stop DMA.
231 william 62 if ((sif1dma.chcr.MOD == NORMAL_MODE) || sif1.ee.end)
232 william 31 {
233     done = true;
234     EndEE();
235     }
236     else
237     {
238     done = false;
239     if (!ProcessEETag()) return;
240     }
241     }
242     else
243     {
244     if (sif1.fifo.free() > 0)
245     {
246     WriteEEtoFifo();
247     }
248     }
249     }
250    
251     // Handle the IOP transfer.
252 william 62 static __fi void HandleIOPTransfer()
253 william 31 {
254     if (sif1.iop.counter > 0)
255     {
256     if (sif1.fifo.size > 0)
257     {
258     WriteFifoToIOP();
259     }
260     }
261    
262     if (sif1.iop.counter <= 0)
263     {
264     if (sif1.iop.end)
265     {
266     done = true;
267     EndIOP();
268     }
269     else if (sif1.fifo.size >= 4)
270     {
271    
272     done = false;
273     SIFIOPReadTag();
274     }
275     }
276     }
277    
278 william 62 static __fi void Sif1End()
279 william 31 {
280 william 273 psHu32(SBUS_F240) &= ~0x40;
281     psHu32(SBUS_F240) &= ~0x4000;
282    
283 william 31 SIF_LOG("SIF1 DMA end...");
284     }
285    
286     // Transfer EE to IOP, putting data in the fifo as an intermediate step.
287 william 62 __fi void SIF1Dma()
288 william 31 {
289     int BusyCheck = 0;
290     Sif1Init();
291    
292     do
293     {
294     //I realise this is very hacky in a way but its an easy way of checking if both are doing something
295     BusyCheck = 0;
296    
297     if (sif1.ee.busy)
298     {
299 william 62 if(sif1.fifo.free() > 0 || (sif1.ee.end == true && sif1dma.qwc == 0))
300     {
301     BusyCheck++;
302     HandleEETransfer();
303     }
304 william 31 }
305    
306     if (sif1.iop.busy)
307     {
308 william 62 if(sif1.fifo.size >= 4 || (sif1.iop.end == true && sif1.iop.counter == 0))
309     {
310     BusyCheck++;
311     HandleIOPTransfer();
312     }
313 william 31 }
314    
315 william 62 } while (/*!done &&*/ BusyCheck > 0);
316 william 31
317     Sif1End();
318     }
319    
320 william 62 __fi void sif1Interrupt()
321 william 31 {
322     HW_DMA10_CHCR &= ~0x01000000; //reset TR flag
323     psxDmaInterrupt2(3);
324     }
325    
326 william 62 __fi void EEsif1Interrupt()
327 william 31 {
328     hwDmacIrq(DMAC_SIF1);
329 william 62 sif1dma.chcr.STR = false;
330 william 31 }
331    
332     // Do almost exactly the same thing as psxDma10 in IopDma.cpp.
333     // Main difference is this checks for iop, where psxDma10 checks for ee.
334 william 62 __fi void dmaSIF1()
335 william 31 {
336 william 62 SIF_LOG(wxString(L"dmaSIF1" + sif1dma.cmqt_to_str()).To8BitData());
337 william 31
338     if (sif1.fifo.readPos != sif1.fifo.writePos)
339     {
340     SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos");
341     }
342    
343 william 62 //if(sif1dma.chcr.MOD == CHAIN_MODE && sif1dma.qwc > 0) DevCon.Warning(L"SIF1 QWC on Chain CHCR " + sif1dma.chcr.desc());
344 william 31
345     psHu32(SBUS_F240) |= 0x4000;
346     sif1.ee.busy = true;
347    
348 william 62 // Okay, this here is needed currently (r3644).
349     // FFX battles in the thunder plains map die otherwise, Phantasy Star 4 as well
350     // These 2 games could be made playable again by increasing the time the EE or the IOP run,
351     // showing that this is very timing sensible.
352     // Doing this DMA unfortunately brings back an old warning in Legend of Legaia though, but it still works.
353 william 31 if (sif1.iop.busy)
354     {
355     SIF1Dma();
356     }
357     }

  ViewVC Help
Powered by ViewVC 1.1.22