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

Diff of /trunk/pcsx2/IPU/IPU.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 31 by william, Tue Sep 7 03:24:11 2010 UTC revision 62 by william, Tue Sep 7 11:08:22 2010 UTC
# Line 13  Line 13 
13   *  If not, see <http://www.gnu.org/licenses/>.   *  If not, see <http://www.gnu.org/licenses/>.
14   */   */
15    
 // ----------------------------------------------------------------------------  
 // PCH Warning!  This file, when compiled with PCH + Optimizations, fails in very curious  
 // and unexpected ways (most obvious is a freeze in the middle of the New Game video of  
 // Final Fantasy XII).  So make sure to force-disable PCH for this file at ALL times.  
 // ----------------------------------------------------------------------------  
   
16  #include "PrecompiledHeader.h"  #include "PrecompiledHeader.h"
17  #include "Common.h"  #include "Common.h"
18    
19  #include "IPU.h"  #include "IPU.h"
20    #include "IPUdma.h"
21  #include "yuv2rgb.h"  #include "yuv2rgb.h"
22    #include "mpeg2lib/Mpeg.h"
23    
24  #include "Vif.h"  #include "Vif.h"
25  #include "Gif.h"  #include "Gif.h"
26  #include "Vif_Dma.h"  #include "Vif_Dma.h"
27    #include <limits.h>
28    
29  // Zero cycle IRQ schedules aren't really good, but the IPU uses them.  static __fi void IPU_INT0_FROM()
30  // Better to throw the IRQ inline:  {
31            if (ipu0dma.qwc > 0 && ipu0dma.chcr.STR) ipu0Interrupt();
32  #define IPU_INT0_FROM()  ipu0Interrupt()  }
 //#define IPU_INT0_FROM()  CPU_INT( DMAC_FROM_IPU, 0 )  
   
 // IPU Inline'd IRQs : Calls the IPU interrupt handlers directly instead of  
 // feeding them through the EE's branch test. (see IPU.h for details)  
   
   
   
 static tIPU_DMA g_nDMATransfer(0);  
 static tIPU_cmd ipu_cmd;  
 static IPUStatus IPU1Status;  
33    
34  // FIXME - g_nIPU0Data and Pointer are not saved in the savestate, which breaks savestates for some  tIPU_cmd ipu_cmd;
 // FMVs at random (if they get saved during the half frame of a 30fps rate).  The fix is complicated  
 // since coroutine is such a pita.  (air)  
 int g_nIPU0Data = 0; // data left to transfer  
 u8* g_pIPU0Pointer = NULL;  
35    
36  void ReorderBitstream();  void ReorderBitstream();
37    
38  // the BP doesn't advance and returns -1 if there is no data to be read  // the BP doesn't advance and returns -1 if there is no data to be read
39  tIPU_BP g_BP;  __aligned16 tIPU_BP g_BP;
 static coroutine_t s_routine; // used for executing BDEC/IDEC  
 static int s_RoutineDone = 0;  
 static u32 s_tempstack[0x4000]; // 64k  
40    
41  void IPUWorker();  void IPUWorker();
42    
43  // Color conversion stuff, the memory layout is a total hack  // Color conversion stuff, the memory layout is a total hack
44  // convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t)  // convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t)
45  //char convert_data_buffer[sizeof(convert_rgb_t)];  //char convert_data_buffer[sizeof(convert_rgb_t)];
46  char convert_data_buffer[0x1C];  //char convert_data_buffer[0x1C];                                                       // unused?
47    //u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'};          // unused?
48    
49  // Quantization matrix  // Quantization matrix
50  static u8 niq[64];                      //non-intraquant matrix  static u16 vqclut[16];                          //clut conversion table
51  static u8 iq[64];                       //intraquant matrix  static u8 s_thresh[2];                          //thresholds for color conversions
 u16 vqclut[16];                         //clut conversion table  
 static u8 s_thresh[2];          //thresholds for color conversions  
52  int coded_block_pattern = 0;  int coded_block_pattern = 0;
 __aligned16 macroblock_8 mb8;  
 __aligned16 macroblock_16 mb16;  
 __aligned16 macroblock_rgb32 rgb32;  
 __aligned16 macroblock_rgb16 rgb16;  
53    
 u8 indx4[16*16/2];  
 bool mpeg2_inited = false;              //mpeg2_idct_init() must be called only once  
 u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'};  
 decoder_t g_decoder;                                            //static, only to place it in bss  
 decoder_t tempdec;  
54    
55  extern "C"  u8 indx4[16*16/2];
56  {  __aligned16 decoder_t decoder;
         extern u8 mpeg2_scan_norm[64];  
         extern u8 mpeg2_scan_alt[64];  
 }  
57    
58  __aligned16 u8 _readbits[80];   //local buffer (ring buffer)  __aligned16 u8 _readbits[80];   //local buffer (ring buffer)
59  u8* readbits = _readbits; // always can decrement by one 1qw  u8* readbits = _readbits;               // always can decrement by one 1qw
60    
61  __forceinline void IPUProcessInterrupt()  __fi void IPUProcessInterrupt()
62  {  {
63          if (ipuRegs->ctrl.BUSY && g_BP.IFC) IPUWorker();          if (ipuRegs.ctrl.BUSY && g_BP.IFC) IPUWorker();
 }  
   
 void init_g_decoder()  
 {  
         //other stuff  
         g_decoder.intra_quantizer_matrix = (u8*)iq;  
         g_decoder.non_intra_quantizer_matrix = (u8*)niq;  
         g_decoder.picture_structure = FRAME_PICTURE;    //default: progressive...my guess:P  
         g_decoder.mb8 = &mb8;  
         g_decoder.mb16 = &mb16;  
         g_decoder.rgb32 = &rgb32;  
         g_decoder.rgb16 = &rgb16;  
         g_decoder.stride = 16;  
 }  
   
 void mpeg2_init()  
 {  
         if (!mpeg2_inited)  
         {  
                 mpeg2_idct_init();  
                 yuv2rgb_init();  
                 memzero(mb8.Y);  
                 memzero(mb8.Cb);  
                 memzero(mb8.Cr);  
                 memzero(mb16.Y);  
                 memzero(mb16.Cb);  
                 memzero(mb16.Cr);  
                 mpeg2_inited = true;  
         }  
64  }  }
65    
66  /////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////
67  // Register accesses (run on EE thread)  // Register accesses (run on EE thread)
68  int ipuInit()  int ipuInit()
69  {  {
70          memzero(*ipuRegs);          memzero(ipuRegs);
71          memzero(g_BP);          memzero(g_BP);
72          init_g_decoder();          memzero(decoder);
73          g_nDMATransfer.reset();  
74          IPU1Status.InProgress = false;          decoder.picture_structure = FRAME_PICTURE;      //default: progressive...my guess:P
75          IPU1Status.DMAMode = DMA_MODE_NORMAL;  
         IPU1Status.DMAFinished = true;  
76          ipu_fifo.init();          ipu_fifo.init();
77          ipu_cmd.clear();          ipu_cmd.clear();
78            
79          return 0;          return 0;
80  }  }
81    
# Line 145  void ipuReset() Line 84  void ipuReset()
84          ipuInit();          ipuInit();
85  }  }
86    
 void ipuShutdown()  
 {  
 }  
   
87  void ReportIPU()  void ReportIPU()
88  {  {
89          Console.WriteLn(g_nDMATransfer.desc());          //Console.WriteLn(g_nDMATransfer.desc());
90          Console.WriteLn(ipu_fifo.in.desc());          Console.WriteLn(ipu_fifo.in.desc());
91          Console.WriteLn(ipu_fifo.out.desc());          Console.WriteLn(ipu_fifo.out.desc());
92          Console.WriteLn(g_BP.desc());          Console.WriteLn(g_BP.desc());
         Console.WriteLn("niq = 0x%x, iq = 0x%x.", niq, iq);  
93          Console.WriteLn("vqclut = 0x%x.", vqclut);          Console.WriteLn("vqclut = 0x%x.", vqclut);
94          Console.WriteLn("s_thresh = 0x%x.", s_thresh);          Console.WriteLn("s_thresh = 0x%x.", s_thresh);
95          Console.WriteLn("coded_block_pattern = 0x%x.", coded_block_pattern);          Console.WriteLn("coded_block_pattern = 0x%x.", coded_block_pattern);
96          Console.WriteLn("g_decoder = 0x%x.", g_decoder);          Console.WriteLn("g_decoder = 0x%x.", &decoder);
97          Console.WriteLn("mpeg2: scan_norm = 0x%x, alt = 0x%x.", mpeg2_scan_norm, mpeg2_scan_alt);          Console.WriteLn("mpeg2_scan = 0x%x.", &mpeg2_scan);
98          Console.WriteLn(ipu_cmd.desc());          Console.WriteLn(ipu_cmd.desc());
99          Console.WriteLn("_readbits = 0x%x. readbits - _readbits, which is also frozen, is 0x%x.",          Console.WriteLn("_readbits = 0x%x. readbits - _readbits, which is also frozen, is 0x%x.",
100                  _readbits, readbits - _readbits);                  _readbits, readbits - _readbits);
101          Console.Newline();          Console.Newline();
102  }  }
 // fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point.  
