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

Contents of /trunk/pcsx2/Sif0.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 2 months ago) by william
File size: 9129 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-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 sif0;
24
25 static bool done = false;
26
27 static __fi void Sif0Init()
28 {
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 static __fi bool WriteFifoToEE()
37 {
38 const int readSize = min((s32)sif0dma.qwc, sif0.fifo.size >> 2);
39
40 tDMA_TAG *ptag;
41
42 //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
45 ptag = sif0dma.getAddr(sif0dma.madr, DMAC_SIF0, true);
46 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 //Cpu->Clear(sif0dma.madr, readSize*4);
56
57 sif0dma.madr += readSize << 4;
58 sif0.ee.cycles += readSize; // fixme : BIAS is factored in above
59 sif0dma.qwc -= readSize;
60
61 return true;
62 }
63
64 // Write IOP to Fifo.
65 static __fi bool WriteIOPtoFifo()
66 {
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 sif0.fifo.write((u32*)iopPhysMem(hw_dma9.madr), writeSize);
73 hw_dma9.madr += writeSize << 2;
74
75 // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords).
76 sif0.iop.cycles += (writeSize >> 2)/* * BIAS*/; // fixme : should be >> 4
77 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 static __fi bool ProcessEETag()
84 {
85 static __aligned16 u32 tag[4];
86 tDMA_TAG& ptag(*(tDMA_TAG*)tag);
87
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 sif0dma.unsafeTransfer(&ptag);
92 sif0dma.madr = tag[1];
93
94 SIF_LOG("SIF0 EE dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)",
95 sif0dma.madr, sif0dma.qwc, ptag.ID, ptag.IRQ, tag[1], tag[0]);
96
97 if (sif0dma.chcr.TIE && ptag.IRQ)
98 {
99 //Console.WriteLn("SIF0 TIE");
100 sif0.ee.end = true;
101 }
102
103 switch (ptag.ID)
104 {
105 case TAG_CNT: break;
106
107 case TAG_CNTS:
108 if (dmacRegs.ctrl.STS != NO_STS)
109 dmacRegs.stadr.ADDR = sif0dma.madr + (sif0dma.qwc * 16);
110 break;
111
112 case TAG_END:
113 sif0.ee.end = true;
114 break;
115 }
116 return true;
117 }
118
119 // Read Fifo into an iop tag, and transfer it to hw_dma9. And presumably process it.
120 static __fi bool ProcessIOPTag()
121 {
122 // Process DMA tag at hw_dma9.tadr
123 sif0.iop.data = *(sifData *)iopPhysMem(hw_dma9.tadr);
124 sif0.iop.data.words = (sif0.iop.data.words + 3) & 0xfffffffc; // Round up to nearest 4.
125
126 // 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
129 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 sif0.iop.counter = sif0words;
138
139 // IOP tags have an IRQ bit and an End of Transfer bit:
140 if (sif0tag.IRQ || (sif0tag.ID & 4)) sif0.iop.end = true;
141 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
143 return true;
144 }
145
146 // Stop transferring ee, and signal an interrupt.
147 static __fi void EndEE()
148 {
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 static __fi void EndIOP()
163 {
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 static __fi void HandleEETransfer()
182 {
183 if(sif0dma.chcr.STR == false)
184 {
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 if (dmacRegs.ctrl.STS == STS_SIF0)
192 {
193 DevCon.Warning("SIF0 stall control");
194 }
195
196 /*if (sif0dma.qwc == 0)
197 if (sif0dma.chcr.MOD == NORMAL_MODE)
198 if (!sif0.ee.end){
199 DevCon.Warning("sif0 irq prevented");
200 done = true;
201 return;
202 }*/
203
204 if (sif0dma.qwc <= 0)
205 {
206 if ((sif0dma.chcr.MOD == NORMAL_MODE) || sif0.ee.end)
207 {
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 if (sif0dma.qwc > 0) // If we're writing something, continue to do so.
221 {
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 static __fi void HandleIOPTransfer()
260 {
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 // Read Fifo into an iop tag, and transfer it to hw_dma9.
272 // 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 static __fi void Sif0End()
287 {
288 psHu32(SBUS_F240) &= ~0x20;
289 psHu32(SBUS_F240) &= ~0x2000;
290
291 SIF_LOG("SIF0 DMA end...");
292 }
293
294 // Transfer IOP to EE, putting data in the fifo as an intermediate step.
295 __fi void SIF0Dma()
296 {
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 if(sif0.fifo.free() > 0 || (sif0.iop.end == true && sif0.iop.counter == 0))
308 {
309 BusyCheck++;
310 HandleIOPTransfer();
311 }
312 }
313 if (sif0.ee.busy)
314 {
315 if(sif0.fifo.size >= 4 || (sif0.ee.end == true && sif0dma.qwc == 0))
316 {
317 BusyCheck++;
318 HandleEETransfer();
319 }
320 }
321 } while (/*!done && */BusyCheck > 0); // Substituting (sif0.ee.busy || sif0.iop.busy) breaks things.
322
323 Sif0End();
324 }
325
326 __fi void sif0Interrupt()
327 {
328 HW_DMA9_CHCR &= ~0x01000000;
329 psxDmaInterrupt2(2);
330 }
331
332 __fi void EEsif0Interrupt()
333 {
334 hwDmacIrq(DMAC_SIF0);
335 sif0dma.chcr.STR = false;
336 }
337
338 __fi void dmaSIF0()
339 {
340 SIF_LOG(wxString(L"dmaSIF0" + sif0dma.cmqt_to_str()).To8BitData());
341
342 if (sif0.fifo.readPos != sif0.fifo.writePos)
343 {
344 SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos");
345 }
346
347 //if(sif0dma.chcr.MOD == CHAIN_MODE && sif0dma.qwc > 0) DevCon.Warning(L"SIF0 QWC on Chain CHCR " + sif0dma.chcr.desc());
348 psHu32(SBUS_F240) |= 0x2000;
349 sif0.ee.busy = true;
350
351 // 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 if (sif0.iop.busy)
357 {
358 //hwIntcIrq(INTC_SBUS); // not sure, so let's not
359 SIF0Dma();
360 }
361 }

  ViewVC Help
Powered by ViewVC 1.1.22