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

Contents of /trunk/pcsx2/Sif1.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 401 - (show 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 /* 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 static __fi void Sif1Init()
28 {
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 static __fi bool WriteEEtoFifo()
37 {
38 // There's some data ready to transfer into the fifo..
39
40 SIF_LOG("Sif 1: Write EE to Fifo");
41 const int writeSize = min((s32)sif1dma.qwc, sif1.fifo.free() >> 2);
42
43 tDMA_TAG *ptag;
44
45 ptag = sif1dma.getAddr(sif1dma.madr, DMAC_SIF1, false);
46 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 sif1dma.madr += writeSize << 4;
55 hwDmacSrcTadrInc(sif1dma);
56 sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above
57 sif1dma.qwc -= writeSize;
58
59 return true;
60 }
61
62 // Read from the fifo and write to IOP
63 static __fi bool WriteFifoToIOP()
64 {
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 sif1.fifo.read((u32*)iopPhysMem(hw_dma10.madr), readSize);
73 psxCpu->Clear(hw_dma10.madr, readSize);
74 hw_dma10.madr += readSize << 2;
75 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 static __fi bool ProcessEETag()
83 {
84 // Chain mode
85 tDMA_TAG *ptag;
86 SIF_LOG("Sif1: ProcessEETag");
87
88 // Process DMA tag at sif1dma.tadr
89 ptag = sif1dma.DMAtransfer(sif1dma.tadr, DMAC_SIF1);
90 if (ptag == NULL)
91 {
92 Console.WriteLn("Sif1 ProcessEETag: ptag = NULL");
93 return false;
94 }
95
96 if (sif1dma.chcr.TTE)
97 {
98 Console.WriteLn("SIF1 TTE");
99 sif1.fifo.write((u32*)ptag + 2, 2);
100 }
101
102 if (sif1dma.chcr.TIE && ptag->IRQ)
103 {
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 sif1dma.madr = ptag[1]._u32;
114 sif1dma.tadr += 16;
115 break;
116
117 case TAG_CNT:
118 sif1dma.tadr += 16;
119 sif1dma.madr = sif1dma.tadr;
120 break;
121
122 case TAG_NEXT:
123 sif1dma.madr = sif1dma.tadr + 16;
124 sif1dma.tadr = ptag[1]._u32;
125 break;
126
127 case TAG_REF:
128 case TAG_REFS:
129 if(ptag->ID == TAG_REFS && dmacRegs.ctrl.STD == STD_SIF1) DevCon.Warning("SIF1 Drain Stall Control not implemented");
130 sif1dma.madr = ptag[1]._u32;
131 sif1dma.tadr += 16;
132 break;
133
134 case TAG_END:
135 sif1.ee.end = true;
136 sif1dma.madr = sif1dma.tadr + 16;
137 //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4);
138 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 static __fi bool SIFIOPReadTag()
148 {
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 hw_dma10.madr = sif1data & 0xffffff;
157
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 static __fi void EndEE()
166 {
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 CPU_INT(DMAC_SIF1, /*min((int)(*/sif1.ee.cycles*BIAS/*), 384)*/);
182 }
183
184 // Stop processing IOP, and signal an interrupt.
185 static __fi void EndIOP()
186 {
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 PSX_INT(IopEvt_SIF1, /*min((*/sif1.iop.cycles/* * 26*//*), 1024)*/);
203 }
204
205 // Handle the EE transfer.
206 static __fi void HandleEETransfer()
207 {
208 if(sif1dma.chcr.STR == false)
209 {
210 DevCon.Warning("Replacement for irq prevention hack EE SIF1");
211 sif1.ee.end = false;
212 sif1.ee.busy = false;
213 return;
214 }
215 if (dmacRegs.ctrl.STD == STD_SIF1)
216 {
217 DevCon.Warning("SIF1 stall control"); // STD == fromSIF1
218 }
219
220 /*if (sif1dma.qwc == 0)
221 if (sif1dma.chcr.MOD == NORMAL_MODE)
222 if (!sif1.ee.end){
223 DevCon.Warning("sif1 irq prevented CHCR %x QWC %x", sif1dma.chcr, sif1dma.qwc);
224 done = true;
225 return;
226 }*/
227
228 // If there's no more to transfer.
229 if (sif1dma.qwc <= 0)
230 {
231 // If NORMAL mode or end of CHAIN then stop DMA.
232 if ((sif1dma.chcr.MOD == NORMAL_MODE) || sif1.ee.end)
233 {
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 static __fi void HandleIOPTransfer()
254 {
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 static __fi void Sif1End()
280 {
281 psHu32(SBUS_F240) &= ~0x40;
282 psHu32(SBUS_F240) &= ~0x4000;
283
284 DMA_LOG("SIF1 DMA End");
285 }
286
287 // Transfer EE to IOP, putting data in the fifo as an intermediate step.
288 __fi void SIF1Dma()
289 {
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 if(sif1.fifo.free() > 0 || (sif1.ee.end == true && sif1dma.qwc == 0))
301 {
302 BusyCheck++;
303 HandleEETransfer();
304 }
305 }
306
307 if (sif1.iop.busy)
308 {
309 if(sif1.fifo.size >= 4 || (sif1.iop.end == true && sif1.iop.counter == 0))
310 {
311 BusyCheck++;
312 HandleIOPTransfer();
313 }
314 }
315
316 } while (/*!done &&*/ BusyCheck > 0);
317
318 Sif1End();
319 }
320
321 __fi void sif1Interrupt()
322 {
323 HW_DMA10_CHCR &= ~0x01000000; //reset TR flag
324 psxDmaInterrupt2(3);
325 }
326
327 __fi void EEsif1Interrupt()
328 {
329 hwDmacIrq(DMAC_SIF1);
330 sif1dma.chcr.STR = false;
331 }
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 __fi void dmaSIF1()
336 {
337 SIF_LOG(wxString(L"dmaSIF1" + sif1dma.cmqt_to_str()).To8BitData());
338
339 if (sif1.fifo.readPos != sif1.fifo.writePos)
340 {
341 SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos");
342 }
343
344 //if(sif1dma.chcr.MOD == CHAIN_MODE && sif1dma.qwc > 0) DevCon.Warning(L"SIF1 QWC on Chain CHCR " + sif1dma.chcr.desc());
345
346 psHu32(SBUS_F240) |= 0x4000;
347 sif1.ee.busy = true;
348
349 // 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 if (sif1.iop.busy)
355 {
356 SIF1Dma();
357 }
358 }

  ViewVC Help
Powered by ViewVC 1.1.22