103    
104  void SaveStateBase::ipuFreeze()  void SaveStateBase::ipuFreeze()
105  {  {
106          // Get a report of the status of the ipu variables when saving and loading savestates.          // Get a report of the status of the ipu variables when saving and loading savestates.
107          //ReportIPU();          //ReportIPU();
108          FreezeTag("IPU");          FreezeTag("IPU");
   
         // old versions saved the IPU regs, but they're already saved as part of HW!  
         //FreezeMem(ipuRegs, sizeof(IPUregisters));  
   
         Freeze(g_nDMATransfer);  
109          Freeze(ipu_fifo);          Freeze(ipu_fifo);
110    
111          Freeze(g_BP);          Freeze(g_BP);
         Freeze(niq);  
         Freeze(iq);  
112          Freeze(vqclut);          Freeze(vqclut);
113          Freeze(s_thresh);          Freeze(s_thresh);
114          Freeze(coded_block_pattern);          Freeze(coded_block_pattern);
115          Freeze(g_decoder);          Freeze(decoder);
         Freeze(mpeg2_scan_norm);  
         Freeze(mpeg2_scan_alt);  
   
116          Freeze(ipu_cmd);          Freeze(ipu_cmd);
   
117          Freeze(_readbits);          Freeze(_readbits);
118    
119          int temp = readbits - _readbits;          int temp = readbits - _readbits;
# Line 200  void SaveStateBase::ipuFreeze() Line 122  void SaveStateBase::ipuFreeze()
122          if (IsLoading())          if (IsLoading())
123          {          {
124                  readbits = _readbits;                  readbits = _readbits;
                 init_g_decoder();  
                 mpeg2_init();  
125          }          }
126  }  }
127    
128  bool ipuCanFreeze()  void tIPU_CMD_IDEC::log() const
129  {  {
130          return (ipu_cmd.current == -1);          IPU_LOG("IDEC command.");
131    
132            if (FB) IPU_LOG(" Skip %d       bits.", FB);
133            IPU_LOG(" Quantizer step code=0x%X.", QSC);
134    
135            if (DTD == 0)
136                    IPU_LOG(" Does not decode DT.");
137            else
138                    IPU_LOG(" Decodes DT.");
139    
140            if (SGN == 0)
141                    IPU_LOG(" No bias.");
142            else
143                    IPU_LOG(" Bias=128.");
144    
145            if (DTE == 1) IPU_LOG(" Dither Enabled.");
146            if (OFM == 0)
147                    IPU_LOG(" Output format is RGB32.");
148            else
149                    IPU_LOG(" Output format is RGB16.");
150    
151            IPU_LOG("");
152  }  }
153    
154  __forceinline u32 ipuRead32(u32 mem)  void tIPU_CMD_BDEC::log(int s_bdec) const
155    {
156            IPU_LOG("BDEC(macroblock decode) command %x, num: 0x%x", cpuRegs.pc, s_bdec);
157            if (FB) IPU_LOG(" Skip 0x%X bits.", FB);
158    
159            if (MBI)
160                    IPU_LOG(" Intra MB.");
161            else
162                    IPU_LOG(" Non-intra MB.");
163    
164            if (DCR)
165                    IPU_LOG(" Resets DC prediction value.");
166            else
167                    IPU_LOG(" Doesn't reset DC prediction value.");
168    
169            if (DT)
170                    IPU_LOG(" Use field DCT.");
171            else
172                    IPU_LOG(" Use frame DCT.");
173    
174            IPU_LOG(" Quantizer step=0x%X", QSC);
175    }
176    
177    void tIPU_CMD_CSC::log_from_YCbCr() const
178    {
179            IPU_LOG("CSC(Colorspace conversion from YCbCr) command (%d).", MBC);
180            if (OFM)
181                    IPU_LOG("Output format is RGB16. ");
182            else
183                    IPU_LOG("Output format is RGB32. ");
184    
185            if (DTE) IPU_LOG("Dithering enabled.");
186    }
187    
188    void tIPU_CMD_CSC::log_from_RGB32() const
189    {
190            IPU_LOG("PACK (Colorspace conversion from RGB32) command.");
191    
192            if (OFM)
193                    IPU_LOG("Output format is RGB16. ");
194            else
195                    IPU_LOG("Output format is INDX4. ");
196    
197            if (DTE) IPU_LOG("Dithering enabled.");
198    
199            IPU_LOG("Number of macroblocks to be converted: %d", MBC);
200    }
201    
202    
203    __fi u32 ipuRead32(u32 mem)
204  {  {
205          // Note: It's assumed that mem's input value is always in the 0x10002000 page          // Note: It's assumed that mem's input value is always in the 0x10002000 page
206          // of memory (if not, it's probably bad code).          // of memory (if not, it's probably bad code).
# Line 223  __forceinline u32 ipuRead32(u32 mem) Line 213  __forceinline u32 ipuRead32(u32 mem)
213          switch (mem)          switch (mem)
214          {          {
215                  ipucase(IPU_CTRL): // IPU_CTRL                  ipucase(IPU_CTRL): // IPU_CTRL
216                          ipuRegs->ctrl.IFC = g_BP.IFC;                          ipuRegs.ctrl.IFC = g_BP.IFC;
217                          ipuRegs->ctrl.CBP = coded_block_pattern;                          ipuRegs.ctrl.CBP = coded_block_pattern;
218    
219                          if (!ipuRegs->ctrl.BUSY)                          if (!ipuRegs.ctrl.BUSY)
220                                  IPU_LOG("Ipu read32: IPU_CTRL=0x%08X %x", ipuRegs->ctrl._u32, cpuRegs.pc);                                  IPU_LOG("read32: IPU_CTRL=0x%08X", ipuRegs.ctrl._u32);
221    
222                          return ipuRegs->ctrl._u32;                  return ipuRegs.ctrl._u32;
223    
224                  ipucase(IPU_BP): // IPU_BP                  ipucase(IPU_BP): // IPU_BP
225                          ipuRegs->ipubp = g_BP.BP & 0x7f;                          ipuRegs.ipubp = g_BP.BP & 0x7f;
226                          ipuRegs->ipubp |= g_BP.IFC << 8;                          ipuRegs.ipubp |= g_BP.IFC << 8;
227                          ipuRegs->ipubp |= (g_BP.FP /*+ g_BP.bufferhasnew*/) << 16;                          ipuRegs.ipubp |= (g_BP.FP /*+ g_BP.bufferhasnew*/) << 16;
228    
229                            IPU_LOG("read32: IPU_BP=0x%08X", ipuRegs.ipubp);
230                    return ipuRegs.ipubp;
231    
                         IPU_LOG("Ipu read32: IPU_BP=0x%08X", ipuRegs->ipubp);  
                         return ipuRegs->ipubp;  
232                  default:                  default:
233                          IPU_LOG("Ipu read32: Addr=0x%x Value = 0x%08X", mem, *(u32*)(((u8*)ipuRegs) + mem));                          IPU_LOG("read32: Addr=0x%08X Value = 0x%08X", mem, psHu32(IPU_CMD + mem));
234          }          }
235    
236          return *(u32*)(((u8*)ipuRegs) + mem);          return psHu32(IPU_CMD + mem);
237  }  }
238    
239  __forceinline u64 ipuRead64(u32 mem)  __fi u64 ipuRead64(u32 mem)
240  {  {
241          // Note: It's assumed that mem's input value is always in the 0x10002000 page          // Note: It's assumed that mem's input value is always in the 0x10002000 page
242          // of memory (if not, it's probably bad code).          // of memory (if not, it's probably bad code).
# Line 258  __forceinline u64 ipuRead64(u32 mem) Line 249  __forceinline u64 ipuRead64(u32 mem)
249          switch (mem)          switch (mem)
250          {          {
251                  ipucase(IPU_CMD): // IPU_CMD                  ipucase(IPU_CMD): // IPU_CMD
252                          if (ipuRegs->cmd.DATA & 0xffffff)                          if (ipuRegs.cmd.DATA & 0xffffff)
253                                  IPU_LOG("Ipu read64: IPU_CMD=BUSY=%x, DATA=%08X", ipuRegs->cmd.BUSY ? 1 : 0, ipuRegs->cmd.DATA);                                  IPU_LOG("read64: IPU_CMD=BUSY=%x, DATA=%08X", ipuRegs.cmd.BUSY ? 1 : 0, ipuRegs.cmd.DATA);
254                          break;                          break;
255    
256                  ipucase(IPU_CTRL):                  ipucase(IPU_CTRL):
# Line 271  __forceinline u64 ipuRead64(u32 mem) Line 262  __forceinline u64 ipuRead64(u32 mem)
262                          break;                          break;
263    
264                  ipucase(IPU_TOP): // IPU_TOP                  ipucase(IPU_TOP): // IPU_TOP
265                          IPU_LOG("Ipu read64: IPU_TOP=%x,  bp = %d", ipuRegs->top, g_BP.BP);                          IPU_LOG("read64: IPU_TOP=%x,  bp = %d", ipuRegs.top, g_BP.BP);
266                          break;                          break;
267    
268                  default:                  default:
269                          IPU_LOG("Ipu read64: Unknown=%x", mem);                          IPU_LOG("read64: Unknown=%x", mem);
270                          break;                          break;
271          }          }
272          return *(u64*)(((u8*)ipuRegs) + mem);          return psHu64(IPU_CMD + mem);
273  }  }
274    
275  void ipuSoftReset()  void ipuSoftReset()
276  {  {
         mpeg2_init();  
277          ipu_fifo.clear();          ipu_fifo.clear();
278    
279          coded_block_pattern = 0;          coded_block_pattern = 0;
280    
281          ipuRegs->ctrl.reset();          ipuRegs.ctrl.reset();
282          ipuRegs->top = 0;          ipuRegs.top = 0;
283          ipu_cmd.clear();          ipu_cmd.clear();
284            ipuRegs.cmd.BUSY = 0;
285    
286          g_BP.BP = 0;          g_BP.BP = 0;
287          g_BP.FP = 0;          g_BP.FP = 0;
288          //g_BP.bufferhasnew = 0;          //g_BP.bufferhasnew = 0;
289  }  }
290    
291  __forceinline void ipuWrite32(u32 mem, u32 value)  __fi bool ipuWrite32(u32 mem, u32 value)
292  {  {
293          // Note: It's assumed that mem's input value is always in the 0x10002000 page          // Note: It's assumed that mem's input value is always in the 0x10002000 page
294          // of memory (if not, it's probably bad code).          // of memory (if not, it's probably bad code).
# Line 310  __forceinline void ipuWrite32(u32 mem, u Line 301  __forceinline void ipuWrite32(u32 mem, u
301          switch (mem)          switch (mem)
302          {          {
303                  ipucase(IPU_CMD): // IPU_CMD                  ipucase(IPU_CMD): // IPU_CMD
304                          IPU_LOG("Ipu write32: IPU_CMD=0x%08X", value);                          IPU_LOG("write32: IPU_CMD=0x%08X", value);
305                          IPUCMD_WRITE(value);                          IPUCMD_WRITE(value);
306                          break;                  return false;
307    
308                  ipucase(IPU_CTRL): // IPU_CTRL                  ipucase(IPU_CTRL): // IPU_CTRL
309              // CTRL = the first 16 bits of ctrl [0x8000ffff], + value for the next 16 bits,              // CTRL = the first 16 bits of ctrl [0x8000ffff], + value for the next 16 bits,
310              // minus the reserved bits. (18-19; 27-29) [0x47f30000]              // minus the reserved bits. (18-19; 27-29) [0x47f30000]
311                          ipuRegs->ctrl.write(value);                          ipuRegs.ctrl.write(value);
312                          if (ipuRegs->ctrl.IDP == 3)                          if (ipuRegs.ctrl.IDP == 3)
313                          {                          {
314                                  Console.WriteLn("IPU Invalid Intra DC Precision, switching to 9 bits");                                  Console.WriteLn("IPU Invalid Intra DC Precision, switching to 9 bits");
315                                  ipuRegs->ctrl.IDP = 1;                                  ipuRegs.ctrl.IDP = 1;
316                          }                          }
317    
318                          if (ipuRegs->ctrl.RST) ipuSoftReset(); // RESET                          if (ipuRegs.ctrl.RST) ipuSoftReset(); // RESET
319    
320                          IPU_LOG("Ipu write32: IPU_CTRL=0x%08X", value);                          IPU_LOG("write32: IPU_CTRL=0x%08X", value);
321                          break;                  return false;
   
                 default:  
                         IPU_LOG("Ipu write32: Unknown=%x", mem);  
                         *(u32*)((u8*)ipuRegs + mem) = value;  
                         break;  
322          }          }
323            return true;
324  }  }
325    
326  __forceinline void ipuWrite64(u32 mem, u64 value)  // returns FALSE when the writeback is handled, TRUE if the caller should do the
327    // writeback itself.
328    __fi bool ipuWrite64(u32 mem, u64 value)
329  {  {
330          // Note: It's assumed that mem's input value is always in the 0x10002000 page          // Note: It's assumed that mem's input value is always in the 0x10002000 page
331          // of memory (if not, it's probably bad code).          // of memory (if not, it's probably bad code).
# Line 349  __forceinline void ipuWrite64(u32 mem, u Line 338  __forceinline void ipuWrite64(u32 mem, u
338          switch (mem)          switch (mem)
339          {          {
340                  ipucase(IPU_CMD):                  ipucase(IPU_CMD):
341                          IPU_LOG("Ipu write64: IPU_CMD=0x%08X", value);                          IPU_LOG("write64: IPU_CMD=0x%08X", value);
342                          IPUCMD_WRITE((u32)value);                          IPUCMD_WRITE((u32)value);
343                          break;                  return false;
   
                 default:  
                         IPU_LOG("Ipu write64: Unknown=%x", mem);  
                         *(u64*)((u8*)ipuRegs + mem) = value;  
                         break;  
344          }          }
345    
346            return true;
347  }  }
348    
349    
# Line 371  static void ipuBCLR(u32 val) Line 357  static void ipuBCLR(u32 val)
357          g_BP.BP = val & 0x7F;          g_BP.BP = val & 0x7F;
358          g_BP.FP = 0;          g_BP.FP = 0;
359          //g_BP.bufferhasnew = 0;          //g_BP.bufferhasnew = 0;
360          ipuRegs->ctrl.BUSY = 0;          ipuRegs.ctrl.BUSY = 0;
361          ipuRegs->cmd.BUSY = 0;          ipuRegs.cmd.BUSY = 0;
362          memzero_ptr<80>(readbits);          memzero(_readbits);
363          IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X", g_BP.BP);          IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X", g_BP.BP);
364  }  }
365    
366  static BOOL ipuIDEC(u32 val)  static bool ipuIDEC(u32 val, bool resume)
367  {  {
368          tIPU_CMD_IDEC idec(val);          tIPU_CMD_IDEC idec(val);
369    
370          idec.log();          if (!resume)
371          g_BP.BP += idec.FB;//skip FB bits          {
372                    idec.log();
373                    g_BP.BP += idec.FB;//skip FB bits
374    
375          //from IPU_CTRL          //from IPU_CTRL
376          ipuRegs->ctrl.PCT = I_TYPE; //Intra DECoding;)                  ipuRegs.ctrl.PCT = I_TYPE; //Intra DECoding;)
377          g_decoder.coding_type = ipuRegs->ctrl.PCT;  
378          g_decoder.mpeg1 = ipuRegs->ctrl.MP1;                  decoder.coding_type                     = ipuRegs.ctrl.PCT;
379          g_decoder.q_scale_type  = ipuRegs->ctrl.QST;                  decoder.mpeg1                           = ipuRegs.ctrl.MP1;
380          g_decoder.intra_vlc_format = ipuRegs->ctrl.IVF;                  decoder.q_scale_type            = ipuRegs.ctrl.QST;
381          g_decoder.scan = ipuRegs->ctrl.AS ? mpeg2_scan_alt : mpeg2_scan_norm;                  decoder.intra_vlc_format        = ipuRegs.ctrl.IVF;
382          g_decoder.intra_dc_precision = ipuRegs->ctrl.IDP;                  decoder.scantype                        = ipuRegs.ctrl.AS;
383                    decoder.intra_dc_precision      = ipuRegs.ctrl.IDP;
384    
385          //from IDEC value          //from IDEC value
386          g_decoder.quantizer_scale = idec.QSC;                  decoder.quantizer_scale         = idec.QSC;
387          g_decoder.frame_pred_frame_dct = !idec.DTD;                  decoder.frame_pred_frame_dct= !idec.DTD;
388          g_decoder.sgn = idec.SGN;                  decoder.sgn = idec.SGN;
389          g_decoder.dte = idec.DTE;                  decoder.dte = idec.DTE;
390          g_decoder.ofm = idec.OFM;                  decoder.ofm = idec.OFM;
391    
392          //other stuff          //other stuff
393          g_decoder.dcr = 1; // resets DC prediction value                  decoder.dcr = 1; // resets DC prediction value
394            }
         s_routine = so_create(mpeg2sliceIDEC, &s_RoutineDone, s_tempstack, sizeof(s_tempstack));  
         pxAssert(s_routine != NULL);  
         so_call(s_routine);  
         if (s_RoutineDone) s_routine = NULL;  
395    
396          return s_RoutineDone;          return mpeg2sliceIDEC();
397  }  }
398    
399  static int s_bdec = 0;  static int s_bdec = 0;
400    
401  static __forceinline BOOL ipuBDEC(u32 val)  static __fi bool ipuBDEC(u32 val, bool resume)
402  {  {
403          tIPU_CMD_BDEC bdec(val);          tIPU_CMD_BDEC bdec(val);
404    
405          bdec.log(s_bdec);          if (!resume)
406          if (IsDebugBuild) s_bdec++;          {
407                    bdec.log(s_bdec);
408                    if (IsDebugBuild) s_bdec++;
409    
410          g_BP.BP += bdec.FB;//skip FB bits          g_BP.BP += bdec.FB;//skip FB bits
411          g_decoder.coding_type = I_TYPE;                  decoder.coding_type                     = I_TYPE;
412          g_decoder.mpeg1 = ipuRegs->ctrl.MP1;                  decoder.mpeg1                           = ipuRegs.ctrl.MP1;
413          g_decoder.q_scale_type  = ipuRegs->ctrl.QST;                  decoder.q_scale_type            = ipuRegs.ctrl.QST;
414          g_decoder.intra_vlc_format = ipuRegs->ctrl.IVF;                  decoder.intra_vlc_format        = ipuRegs.ctrl.IVF;
415          g_decoder.scan = ipuRegs->ctrl.AS ? mpeg2_scan_alt : mpeg2_scan_norm;                  decoder.scantype                        = ipuRegs.ctrl.AS;
416          g_decoder.intra_dc_precision = ipuRegs->ctrl.IDP;                  decoder.intra_dc_precision      = ipuRegs.ctrl.IDP;
417    
418          //from BDEC value          //from BDEC value
419          /* JayteeMaster: the quantizer (linear/non linear) depends on the q_scale_type */                  decoder.quantizer_scale         = decoder.q_scale_type ? non_linear_quantizer_scale [bdec.QSC] : bdec.QSC << 1;
420          g_decoder.quantizer_scale = g_decoder.q_scale_type ? non_linear_quantizer_scale [bdec.QSC] : bdec.QSC << 1;                  decoder.macroblock_modes        = bdec.DT ? DCT_TYPE_INTERLACED : 0;
421          g_decoder.macroblock_modes = bdec.DT ? DCT_TYPE_INTERLACED : 0;                  decoder.dcr                                     = bdec.DCR;
422          g_decoder.dcr = bdec.DCR;                  decoder.macroblock_modes        |= bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN;
         g_decoder.macroblock_modes |= bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN;  
423    
424          memzero(mb8);                  memzero_sse_a(decoder.mb8);
425          memzero(mb16);                  memzero_sse_a(decoder.mb16);
426            }
         s_routine = so_create(mpeg2_slice, &s_RoutineDone, s_tempstack, sizeof(s_tempstack));  
         pxAssert(s_routine != NULL);  
         so_call(s_routine);  
427    
428          if (s_RoutineDone) s_routine = NULL;          return mpeg2_slice();
         return s_RoutineDone;  
429  }  }
430    
431  static BOOL __fastcall ipuVDEC(u32 val)  static bool __fastcall ipuVDEC(u32 val)
432  {  {
433          switch (ipu_cmd.pos[0])          switch (ipu_cmd.pos[0])
434          {          {
435                  case 0:                  case 0:
436                          ipuRegs->cmd.DATA = 0;                          ipuRegs.cmd.DATA = 0;
437                          if (!getBits32((u8*)&g_decoder.bitstream_buf, 0)) return FALSE;                          if (!getBits32((u8*)&decoder.bitstream_buf, 0)) return false;
438    
439                          g_decoder.bitstream_bits = -16;                          decoder.bitstream_bits = -16;
440                          BigEndian(g_decoder.bitstream_buf, g_decoder.bitstream_buf);                          BigEndian(decoder.bitstream_buf, decoder.bitstream_buf);
441    
442                          switch ((val >> 26) & 3)                          switch ((val >> 26) & 3)
443                          {                          {
444                                  case 0://Macroblock Address Increment                                  case 0://Macroblock Address Increment
445                                          g_decoder.mpeg1 = ipuRegs->ctrl.MP1;                                          decoder.mpeg1 = ipuRegs.ctrl.MP1;
446                                          ipuRegs->cmd.DATA = get_macroblock_address_increment(&g_decoder);                                          ipuRegs.cmd.DATA = get_macroblock_address_increment();
447                                          break;                                          break;
448    
449                                  case 1://Macroblock Type        //known issues: no error detected                                  case 1://Macroblock Type
450                                          g_decoder.frame_pred_frame_dct = 1;//prevent DCT_TYPE_INTERLACED                                          decoder.frame_pred_frame_dct = 1;
451                                          g_decoder.coding_type = ipuRegs->ctrl.PCT;                                          decoder.coding_type = ipuRegs.ctrl.PCT;
452                                          ipuRegs->cmd.DATA = get_macroblock_modes(&g_decoder);                                          ipuRegs.cmd.DATA = get_macroblock_modes();
453                                          break;                                          break;
454    
455                                  case 2://Motion Code            //known issues: no error detected                                  case 2://Motion Code
456                                          ipuRegs->cmd.DATA = get_motion_delta(&g_decoder, 0);                                          ipuRegs.cmd.DATA = get_motion_delta(0);
457                                          break;                                          break;
458    
459                                  case 3://DMVector                                  case 3://DMVector
460                                          ipuRegs->cmd.DATA = get_dmv(&g_decoder);                                          ipuRegs.cmd.DATA = get_dmv();
461                                          break;                                          break;
462                          }                          }
463    
464                          g_BP.BP += (g_decoder.bitstream_bits + 16);                          g_BP.BP += (int)decoder.bitstream_bits + 16;
465    
466                          if ((int)g_BP.BP < 0)                          if ((int)g_BP.BP < 0)
467                          {                          {
# Line 486  static BOOL __fastcall ipuVDEC(u32 val) Line 469  static BOOL __fastcall ipuVDEC(u32 val)
469                                  ReorderBitstream();                                  ReorderBitstream();
470                          }                          }
471    
472                          FillInternalBuffer(&g_BP.BP, 1, 0);                          ipuRegs.cmd.DATA = (ipuRegs.cmd.DATA & 0xFFFF) | ((decoder.bitstream_bits + 16) << 16);
473                            ipuRegs.ctrl.ECD = (ipuRegs.cmd.DATA == 0);
                         ipuRegs->cmd.DATA = (ipuRegs->cmd.DATA & 0xFFFF) | ((g_decoder.bitstream_bits + 16) << 16);  
                         ipuRegs->ctrl.ECD = (ipuRegs->cmd.DATA == 0);  
474    
475                  case 1:                  case 1:
476                          if (!getBits32((u8*)&ipuRegs->top, 0))                          if (!getBits32((u8*)&ipuRegs.top, 0))
477                          {                          {
478                                  ipu_cmd.pos[0] = 1;                                  ipu_cmd.pos[0] = 1;
479                                  return FALSE;                                  return false;
480                          }                          }
481    
482                          BigEndian(ipuRegs->top, ipuRegs->top);                          BigEndian(ipuRegs.top, ipuRegs.top);
483    
484                          IPU_LOG("IPU VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d",                          IPU_LOG("VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d",
485                                  ipuRegs->cmd.DATA, ipuRegs->cmd.DATA >> 16, val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ?                                  ipuRegs.cmd.DATA, ipuRegs.cmd.DATA >> 16, val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ?
486                                  ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")), ipuRegs->ctrl.PCT);                                  ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")), ipuRegs.ctrl.PCT);
487                          return TRUE;                          return true;
488    
489                          jNO_DEFAULT                          jNO_DEFAULT
490          }          }
491    
492          return FALSE;          return false;
493  }  }
494    
495  static __forceinline BOOL ipuFDEC(u32 val)  static __fi bool ipuFDEC(u32 val)
496  {  {
497          if (!getBits32((u8*)&ipuRegs->cmd.DATA, 0)) return FALSE;          if (!getBits32((u8*)&ipuRegs.cmd.DATA, 0)) return false;
498    
499          BigEndian(ipuRegs->cmd.DATA, ipuRegs->cmd.DATA);          BigEndian(ipuRegs.cmd.DATA, ipuRegs.cmd.DATA);
500          ipuRegs->top = ipuRegs->cmd.DATA;          ipuRegs.top = ipuRegs.cmd.DATA;
501    
502          IPU_LOG("FDEC read: 0x%8.8x", ipuRegs->top);          IPU_LOG("FDEC read: 0x%08x", ipuRegs.top);
503    
504          return TRUE;          return true;
505  }  }
506    
507  static BOOL ipuSETIQ(u32 val)  static bool ipuSETIQ(u32 val)
508  {  {
509          int i;          int i;
510    
511          if ((val >> 27) & 1)          if ((val >> 27) & 1)
512          {          {
513                  ipu_cmd.pos[0] += getBits((u8*)niq + ipu_cmd.pos[0], 512 - 8 * ipu_cmd.pos[0], 1); // 8*8*8                  u8 (&niq)[64] = decoder.niq;
514    
515                  IPU_LOG("Read non-intra quantization matrix from IPU FIFO.");                  for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
516                    {
517                            if (!getBits64((u8*)niq + 8 * ipu_cmd.pos[0], 1)) return false;
518                    }
519    
520                    IPU_LOG("Read non-intra quantization matrix from FIFO.");
521                  for (i = 0; i < 8; i++)                  for (i = 0; i < 8; i++)
522                  {                  {
523                          IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",                          IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
# Line 541  static BOOL ipuSETIQ(u32 val) Line 527  static BOOL ipuSETIQ(u32 val)
527          }          }
528          else          else
529          {          {
530                  ipu_cmd.pos[0] += getBits((u8*)iq + 8 * ipu_cmd.pos[0], 512 - 8 * ipu_cmd.pos[0], 1);                  u8 (&iq)[64] = decoder.iq;
531    
532                  IPU_LOG("Read intra quantization matrix from IPU FIFO.");                  for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
533                    {
534                            if (!getBits64((u8*)iq + 8 * ipu_cmd.pos[0], 1)) return false;
535                    }
536    
537                    IPU_LOG("Read intra quantization matrix from FIFO.");
538                  for (i = 0; i < 8; i++)                  for (i = 0; i < 8; i++)
539                  {                  {
540                          IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",                          IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
# Line 552  static BOOL ipuSETIQ(u32 val) Line 543  static BOOL ipuSETIQ(u32 val)
543                  }                  }
544          }          }
545    
546          return ipu_cmd.pos[0] == 64;          return true;
547  }  }
548    
549  static BOOL ipuSETVQ(u32 val)  static bool ipuSETVQ(u32 val)
550  {  {
551          ipu_cmd.pos[0] += getBits((u8*)vqclut + ipu_cmd.pos[0], 256 - 8 * ipu_cmd.pos[0], 1); // 16*2*8          for(;ipu_cmd.pos[0] < 4; ipu_cmd.pos[0]++)
   
         if (ipu_cmd.pos[0] == 32)  
552          {          {
553                  IPU_LOG("IPU SETVQ command.\nRead VQCLUT table from IPU FIFO.");                  if (!getBits64(((u8*)vqclut) + 8 * ipu_cmd.pos[0], 1)) return false;
                 IPU_LOG(  
                     "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d "  
                     "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d"  
                     "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d "  
                     "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d",  
                     vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F,  
                     vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F,  
                     vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F,  
                     vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F,  
                     vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F,  
                     vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F,  
                     vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F,  
                     vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F,  
                     vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F,  
                     vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F,  
                     vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F,  
                     vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F,  
                     vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F,  
                     vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F,  
                     vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F,  
                     vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F);  
554          }          }
555    
556          return ipu_cmd.pos[0] == 32;          IPU_LOG("SETVQ command.\nRead VQCLUT table from FIFO.");
557            IPU_LOG(
558                "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d "
559                "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d"
560                "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d "
561                "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d",
562                vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F,
563                vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F,
564                vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F,
565                vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F,
566                vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F,
567                vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F,
568                vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F,
569                vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F,
570                vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F,
571                vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F,
572                vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F,
573                vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F,
574                vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F,
575                vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F,
576                vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F,
577                vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F);
578    
579            return true;
580  }  }
581    
582  // IPU Transfers are split into 8Qwords so we need to send ALL the data  // IPU Transfers are split into 8Qwords so we need to send ALL the data
583  static BOOL __fastcall ipuCSC(u32 val)  static bool __fastcall ipuCSC(u32 val)
584  {  {
585          tIPU_CMD_CSC csc(val);          tIPU_CMD_CSC csc(val);
586          csc.log_from_YCbCr();          csc.log_from_YCbCr();
587    
588          for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)          for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
589          {          {
590                    for(;ipu_cmd.pos[0] < 48; ipu_cmd.pos[0]++)
                 if (ipu_cmd.pos[0] < 3072 / 8)  
591                  {                  {
592                          ipu_cmd.pos[0] += getBits((u8*) & mb8 + ipu_cmd.pos[0], 3072 - 8 * ipu_cmd.pos[0], 1);                          if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
   
                         if (ipu_cmd.pos[0] < 3072 / 8) return FALSE;  
   
                         ipu_csc(&mb8, &rgb32, 0);  
                         if (csc.OFM) ipu_dither(&rgb32, &rgb16, csc.DTE);  
593                  }                  }
594    
595                    ipu_csc(decoder.mb8, decoder.rgb32, 0);
596                    if (csc.OFM) ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
597                    
598                  if (csc.OFM)                  if (csc.OFM)
599                  {                  {
600                          while (ipu_cmd.pos[1] < 32)                          while (ipu_cmd.pos[1] < 32)
601                          {                          {
602                                  ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);                                  ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
603    
604                                  if (ipu_cmd.pos[1] <= 0) return FALSE;                                  if (ipu_cmd.pos[1] <= 0) return false;
605                          }                          }
606                  }                  }
607                  else                  else
608                  {                  {
609                          while (ipu_cmd.pos[1] < 64)                          while (ipu_cmd.pos[1] < 64)
610                          {                          {
611                                  ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);                                  ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);
612    
613                                  if (ipu_cmd.pos[1] <= 0) return FALSE;                                  if (ipu_cmd.pos[1] <= 0) return false;
614                          }                          }
615                  }                  }
616    
# Line 630  static BOOL __fastcall ipuCSC(u32 val) Line 618  static BOOL __fastcall ipuCSC(u32 val)
618                  ipu_cmd.pos[1] = 0;                  ipu_cmd.pos[1] = 0;
619          }          }
620    
621          return TRUE;          return true;
622  }  }
623    
624  // Todo - Need to add the same stop and start code as CSC  // Todo - Need to add the same stop and start code as CSC
625  static BOOL ipuPACK(u32 val)  static bool ipuPACK(u32 val)
626  {  {
627          tIPU_CMD_CSC  csc(val);          tIPU_CMD_CSC  csc(val);
628          csc.log_from_RGB32();          csc.log_from_RGB32();
629    
630          for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)          for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
631          {          {
632                  if (ipu_cmd.pos[0] < 512)                  for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
633                  {                  {
634                          ipu_cmd.pos[0] += getBits((u8*) & mb8 + ipu_cmd.pos[0], 512 - 8 * ipu_cmd.pos[0], 1);                          if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
635                    }
                         if (ipu_cmd.pos[0] < 64) return FALSE;  
636    
637                          ipu_csc(&mb8, &rgb32, 0);                  ipu_csc(decoder.mb8, decoder.rgb32, 0);
638                          ipu_dither(&rgb32, &rgb16, csc.DTE);                  ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
639    
640                          if (csc.OFM) ipu_vq(&rgb16, indx4);                  if (csc.OFM) ipu_vq(decoder.rgb16, indx4);
                 }  
641    
642                  if (csc.OFM)                  if (csc.OFM)
643                  {                  {
644                          ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);                          ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
645    
646                          if (ipu_cmd.pos[1] < 32) return FALSE;                          if (ipu_cmd.pos[1] < 32) return false;
647                  }                  }
648                  else                  else
649                  {                  {
650                          ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*)indx4) + 4 * ipu_cmd.pos[1], 8 - ipu_cmd.pos[1]);                          ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*)indx4) + 4 * ipu_cmd.pos[1], 8 - ipu_cmd.pos[1]);
651    
652                          if (ipu_cmd.pos[1] < 8) return FALSE;                          if (ipu_cmd.pos[1] < 8) return false;
653                  }                  }
654    
655                  ipu_cmd.pos[0] = 0;                  ipu_cmd.pos[0] = 0;
# Line 677  static void ipuSETTH(u32 val) Line 663  static void ipuSETTH(u32 val)
663  {  {
664          s_thresh[0] = (val & 0xff);          s_thresh[0] = (val & 0xff);
665          s_thresh[1] = ((val >> 16) & 0xff);          s_thresh[1] = ((val >> 16) & 0xff);
666          IPU_LOG("IPU SETTH (Set threshold value)command %x.", val&0xff00ff);          IPU_LOG("SETTH (Set threshold value)command %x.", val&0xff00ff);
667  }  }
668    
669  ///////////////////////  // --------------------------------------------------------------------------------------
670  // IPU Worker Thread //  //  CORE Functions (referenced from MPEG library)
671  ///////////////////////  // --------------------------------------------------------------------------------------
672  __forceinline void IPU_INTERRUPT() //dma  __fi void ipu_csc(macroblock_8& mb8, macroblock_rgb32& rgb32, int sgn)
673  {  {
674          hwIntcIrq(INTC_IPU);          int i;
675  }          u8* p = (u8*)&rgb32;
   
 void IPUCMD_WRITE(u32 val)  
 {  
         // don't process anything if currently busy  
         if (ipuRegs->ctrl.BUSY) Console.WriteLn("IPU BUSY!"); // wait for thread  
676    
677          ipuRegs->ctrl.ECD = 0;          yuv2rgb();
         ipuRegs->ctrl.SCD = 0; //clear ECD/SCD  
         ipuRegs->cmd.DATA = val;  
         ipu_cmd.pos[0] = 0;  
678    
679          switch (ipuRegs->cmd.CMD)          if (s_thresh[0] > 0)
680          {          {
681                  case SCE_IPU_BCLR:                  for (i = 0; i < 16*16; i++, p += 4)
682                          ipuBCLR(val);                  {
683                          IPU_INTERRUPT(); //DMAC_TO_IPU                          if ((p[0] < s_thresh[0]) && (p[1] < s_thresh[0]) && (p[2] < s_thresh[0]))
684                          return;                                  *(u32*)p = 0;
685                            else if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
686                  case SCE_IPU_VDEC:                                  p[3] = 0x40;
687                    }
688                          g_BP.BP += val & 0x3F;          }
689            else if (s_thresh[1] > 0)
690                          // check if enough data in queue          {
691                          if (ipuVDEC(val)) return;                  for (i = 0; i < 16*16; i++, p += 4)
692                    {
693                          ipuRegs->cmd.BUSY = 0x80000000;                          if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
694                          ipuRegs->topbusy = 0x80000000;                                  p[3] = 0x40;
695                          break;                  }
696            }
697                  case SCE_IPU_FDEC:          if (sgn)
698                          IPU_LOG("IPU FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, FP %d, CHCR 0x%x, %x",          {
699                                  val & 0x3f, g_BP.IFC, (int)g_BP.BP, g_BP.FP, ipu1dma->chcr._u32, cpuRegs.pc);                  for (i = 0; i < 16*16; i++, p += 4)
700                          g_BP.BP += val & 0x3F;                  {
701                          if (ipuFDEC(val)) return;                          *(u32*)p ^= 0x808080;
702                          ipuRegs->cmd.BUSY = 0x80000000;                  }
                         ipuRegs->topbusy = 0x80000000;  
                         break;  
   
                 case SCE_IPU_SETTH:  
                         ipuSETTH(val);  
                         hwIntcIrq(INTC_IPU);  
                         return;  
   
                 case SCE_IPU_SETIQ:  
                         IPU_LOG("IPU SETIQ command.");  
                         if (val & 0x3f) IPU_LOG("Skip %d bits.", val & 0x3f);  
                         g_BP.BP += val & 0x3F;  
                         if (ipuSETIQ(ipuRegs->cmd.DATA)) return;  
                         break;  
   
                 case SCE_IPU_SETVQ:  
                         if (ipuSETVQ(ipuRegs->cmd.DATA)) return;  
                         break;  
   
                 case SCE_IPU_CSC:  
                         ipu_cmd.pos[1] = 0;  
                         ipu_cmd.index = 0;  
   
                         if (ipuCSC(ipuRegs->cmd.DATA))  
                         {  
                                 if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR)  IPU_INT0_FROM();  
                                 return;  
                         }  
                         break;  
   
                 case SCE_IPU_PACK:  
                         ipu_cmd.pos[1] = 0;  
                         ipu_cmd.index = 0;  
                         if (ipuPACK(ipuRegs->cmd.DATA)) return;  
                         break;  
   
                 case SCE_IPU_IDEC:  
                         if (ipuIDEC(val))  
                         {  
                                 // idec done, ipu0 done too  
                                 if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR) IPU_INT0_FROM();  
                                 return;  
                         }  
                         ipuRegs->topbusy = 0x80000000;  
                         // have to resort to the thread  
                         ipu_cmd.current = val >> 28;  
                         ipuRegs->ctrl.BUSY = 1;  
                         return;  
   
                 case SCE_IPU_BDEC:  
                         if (ipuBDEC(val))  
                         {  
                                 if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR) IPU_INT0_FROM();  
                                 if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         ipuRegs->topbusy = 0x80000000;  
                         ipu_cmd.current = val >> 28;  
                         ipuRegs->ctrl.BUSY = 1;  
                         return;  
703          }          }
   
         // have to resort to the thread  
         ipu_cmd.current = val >> 28;  
         ipuRegs->ctrl.BUSY = 1;  
         if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
