/[pcsx2_0.9.7]/trunk/pcsx2/ps2/GIFpath.cpp
ViewVC logotype

Contents of /trunk/pcsx2/ps2/GIFpath.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 30539 byte(s)
re-commit (had local access denied errors when committing)
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 #include "Common.h"
18 #include "GS.h"
19 #include "Gif.h"
20 #include "Vif_Dma.h"
21 #include "Vif.h"
22 #include <xmmintrin.h>
23
24 // --------------------------------------------------------------------------------------
25 // GIFpath -- the GIFtag Parser
26 // --------------------------------------------------------------------------------------
27
28 enum GIF_FLG
29 {
30 GIF_FLG_PACKED = 0,
31 GIF_FLG_REGLIST = 1,
32 GIF_FLG_IMAGE = 2,
33 GIF_FLG_IMAGE2 = 3
34 };
35
36 enum GIF_REG
37 {
38 GIF_REG_PRIM = 0x00,
39 GIF_REG_RGBA = 0x01,
40 GIF_REG_STQ = 0x02,
41 GIF_REG_UV = 0x03,
42 GIF_REG_XYZF2 = 0x04,
43 GIF_REG_XYZ2 = 0x05,
44 GIF_REG_TEX0_1 = 0x06,
45 GIF_REG_TEX0_2 = 0x07,
46 GIF_REG_CLAMP_1 = 0x08,
47 GIF_REG_CLAMP_2 = 0x09,
48 GIF_REG_FOG = 0x0a,
49 GIF_REG_XYZF3 = 0x0c,
50 GIF_REG_XYZ3 = 0x0d,
51 GIF_REG_A_D = 0x0e,
52 GIF_REG_NOP = 0x0f,
53 };
54
55 // GIFTAG
56 // Members of this structure are in CAPS to help visually denote that they are representative
57 // of actual hw register states of the GIF, unlike the internal tracking vars in GIFPath, which
58 // are modified during the GIFtag unpacking process.
59 struct GIFTAG
60 {
61 u16 NLOOP : 15;
62 u16 EOP : 1;
63
64 // Note that contents of the Dummy bits on real hardware is likely used to maintain state
65 // information regarding tag processing (namely nllop and curreg info, so to resume partial
66 // transfers later).
67 u16 _dummy0 : 16;
68 u32 _dummy1 : 14;
69
70 u32 PRE : 1;
71 u32 PRIM : 11;
72 u32 FLG : 2;
73 u32 NREG : 4;
74 u32 REGS[2];
75
76 GIFTAG() {}
77
78 wxString DumpRegsToString() const;
79 wxString ToString() const;
80 };
81
82 wxString GIFTAG::DumpRegsToString() const
83 {
84 static const char* PackedModeRegsLabel[] =
85 {
86 "PRIM", "RGBA", "STQ", "UV",
87 "XYZF2", "XYZ2", "TEX0_1", "TEX0_2",
88 "CLAMP_1", "CLAMP_2", "FOG", "Unknown",
89 "XYZF3", "XYZ3", "A_D", "NOP"
90 };
91
92 u32 tempreg = REGS[0];
93 uint numregs = ((NREG-1)&0xf) + 1;
94
95 FastFormatUnicode result;
96 result.Write("NREG=0x%02X (", NREG);
97
98 for (u32 i = 0; i < numregs; i++) {
99 if (i == 8) tempreg = REGS[1];
100 if (i > 0) result.Write(" ");
101 result.Write(PackedModeRegsLabel[tempreg & 0xf]);
102 tempreg >>= 4;
103 }
104
105 result.Write(")");
106 return result;
107 }
108
109 wxString GIFTAG::ToString() const
110 {
111 static const char* GifTagModeLabel[] =
112 {
113 "Packed", "RegList", "Image", "Image2"
114 };
115
116 FastFormatUnicode result;
117 result.Write("NLOOP=0x%04X, EOP=%u, PRE=%u, PRIM=0x%03X, MODE=%s",
118 NLOOP, EOP, PRE, PRIM, GifTagModeLabel[FLG]);
119
120 return result;
121 }
122
123
124 // --------------------------------------------------------------------------------------
125 // GIFPath -- PS2 GIFtag info (one for each path).
126 // --------------------------------------------------------------------------------------
127 // fixme: The real PS2 has a single internal PATH and 3 logical sources, not 3 entirely
128 // separate paths. But for that to work properly we need also interlocked path sources.
129 // That is, when the GIF selects a source, it sticks to that source until an EOP. Currently
130 // this is not emulated!
131
132 struct GIFPath
133 {
134 const GIFTAG tag; // A copy of the "original" tag -- modification allowed only by SetTag(), so let's make it const.
135 u8 regs[16]; // positioned after tag ensures 16-bit aligned (in case we SSE optimize later)
136
137 u32 nloop; // local copy nloop counts toward zero, and leaves the tag copy unmodified.
138 u32 curreg; // reg we left of on (for traversing through loops)
139 u32 numregs; // number of regs (when NREG is 0, numregs is 16)
140 u32 DetectE;
141
142 GIFPath();
143
144 void Reset();
145 void PrepPackedRegs();
146 bool StepReg();
147 u8 GetReg();
148 bool IsActive() const;
149
150 template< bool Aligned >
151 void SetTag(const void* mem);
152
153 template< GIF_PATH pathidx, bool Aligned >
154 int CopyTag(const u128* pMem, u32 size);
155
156 int ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size);
157 };
158
159 typedef void (__fastcall *GIFRegHandler)(const u32* data);
160
161 struct GifPathStruct
162 {
163 const GIFRegHandler Handlers[0x100-0x60]; // handlers for 0x60->0x100
164 GIFPath path[3];
165
166 __fi GIFPath& operator[]( int idx ) { return path[idx]; }
167 };
168
169
170 // --------------------------------------------------------------------------------------
171 // SIGNAL / FINISH / LABEL
172 // --------------------------------------------------------------------------------------
173
174 bool SIGNAL_IMR_Pending = false;
175 u32 SIGNAL_Data_Pending[2];
176
177
178 // SIGNAL : This register is a double-throw. If the SIGNAL bit in CSR is clear, set the CSR
179 // and raise a gsIrq. If CSR is already *set*, then do not raise a gsIrq, and ignore all
180 // subsequent drawing operations and writes to general purpose registers to the GS. (note:
181 // I'm pretty sure this includes direct GS and GSreg accesses, as well as those coming
182 // through the GIFpath -- but that behavior isn't confirmed yet). Privileged writes are
183 // still active.
184 //
185 // Ignorance continues until the SIGNAL bit in CSR is manually cleared by the EE. And here's
186 // the tricky part: the interrupt from the second SIGNAL is still pending, and should be
187 // raised once the EE has reset the *IMR* mask for SIGNAL -- meaning setting the bit to 1
188 // (disabled/masked) and then back to 0 (enabled/unmasked). Until the *IMR* is cleared, the
189 // SIGNAL is still in the second throw stage, and will freeze the GS upon being written.
190 //
191 static void __fastcall RegHandlerSIGNAL(const u32* data)
192 {
193 // HACK:
194 // Soul Calibur 3 seems to be doing SIGNALs on PATH2 and PATH3 simultaneously, and isn't
195 // too happy with the results (dies on bootup). It properly clears the SIGNAL interrupt
196 // but seems to get stuck on a VBLANK OVERLAP loop. Fixing SIGNAL so that it properly
197 // stalls the GIF might fix it. Investigating the game's internals more deeply may also
198 // be revealing. --air
199
200 if (CSRreg.SIGNAL)
201 {
202 // Time to ignore all subsequent drawing operations. (which is not yet supported)
203 if (!SIGNAL_IMR_Pending)
204 {
205 //DevCon.WriteLn( Color_StrongOrange, "GS SIGNAL double throw encountered!" );
206 SIGNAL_IMR_Pending = true;
207 SIGNAL_Data_Pending[0] = data[0];
208 SIGNAL_Data_Pending[1] = data[1];
209
210 // [TODO] (SIGNAL) : Disable GIFpath DMAs here!
211 // All PATHs and DMAs should be disabled until the CSR is written and the
212 // SIGNAL bit cleared.
213 }
214 }
215 else
216 {
217 GIF_LOG("GS SIGNAL data=%x_%x IMR=%x CSRr=%x",data[0], data[1], GSIMR, GSCSRr);
218 GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]);
219
220 if (!(GSIMR&0x100))
221 gsIrq();
222
223 CSRreg.SIGNAL = true;
224 }
225 }
226
227 // FINISH : Enables end-of-draw signaling. When FINISH is written it tells the GIF to
228 // raise a gsIrq and set the FINISH bit of CSR when the *current drawing operation* is
229 // finished. Translation: Only after all three logical GIFpaths are in EOP status.
230 //
231 // This feature can be used for both reversing the GS transfer mode (downloading post-
232 // processing effects to the EE), and more importantly for *DMA synch* between the
233 // three logical GIFpaths.
234 //
235 static void __fastcall RegHandlerFINISH(const u32* data)
236 {
237 GifTagLog("GIFpath FINISH data=%x_%x CSRr=%x", data[0], data[1], GSCSRr);
238
239 // The FINISH bit is set here, and then it will be cleared when all three
240 // logical GIFpaths finish their packets (EOPs) At that time (found below
241 // in the GIFpath_Parser), IMR is tested and a gsIrq() raised if needed.
242
243 CSRreg.FINISH = true;
244 }
245
246 static void __fastcall RegHandlerLABEL(const u32* data)
247 {
248 GifTagLog( "GIFpath LABEL" );
249 GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID&~data[1])|(data[0]&data[1]);
250 }
251
252 static void __fastcall RegHandlerUNMAPPED(const u32* data)
253 {
254 const int regidx = ((u8*)data)[8];
255
256 // Known "unknowns":
257 // It's possible that anything above 0x63 should just be silently ignored, but in the
258 // offhand chance not, I'm documenting known cases of unknown register use here.
259 //
260 // 0x7F -->
261 // the bios likes to write to 0x7f using an EOP giftag with NLOOP set to 4.
262 // Not sure what it's trying to accomplish exactly. Ignoring seems to work fine,
263 // and is probably the intended behavior (it's likely meant to be a NOP).
264 //
265 // 0xEE -->
266 // .hack Infection [PAL confirmed, NTSC unknown] uses 0xee when you zoom the camera.
267 // The use hasn't been researched yet so parameters are unknown. Everything seems
268 // to work fine as usual -- The 0xEE address in common programming terms is typically
269 // left over uninitialized data, and this might be a case of that, which is to be
270 // silently ignored.
271 //
272 // Guitar Hero 3+ : Massive spamming when using superVU (along with several VIF errors)
273 // Using microVU avoids the GIFtag errors, so probably just one of sVU's hacks conflicting
274 // with one of VIF's hacks, and causing corrupted packet data.
275
276 if( regidx != 0x7f && regidx != 0xee )
277 DbgCon.Warning( "Ignoring Unmapped GIFtag Register, Index = %02x", regidx );
278 }
279
280 #define INSERT_UNMAPPED_4 RegHandlerUNMAPPED, RegHandlerUNMAPPED, RegHandlerUNMAPPED, RegHandlerUNMAPPED,
281 #define INSERT_UNMAPPED_16 INSERT_UNMAPPED_4 INSERT_UNMAPPED_4 INSERT_UNMAPPED_4 INSERT_UNMAPPED_4
282 #define INSERT_UNMAPPED_64 INSERT_UNMAPPED_16 INSERT_UNMAPPED_16 INSERT_UNMAPPED_16 INSERT_UNMAPPED_16
283
284 static __aligned16 GifPathStruct s_gifPath =
285 {
286 RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL, RegHandlerUNMAPPED,
287
288 // Rest are mapped to Unmapped
289 INSERT_UNMAPPED_4 INSERT_UNMAPPED_4 INSERT_UNMAPPED_4
290 INSERT_UNMAPPED_64 INSERT_UNMAPPED_64 INSERT_UNMAPPED_16
291 };
292
293 // --------------------------------------------------------------------------------------
294 // GIFPath Method Implementations
295 // --------------------------------------------------------------------------------------
296
297 GIFPath::GIFPath() : tag()
298 {
299 Reset();
300 }
301
302 __fi void GIFPath::Reset()
303 {
304 memzero(*this);
305 const_cast<GIFTAG&>(tag).EOP = 1;
306 }
307
308 __fi bool GIFPath::StepReg()
309 {
310 if (++curreg >= numregs) {
311 curreg = 0;
312 if (--nloop == 0) {
313 return false;
314 }
315 }
316 return true;
317 }
318
319 __fi u8 GIFPath::GetReg() { return regs[curreg]; }
320
321 // Unpack the registers - registers are stored as a sequence of 4 bit values in the
322 // upper 64 bits of the GIFTAG. That sucks for us when handling partialized GIF packets
323 // coming in from paths 2 and 3, so we unpack them into an 8 bit array here.
324 //
325 __fi void GIFPath::PrepPackedRegs()
326 {
327 // Only unpack registers if we're starting a new pack. Otherwise the unpacked
328 // array should have already been initialized by a previous partial transfer.
329
330 if (curreg != 0) return;
331 DetectE = 0;
332 u32 tempreg = tag.REGS[0];
333 numregs = ((tag.NREG-1)&0xf) + 1;
334
335 for (u32 i = 0; i < numregs; i++) {
336 if (i == 8) tempreg = tag.REGS[1];
337 regs[i] = tempreg & 0xf;
338 if(regs[i] == 0xe) DetectE++;
339 tempreg >>= 4;
340 }
341 }
342
343
344 template< bool Aligned >
345 __fi void GIFPath::SetTag(const void* mem)
346 {
347 _mm_store_ps( (float*)&tag, Aligned ? _mm_load_ps((const float*)mem) : _mm_loadu_ps((const float*)mem) );
348
349 nloop = tag.NLOOP;
350 curreg = 0;
351 }
352
353 __fi bool GIFPath::IsActive() const
354 {
355 return (nloop != 0) || !tag.EOP;
356 }
357
358 void SaveStateBase::gifPathFreeze()
359 {
360 FreezeTag( "GIFpath" );
361 Freeze( s_gifPath.path );
362 }
363
364
365 static __fi void gsHandler(const u8* pMem)
366 {
367 const int reg = pMem[8];
368
369 if (reg == 0x50)
370 {
371 vif1.BITBLTBUF._u64 = *(u64*)pMem;
372 }
373 else if (reg == 0x52)
374 {
375 vif1.TRXREG._u64 = *(u64*)pMem;
376 }
377 else if (reg == 0x53)
378 {
379 // local -> host
380 if ((pMem[0] & 3) == 1)
381 {
382 //Onimusha does TRXREG without BLTDIVIDE first, so we "assume" 32bit for this equation, probably isnt important.
383 // ^ WTF, seriously? This is really important (pseudonym)
384 u8 bpp = 32;
385
386 switch(vif1.BITBLTBUF.SPSM & 7)
387 {
388 case 0:
389 bpp = 32;
390 break;
391 case 1:
392 bpp = 24;
393 break;
394 case 2:
395 bpp = 16;
396 break;
397 case 3:
398 bpp = 8;
399 break;
400 // 4 is 4 bit but this is forbidden
401 default:
402 Console.Error("Illegal format for GS upload: SPSM=0%02o", vif1.BITBLTBUF.SPSM);
403 }
404
405 VIF_LOG("GS Download %dx%d SPSM=%x bpp=%d", vif1.TRXREG.RRW, vif1.TRXREG.RRH, vif1.BITBLTBUF.SPSM, bpp);
406
407 // qwords, rounded down; any extra bits are lost
408 // games must take care to ensure transfer rectangles are exact multiples of a qword
409 vif1.GSLastDownloadSize = vif1.TRXREG.RRW * vif1.TRXREG.RRH * bpp >> 7;
410 //DevCon.Warning("GS download in progress");
411 gifRegs.stat.OPH = true;
412 }
413 }
414 if (reg >= 0x60)
415 {
416 // Question: What happens if an app writes to uncharted register space on real PS2
417 // hardware (handler 0x63 and higher)? Probably a silent ignorance, but not tested
418 // so just guessing... --air
419
420 s_gifPath.Handlers[reg-0x60]((const u32*)pMem);
421 }
422 }
423
424 #define incTag(y) do { \
425 pMem += (y*16); \
426 size -= (y); \
427 } while(false)
428
429 #define aMin(x, y) std::min(x, y)
430
431 // Parameters:
432 // size - max size of incoming data stream, in qwc (simd128). If the path is PATH1, and the
433 // path does not terminate (EOP) within the specified size, it is assumed that the path must
434 // loop around to the start of VU memory and continue processing.
435 __fi int GIFPath::ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size)
436 {
437 u32 startSize = size; // Start Size
438
439 while (size > 0) {
440 if (!nloop) {
441
442 SetTag<false>(pMem);
443 incTag(1);
444 }
445 else
446 {
447 switch(tag.FLG) {
448 case GIF_FLG_PACKED:
449 {
450 GifTagLog("Packed Mode");
451 numregs = ((tag.NREG-1)&0xf) + 1;
452
453 // Note: curreg is *usually* zero here, but can be non-zero if a previous fragment was
454 // handled via this optimized copy code below.
455
456 const u32 listlen = (nloop * numregs) - curreg; // the total length of this packed register list (in QWC)
457 u32 len;
458
459 if(size < listlen)
460 {
461 len = size;
462
463 // We need to calculate both the number of full iterations of regs copied (nloops),
464 // and any remaining registers not copied by this fragment. A div/mod pair should
465 // hopefully be optimized by the compiler into a single x86 div. :)
466
467 const int nloops_copied = len / numregs;
468 const int regs_not_copied = len % numregs;
469
470 // Make sure to add regs_not_copied to curreg, to handle cases of multiple partial fragments.
471 // (example: 3 fragments each of only 2 regs, then curreg should be 0, 2, and then 4 after
472 // each call to GIFPath_Parse; with no change to NLOOP). Because of this we also need to
473 // check for cases where curreg wraps past an nloop.
474
475 nloop -= nloops_copied;
476 curreg += regs_not_copied;
477 if(curreg >= numregs)
478 {
479 --nloop;
480 curreg -= numregs;
481 }
482 }
483 else
484 {
485 len = listlen;
486 curreg = 0;
487 nloop = 0;
488 }
489 incTag(len);
490 }
491 break;
492 case GIF_FLG_REGLIST:
493 {
494 GifTagLog("Reglist Mode EOP %x", tag.EOP);
495
496 // In reglist mode, the GIF packs 2 registers into each QWC. The nloop however
497 // can be an odd number, in which case the upper half of the final QWC is ignored (skipped).
498
499 numregs = ((tag.NREG-1)&0xf) + 1;
500 const u32 total_reglen = (nloop * numregs) - curreg; // total 'expected length' of this packed register list (in registers)
501 const u32 total_listlen = (total_reglen+1) / 2; // total 'expected length' of the register list, in QWC! (+1 so to round it up)
502
503 u32 len;
504
505 if(size < total_listlen)
506 {
507 //Console.Warning("GIF path %d Fragmented REGLIST! Please report if you experience problems", pathidx + 1);
508
509 len = size;
510 const u32 reglen = len * 2;
511
512 const int nloops_copied = reglen / numregs;
513 const int regs_not_copied = reglen % numregs;
514
515 //DevCon.Warning("Hit it path %d", pathidx + 1);
516 curreg += regs_not_copied;
517 nloop -= nloops_copied;
518
519 if(curreg >= numregs)
520 {
521 --nloop;
522 curreg -= numregs;
523 }
524 }
525 else
526 {
527 len = total_listlen;
528 curreg = 0;
529 nloop = 0;
530 }
531
532 incTag(len);
533 //if(curreg != 0 || (len % numregs) > 0) DevCon.Warning("Oops c %x n %x m %x r %x", curreg, nloop, (len % numregs), numregs);
534 }
535 break;
536 case GIF_FLG_IMAGE:
537 case GIF_FLG_IMAGE2:
538 {
539 GifTagLog("IMAGE Mode");
540 int len = aMin(size, nloop);
541 incTag(len);
542 nloop -= len;
543 }
544 break;
545 }
546 }
547 if(pathidx == GIF_PATH_1)
548 {
549 if(size == 0 && (!tag.EOP || nloop > 0))
550 {
551 if(startSize < 0x400)
552 {
553 size = 0x400 - startSize;
554 startSize = 0x400;
555 pMem -= 0x4000;
556 }
557 else
558 {
559 // Note: The BIOS does an XGKICK on the VU1 and lets it DMA to the GS without an EOP
560 // (seemingly to loop forever), only to write an EOP later on. No other game is known to
561 // do anything of the sort.
562 // So lets just cap the DMA at 16k, and force it to "look" like it's terminated for now.
563 // (note: truly accurate emulation would mean having the VU1's XGKICK break execution,
564 // split time to EE and other processors, and then resume the kick's DMA later.
565 // ... yea, not happening for a while. ;) -- air
566
567 Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize);
568 nloop = 0;
569 const_cast<GIFTAG&>(tag).EOP = 1;
570 }
571 }
572 }
573 if (tag.EOP && !nloop) break;
574 }
575
576 size = (startSize - size);
577
578
579 return size;
580 }
581
582 __ri void MemCopy_WrappedDest( const u128* src, u128* destBase, uint& destStart, uint destSize, uint len )
583 {
584 uint endpos = destStart + len;
585 if( endpos < destSize )
586 {
587 memcpy_qwc(&destBase[destStart], src, len );
588 destStart += len;
589 }
590 else
591 {
592 uint firstcopylen = destSize - destStart;
593 memcpy_qwc(&destBase[destStart], src, firstcopylen );
594
595 destStart = endpos % destSize;
596 memcpy_qwc(destBase, src+firstcopylen, destStart );
597 }
598 }
599
600 __ri void MemCopy_WrappedSrc( const u128* srcBase, uint& srcStart, uint srcSize, u128* dest, uint len )
601 {
602 uint endpos = srcStart + len;
603 if( endpos < srcSize )
604 {
605 memcpy_qwc(dest, &srcBase[srcStart], len );
606 srcStart += len;
607 }
608 else
609 {
610 uint firstcopylen = srcSize - srcStart;
611 memcpy_qwc(dest, &srcBase[srcStart], firstcopylen );
612
613 srcStart = endpos % srcSize;
614 memcpy_qwc(dest+firstcopylen, srcBase, srcStart );
615 }
616 }
617
618 #define copyTag() do { \
619 _mm_store_ps( (float*)&RingBuffer.m_Ring[ringpos], Aligned ? _mm_load_ps((float*)pMem128) : _mm_loadu_ps((float*)pMem128)); \
620 ++pMem128; --size; \
621 ringpos = (ringpos+1)&RingBufferMask; \
622 } while(false)
623
624 // Parameters:
625 // size - max size of incoming data stream, in qwc (simd128). If the path is PATH1, and the
626 // path does not terminate (EOP) within the specified size, it is assumed that the path must
627 // loop around to the start of VU memory and continue processing.
628 template< GIF_PATH pathidx, bool Aligned >
629 __fi int GIFPath::CopyTag(const u128* pMem128, u32 size)
630 {
631 uint& ringpos = GetMTGS().m_packet_writepos;
632 const uint original_ringpos = ringpos;
633
634 u32 startSize = size; // Start Size
635
636 while (size > 0) {
637 if (!nloop) {
638
639 SetTag<Aligned>((u8*)pMem128);
640 copyTag();
641
642 GifTagLog("\tSetTag: %ls", tag.ToString().c_str());
643
644 if(nloop > 0)
645 {
646 switch(pathidx)
647 {
648 case GIF_PATH_1:
649 if(tag.FLG & 2)GSTransferStatus.PTH1 = IMAGE_MODE;
650 else GSTransferStatus.PTH1 = TRANSFER_MODE;
651 break;
652 case GIF_PATH_2:
653 if(tag.FLG & 2)GSTransferStatus.PTH2 = IMAGE_MODE;
654 else GSTransferStatus.PTH2 = TRANSFER_MODE;
655 break;
656 case GIF_PATH_3:
657 if(vif1Regs.mskpath3 == 1 && GSTransferStatus.PTH3 == STOPPED_MODE)
658 {
659 GSTransferStatus.PTH3 = IDLE_MODE;
660
661 }
662 else
663 {
664 if(tag.FLG & 2) GSTransferStatus.PTH3 = IMAGE_MODE;
665 else GSTransferStatus.PTH3 = TRANSFER_MODE;
666 }
667 break;
668 }
669
670 }
671 if(GSTransferStatus.PTH3 < PENDINGSTOP_MODE || pathidx != 2)
672 {
673 gifRegs.stat.OPH = true;
674 gifRegs.stat.APATH = pathidx + 1;
675 }
676
677 if(pathidx == GIF_PATH_3)
678 {
679 break;
680 }
681 }
682 else
683 {
684 switch(pathidx)
685 {
686 case GIF_PATH_1:
687 if(tag.FLG & 2)GSTransferStatus.PTH1 = IMAGE_MODE;
688 else GSTransferStatus.PTH1 = TRANSFER_MODE;
689 break;
690 case GIF_PATH_2:
691 if(tag.FLG & 2)GSTransferStatus.PTH2 = IMAGE_MODE;
692 else GSTransferStatus.PTH2 = TRANSFER_MODE;
693 break;
694 case GIF_PATH_3:
695 if(tag.FLG & 2) GSTransferStatus.PTH3 = IMAGE_MODE;
696 else GSTransferStatus.PTH3 = TRANSFER_MODE;
697
698 break;
699 }
700 gifRegs.stat.APATH = pathidx + 1;
701 gifRegs.stat.OPH = true;
702
703 switch(tag.FLG) {
704 case GIF_FLG_PACKED:
705 GifTagLog("Packed Mode EOP %x : %ls", tag.EOP, tag.DumpRegsToString().c_str());
706 PrepPackedRegs();
707
708 if(DetectE > 0)
709 {
710 do {
711 if (GetReg() == 0xe) {
712 gsHandler((u8*)pMem128);
713 }
714 copyTag();
715 } while(StepReg() && size > 0 && SIGNAL_IMR_Pending == false);
716 }
717 else
718 {
719 //DevCon.WriteLn(Color_Orange, "No E detected on Path%d: nloop=%x, numregs=%x, curreg=%x, size=%x", pathidx + 1, nloop, numregs, curreg, size);
720
721 // Note: curreg is *usually* zero here, but can be non-zero if a previous fragment was
722 // handled via this optimized copy code below.
723
724 const u32 listlen = (nloop * numregs) - curreg; // the total length of this packed register list (in QWC)
725 u32 len;
726
727 if(size < listlen)
728 {
729 len = size;
730
731 // We need to calculate both the number of full iterations of regs copied (nloops),
732 // and any remaining registers not copied by this fragment. A div/mod pair should
733 // hopefully be optimized by the compiler into a single x86 div. :)
734
735 const int nloops_copied = len / numregs;
736 const int regs_not_copied = len % numregs;
737
738 // Make sure to add regs_not_copied to curreg, to handle cases of multiple partial fragments.
739 // (example: 3 fragments each of only 2 regs, then curreg should be 0, 2, and then 4 after
740 // each call to GIFPath_Parse; with no change to NLOOP). Because of this we also need to
741 // check for cases where curreg wraps past an nloop.
742
743 nloop -= nloops_copied;
744 curreg += regs_not_copied;
745 if(curreg >= numregs)
746 {
747 --nloop;
748 curreg -= numregs;
749 }
750 }
751 else
752 {
753 len = listlen;
754 curreg = 0;
755 nloop = 0;
756 }
757
758 MemCopy_WrappedDest( pMem128, RingBuffer.m_Ring, ringpos, RingBufferSize, len );
759 pMem128 += len;
760 size -= len;
761 }
762 break;
763 case GIF_FLG_REGLIST:
764 {
765 GifTagLog("Reglist Mode EOP %x", tag.EOP);
766
767 // In reglist mode, the GIF packs 2 registers into each QWC. The nloop however
768 // can be an odd number, in which case the upper half of the final QWC is ignored (skipped).
769
770 numregs = ((tag.NREG-1)&0xf) + 1;
771 const u32 total_reglen = (nloop * numregs) - curreg; // total 'expected length' of this packed register list (in registers)
772 const u32 total_listlen = (total_reglen+1) / 2; // total 'expected length' of the register list, in QWC! (+1 so to round it up)
773
774 u32 len;
775
776 if(size < total_listlen)
777 {
778 //Console.Warning("GIF path %d Fragmented REGLIST! Please report if you experience problems", pathidx + 1);
779
780 len = size;
781 const u32 reglen = len * 2;
782
783 const int nloops_copied = reglen / numregs;
784 const int regs_not_copied = reglen % numregs;
785
786 //DevCon.Warning("Hit it path %d", pathidx + 1);
787 curreg += regs_not_copied;
788 nloop -= nloops_copied;
789
790 if(curreg >= numregs)
791 {
792 --nloop;
793 curreg -= numregs;
794 }
795 }
796 else
797 {
798 len = total_listlen;
799 curreg = 0;
800 nloop = 0;
801 }
802
803 MemCopy_WrappedDest( pMem128, RingBuffer.m_Ring, ringpos, RingBufferSize, len );
804 pMem128 += len;
805 size -= len;
806 }
807 break;
808 case GIF_FLG_IMAGE:
809 case GIF_FLG_IMAGE2:
810 {
811 GifTagLog("IMAGE Mode EOP %x", tag.EOP);
812 int len = aMin(size, nloop);
813
814 MemCopy_WrappedDest( pMem128, RingBuffer.m_Ring, ringpos, RingBufferSize, len );
815
816 pMem128 += len;
817 size -= len;
818 nloop -= len;
819 }
820 break;
821 }
822 }
823
824 if(pathidx == GIF_PATH_1)
825 {
826 if(size == 0 && (!tag.EOP || nloop > 0))
827 {
828 if(startSize < 0x3ff)
829 {
830 size = 0x3ff - startSize;
831 startSize = 0x3ff;
832 pMem128 -= 0x400;
833 }
834 else
835 {
836 // Note: The BIOS does an XGKICK on the VU1 and lets it DMA to the GS without an EOP
837 // (seemingly to loop forever), only to write an EOP later on. No other game is known to
838 // do anything of the sort.
839 // So lets just cap the DMA at 16k, and force it to "look" like it's terminated for now.
840 // (note: truly accurate emulation would mean having the VU1's XGKICK break execution,
841 // split time to EE and other processors, and then resume the kick's DMA later.
842 // ... yea, not happening for a while. ;) -- air
843
844 Console.Warning("GIFTAG error, size exceeded VU memory size %x", startSize);
845 nloop = 0;
846 const_cast<GIFTAG&>(tag).EOP = 1;
847
848 // Don't send the packet to the GS -- its incomplete and might cause the GS plugin
849 // to get confused and die. >_<
850
851 ringpos = original_ringpos;
852 }
853 }
854 }
855
856 if (tag.EOP && !nloop)
857 {
858 if (CSRreg.FINISH)
859 {
860 // IMPORTANT: only signal FINISH if ALL THREE paths are stopped (nloop is zero and EOP is set)
861 // FINISH is *not* a per-path register, and it seems to pretty clearly indicate that all active
862 // drawing *and* image transfer actions must be finished before the IRQ raises.
863
864 if(gifRegs.stat.P1Q || gifRegs.stat.P2Q || gifRegs.stat.P3Q)
865 {
866 //GH3 and possibly others have path data queued waiting for another path to finish! we need to check they are done too
867 //DevCon.Warning("Early FINISH signal! P1 %x P2 %x P3 %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.P3Q);
868 }
869 else if (!(GSIMR&0x200) && !s_gifPath.path[0].IsActive() && !s_gifPath.path[1].IsActive() && !s_gifPath.path[2].IsActive())
870 {
871 gsIrq();
872 }
873 }
874
875 // [TODO] : DMAC Arbitration rights should select the next queued GIF transfer here.
876
877 break;
878 }
879 if(SIGNAL_IMR_Pending == true)
880 {
881 //DevCon.Warning("Path %x", pathidx + 1);
882 break;
883 }
884 }
885
886 size = (startSize - size);
887
888 if (tag.EOP && nloop == 0) {
889
890 /*if(gifRegs.stat.DIR == 0)gifRegs.stat.OPH = false;
891 gifRegs.stat.APATH = GIF_APATH_IDLE;*/
892 switch(pathidx)
893 {
894 case GIF_PATH_1:
895 GSTransferStatus.PTH1 = STOPPED_MODE;
896 break;
897 case GIF_PATH_2:
898 GSTransferStatus.PTH2 = STOPPED_MODE;
899 break;
900 case GIF_PATH_3:
901 //For huge chunks we may have delay problems, so we need to stall it till the interrupt, else we get desync (Lemmings)
902 if(size > 8) GSTransferStatus.PTH3 = PENDINGSTOP_MODE;
903 else GSTransferStatus.PTH3 = STOPPED_MODE;
904 break;
905 }
906 }
907 else if( nloop == 0)
908 {
909 //Need to set GIF as WAITING, sometimes it can get stuck in a bit of a loop if other paths think it's still doing REGLIST for example.
910 //Do NOT use IDLE mode here, it will freak Path3 masking out if it gets used.
911 switch(pathidx)
912 {
913 case GIF_PATH_1:
914 GSTransferStatus.PTH1 = WAITING_MODE;
915 break;
916 case GIF_PATH_2:
917 GSTransferStatus.PTH2 = WAITING_MODE;
918 break;
919 case GIF_PATH_3:
920 if(GSTransferStatus.PTH3 < IDLE_MODE) GSTransferStatus.PTH3 = WAITING_MODE;
921 break;
922 }
923 }
924
925 if(pathidx == 2)
926 {
927 //if(nloop <= 16 && GSTransferStatus.PTH3 == IMAGE_MODE)GSTransferStatus.PTH3 = PENDINGIMAGE_MODE;
928 if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO
929 //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3);
930 gifch.madr += size * 16;
931 gifch.qwc -= size;
932 hwDmacSrcTadrInc(gifch);
933 }
934 }
935
936 return size;
937 }
938
939 // Parameters:
940 // size - max size of incoming data stream, in qwc (simd128). If the path is PATH1, and the
941 // path does not terminate (EOP) within the specified size, it is assumed that the path must
942 // loop around to the start of VU memory and continue processing.
943 __fi int GIFPath_CopyTag(GIF_PATH pathidx, const u128* pMem, u32 size)
944 {
945 switch( pathidx )
946 {
947 case GIF_PATH_1:
948 pxAssertMsg(!s_gifPath[GIF_PATH_2].IsActive(), "GIFpath conflict: Attempted to start PATH1 while PATH2 is already active.");
949 pxAssertMsg(!s_gifPath[GIF_PATH_3].IsActive() || (GSTransferStatus.PTH3 == IMAGE_MODE), "GIFpath conflict: Attempted to start PATH1 while PATH3 is already active.");
950 return s_gifPath[GIF_PATH_1].CopyTag<GIF_PATH_1,true>(pMem, size);
951 case GIF_PATH_2:
952 pxAssertMsg(!s_gifPath[GIF_PATH_1].IsActive(), "GIFpath conflict: Attempted to start PATH2 while PATH1 is already active.");
953 pxAssertMsg(!s_gifPath[GIF_PATH_3].IsActive() || (GSTransferStatus.PTH3 == IMAGE_MODE), "GIFpath conflict: Attempted to start PATH2 while PATH3 is already active.");
954 return s_gifPath[GIF_PATH_2].CopyTag<GIF_PATH_2,false>(pMem, size);
955 case GIF_PATH_3:
956 pxAssertMsg(!s_gifPath[GIF_PATH_1].IsActive(), "GIFpath conflict: Attempted to start PATH3 while PATH1 is already active.");
957 pxAssertMsg(!s_gifPath[GIF_PATH_2].IsActive(), "GIFpath conflict: Attempted to start PATH3 while PATH2 is already active.");
958 return s_gifPath[GIF_PATH_3].CopyTag<GIF_PATH_3,true>(pMem, size);
959
960 jNO_DEFAULT;
961 }
962
963 return 0; // unreachable
964 }
965
966 // Quick version for queuing PATH1 data.
967 // This version calculates the real length of the packet data only. It does not process
968 // IRQs or DMA status updates.
969 __fi int GIFPath_ParseTagQuick(GIF_PATH pathidx, const u8* pMem, u32 size)
970 {
971 int retSize = s_gifPath[pathidx].ParseTagQuick(pathidx, pMem, size);
972 return retSize;
973 }
974
975 // Clears all GIFpath data to zero.
976 void GIFPath_Reset()
977 {
978 for(uint i=0; i<3; ++i )
979 s_gifPath.path[i].Reset();
980 }
981
982 // This is a hackfix tool provided for "canceling" the contents of the GIFpath when
983 // invalid GIFdma states are encountered (typically needed for PATH3 only).
984 __fi void GIFPath_Clear( GIF_PATH pathidx )
985 {
986 memzero(s_gifPath.path[pathidx]);
987 s_gifPath.path[pathidx].Reset();
988
989 GSTransferStatus._u32 &= ~(0xf << (pathidx * 4));
990 GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
991 if( GSgifSoftReset == NULL ) return;
992 GetMTGS().SendSimplePacket( GS_RINGTYPE_SOFTRESET, (1<<pathidx), 0, 0 );
993 }

  ViewVC Help
Powered by ViewVC 1.1.22