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

Annotation of /trunk/pcsx2/Sif0.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 401 - (hide annotations) (download)
Fri Feb 25 17:31:09 2011 UTC (9 years, 9 months ago) by william
File size: 9128 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 sif0;
24    
25     static bool done = false;
26    
27 william 62 static __fi void Sif0Init()
28 william 31 {
29     SIF_LOG("SIF0 DMA start...");
30     done = false;
31     sif0.ee.cycles = 0;
32     sif0.iop.cycles = 0;
33     }
34    
35     // Write from Fifo to EE.
36 william 62 static __fi bool WriteFifoToEE()
37 william 31 {
38 william 62 const int readSize = min((s32)sif0dma.qwc, sif0.fifo.size >> 2);
39 william 31
40     tDMA_TAG *ptag;
41    
42 william 62 //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X", readSize, sif0dma.madr);
43     SIF_LOG("Write Fifo to EE: ----------- %lX of %lX", readSize << 2, sif0dma.qwc << 2);
44 william 31
45 william 62 ptag = sif0dma.getAddr(sif0dma.madr, DMAC_SIF0, true);
46 william 31 if (ptag == NULL)
47     {
48     DevCon.Warning("Write Fifo to EE: ptag == NULL");
49     return false;
50     }
51    
52     sif0.fifo.read((u32*)ptag, readSize << 2);
53    
54     // Clearing handled by vtlb memory protection and manual blocks.
55 william 62 //Cpu->Clear(sif0dma.madr, readSize*4);
56 william 31
57 william 62 sif0dma.madr += readSize << 4;
58 william 31 sif0.ee.cycles += readSize; // fixme : BIAS is factored in above
59 william 62 sif0dma.qwc -= readSize;
60 william 31
61     return true;
62     }
63    
64     // Write IOP to Fifo.
65 william 62 static __fi bool WriteIOPtoFifo()
66 william 31 {
67     // There's some data ready to transfer into the fifo..
68     const int writeSize = min(sif0.iop.counter, sif0.fifo.free());
69    
70     SIF_LOG("Write IOP to Fifo: +++++++++++ %lX of %lX", writeSize, sif0.iop.counter);
71    
72 william 273 sif0.fifo.write((u32*)iopPhysMem(hw_dma9.madr), writeSize);
73     hw_dma9.madr += writeSize << 2;
74 william 31
75     // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords).
76 william 62 sif0.iop.cycles += (writeSize >> 2)/* * BIAS*/; // fixme : should be >> 4
77 william 31 sif0.iop.counter -= writeSize;
78    
79     return true;
80     }
81    
82     // Read Fifo into an ee tag, transfer it to sif0dma, and process it.
83 william 62 static __fi bool ProcessEETag()
84 william 31 {
85     static __aligned16 u32 tag[4];
86 william 273 tDMA_TAG& ptag(*(tDMA_TAG*)tag);
87 william 31
88     sif0.fifo.read((u32*)&tag[0], 4); // Tag
89     SIF_LOG("SIF0 EE read tag: %x %x %x %x", tag[0], tag[1], tag[2], tag[3]);
90    
91 william 273 sif0dma.unsafeTransfer(&ptag);
92 william 62 sif0dma.madr = tag[1];
93 william 31
94     SIF_LOG("SIF0 EE dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)",
95 william 62 sif0dma.madr, sif0dma.qwc, ptag.ID, ptag.IRQ, tag[1], tag[0]);
96 william 31
97 william 62 if (sif0dma.chcr.TIE && ptag.IRQ)
98 william 31 {
99     //Console.WriteLn("SIF0 TIE");
100     sif0.ee.end = true;
101     }
102    
103     switch (ptag.ID)
104     {
105 william 273 case TAG_CNT: break;
106 william 31
107 william 273 case TAG_CNTS:
108 william 401 if (dmacRegs.ctrl.STS == STS_SIF0)
109 william 62 dmacRegs.stadr.ADDR = sif0dma.madr + (sif0dma.qwc * 16);
110 william 273 break;
111 william 31
112     case TAG_END:
113     sif0.ee.end = true;
114     break;
115     }
116     return true;
117     }
118    
119 william 273 // Read Fifo into an iop tag, and transfer it to hw_dma9. And presumably process it.
120 william 62 static __fi bool ProcessIOPTag()
121 william 31 {
122 william 273 // Process DMA tag at hw_dma9.tadr
123     sif0.iop.data = *(sifData *)iopPhysMem(hw_dma9.tadr);
124 william 31 sif0.iop.data.words = (sif0.iop.data.words + 3) & 0xfffffffc; // Round up to nearest 4.
125    
126 william 273 // send the EE's side of the DMAtag. The tag is only 64 bits, with the upper 64 bits
127     // ignored by the EE.
128 william 31
129 william 273 sif0.fifo.write((u32*)iopPhysMem(hw_dma9.tadr + 8), 2);
130     sif0.fifo.writePos = (sif0.fifo.writePos + 2) & (FIFO_SIF_W - 1); // iggy on the upper 64.
131     sif0.fifo.size += 2;
132    
133     hw_dma9.tadr += 16; ///hw_dma9.madr + 16 + sif0.sifData.words << 2;
134    
135     // We're only copying the first 24 bits. Bits 30 and 31 (checked below) are Stop/IRQ bits.
136     hw_dma9.madr = sif0data & 0xFFFFFF;
137 william 31 sif0.iop.counter = sif0words;
138    
139 william 273 // IOP tags have an IRQ bit and an End of Transfer bit:
140 william 31 if (sif0tag.IRQ || (sif0tag.ID & 4)) sif0.iop.end = true;
141 william 273 SIF_LOG("SIF0 IOP Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)", hw_dma9.madr, hw_dma9.tadr, sif0.iop.counter, sif0words, sif0data);
142 william 31
143     return true;
144     }
145    
146     // Stop transferring ee, and signal an interrupt.
147 william 62 static __fi void EndEE()
148 william 31 {
149     SIF_LOG("Sif0: End EE");
150     sif0.ee.end = false;
151     sif0.ee.busy = false;
152     if (sif0.ee.cycles == 0)
153     {
154     SIF_LOG("SIF0 EE: cycles = 0");
155     sif0.ee.cycles = 1;
156     }
157    
158     CPU_INT(DMAC_SIF0, sif0.ee.cycles*BIAS);
159     }
160    
161     // Stop transferring iop, and signal an interrupt.
162 william 62 static __fi void EndIOP()
163 william 31 {
164     SIF_LOG("Sif0: End IOP");
165     sif0data = 0;
166     sif0.iop.end = false;
167     sif0.iop.busy = false;
168    
169     if (sif0.iop.cycles == 0)
170     {
171     DevCon.Warning("SIF0 IOP: cycles = 0");
172     sif0.iop.cycles = 1;
173     }
174     // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords)
175     // So when we're all done, the equation looks like thus:
176     //PSX_INT(IopEvt_SIF0, ( ( sif0.iop.cycles*BIAS ) / 4 ) / 8);
177     PSX_INT(IopEvt_SIF0, sif0.iop.cycles);
178     }
179    
180     // Handle the EE transfer.
181 william 62 static __fi void HandleEETransfer()
182 william 31 {
183 william 62 if(sif0dma.chcr.STR == false)
184 william 31 {
185     DevCon.Warning("Replacement for irq prevention hack EE SIF0");
186     sif0.ee.end = false;
187     sif0.ee.busy = false;
188     return;
189     }
190    
191 william 62 if (dmacRegs.ctrl.STS == STS_SIF0)
192 william 31 {
193     DevCon.Warning("SIF0 stall control");
194     }
195    
196 william 62 /*if (sif0dma.qwc == 0)
197     if (sif0dma.chcr.MOD == NORMAL_MODE)
198 william 31 if (!sif0.ee.end){
199     DevCon.Warning("sif0 irq prevented");
200     done = true;
201     return;
202     }*/
203    
204 william 62 if (sif0dma.qwc <= 0)
205 william 31 {
206 william 62 if ((sif0dma.chcr.MOD == NORMAL_MODE) || sif0.ee.end)
207 william 31 {
208     // Stop transferring ee, and signal an interrupt.
209     done = true;
210     EndEE();
211     }
212     else if (sif0.fifo.size >= 4) // Read a tag
213     {
214     // Read Fifo into an ee tag, transfer it to sif0dma
215     // and process it.
216     ProcessEETag();
217     }
218     }
219    
220 william 62 if (sif0dma.qwc > 0) // If we're writing something, continue to do so.
221 william 31 {
222     // Write from Fifo to EE.
223     if (sif0.fifo.size > 0)
224     {
225     WriteFifoToEE();
226     }
227     }
228     }
229    
230     // Handle the IOP transfer.
231     // Note: Test any changes in this function against Grandia III.
232     // What currently happens is this:
233     // SIF0 DMA start...
234     // SIF + 4 = 4 (pos=4)
235     // SIF0 IOP Tag: madr=19870, tadr=179cc, counter=8 (00000008_80019870)
236     // SIF - 4 = 0 (pos=4)
237     // SIF0 EE read tag: 90000002 935c0 0 0
238     // SIF0 EE dest chain tag madr:000935C0 qwc:0002 id:1 irq:1(000935C0_90000002)
239     // Write Fifo to EE: ----------- 0 of 8
240     // SIF - 0 = 0 (pos=4)
241     // Write IOP to Fifo: +++++++++++ 8 of 8
242     // SIF + 8 = 8 (pos=12)
243     // Write Fifo to EE: ----------- 8 of 8
244     // SIF - 8 = 0 (pos=12)
245     // Sif0: End IOP
246     // Sif0: End EE
247     // SIF0 DMA end...
248    
249     // What happens if (sif0.iop.counter > 0) is handled first is this
250    
251     // SIF0 DMA start...
252     // ...
253     // SIF + 8 = 8 (pos=12)
254     // Sif0: End IOP
255     // Write Fifo to EE: ----------- 8 of 8
256     // SIF - 8 = 0 (pos=12)
257     // SIF0 DMA end...
258    
259 william 62 static __fi void HandleIOPTransfer()
260 william 31 {
261     if (sif0.iop.counter <= 0) // If there's no more to transfer
262     {
263     if (sif0.iop.end)
264     {
265     // Stop transferring iop, and signal an interrupt.
266     done = true;
267     EndIOP();
268     }
269     else
270     {
271 william 273 // Read Fifo into an iop tag, and transfer it to hw_dma9.
272 william 31 // And presumably process it.
273     ProcessIOPTag();
274     }
275     }
276     else
277     {
278     // Write IOP to Fifo.
279     if (sif0.fifo.free() > 0)
280     {
281     WriteIOPtoFifo();
282     }
283     }
284     }
285    
286 william 62 static __fi void Sif0End()
287 william 31 {
288 william 273 psHu32(SBUS_F240) &= ~0x20;
289     psHu32(SBUS_F240) &= ~0x2000;
290    
291 william 401 DMA_LOG("SIF0 DMA End");
292 william 31 }
293    
294     // Transfer IOP to EE, putting data in the fifo as an intermediate step.
295 william 62 __fi void SIF0Dma()
296 william 31 {
297     int BusyCheck = 0;
298     Sif0Init();
299    
300     do
301     {
302     //I realise this is very hacky in a way but its an easy way of checking if both are doing something
303     BusyCheck = 0;
304    
305     if (sif0.iop.busy)
306     {
307 william 62 if(sif0.fifo.free() > 0 || (sif0.iop.end == true && sif0.iop.counter == 0))
308     {
309     BusyCheck++;
310     HandleIOPTransfer();
311     }
312 william 31 }
313     if (sif0.ee.busy)
314     {
315 william 62 if(sif0.fifo.size >= 4 || (sif0.ee.end == true && sif0dma.qwc == 0))
316     {
317     BusyCheck++;
318     HandleEETransfer();
319     }
320 william 31 }
321 william 62 } while (/*!done && */BusyCheck > 0); // Substituting (sif0.ee.busy || sif0.iop.busy) breaks things.
322 william 31
323     Sif0End();
324     }
325    
326 william 62 __fi void sif0Interrupt()
327 william 31 {
328     HW_DMA9_CHCR &= ~0x01000000;
329     psxDmaInterrupt2(2);
330     }
331    
332 william 62 __fi void EEsif0Interrupt()
333 william 31 {
334     hwDmacIrq(DMAC_SIF0);
335 william 62 sif0dma.chcr.STR = false;
336 william 31 }
337    
338 william 62 __fi void dmaSIF0()
339 william 31 {
340 william 62 SIF_LOG(wxString(L"dmaSIF0" + sif0dma.cmqt_to_str()).To8BitData());
341 william 31
342     if (sif0.fifo.readPos != sif0.fifo.writePos)
343     {
344     SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos");
345     }
346    
347 william 62 //if(sif0dma.chcr.MOD == CHAIN_MODE && sif0dma.qwc > 0) DevCon.Warning(L"SIF0 QWC on Chain CHCR " + sif0dma.chcr.desc());
348 william 31 psHu32(SBUS_F240) |= 0x2000;
349     sif0.ee.busy = true;
350    
351 william 62 // Okay, this here is needed currently (r3644).
352     // FFX battles in the thunder plains map die otherwise, Phantasy Star 4 as well
353     // These 2 games could be made playable again by increasing the time the EE or the IOP run,
354     // showing that this is very timing sensible.
355     // Doing this DMA unfortunately brings back an old warning in Legend of Legaia though, but it still works.
356 william 31 if (sif0.iop.busy)
357     {
358 william 62 //hwIntcIrq(INTC_SBUS); // not sure, so let's not
359 william 31 SIF0Dma();
360     }
361     }

  ViewVC Help
Powered by ViewVC 1.1.22