704  }  }
705    
706  void IPUWorker()  __fi void ipu_dither(const macroblock_rgb32& rgb32, macroblock_rgb16& rgb16, int dte)
707  {  {
708          pxAssert(ipuRegs->ctrl.BUSY);          int i, j;
709            for (i = 0; i < 16; ++i)
         switch (ipu_cmd.current)  
710          {          {
711                  case SCE_IPU_VDEC:                  for (j = 0; j < 16; ++j)
712                          if (!ipuVDEC(ipuRegs->cmd.DATA))                  {
713                          {                          rgb16.c[i][j].r = rgb32.c[i][j].r >> 3;
714                                  if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);                          rgb16.c[i][j].g = rgb32.c[i][j].g >> 3;
715                                  return;                          rgb16.c[i][j].b = rgb32.c[i][j].b >> 3;
716                          }                          rgb16.c[i][j].a = rgb32.c[i][j].a == 0x40;
717                          ipuRegs->cmd.BUSY = 0;                  }
                         ipuRegs->topbusy = 0;  
                         break;  
   
                 case SCE_IPU_FDEC:  
                         if (!ipuFDEC(ipuRegs->cmd.DATA))  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         ipuRegs->cmd.BUSY = 0;  
                         ipuRegs->topbusy = 0;  
                         break;  
   
                 case SCE_IPU_SETIQ:  
                         if (!ipuSETIQ(ipuRegs->cmd.DATA))  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         break;  
   
                 case SCE_IPU_SETVQ:  
                         if (!ipuSETVQ(ipuRegs->cmd.DATA))  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         break;  
   
                 case SCE_IPU_CSC:  
                         if (!ipuCSC(ipuRegs->cmd.DATA))  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR)  IPU_INT0_FROM();  
                         break;  
   
                 case SCE_IPU_PACK:  
                         if (!ipuPACK(ipuRegs->cmd.DATA))  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
                         break;  
   
                 case SCE_IPU_IDEC:  
                         so_call(s_routine);  
                         if (!s_RoutineDone)  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
   
                         ipuRegs->ctrl.OFC = 0;  
                         ipuRegs->ctrl.BUSY = 0;  
                         ipuRegs->topbusy = 0;  
                         ipuRegs->cmd.BUSY = 0;  
                         ipu_cmd.current = 0xffffffff;  
   
                         // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it  
                         if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR) IPU_INT0_FROM();  
                         s_routine = NULL;  
                         break;  
   
                 case SCE_IPU_BDEC:  
                         so_call(s_routine);  
                         if (!s_RoutineDone)  
                         {  
                                 if(ipu1dma->chcr.STR == false) hwIntcIrq(INTC_IPU);  
                                 return;  
                         }  
   
                         ipuRegs->ctrl.BUSY = 0;  
                         ipuRegs->topbusy = 0;  
                         ipuRegs->cmd.BUSY = 0;  
                         ipu_cmd.current = 0xffffffff;  
   
                         if (ipu0dma->qwc > 0 && ipu0dma->chcr.STR) IPU_INT0_FROM();  
                         s_routine = NULL;  
                         if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) hwIntcIrq(INTC_IPU);  
                         return;  
   
                 default:  
                         Console.WriteLn("Unknown IPU command: %x", ipuRegs->cmd.CMD);  
                         break;  
