/[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 401 - (hide annotations) (download)
Fri Feb 25 17:31:09 2011 UTC (9 years, 4 months ago) by william
File size: 8287 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 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 401 if(ptag->ID == TAG_REFS && dmacRegs.ctrl.STD == STD_SIF1) DevCon.Warning("SIF1 Drain Stall Control not implemented");
130 william 62 sif1dma.madr = ptag[1]._u32;
131     sif1dma.tadr += 16;
132 william 31 break;
133    
134     case TAG_END:
135     sif1.ee.end = true;
136 william 62 sif1dma.madr = sif1dma.tadr + 16;
137 william 280 //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4);
138 william 31 break;
139    
140     default:
141     Console.WriteLn("Bad addr1 source chain");
142     }
143     return true;
144     }
145    
146     // Write fifo to data, and put it in IOP.
147 william 62 static __fi bool SIFIOPReadTag()
148 william 31 {
149     // Read a tag.
150     sif1.fifo.read((u32*)&sif1.iop.data, 4);
151     //sif1words = (sif1words + 3) & 0xfffffffc; // Round up to nearest 4.
152     SIF_LOG("SIF 1 IOP: dest chain tag madr:%08X wc:%04X id:%X irq:%d",
153     sif1data & 0xffffff, sif1words, sif1tag.ID, sif1tag.IRQ);
154    
155     // Only use the first 24 bits.
156 william 273 hw_dma10.madr = sif1data & 0xffffff;
157 william 31
158     sif1.iop.counter = sif1words;
159     if (sif1tag.IRQ || (sif1tag.ID & 4)) sif1.iop.end = true;
160    
161     return true;
162     }
163    
164     // Stop processing EE, and signal an interrupt.
165 william 62 static __fi void EndEE()
166 william 31 {
167     sif1.ee.end = false;
168     sif1.ee.busy = false;
169     SIF_LOG("Sif 1: End EE");
170    
171     // Voodoocycles : Okami wants around 100 cycles when booting up
172     // Other games reach like 50k cycles here, but the EE will long have given up by then and just retry.
173     // (Cause of double interrupts on the EE)
174     if (sif1.ee.cycles == 0)
175     {
176     SIF_LOG("SIF1 EE: cycles = 0");
177     sif1.ee.cycles = 1;
178     }
179    
180    
181 william 62 CPU_INT(DMAC_SIF1, /*min((int)(*/sif1.ee.cycles*BIAS/*), 384)*/);
182 william 31 }
183    
184     // Stop processing IOP, and signal an interrupt.
185 william 62 static __fi void EndIOP()
186 william 31 {
187     sif1data = 0;
188     sif1.iop.end = false;
189     sif1.iop.busy = false;
190     SIF_LOG("Sif 1: End IOP");
191    
192     //Fixme ( voodoocycles ):
193     //The *24 are needed for ecco the dolphin (CDVD hangs) and silver surfer (Pad not detected)
194     //Greater than *35 break rebooting when trying to play Tekken5 arcade history
195     //Total cycles over 1024 makes SIF too slow to keep up the sound stream in so3...
196     if (sif1.iop.cycles == 0)
197     {
198     DevCon.Warning("SIF1 IOP: cycles = 0");
199     sif1.iop.cycles = 1;
200     }
201     // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords)
202 william 62 PSX_INT(IopEvt_SIF1, /*min((*/sif1.iop.cycles/* * 26*//*), 1024)*/);
203 william 31 }
204    
205     // Handle the EE transfer.
206 william 62 static __fi void HandleEETransfer()
207 william 31 {
208 william 62 if(sif1dma.chcr.STR == false)
209 william 31 {
210     DevCon.Warning("Replacement for irq prevention hack EE SIF1");
211     sif1.ee.end = false;
212     sif1.ee.busy = false;
213     return;
214     }
215 william 62 if (dmacRegs.ctrl.STD == STD_SIF1)
216 william 31 {
217     DevCon.Warning("SIF1 stall control"); // STD == fromSIF1
218     }
219    
220 william 62 /*if (sif1dma.qwc == 0)
221     if (sif1dma.chcr.MOD == NORMAL_MODE)
222 william 31 if (!sif1.ee.end){
223 william 62 DevCon.Warning("sif1 irq prevented CHCR %x QWC %x", sif1dma.chcr, sif1dma.qwc);
224 william 31 done = true;
225     return;
226     }*/
227    
228     // If there's no more to transfer.
229 william 62 if (sif1dma.qwc <= 0)
230 william 31 {
231     // If NORMAL mode or end of CHAIN then stop DMA.
232 william 62 if ((sif1dma.chcr.MOD == NORMAL_MODE) || sif1.ee.end)
233 william 31 {
234     done = true;
235     EndEE();
236     }
237     else
238     {
239     done = false;
240     if (!ProcessEETag()) return;
241     }
242     }
243     else
244     {
245     if (sif1.fifo.free() > 0)
246     {
247     WriteEEtoFifo();
248     }
249     }
250     }
251    
252     // Handle the IOP transfer.
253 william 62 static __fi void HandleIOPTransfer()
254 william 31 {
255     if (sif1.iop.counter > 0)
256     {
257     if (sif1.fifo.size > 0)
258     {
259     WriteFifoToIOP();
260     }
261     }
262    
263     if (sif1.iop.counter <= 0)
264     {
265     if (sif1.iop.end)
266     {
267     done = true;
268     EndIOP();
269     }
270     else if (sif1.fifo.size >= 4)
271     {
272    
273     done = false;
274     SIFIOPReadTag();
275     }
276     }
277     }
278    
279 william 62 static __fi void Sif1End()
280 william 31 {
281 william 273 psHu32(SBUS_F240) &= ~0x40;
282     psHu32(SBUS_F240) &= ~0x4000;
283    
284 william 401 DMA_LOG("SIF1 DMA End");
285 william 31 }
286    
287     // Transfer EE to IOP, putting data in the fifo as an intermediate step.
288 william 62 __fi void SIF1Dma()
289 william 31 {
290     int BusyCheck = 0;
291     Sif1Init();
292    
293     do
294     {
295     //I realise this is very hacky in a way but its an easy way of checking if both are doing something
296     BusyCheck = 0;
297    
298     if (sif1.ee.busy)
299     {
300 william 62 if(sif1.fifo.free() > 0 || (sif1.ee.end == true && sif1dma.qwc == 0))
301     {
302     BusyCheck++;
303     HandleEETransfer();
304     }
305 william 31 }
306    
307     if (sif1.iop.busy)
308     {
309 william 62 if(sif1.fifo.size >= 4 || (sif1.iop.end == true && sif1.iop.counter == 0))
310     {
311     BusyCheck++;
312     HandleIOPTransfer();
313     }
314 william 31 }
315    
316 william 62 } while (/*!done &&*/ BusyCheck > 0);
317 william 31
318     Sif1End();
319     }
320    
321 william 62 __fi void sif1Interrupt()
322 william 31 {
323     HW_DMA10_CHCR &= ~0x01000000; //reset TR flag
324     psxDmaInterrupt2(3);
325     }
326    
327 william 62 __fi void EEsif1Interrupt()
328 william 31 {
329     hwDmacIrq(DMAC_SIF1);
330 william 62 sif1dma.chcr.STR = false;
331 william 31 }
332    
333     // Do almost exactly the same thing as psxDma10 in IopDma.cpp.
334     // Main difference is this checks for iop, where psxDma10 checks for ee.
335 william 62 __fi void dmaSIF1()
336 william 31 {
337 william 62 SIF_LOG(wxString(L"dmaSIF1" + sif1dma.cmqt_to_str()).To8BitData());
338 william 31
339     if (sif1.fifo.readPos != sif1.fifo.writePos)
340     {
341     SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos");
342     }
343    
344 william 62 //if(sif1dma.chcr.MOD == CHAIN_MODE && sif1dma.qwc > 0) DevCon.Warning(L"SIF1 QWC on Chain CHCR " + sif1dma.chcr.desc());
345 william 31
346     psHu32(SBUS_F240) |= 0x4000;
347     sif1.ee.busy = true;
348    
349 william 62 // Okay, this here is needed currently (r3644).
350     // FFX battles in the thunder plains map die otherwise, Phantasy Star 4 as well
351     // These 2 games could be made playable again by increasing the time the EE or the IOP run,
352     // showing that this is very timing sensible.
353     // Doing this DMA unfortunately brings back an old warning in Legend of Legaia though, but it still works.
354 william 31 if (sif1.iop.busy)
355     {
356     SIF1Dma();
357     }
358     }

  ViewVC Help
Powered by ViewVC 1.1.22