718          }          }
719    }
720    
721          // success  __fi void ipu_vq(macroblock_rgb16& rgb16, u8* indx4)
722          ipuRegs->ctrl.BUSY = 0;  {
723          ipu_cmd.current = 0xffffffff;          Console.Error("IPU: VQ not implemented");
724    }
725    
726    __fi void ipu_copy(const macroblock_8& mb8, macroblock_16& mb16)
727    {
728            const u8        *s = (const u8*)&mb8;
729            s16     *d = (s16*)&mb16;
730            int i;
731            for (i = 0; i < 256; i++) *d++ = *s++;          //Y  bias       - 16
732            for (i = 0; i < 64; i++) *d++ = *s++;           //Cr bias       - 128
733            for (i = 0; i < 64; i++) *d++ = *s++;           //Cb bias       - 128
734  }  }
735    
736  /////////////////  
737  // Buffer reader  // --------------------------------------------------------------------------------------
738    //  Buffer reader
739    // --------------------------------------------------------------------------------------
740    
741  // move the readbits queue  // move the readbits queue
742  __forceinline void inc_readbits()  __fi void inc_readbits()
743  {  {
744          readbits += 16;          readbits += 16;
745          if (readbits >= _readbits + 64)          if (readbits >= _readbits + 64)
# Line 913  __forceinline void inc_readbits() Line 752  __forceinline void inc_readbits()
752  }  }
753    
754  // returns the pointer of readbits moved by 1 qword  // returns the pointer of readbits moved by 1 qword
755  __forceinline u8* next_readbits()  __fi u8* next_readbits()
756  {  {
757          return readbits + 16;          return readbits + 16;
758  }  }
# Line 945  u16 __fastcall FillInternalBuffer(u32 * Line 784  u16 __fastcall FillInternalBuffer(u32 *
784                  inc_readbits();                  inc_readbits();
785                  g_BP.FP = 1;                  g_BP.FP = 1;
786          }          }
787            
788          if ((g_BP.FP < 2) && (*(int*)pointer + size) >= 128)          if ((g_BP.FP < 2) && ((*(int*)pointer + size) >= 128))
789          {          {
790                  if (ipu_fifo.in.read(next_readbits())) g_BP.FP += 1;                  if (ipu_fifo.in.read(next_readbits())) g_BP.FP += 1;
791          }          }
# Line 969  u16 __fastcall FillInternalBuffer(u32 * Line 808  u16 __fastcall FillInternalBuffer(u32 *
808    
809  // whenever reading fractions of bytes. The low bits always come from the next byte  // whenever reading fractions of bytes. The low bits always come from the next byte
810  // while the high bits come from the current byte  // while the high bits come from the current byte
811  u8 __fastcall getBits32(u8 *address, u32 advance)  u8 __fastcall getBits128(u8 *address, u32 advance)
812  {  {
813          register u32 mask, shift = 0;          u64 mask2;
814            u128 mask;
815          u8* readpos;          u8* readpos;
816    
817          // Check if the current BP has exceeded or reached the limit of 128          // Check if the current BP has exceeded or reached the limit of 128
818          if (FillInternalBuffer(&g_BP.BP, 1, 32) < 32) return 0;          if (FillInternalBuffer(&g_BP.BP, 1, 128) < 128) return 0;
819    
820          readpos = readbits + (int)g_BP.BP / 8;          readpos = readbits + (int)g_BP.BP / 8;
821    
822          if (g_BP.BP & 7)          if (uint shift = (g_BP.BP & 7))
823          {          {
824                  shift = g_BP.BP & 7;                  mask2 = 0xff >> shift;
825                  mask = (0xff >> shift);                  mask.lo = mask2 | (mask2 << 8) | (mask2 << 16) | (mask2 << 24) | (mask2 << 32) | (mask2 << 40) | (mask2 << 48) | (mask2 << 56);
826                  mask = mask | (mask << 8) | (mask << 16) | (mask << 24);                  mask.hi = mask2 | (mask2 << 8) | (mask2 << 16) | (mask2 << 24) | (mask2 << 32) | (mask2 << 40) | (mask2 << 48) | (mask2 << 56);        
827    
828                    u128 notMask;
829                    u128 data = *(u128*)(readpos + 1);
830                    notMask.lo = ~mask.lo & data.lo;
831                    notMask.hi = ~mask.hi & data.hi;
832                    notMask.lo >>= 8 - shift;
833                    notMask.lo |= (notMask.hi & (ULLONG_MAX >> (64 - shift))) << (64 - shift);
834                    notMask.hi >>= 8 - shift;
835    
836                  *(u32*)address = ((~mask & *(u32*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u32*)readpos) << shift);                  mask.hi = (((*(u128*)readpos).hi & mask.hi) << shift) | (((*(u128*)readpos).lo & mask.lo) >> (64 - shift));
837                    mask.lo = ((*(u128*)readpos).lo & mask.lo) << shift;
838                    
839                    notMask.lo |= mask.lo;
840                    notMask.hi |= mask.hi;
841                    *(u128*)address = notMask;
842          }          }
843          else          else
844          {          {
845                  *(u32*)address = *(u32*)readpos;                  *(u128*)address = *(u128*)readpos;
846          }          }
847    
848          if (advance) g_BP.BP += 32;          if (advance) g_BP.BP += 128;
849    
850          return 1;          return 1;
851  }  }
852    
853  __forceinline u8 __fastcall getBits16(u8 *address, u32 advance)  // whenever reading fractions of bytes. The low bits always come from the next byte
854    // while the high bits come from the current byte
855    u8 __fastcall getBits64(u8 *address, u32 advance)
856  {  {
857          register u32 mask, shift = 0;          register u64 mask = 0;
858          u8* readpos;          u8* readpos;
859    
860          // Check if the current BP has exceeded or reached the limit of 128          // Check if the current BP has exceeded or reached the limit of 128
861          if (FillInternalBuffer(&g_BP.BP, 1, 16) < 16) return 0;          if (FillInternalBuffer(&g_BP.BP, 1, 64) < 64) return 0;
862    
863          readpos = readbits + (int)g_BP.BP / 8;          readpos = readbits + (int)g_BP.BP / 8;
864    
865          if (g_BP.BP & 7)          if (uint shift = (g_BP.BP & 7))
866          {          {
                 shift = g_BP.BP & 7;  
867                  mask = (0xff >> shift);                  mask = (0xff >> shift);
868                  mask = mask | (mask << 8);                  mask = mask | (mask << 8) | (mask << 16) | (mask << 24) | (mask << 32) | (mask << 40) | (mask << 48) | (mask << 56);
869    
870                  *(u16*)address = ((~mask & *(u16*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u16*)readpos) << shift);                  *(u64*)address = ((~mask & *(u64*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u64*)readpos) << shift);
871          }          }
872          else          else
873          {          {
874                  *(u16*)address = *(u16*)readpos;                  *(u64*)address = *(u64*)readpos;
875          }          }
876    
877          if (advance) g_BP.BP += 16;          if (advance) g_BP.BP += 64;
878    
879          return 1;          return 1;
880  }  }
881    
882  u8 __fastcall getBits8(u8 *address, u32 advance)  // whenever reading fractions of bytes. The low bits always come from the next byte
883    // while the high bits come from the current byte
884    u8 __fastcall getBits32(u8 *address, u32 advance)
885  {  {
886          register u32 mask, shift = 0;          u32 mask;
887          u8* readpos;          u8* readpos;
888    
889          // Check if the current BP has exceeded or reached the limit of 128          // Check if the current BP has exceeded or reached the limit of 128
890          if (FillInternalBuffer(&g_BP.BP, 1, 8) < 8)          if (FillInternalBuffer(&g_BP.BP, 1, 32) < 32) return 0;
                 return 0;  
891    
892          readpos = readbits + (int)g_BP.BP / 8;          readpos = readbits + (int)g_BP.BP / 8;
893    
894          if (g_BP.BP & 7)          if (uint shift = (g_BP.BP & 7))
895          {          {
                 shift = g_BP.BP & 7;  
896                  mask = (0xff >> shift);                  mask = (0xff >> shift);
897                    mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
898    
899                  *(u8*)address = (((~mask) & readpos[1]) >> (8 - shift)) | (((mask) & *readpos) << shift);                  *(u32*)address = ((~mask & *(u32*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u32*)readpos) << shift);
900          }          }
901          else          else
902          {          {
903                  *(u8*)address = *(u8*)readpos;                  *(u32*)address = *(u32*)readpos;
904          }          }
905    
906          if (advance) g_BP.BP += 8;          if (advance) g_BP.BP += 32;
907    
908          return 1;          return 1;
909  }  }
910    
911  int __fastcall getBits(u8 *address, u32 size, u32 advance)  __fi u8 __fastcall getBits16(u8 *address, u32 advance)
912  {  {
913          register u32 mask = 0, shift = 0, howmuch;          u32 mask;
914          u8* oldbits, *oldaddr = address;          u8* readpos;
         u32 pointer = 0, temp;  
915    
916          // Check if the current BP has exceeded or reached the limit of 128          // Check if the current BP has exceeded or reached the limit of 128
917          if (FillInternalBuffer(&g_BP.BP, 1, 8) < 8) return 0;          if (FillInternalBuffer(&g_BP.BP, 1, 16) < 16) return 0;
918    
919          oldbits = readbits;          readpos = readbits + (int)g_BP.BP / 8;
         // Backup the current BP in case of VDEC/FDEC  
         pointer = g_BP.BP;  
920    
921          if (pointer & 7)          if (uint shift = (g_BP.BP & 7))
922          {          {
923                  address--;                  mask = (0xff >> shift);
924                  while (size)                  mask = mask | (mask << 8);
                 {  
                         if (shift == 0)  
                         {  
                                 *++address = 0;  
                                 shift = 8;  
                         }  
   
                         temp = shift; // Lets not pass a register to min.  
                         howmuch = min(min(8 - (pointer & 7), 128 - pointer), min(size, temp));  
925    
926                          if (FillInternalBuffer(&pointer, advance, 8) < 8)                  *(u16*)address = ((~mask & *(u16*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u16*)readpos) << shift);
                         {  
                                 if (advance) g_BP.BP = pointer;  
                                 return address - oldaddr;  
927                          }                          }
   
                         mask = ((0xFF >> (pointer & 7)) << (8 - howmuch - (pointer & 7))) & 0xFF;  
                         mask &= readbits[((pointer) >> 3)];  
                         mask >>= 8 - howmuch - (pointer & 7);  
                         pointer += howmuch;  
                         size -= howmuch;  
                         shift -= howmuch;  
                         *address |= mask << shift;  
                 }  
                 ++address;  
         }  
928          else          else
929          {          {
930                  u8* readmem;                  *(u16*)address = *(u16*)readpos;
                 while (size)  
                 {  
                         if (FillInternalBuffer(&pointer, advance, 8) < 8)  
                         {  
                                 if (advance) g_BP.BP = pointer;  
                                 return address -oldaddr;  
                         }  
   
                         howmuch = min(128 - pointer, size);  
                         size -= howmuch;  
   
                         readmem = readbits + (pointer >> 3);  
                         pointer += howmuch;  
                         howmuch >>= 3;  
   
                         while (howmuch >= 4)  
                         {  
                                 *(u32*)address = *(u32*)readmem;  
                                 howmuch -= 4;  
                                 address += 4;  
                                 readmem += 4;  
                         }  
   
                         switch (howmuch)  
                         {  
                                 case 3:  
                                         address[2] = readmem[2];  
                                 case 2:  
                                         address[1] = readmem[1];  
                                 case 1:  
                                         address[0] = readmem[0];  
                                 case 0:  
                                         break;  
   
                                         jNO_DEFAULT  
931                          }                          }
932    
933                          address += howmuch;          if (advance) g_BP.BP += 16;
                 }  
         }  
   
         // If not advance then reset the Reading buffer value  
         if (advance)  
                 g_BP.BP = pointer;  
         else  
                 readbits = oldbits; // restore the last pointer  
934    
935          return address - oldaddr;          return 1;
936  }  }
937    
938  ///////////////////// CORE FUNCTIONS /////////////////  u8 __fastcall getBits8(u8 *address, u32 advance)
 void Skl_YUV_To_RGB32_MMX(u8 *RGB, const int Dst_BpS, const u8 *Y, const u8 *U, const u8 *V,  
                           const int Src_BpS, const int Width, const int Height);  
   
 void __fastcall ipu_csc(macroblock_8 *mb8, macroblock_rgb32 *rgb32, int sgn)  
939  {  {
940          int i;          u32 mask;
941          u8* p = (u8*)rgb32;          u8* readpos;
942    
943          yuv2rgb_sse2();          // Check if the current BP has exceeded or reached the limit of 128
944            if (FillInternalBuffer(&g_BP.BP, 1, 8) < 8)
945                    return 0;
946    
947          if (s_thresh[0] > 0)          readpos = readbits + (int)g_BP.BP / 8;
         {  
                 for (i = 0; i < 16*16; i++, p += 4)  
                 {  
                         if ((p[0] < s_thresh[0]) && (p[1] < s_thresh[0]) && (p[2] < s_thresh[0]))  
                                 *(u32*)p = 0;  
                         else if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))  
                                 p[3] = 0x40;  
                 }  
         }  
         else if (s_thresh[1] > 0)  
         {  
                 for (i = 0; i < 16*16; i++, p += 4)  
                 {  
                         if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))  
                                 p[3] = 0x40;  
                 }  
         }  
         if (sgn)  
         {  
                 for (i = 0; i < 16*16; i++, p += 4)  
                 {  
                         *(u32*)p ^= 0x808080;  
                 }  
         }  
 }  
948    
949  void __fastcall ipu_dither(const macroblock_rgb32* rgb32, macroblock_rgb16 *rgb16, int dte)          if (uint shift = (g_BP.BP & 7))
950  {                          {
951          int i, j;                  mask = (0xff >> shift);
952          for (i = 0; i < 16; ++i)                  *(u8*)address = (((~mask) & readpos[1]) >> (8 - shift)) | (((mask) & *readpos) << shift);
953                            }
954            else
955          {          {
956                  for (j = 0; j < 16; ++j)                  *(u8*)address = *(u8*)readpos;
                 {  
                         rgb16->c[i][j].r = rgb32->c[i][j].r >> 3;  
                         rgb16->c[i][j].g = rgb32->c[i][j].g >> 3;  
                         rgb16->c[i][j].b = rgb32->c[i][j].b >> 3;  
                         rgb16->c[i][j].a = rgb32->c[i][j].a == 0x40;  
957                  }                  }
         }  
 }  
   
 void __fastcall ipu_vq(macroblock_rgb16 *rgb16, u8* indx4)  
 {  
         Console.Error("IPU: VQ not implemented");  
 }  
   
 void __fastcall ipu_copy(const macroblock_8 *mb8, macroblock_16 *mb16)  
 {  
         const u8        *s = (const u8*)mb8;  
         s16     *d = (s16*)mb16;  
         int i;  
         for (i = 0; i < 256; i++) *d++ = *s++;          //Y  bias       - 16  
         for (i = 0; i < 64; i++) *d++ = *s++;           //Cr bias       - 128  
         for (i = 0; i < 64; i++) *d++ = *s++;           //Cb bias       - 128  
 }  
   
   
   
 static __forceinline bool ipuDmacPartialChain(tDMA_TAG tag)  
 {  
         switch (tag.ID)  
         {  
                 case TAG_REFE:  // refe  
                         ipu1dma->tadr += 16;  
                         return true;  
   
                 case TAG_END: // end  
                         ipu1dma->tadr = ipu1dma->madr;  
                         return true;  
         }  
         return false;  
 }  
958    
959  extern void gsInterrupt();          if (advance) g_BP.BP += 8;
 extern void vif1Interrupt();  
   
 static __forceinline void ipuDmacSrcChain()  
 {  
960    
961                  switch (IPU1Status.ChainMode)          return 1;
                 {  
                         case TAG_REFE: // refe  
                                 //if(IPU1Status.InProgress == false) ipu1dma->tadr += 16;  
                                 if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true;  
                                 break;  
                         case TAG_CNT: // cnt  
                                 // Set the taddr to the next tag  
                                 ipu1dma->tadr = ipu1dma->madr;  
                                 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;  
                                 break;  
   
                         case TAG_NEXT: // next  
                                 ipu1dma->tadr = IPU1Status.NextMem;  
                                 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;  
                                 break;  
   
                         case TAG_REF: // ref  
                                 //if(IPU1Status.InProgress == false)ipu1dma->tadr += 16;  
                                 //if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = false;  
                                 break;  
   
                         case TAG_END: // end  
                                 ipu1dma->tadr = ipu1dma->madr;  
                                 if(IPU1Status.DMAFinished == false) IPU1Status.DMAFinished = true;  
                                 break;  
                 }  
962  }  }
963    
964  static __forceinline bool WaitGSPaths()  // --------------------------------------------------------------------------------------
965    //  IPU Worker / Dispatcher
966    // --------------------------------------------------------------------------------------
967    void IPUCMD_WRITE(u32 val)
968  {  {
969          if(CHECK_IPUWAITHACK)          // don't process anything if currently busy
970          {          if (ipuRegs.ctrl.BUSY) Console.WriteLn("IPU BUSY!"); // wait for thread
                 if(GSTransferStatus.PTH3 < STOPPED_MODE)  
                 {  
                         //GIF_LOG("Flushing gif chcr %x tadr %x madr %x qwc %x", gif->chcr._u32, gif->tadr, gif->madr, gif->qwc);  
                         //DevCon.WriteLn("Waiting for GIF");  
                         return false;  
                 }  
   
                 if(GSTransferStatus.PTH2 != STOPPED_MODE)  
                 {  
                         //DevCon.WriteLn("Waiting for VIF");  
                         return false;  
                 }  
                 if(GSTransferStatus.PTH1 != STOPPED_MODE)  
                 {  
                         //DevCon.WriteLn("Waiting for VU");  
                         return false;  
                 }  
         }  
         return true;  
 }  
   
 static __forceinline int IPU1chain() {  
971    
972          int totalqwc = 0;          ipuRegs.ctrl.ECD = 0;
973            ipuRegs.ctrl.SCD = 0; //clear ECD/SCD
974            ipu_cmd.clear();
975            ipu_cmd.current = val;
976    
977          if (ipu1dma->qwc > 0 && IPU1Status.InProgress == true)          switch (val >> 28)
978          {          {
979                    case SCE_IPU_BCLR:
980                            ipuBCLR(val);
981                            hwIntcIrq(INTC_IPU); //DMAC_TO_IPU
982                            return;
983    
984                  int qwc = ipu1dma->qwc;                  case SCE_IPU_VDEC:
                 u32 *pMem;  
   
                 pMem = (u32*)dmaGetAddr(ipu1dma->madr, false);  
   
                 if (pMem == NULL)  
                 {  
                         Console.Error("ipu1dma NULL!"); return totalqwc;  
                 }  
   
                 //Write our data to the fifo  
                 qwc = ipu_fifo.in.write(pMem, qwc);  
                 ipu1dma->madr += qwc << 4;  
                 ipu1dma->qwc -= qwc;  
                 totalqwc += qwc;  
         }  
         if( ipu1dma->qwc == 0)  
         {  
                 //Update TADR etc  
                 if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain();  
                 //If the transfer has finished or we have room in the FIFO, schedule to the interrupt code.  
                   
                 //No data left  
                 IPU1Status.InProgress = false;  
         } //If we still have data the commands should pull this across when need be.  
985    
986          return totalqwc;                          g_BP.BP += val & 0x3F;
 }  
987    
988  //static __forceinline bool WaitGSPaths()                          // check if enough data in queue
989  //{                          if (ipuVDEC(val)) return;
 //      //Wait for all GS paths to be clear  
 //      if (GSTransferStatus._u32 != 0x2a)  
 //      {  
 //              if(GSTransferStatus.PTH3 != STOPPED_MODE && vif1Regs->mskpath3) return true;  
 //              IPU_LOG("Waiting for GS transfers to finish %x", GSTransferStatus._u32);  
 //              IPU_INT_TO(4);  
 //              return false;  
 //      }  
 //      return true;  
 //}  
990    
991                            ipuRegs.cmd.BUSY = 0x80000000;
992                            ipuRegs.topbusy = 0x80000000;
993                            break;
994    
995                    case SCE_IPU_FDEC:
996                            IPU_LOG("FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, FP %d, CHCR 0x%x",
997                                    val & 0x3f, g_BP.IFC, (int)g_BP.BP, g_BP.FP, ipu1dma.chcr._u32);
998                            g_BP.BP += val & 0x3F;
999                            if (ipuFDEC(val)) return;
1000                            ipuRegs.cmd.BUSY = 0x80000000;
1001                            ipuRegs.topbusy = 0x80000000;
1002                            break;
1003    
1004  int IPU1dma()                  case SCE_IPU_SETTH:
1005  {                          ipuSETTH(val);
1006          int ipu1cycles = 0;                          hwIntcIrq(INTC_IPU);
1007          int totalqwc = 0;                          return;
1008    
1009          //We need to make sure GIF has flushed before sending IPU data, it seems to REALLY screw FFX videos                  case SCE_IPU_SETIQ:
1010      //if(!WaitGSPaths()) return totalqwc;                          IPU_LOG("SETIQ command.");
1011                            if (val & 0x3f) IPU_LOG("Skip %d bits.", val & 0x3f);
1012                            g_BP.BP += val & 0x3F;
1013                            if (ipuSETIQ(val)) return;
1014                            break;
1015    
1016          if(ipu1dma->chcr.STR == false || IPU1Status.DMAMode == 2)                  case SCE_IPU_SETVQ:
1017          {                          if (ipuSETVQ(val)) return;
1018                  //We MUST stop the IPU from trying to fill the FIFO with more data if the DMA has been suspended                          break;
                 //if we don't, we risk causing the data to go out of sync with the fifo and we end up losing some!  
                 //This is true for Dragons Quest 8 and probably others which suspend the DMA.  
                 DevCon.Warning("IPU1 running when IPU1 DMA disabled! CHCR %x QWC %x", ipu1dma->chcr._u32, ipu1dma->qwc);  
                 return 0;  
         }  
1019    
1020          IPU_LOG("IPU1 DMA Called QWC %x Finished %d In Progress %d tadr %x", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma->tadr);                  case SCE_IPU_CSC:
1021                            ipu_cmd.pos[1] = 0;
1022                            ipu_cmd.index = 0;
1023    
1024          switch(IPU1Status.DMAMode)                          if (ipuCSC(val))
         {  
                 case DMA_MODE_NORMAL:  
1025                          {                          {
1026                                  if(!WaitGSPaths())                                  IPU_INT0_FROM();
1027                                  { // legacy WaitGSPaths() for now                                  return;
                                         IPU_INT_TO(4); //Give it a short wait.  
                                         return totalqwc;  
                                 }  
                                 IPU_LOG("Processing Normal QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);  
                                 if(IPU1Status.InProgress == true) totalqwc += IPU1chain();  
1028                          }                          }
1029                          break;                          break;
1030    
1031                  case DMA_MODE_CHAIN:                  case SCE_IPU_PACK:
1032                          {                          ipu_cmd.pos[1] = 0;
1033                                  if(IPU1Status.InProgress == true) //No transfer is ready to go so we need to set one up                          ipu_cmd.index = 0;
1034                                  {                          if (ipuPACK(val)) return;
1035                                          if(!WaitGSPaths())                          break;
                                         { // legacy WaitGSPaths() for now  
                                                 IPU_INT_TO(4); //Give it a short wait.  
                                                 return totalqwc;  
                                         }  
                                         IPU_LOG("Processing Chain QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);  
                                         totalqwc += IPU1chain();  
                                         //Set the TADR forward  
                                 }  
   
   
                                 if(IPU1Status.InProgress == false && IPU1Status.DMAFinished == false) //No transfer is ready to go so we need to set one up  
                                 {  
                                         tDMA_TAG* ptag = dmaGetAddr(ipu1dma->tadr, false);  //Set memory pointer to TADR  
   
                                         if (!ipu1dma->transfer("IPU1", ptag))  
                                         {  
                                                 return totalqwc;  
                                         }  
   
                                         ipu1cycles += 1; // Add 1 cycles from the QW read for the tag  
                                         IPU1Status.ChainMode = ptag->ID;  
   
                                         if(ipu1dma->chcr.TTE) DevCon.Warning("TTE?");  
   
                                         switch (IPU1Status.ChainMode)  
                                         {  
                                                 case TAG_REFE: // refe  
                                                         // do not change tadr  
                                                         //ipu1dma->tadr += 16;  
                                                         ipu1dma->tadr += 16;  
                                                         ipu1dma->madr = ptag[1]._u32;  
                                                         IPU_LOG("Tag should end on %x", ipu1dma->tadr);  
   
                                                         break;  
   
                                                 case TAG_CNT: // cnt  
                                                         ipu1dma->madr = ipu1dma->tadr + 16;  
                                                         IPU_LOG("Tag should end on %x", ipu1dma->madr + ipu1dma->qwc * 16);  
                                                         //ipu1dma->tadr = ipu1dma->madr + (ipu1dma->qwc * 16);  
                                                         // Set the taddr to the next tag  
                                                         //IPU1Status.DMAFinished = false;  
                                                         break;  
   
                                                 case TAG_NEXT: // next  
                                                         ipu1dma->madr = ipu1dma->tadr + 16;  
                                                         IPU1Status.NextMem = ptag[1]._u32;  
                                                         IPU_LOG("Tag should end on %x", IPU1Status.NextMem);  
                                                         //IPU1Status.DMAFinished = false;  
                                                         break;  
   
                                                 case TAG_REF: // ref  
                                                         ipu1dma->madr = ptag[1]._u32;  
                                                         ipu1dma->tadr += 16;  
                                                         IPU_LOG("Tag should end on %x", ipu1dma->tadr);  
                                                         //IPU1Status.DMAFinished = false;  
                                                         break;  
   
                                                 case TAG_END: // end  
                                                         // do not change tadr  
                                                         ipu1dma->madr = ipu1dma->tadr + 16;  
                                                         ipu1dma->tadr += 16;  
                                                         IPU_LOG("Tag should end on %x", ipu1dma->madr + ipu1dma->qwc * 16);  
   
                                                         break;  
   
                                                 default:  
                                                         Console.Error("IPU ERROR: different transfer mode!, Please report to PCSX2 Team");  
                                                         break;  
                                         }  
   
                                         //if(ipu1dma->qwc == 0) Console.Warning("Blank QWC!");  
                                         if(ipu1dma->qwc > 0) IPU1Status.InProgress = true;  
                                         IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x",  
                                                         ptag[1]._u32, ptag[0]._u32, ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC);  
   
                                         if (ipu1dma->chcr.TIE && ptag->IRQ) //Tag Interrupt is set, so schedule the end/interrupt  
                                                 IPU1Status.DMAFinished = true;  
1036    
1037                    case SCE_IPU_IDEC:
1038                            if (ipuIDEC(val, false))
1039                            {
1040                                    // idec done, ipu0 done too
1041                                    IPU_INT0_FROM();
1042                                    return;
1043                            }
1044    
1045                                          if(!WaitGSPaths() && ipu1dma->qwc > 0)                          ipuRegs.topbusy = 0x80000000;
1046                                          { // legacy WaitGSPaths() for now                          break;
                                                 IPU_INT_TO(4); //Give it a short wait.  
                                                 return totalqwc;  
                                         }  
                                         IPU_LOG("Processing Start Chain QWC left %x Finished %d In Progress %d", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress);  
                                         totalqwc += IPU1chain();  
                                         //Set the TADR forward  
                                 }  
1047    
1048                    case SCE_IPU_BDEC:
1049                            if (ipuBDEC(val, false))
1050                            {
1051                                    IPU_INT0_FROM();
1052                                    if (ipuRegs.ctrl.SCD || ipuRegs.ctrl.ECD) hwIntcIrq(INTC_IPU);
1053                                    return;
1054                            }
1055                            else
1056                            {
1057                                    ipuRegs.topbusy = 0x80000000;
1058                          }                          }
1059                          break;                          break;
1060          }          }
1061    
1062          //Do this here to prevent double settings on Chain DMA's          // have to resort to the thread
1063          if(totalqwc > 0 || ipu1dma->qwc == 0)          ipuRegs.ctrl.BUSY = 1;
1064          {          if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
                 IPU_INT_TO(totalqwc * BIAS);  
                 if(ipuRegs->ctrl.BUSY && g_BP.IFC) IPUWorker();  
         }  
         else  
         {  
                 IPU_LOG("Here");  
                 cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048);  
         }  
   
         IPU_LOG("Completed Call IPU1 DMA QWC Remaining %x Finished %d In Progress %d tadr %x", ipu1dma->qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1dma->tadr);  
         return totalqwc;  
1065  }  }
1066    
1067  int IPU0dma()  void IPUWorker()
1068  {  {
1069          int readsize;          pxAssert(ipuRegs.ctrl.BUSY);
         static int totalsize = 0;  
         tDMA_TAG* pMem;  
   
         if ((!(ipu0dma->chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0dma->qwc == 0))  
                 return 0;  
   
         pxAssert(!(ipu0dma->chcr.TTE));  
   
         IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc  = %lx",  
                 ipu0dma->chcr._u32, ipu0dma->madr, ipu0dma->qwc);  
   
         pxAssert(ipu0dma->chcr.MOD == NORMAL_MODE);  
   
         pMem = dmaGetAddr(ipu0dma->madr, true);  
   
         readsize = min(ipu0dma->qwc, (u16)ipuRegs->ctrl.OFC);  
         totalsize+=readsize;  
         ipu_fifo.out.read(pMem, readsize);  
   
         ipu0dma->madr += readsize << 4;  
         ipu0dma->qwc -= readsize; // note: qwc is u16  
1070    
1071          if (ipu0dma->qwc == 0)          switch (ipu_cmd.CMD)
1072          {          {
1073                  if (dmacRegs->ctrl.STS == STS_fromIPU)   // STS == fromIPU                  case SCE_IPU_VDEC:
1074                  {                          if (!ipuVDEC(ipu_cmd.current))
                         dmacRegs->stadr.ADDR = ipu0dma->madr;  
                         switch (dmacRegs->ctrl.STD)  
1075                          {                          {
1076                                  case NO_STD:                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1077                                          break;                                  return;
                                 case STD_GIF: // GIF  
                                         Console.Warning("GIFSTALL");  
                                         g_nDMATransfer.GIFSTALL = true;  
                                         break;  
                                 case STD_VIF1: // VIF  
                                         Console.Warning("VIFSTALL");  
                                         g_nDMATransfer.VIFSTALL = true;  
                                         break;  
                                 case STD_SIF1:  
                                         Console.Warning("SIFSTALL");  
                                         g_nDMATransfer.SIFSTALL = true;  
                                         break;  
1078                          }                          }
1079                  }                          ipuRegs.cmd.BUSY = 0;
1080                  //Fixme ( voodoocycles ):                          ipuRegs.topbusy = 0;
1081                  //This was IPU_INT_FROM(readsize*BIAS );                          break;
                 //This broke vids in Digital Devil Saga  
                 //Note that interrupting based on totalsize is just guessing..  
                 IPU_INT_FROM( readsize * BIAS );  
                 totalsize = 0;  
         }  
   
         return readsize;  
 }  
   
 __forceinline void dmaIPU0() // fromIPU  
 {  
         if (ipu0dma->pad != 0)  
         {  
                 // Note: pad is the padding right above qwc, so we're testing whether qwc  
                 // has overflowed into pad.  
             DevCon.Warning(L"IPU0dma's upper 16 bits set to %x\n", ipu0dma->pad);  
                 ipu0dma->qwc = ipu0dma->pad = 0;  
                 //If we are going to clear down IPU0, we should end it too. Going to test this scenario on the PS2 mind - Refraction  
                 ipu0dma->chcr.STR = false;  
                 hwDmacIrq(DMAC_FROM_IPU);  
         }  
         if (ipuRegs->ctrl.BUSY) IPUWorker();  
 }  
   
 __forceinline void dmaIPU1() // toIPU  
 {  
         IPU_LOG("IPU1DMAStart QWC %x, MADR %x, CHCR %x, TADR %x", ipu1dma->qwc, ipu1dma->madr, ipu1dma->chcr._u32, ipu1dma->tadr);  
   
         if (ipu1dma->pad != 0)  
         {  
                 // Note: pad is the padding right above qwc, so we're testing whether qwc  
                 // has overflowed into pad.  
             DevCon.Warning(L"IPU1dma's upper 16 bits set to %x\n", ipu1dma->pad);  
                 ipu1dma->qwc = ipu1dma->pad = 0;  
                 // If we are going to clear down IPU1, we should end it too.  
                 // Going to test this scenario on the PS2 mind - Refraction  
                 ipu1dma->chcr.STR = false;  
                 hwDmacIrq(DMAC_TO_IPU);  
         }  
   
         if (ipu1dma->chcr.MOD == CHAIN_MODE)  //Chain Mode  
         {  
                 IPU_LOG("Setting up IPU1 Chain mode");  
                 if(ipu1dma->qwc == 0)  
                 {  
                         IPU1Status.InProgress = false;  
                         IPU1Status.DMAFinished = false;  
                 }  
                 else  
                 {   //Attempting to continue a previous chain  
                         IPU_LOG("Resuming DMA TAG %x", (ipu1dma->chcr.TAG >> 12));  
                         //We MUST check the CHCR for the tag it last knew, it can be manipulated!  
                         IPU1Status.ChainMode = (ipu1dma->chcr.TAG >> 12) & 0x7;  
                         IPU1Status.InProgress = true;  
                         IPU1Status.DMAFinished = ((ipu1dma->chcr.TAG >> 15) && ipu1dma->chcr.TIE) ? true : false;  
                 }  
1082    
1083                  IPU1Status.DMAMode = DMA_MODE_CHAIN;                  case SCE_IPU_FDEC:
1084                  IPU1dma();                          if (!ipuFDEC(ipu_cmd.current))
1085                  //if (ipuRegs->ctrl.BUSY) IPUWorker();                          {
1086          }                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1087          else //Normal Mode                                  return;
1088          {                          }
1089                  if(ipu1dma->qwc == 0)                          ipuRegs.cmd.BUSY = 0;
1090                  {                          ipuRegs.topbusy = 0;
1091                          ipu1dma->chcr.STR = false;                          break;
                                 // Hack to force stop IPU  
                                 ipuRegs->cmd.BUSY = 0;  
                                 ipuRegs->ctrl.BUSY = 0;  
                                 ipuRegs->topbusy = 0;  
                                 //  
                         hwDmacIrq(DMAC_TO_IPU);  
                         Console.Warning("IPU1 Normal error!");  
                 }  
                 else  
                 {  
                         IPU_LOG("Setting up IPU1 Normal mode");  
                         IPU1Status.InProgress = true;  
                         IPU1Status.DMAFinished = true;  
                         IPU1Status.DMAMode = DMA_MODE_NORMAL;  
                         IPU1dma();  
                         //if (ipuRegs->ctrl.BUSY) IPUWorker();  
                 }  
         }  
 }  
1092    
1093  extern void GIFdma();                  case SCE_IPU_SETIQ:
1094                            if (!ipuSETIQ(ipu_cmd.current))
1095                            {
1096                                    if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1097                                    return;
1098                            }
1099                            break;
1100    
1101  void ipu0Interrupt()                  case SCE_IPU_SETVQ:
1102  {                          if (!ipuSETVQ(ipu_cmd.current))
1103          IPU_LOG("ipu0Interrupt: %x", cpuRegs.cycle);                          {
1104                                    if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1105                                    return;
1106                            }
1107                            break;
1108    
1109          if (g_nDMATransfer.FIREINT0)                  case SCE_IPU_CSC:
1110          {                          if (!ipuCSC(ipu_cmd.current))
1111                  g_nDMATransfer.FIREINT0 = false;                          {
1112                  hwIntcIrq(INTC_IPU);                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1113          }                                  return;
1114                            }
1115                            IPU_INT0_FROM();
1116                            break;
1117    
1118          if (g_nDMATransfer.GIFSTALL)                  case SCE_IPU_PACK:
1119          {                          if (!ipuPACK(ipu_cmd.current))
1120                  // gif                          {
1121                  Console.Warning("IPU GIF Stall");                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1122                  g_nDMATransfer.GIFSTALL = false;                                  return;
1123                  //if (gif->chcr.STR) GIFdma();                          }
1124          }                          break;
1125    
1126          if (g_nDMATransfer.VIFSTALL)                  case SCE_IPU_IDEC:
1127          {                          if (!ipuIDEC(ipu_cmd.current, true))
1128                  // vif                          {
1129                  Console.Warning("IPU VIF Stall");                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1130                  g_nDMATransfer.VIFSTALL = false;                                  return;
1131                  //if (vif1ch->chcr.STR) dmaVIF1();                          }
         }  
1132    
1133          if (g_nDMATransfer.SIFSTALL)                          ipuRegs.ctrl.OFC = 0;
1134          {                          ipuRegs.ctrl.BUSY = 0;
1135                  // sif                          ipuRegs.topbusy = 0;
1136                  Console.Warning("IPU SIF Stall");                          ipuRegs.cmd.BUSY = 0;
1137                  g_nDMATransfer.SIFSTALL = false;                          ipu_cmd.current = 0xffffffff;
1138    
1139                  // Not totally sure whether this needs to be done or not, so I'm                          // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it
1140                  // leaving it commented out for the moment.                          IPU_INT0_FROM();
1141                  //if (sif1dma->chcr.STR) SIF1Dma();                          break;
         }  
1142    
1143          if (g_nDMATransfer.TIE0)                  case SCE_IPU_BDEC:
1144          {                          if (!ipuBDEC(ipu_cmd.current, true))
1145                  g_nDMATransfer.TIE0 = false;                          {
1146          }                                  if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1147                                    return;
1148                            }
1149    
1150          ipu0dma->chcr.STR = false;                          ipuRegs.ctrl.BUSY = 0;
1151          hwDmacIrq(DMAC_FROM_IPU);                          ipuRegs.topbusy = 0;
1152  }                          ipuRegs.cmd.BUSY = 0;
1153                            ipu_cmd.current = 0xffffffff;
1154    
1155  IPU_FORCEINLINE void ipu1Interrupt()                          IPU_INT0_FROM();
1156  {                          if (ipuRegs.ctrl.SCD || ipuRegs.ctrl.ECD) hwIntcIrq(INTC_IPU);
1157          IPU_LOG("ipu1Interrupt %x:", cpuRegs.cycle);                          return;
1158    
1159          if(IPU1Status.DMAFinished == false || IPU1Status.InProgress == true)  //Sanity Check                  default:
1160          {                          Console.WriteLn("Unknown IPU command: %08x", ipu_cmd.current);
1161                  IPU1dma();                          break;
                 return;  
1162          }          }
1163    
1164          IPU_LOG("ipu1 finish %x:", cpuRegs.cycle);          // success
1165          ipu1dma->chcr.STR = false;          ipuRegs.ctrl.BUSY = 0;
1166          IPU1Status.DMAMode = 2;          ipu_cmd.current = 0xffffffff;
         hwDmacIrq(DMAC_TO_IPU);  
1167  }  }

Legend:
Removed from v.31  
changed lines
  Added in v.62

  ViewVC Help
Powered by ViewVC 1.1.22