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

Contents of /trunk/pcsx2/IPU/IPU.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 5 months ago) by william
File size: 23384 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "Common.h"
18
19 #include "IPU.h"
20 #include "IPUdma.h"
21 #include "yuv2rgb.h"
22 #include "mpeg2lib/Mpeg.h"
23
24 #include "Vif.h"
25 #include "Gif.h"
26 #include "Vif_Dma.h"
27 #include <limits.h>
28
29 #include "Utilities/MemsetFast.inl"
30
31 // the BP doesn't advance and returns -1 if there is no data to be read
32 __aligned16 tIPU_cmd ipu_cmd;
33 __aligned16 tIPU_BP g_BP;
34 __aligned16 decoder_t decoder;
35
36 void IPUWorker();
37
38 // Color conversion stuff, the memory layout is a total hack
39 // convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t)
40 //char convert_data_buffer[sizeof(convert_rgb_t)];
41 //char convert_data_buffer[0x1C]; // unused?
42 //u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; // unused?
43
44 // Quantization matrix
45 static u16 vqclut[16]; //clut conversion table
46 static u8 s_thresh[2]; //thresholds for color conversions
47 int coded_block_pattern = 0;
48
49
50 u8 indx4[16*16/2];
51
52
53 void tIPU_cmd::clear()
54 {
55 memzero_sse_a(*this);
56 current = 0xffffffff;
57 }
58
59 __fi void IPUProcessInterrupt()
60 {
61 if (ipuRegs.ctrl.BUSY) // && (g_BP.FP || g_BP.IFC || (ipu1dma.chcr.STR && ipu1dma.qwc > 0)))
62 IPUWorker();
63 }
64
65 /////////////////////////////////////////////////////////
66 // Register accesses (run on EE thread)
67 int ipuInit()
68 {
69 memzero(ipuRegs);
70 memzero(g_BP);
71 memzero(decoder);
72
73 decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P
74
75 ipu_fifo.init();
76 ipu_cmd.clear();
77
78 return 0;
79 }
80
81 void ipuReset()
82 {
83 ipuInit();
84 }
85
86 void ReportIPU()
87 {
88 //Console.WriteLn(g_nDMATransfer.desc());
89 Console.WriteLn(ipu_fifo.in.desc());
90 Console.WriteLn(ipu_fifo.out.desc());
91 Console.WriteLn(g_BP.desc());
92 Console.WriteLn("vqclut = 0x%x.", vqclut);
93 Console.WriteLn("s_thresh = 0x%x.", s_thresh);
94 Console.WriteLn("coded_block_pattern = 0x%x.", coded_block_pattern);
95 Console.WriteLn("g_decoder = 0x%x.", &decoder);
96 Console.WriteLn("mpeg2_scan = 0x%x.", &mpeg2_scan);
97 Console.WriteLn(ipu_cmd.desc());
98 Console.Newline();
99 }
100
101 void SaveStateBase::ipuFreeze()
102 {
103 // Get a report of the status of the ipu variables when saving and loading savestates.
104 //ReportIPU();
105 FreezeTag("IPU");
106 Freeze(ipu_fifo);
107
108 Freeze(g_BP);
109 Freeze(vqclut);
110 Freeze(s_thresh);
111 Freeze(coded_block_pattern);
112 Freeze(decoder);
113 Freeze(ipu_cmd);
114 }
115
116 void tIPU_CMD_IDEC::log() const
117 {
118 IPU_LOG("IDEC command.");
119
120 if (FB) IPU_LOG(" Skip %d bits.", FB);
121 IPU_LOG(" Quantizer step code=0x%X.", QSC);
122
123 if (DTD == 0)
124 IPU_LOG(" Does not decode DT.");
125 else
126 IPU_LOG(" Decodes DT.");
127
128 if (SGN == 0)
129 IPU_LOG(" No bias.");
130 else
131 IPU_LOG(" Bias=128.");
132
133 if (DTE == 1) IPU_LOG(" Dither Enabled.");
134 if (OFM == 0)
135 IPU_LOG(" Output format is RGB32.");
136 else
137 IPU_LOG(" Output format is RGB16.");
138
139 IPU_LOG("");
140 }
141
142 void tIPU_CMD_BDEC::log(int s_bdec) const
143 {
144 IPU_LOG("BDEC(macroblock decode) command %x, num: 0x%x", cpuRegs.pc, s_bdec);
145 if (FB) IPU_LOG(" Skip 0x%X bits.", FB);
146
147 if (MBI)
148 IPU_LOG(" Intra MB.");
149 else
150 IPU_LOG(" Non-intra MB.");
151
152 if (DCR)
153 IPU_LOG(" Resets DC prediction value.");
154 else
155 IPU_LOG(" Doesn't reset DC prediction value.");
156
157 if (DT)
158 IPU_LOG(" Use field DCT.");
159 else
160 IPU_LOG(" Use frame DCT.");
161
162 IPU_LOG(" Quantizer step=0x%X", QSC);
163 }
164
165 void tIPU_CMD_CSC::log_from_YCbCr() const
166 {
167 IPU_LOG("CSC(Colorspace conversion from YCbCr) command (%d).", MBC);
168 if (OFM)
169 IPU_LOG("Output format is RGB16. ");
170 else
171 IPU_LOG("Output format is RGB32. ");
172
173 if (DTE) IPU_LOG("Dithering enabled.");
174 }
175
176 void tIPU_CMD_CSC::log_from_RGB32() const
177 {
178 IPU_LOG("PACK (Colorspace conversion from RGB32) command.");
179
180 if (OFM)
181 IPU_LOG("Output format is RGB16. ");
182 else
183 IPU_LOG("Output format is INDX4. ");
184
185 if (DTE) IPU_LOG("Dithering enabled.");
186
187 IPU_LOG("Number of macroblocks to be converted: %d", MBC);
188 }
189
190
191 __fi u32 ipuRead32(u32 mem)
192 {
193 // Note: It's assumed that mem's input value is always in the 0x10002000 page
194 // of memory (if not, it's probably bad code).
195
196 pxAssert((mem & ~0xff) == 0x10002000);
197 mem &= 0xff; // ipu repeats every 0x100
198
199 IPUProcessInterrupt();
200
201 switch (mem)
202 {
203 ipucase(IPU_CTRL): // IPU_CTRL
204 {
205 ipuRegs.ctrl.IFC = g_BP.IFC;
206 ipuRegs.ctrl.CBP = coded_block_pattern;
207
208 if (!ipuRegs.ctrl.BUSY)
209 IPU_LOG("read32: IPU_CTRL=0x%08X", ipuRegs.ctrl._u32);
210
211 return ipuRegs.ctrl._u32;
212 }
213
214 ipucase(IPU_BP): // IPU_BP
215 {
216 pxAssume(g_BP.FP <= 2);
217
218 ipuRegs.ipubp = g_BP.BP & 0x7f;
219 ipuRegs.ipubp |= g_BP.IFC << 8;
220 ipuRegs.ipubp |= g_BP.FP << 16;
221
222 IPU_LOG("read32: IPU_BP=0x%08X", ipuRegs.ipubp);
223 return ipuRegs.ipubp;
224 }
225
226 default:
227 IPU_LOG("read32: Addr=0x%08X Value = 0x%08X", mem, psHu32(IPU_CMD + mem));
228 }
229
230 return psHu32(IPU_CMD + mem);
231 }
232
233 __fi u64 ipuRead64(u32 mem)
234 {
235 // Note: It's assumed that mem's input value is always in the 0x10002000 page
236 // of memory (if not, it's probably bad code).
237
238 pxAssert((mem & ~0xff) == 0x10002000);
239 mem &= 0xff; // ipu repeats every 0x100
240
241 IPUProcessInterrupt();
242
243 switch (mem)
244 {
245 ipucase(IPU_CMD): // IPU_CMD
246 if (ipuRegs.cmd.DATA & 0xffffff)
247 IPU_LOG("read64: IPU_CMD=BUSY=%x, DATA=%08X", ipuRegs.cmd.BUSY ? 1 : 0, ipuRegs.cmd.DATA);
248 break;
249
250 ipucase(IPU_CTRL):
251 DevCon.Warning("reading 64bit IPU ctrl");
252 break;
253
254 ipucase(IPU_BP):
255 DevCon.Warning("reading 64bit IPU top");
256 break;
257
258 ipucase(IPU_TOP): // IPU_TOP
259 IPU_LOG("read64: IPU_TOP=%x, bp = %d", ipuRegs.top, g_BP.BP);
260 break;
261
262 default:
263 IPU_LOG("read64: Unknown=%x", mem);
264 break;
265 }
266 return psHu64(IPU_CMD + mem);
267 }
268
269 void ipuSoftReset()
270 {
271 ipu_fifo.clear();
272
273 coded_block_pattern = 0;
274
275 ipuRegs.ctrl.reset();
276 ipuRegs.top = 0;
277 ipu_cmd.clear();
278 ipuRegs.cmd.BUSY = 0;
279
280 memzero(g_BP);
281 }
282
283 __fi bool ipuWrite32(u32 mem, u32 value)
284 {
285 // Note: It's assumed that mem's input value is always in the 0x10002000 page
286 // of memory (if not, it's probably bad code).
287
288 pxAssert((mem & ~0xfff) == 0x10002000);
289 mem &= 0xfff;
290
291 switch (mem)
292 {
293 ipucase(IPU_CMD): // IPU_CMD
294 IPU_LOG("write32: IPU_CMD=0x%08X", value);
295 IPUCMD_WRITE(value);
296 IPUProcessInterrupt();
297 return false;
298
299 ipucase(IPU_CTRL): // IPU_CTRL
300 // CTRL = the first 16 bits of ctrl [0x8000ffff], + value for the next 16 bits,
301 // minus the reserved bits. (18-19; 27-29) [0x47f30000]
302 ipuRegs.ctrl.write(value);
303 if (ipuRegs.ctrl.IDP == 3)
304 {
305 Console.WriteLn("IPU Invalid Intra DC Precision, switching to 9 bits");
306 ipuRegs.ctrl.IDP = 1;
307 }
308
309 if (ipuRegs.ctrl.RST) ipuSoftReset(); // RESET
310
311 IPU_LOG("write32: IPU_CTRL=0x%08X", value);
312 return false;
313 }
314 return true;
315 }
316
317 // returns FALSE when the writeback is handled, TRUE if the caller should do the
318 // writeback itself.
319 __fi bool ipuWrite64(u32 mem, u64 value)
320 {
321 // Note: It's assumed that mem's input value is always in the 0x10002000 page
322 // of memory (if not, it's probably bad code).
323
324 pxAssert((mem & ~0xfff) == 0x10002000);
325 mem &= 0xfff;
326
327 switch (mem)
328 {
329 ipucase(IPU_CMD):
330 IPU_LOG("write64: IPU_CMD=0x%08X", value);
331 IPUCMD_WRITE((u32)value);
332 IPUProcessInterrupt();
333 return false;
334 }
335
336 return true;
337 }
338
339
340 //////////////////////////////////////////////////////
341 // IPU Commands (exec on worker thread only)
342
343 static void ipuBCLR(u32 val)
344 {
345 ipu_fifo.in.clear();
346
347 memzero(g_BP);
348 g_BP.BP = val & 0x7F;
349
350 ipuRegs.ctrl.BUSY = 0;
351 ipuRegs.cmd.BUSY = 0;
352 IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X", g_BP.BP);
353 }
354
355 static __ri void ipuIDEC(tIPU_CMD_IDEC idec)
356 {
357 idec.log();
358
359 //from IPU_CTRL
360 ipuRegs.ctrl.PCT = I_TYPE; //Intra DECoding;)
361
362 decoder.coding_type = ipuRegs.ctrl.PCT;
363 decoder.mpeg1 = ipuRegs.ctrl.MP1;
364 decoder.q_scale_type = ipuRegs.ctrl.QST;
365 decoder.intra_vlc_format = ipuRegs.ctrl.IVF;
366 decoder.scantype = ipuRegs.ctrl.AS;
367 decoder.intra_dc_precision = ipuRegs.ctrl.IDP;
368
369 //from IDEC value
370 decoder.quantizer_scale = idec.QSC;
371 decoder.frame_pred_frame_dct= !idec.DTD;
372 decoder.sgn = idec.SGN;
373 decoder.dte = idec.DTE;
374 decoder.ofm = idec.OFM;
375
376 //other stuff
377 decoder.dcr = 1; // resets DC prediction value
378 }
379
380 static int s_bdec = 0;
381
382 static __ri void ipuBDEC(tIPU_CMD_BDEC bdec)
383 {
384 bdec.log(s_bdec);
385 if (IsDebugBuild) s_bdec++;
386
387 decoder.coding_type = I_TYPE;
388 decoder.mpeg1 = ipuRegs.ctrl.MP1;
389 decoder.q_scale_type = ipuRegs.ctrl.QST;
390 decoder.intra_vlc_format = ipuRegs.ctrl.IVF;
391 decoder.scantype = ipuRegs.ctrl.AS;
392 decoder.intra_dc_precision = ipuRegs.ctrl.IDP;
393
394 //from BDEC value
395 decoder.quantizer_scale = decoder.q_scale_type ? non_linear_quantizer_scale [bdec.QSC] : bdec.QSC << 1;
396 decoder.macroblock_modes = bdec.DT ? DCT_TYPE_INTERLACED : 0;
397 decoder.dcr = bdec.DCR;
398 decoder.macroblock_modes |= bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN;
399
400 memzero_sse_a(decoder.mb8);
401 memzero_sse_a(decoder.mb16);
402 }
403
404 static __fi bool ipuVDEC(u32 val)
405 {
406 switch (ipu_cmd.pos[0])
407 {
408 case 0:
409 if (!bitstream_init()) return false;
410
411 switch ((val >> 26) & 3)
412 {
413 case 0://Macroblock Address Increment
414 decoder.mpeg1 = ipuRegs.ctrl.MP1;
415 ipuRegs.cmd.DATA = get_macroblock_address_increment();
416 break;
417
418 case 1://Macroblock Type
419 decoder.frame_pred_frame_dct = 1;
420 decoder.coding_type = ipuRegs.ctrl.PCT;
421 ipuRegs.cmd.DATA = get_macroblock_modes();
422 break;
423
424 case 2://Motion Code
425 ipuRegs.cmd.DATA = get_motion_delta(0);
426 break;
427
428 case 3://DMVector
429 ipuRegs.cmd.DATA = get_dmv();
430 break;
431
432 jNO_DEFAULT
433 }
434
435 // HACK ATTACK! This code OR's the MPEG decoder's bitstream position into the upper
436 // 16 bits of DATA; which really doesn't make sense since (a) we already rewound the bits
437 // back into the IPU internal buffer above, and (b) the IPU doesn't have an MPEG internal
438 // 32-bit decoder buffer of its own anyway. Furthermore, setting the upper 16 bits to
439 // any value other than zero appears to work fine. When set to zero, however, FMVs run
440 // very choppy (basically only decoding/updating every 30th frame or so). So yeah,
441 // someone with knowledge on the subject please feel free to explain this one. :) --air
442
443 // The upper bits are the "length" of the decoded command, where the lower is the address.
444 // This is due to differences with IPU and the MPEG standard. See get_macroblock_address_increment().
445
446 ipuRegs.ctrl.ECD = (ipuRegs.cmd.DATA == 0);
447
448 case 1:
449 if (!getBits32((u8*)&ipuRegs.top, 0))
450 {
451 ipu_cmd.pos[0] = 1;
452 return false;
453 }
454
455 ipuRegs.top = BigEndian(ipuRegs.top);
456
457 IPU_LOG("VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d",
458 ipuRegs.cmd.DATA, ipuRegs.cmd.DATA >> 16, val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ?
459 ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")), ipuRegs.ctrl.PCT);
460
461 return true;
462
463 jNO_DEFAULT
464 }
465
466 return false;
467 }
468
469 static __ri bool ipuFDEC(u32 val)
470 {
471 if (!getBits32((u8*)&ipuRegs.cmd.DATA, 0)) return false;
472
473 ipuRegs.cmd.DATA = BigEndian(ipuRegs.cmd.DATA);
474 ipuRegs.top = ipuRegs.cmd.DATA;
475
476 IPU_LOG("FDEC read: 0x%08x", ipuRegs.top);
477
478 return true;
479 }
480
481 static bool ipuSETIQ(u32 val)
482 {
483 if ((val >> 27) & 1)
484 {
485 u8 (&niq)[64] = decoder.niq;
486
487 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
488 {
489 if (!getBits64((u8*)niq + 8 * ipu_cmd.pos[0], 1)) return false;
490 }
491
492 IPU_LOG("Read non-intra quantization matrix from FIFO.");
493 for (uint i = 0; i < 8; i++)
494 {
495 IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
496 niq[i * 8 + 0], niq[i * 8 + 1], niq[i * 8 + 2], niq[i * 8 + 3],
497 niq[i * 8 + 4], niq[i * 8 + 5], niq[i * 8 + 6], niq[i * 8 + 7]);
498 }
499 }
500 else
501 {
502 u8 (&iq)[64] = decoder.iq;
503
504 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
505 {
506 if (!getBits64((u8*)iq + 8 * ipu_cmd.pos[0], 1)) return false;
507 }
508
509 IPU_LOG("Read intra quantization matrix from FIFO.");
510 for (uint i = 0; i < 8; i++)
511 {
512 IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
513 iq[i * 8 + 0], iq[i * 8 + 1], iq[i * 8 + 2], iq[i *8 + 3],
514 iq[i * 8 + 4], iq[i * 8 + 5], iq[i * 8 + 6], iq[i *8 + 7]);
515 }
516 }
517
518 return true;
519 }
520
521 static bool ipuSETVQ(u32 val)
522 {
523 for(;ipu_cmd.pos[0] < 4; ipu_cmd.pos[0]++)
524 {
525 if (!getBits64(((u8*)vqclut) + 8 * ipu_cmd.pos[0], 1)) return false;
526 }
527
528 IPU_LOG("SETVQ command. Read VQCLUT table from FIFO.\n"
529 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
530 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
531 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
532 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d",
533 vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F,
534 vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F,
535 vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F,
536 vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F,
537 vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F,
538 vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F,
539 vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F,
540 vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F,
541 vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F,
542 vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F,
543 vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F,
544 vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F,
545 vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F,
546 vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F,
547 vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F,
548 vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F);
549
550 return true;
551 }
552
553 // IPU Transfers are split into 8Qwords so we need to send ALL the data
554 static __ri bool ipuCSC(tIPU_CMD_CSC csc)
555 {
556 csc.log_from_YCbCr();
557
558 for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
559 {
560 for(;ipu_cmd.pos[0] < 48; ipu_cmd.pos[0]++)
561 {
562 if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
563 }
564
565 ipu_csc(decoder.mb8, decoder.rgb32, 0);
566 if (csc.OFM) ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
567
568 if (csc.OFM)
569 {
570 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
571 if (ipu_cmd.pos[1] < 32) return false;
572 }
573 else
574 {
575 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);
576 if (ipu_cmd.pos[1] < 64) return false;
577 }
578
579 ipu_cmd.pos[0] = 0;
580 ipu_cmd.pos[1] = 0;
581 }
582
583 return true;
584 }
585
586 static __ri bool ipuPACK(tIPU_CMD_CSC csc)
587 {
588 csc.log_from_RGB32();
589
590 for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
591 {
592 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
593 {
594 if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
595 }
596
597 ipu_csc(decoder.mb8, decoder.rgb32, 0);
598 ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
599
600 if (csc.OFM) ipu_vq(decoder.rgb16, indx4);
601
602 if (csc.OFM)
603 {
604 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
605 if (ipu_cmd.pos[1] < 32) return false;
606 }
607 else
608 {
609 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*)indx4) + 4 * ipu_cmd.pos[1], 8 - ipu_cmd.pos[1]);
610 if (ipu_cmd.pos[1] < 8) return false;
611 }
612
613 ipu_cmd.pos[0] = 0;
614 ipu_cmd.pos[1] = 0;
615 }
616
617 return TRUE;
618 }
619
620 static void ipuSETTH(u32 val)
621 {
622 s_thresh[0] = (val & 0xff);
623 s_thresh[1] = ((val >> 16) & 0xff);
624 IPU_LOG("SETTH (Set threshold value)command %x.", val&0xff00ff);
625 }
626
627 // --------------------------------------------------------------------------------------
628 // CORE Functions (referenced from MPEG library)
629 // --------------------------------------------------------------------------------------
630 __fi void ipu_csc(macroblock_8& mb8, macroblock_rgb32& rgb32, int sgn)
631 {
632 int i;
633 u8* p = (u8*)&rgb32;
634
635 yuv2rgb();
636
637 if (s_thresh[0] > 0)
638 {
639 for (i = 0; i < 16*16; i++, p += 4)
640 {
641 if ((p[0] < s_thresh[0]) && (p[1] < s_thresh[0]) && (p[2] < s_thresh[0]))
642 *(u32*)p = 0;
643 else if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
644 p[3] = 0x40;
645 }
646 }
647 else if (s_thresh[1] > 0)
648 {
649 for (i = 0; i < 16*16; i++, p += 4)
650 {
651 if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
652 p[3] = 0x40;
653 }
654 }
655 if (sgn)
656 {
657 for (i = 0; i < 16*16; i++, p += 4)
658 {
659 *(u32*)p ^= 0x808080;
660 }
661 }
662 }
663
664 __fi void ipu_dither(const macroblock_rgb32& rgb32, macroblock_rgb16& rgb16, int dte)
665 {
666 int i, j;
667 for (i = 0; i < 16; ++i)
668 {
669 for (j = 0; j < 16; ++j)
670 {
671 rgb16.c[i][j].r = rgb32.c[i][j].r >> 3;
672 rgb16.c[i][j].g = rgb32.c[i][j].g >> 3;
673 rgb16.c[i][j].b = rgb32.c[i][j].b >> 3;
674 rgb16.c[i][j].a = rgb32.c[i][j].a == 0x40;
675 }
676 }
677 }
678
679 __fi void ipu_vq(macroblock_rgb16& rgb16, u8* indx4)
680 {
681 Console.Error("IPU: VQ not implemented");
682 }
683
684
685 // --------------------------------------------------------------------------------------
686 // Buffer reader
687 // --------------------------------------------------------------------------------------
688
689 __ri u32 UBITS(uint bits)
690 {
691 uint readpos8 = g_BP.BP/8;
692
693 uint result = BigEndian(*(u32*)( (u8*)g_BP.internal_qwc + readpos8 ));
694 uint bp7 = (g_BP.BP & 7);
695 result <<= bp7;
696 result >>= (32 - bits);
697
698 return result;
699 }
700
701 __ri s32 SBITS(uint bits)
702 {
703 // Read an unaligned 32 bit value and then shift the bits up and then back down.
704
705 uint readpos8 = g_BP.BP/8;
706
707 int result = BigEndian(*(s32*)( (s8*)g_BP.internal_qwc + readpos8 ));
708 uint bp7 = (g_BP.BP & 7);
709 result <<= bp7;
710 result >>= (32 - bits);
711
712 return result;
713 }
714
715 // whenever reading fractions of bytes. The low bits always come from the next byte
716 // while the high bits come from the current byte
717 u8 getBits64(u8 *address, bool advance)
718 {
719 if (!g_BP.FillBuffer(64)) return 0;
720
721 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
722
723 if (uint shift = (g_BP.BP & 7))
724 {
725 u64 mask = (0xff >> shift);
726 mask = mask | (mask << 8) | (mask << 16) | (mask << 24) | (mask << 32) | (mask << 40) | (mask << 48) | (mask << 56);
727
728 *(u64*)address = ((~mask & *(u64*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u64*)readpos) << shift);
729 }
730 else
731 {
732 *(u64*)address = *(u64*)readpos;
733 }
734
735 if (advance) g_BP.Advance(64);
736
737 return 1;
738 }
739
740 // whenever reading fractions of bytes. The low bits always come from the next byte
741 // while the high bits come from the current byte
742 __fi u8 getBits32(u8 *address, bool advance)
743 {
744 if (!g_BP.FillBuffer(32)) return 0;
745
746 const u8* readpos = &g_BP.internal_qwc->_u8[g_BP.BP/8];
747
748 if(uint shift = (g_BP.BP & 7))
749 {
750 u32 mask = (0xff >> shift);
751 mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
752
753 *(u32*)address = ((~mask & *(u32*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u32*)readpos) << shift);
754 }
755 else
756 {
757 // Bit position-aligned -- no masking/shifting necessary
758 *(u32*)address = *(u32*)readpos;
759 }
760
761 if (advance) g_BP.Advance(32);
762
763 return 1;
764 }
765
766 __fi u8 getBits16(u8 *address, bool advance)
767 {
768 if (!g_BP.FillBuffer(16)) return 0;
769
770 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
771
772 if (uint shift = (g_BP.BP & 7))
773 {
774 uint mask = (0xff >> shift);
775 mask = mask | (mask << 8);
776 *(u16*)address = ((~mask & *(u16*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u16*)readpos) << shift);
777 }
778 else
779 {
780 *(u16*)address = *(u16*)readpos;
781 }
782
783 if (advance) g_BP.Advance(16);
784
785 return 1;
786 }
787
788 u8 getBits8(u8 *address, bool advance)
789 {
790 if (!g_BP.FillBuffer(8)) return 0;
791
792 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
793
794 if (uint shift = (g_BP.BP & 7))
795 {
796 uint mask = (0xff >> shift);
797 *(u8*)address = (((~mask) & readpos[1]) >> (8 - shift)) | (((mask) & *readpos) << shift);
798 }
799 else
800 {
801 *(u8*)address = *(u8*)readpos;
802 }
803
804 if (advance) g_BP.Advance(8);
805
806 return 1;
807 }
808
809 // --------------------------------------------------------------------------------------
810 // IPU Worker / Dispatcher
811 // --------------------------------------------------------------------------------------
812
813 // When a command is written, we set some various busy flags and clear some other junk.
814 // The actual decoding will be handled by IPUworker.
815 __fi void IPUCMD_WRITE(u32 val)
816 {
817 // don't process anything if currently busy
818 //if (ipuRegs.ctrl.BUSY) Console.WriteLn("IPU BUSY!"); // wait for thread
819
820 ipuRegs.ctrl.ECD = 0;
821 ipuRegs.ctrl.SCD = 0;
822 ipu_cmd.clear();
823 ipu_cmd.current = val;
824
825 switch (ipu_cmd.CMD)
826 {
827 // BCLR and SETTH require no data so they always execute inline:
828
829 case SCE_IPU_BCLR:
830 ipuBCLR(val);
831 hwIntcIrq(INTC_IPU); //DMAC_TO_IPU
832 ipuRegs.ctrl.BUSY = 0;
833 return;
834
835 case SCE_IPU_SETTH:
836 ipuSETTH(val);
837 hwIntcIrq(INTC_IPU);
838 ipuRegs.ctrl.BUSY = 0;
839 return;
840
841
842
843 case SCE_IPU_IDEC:
844 g_BP.Advance(val & 0x3F);
845 ipuIDEC(val);
846 ipuRegs.SetTopBusy();
847 break;
848
849 case SCE_IPU_BDEC:
850 g_BP.Advance(val & 0x3F);
851 ipuBDEC(val);
852 ipuRegs.SetTopBusy();
853 break;
854
855 case SCE_IPU_VDEC:
856 g_BP.Advance(val & 0x3F);
857 ipuRegs.SetDataBusy();
858 break;
859
860 case SCE_IPU_FDEC:
861 IPU_LOG("FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, CHCR 0x%x",
862 val & 0x3f, g_BP.IFC, g_BP.BP, ipu1dma.chcr._u32);
863
864 g_BP.Advance(val & 0x3F);
865 ipuRegs.SetDataBusy();
866 break;
867
868 case SCE_IPU_SETIQ:
869 IPU_LOG("SETIQ command.");
870 g_BP.Advance(val & 0x3F);
871 break;
872
873 case SCE_IPU_SETVQ:
874 break;
875
876 case SCE_IPU_CSC:
877 break;
878
879 case SCE_IPU_PACK:
880 break;
881
882 jNO_DEFAULT;
883 }
884
885 ipuRegs.ctrl.BUSY = 1;
886
887 //if(!ipu1dma.chcr.STR) hwIntcIrq(INTC_IPU);
888 }
889
890 __noinline void IPUWorker()
891 {
892 pxAssert(ipuRegs.ctrl.BUSY);
893
894 switch (ipu_cmd.CMD)
895 {
896 // These are unreachable (BUSY will always be 0 for them)
897 //case SCE_IPU_BCLR:
898 //case SCE_IPU_SETTH:
899 //break;
900
901 case SCE_IPU_IDEC:
902 if (!mpeg2sliceIDEC()) return;
903
904 //ipuRegs.ctrl.OFC = 0;
905 ipuRegs.topbusy = 0;
906 ipuRegs.cmd.BUSY = 0;
907
908 // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it
909 // Check Mana Khemia 1 "off campus" to trigger a GUST IDEC messup.
910 // This hackfixes it :/
911 //if (ipu0dma.qwc > 0 && ipu0dma.chcr.STR) ipu0Interrupt();
912 break;
913
914 case SCE_IPU_BDEC:
915 if (!mpeg2_slice()) return;
916
917 ipuRegs.topbusy = 0;
918 ipuRegs.cmd.BUSY = 0;
919
920 //if (ipuRegs.ctrl.SCD || ipuRegs.ctrl.ECD) hwIntcIrq(INTC_IPU);
921 break;
922
923 case SCE_IPU_VDEC:
924 if (!ipuVDEC(ipu_cmd.current)) return;
925
926 ipuRegs.topbusy = 0;
927 ipuRegs.cmd.BUSY = 0;
928 break;
929
930 case SCE_IPU_FDEC:
931 if (!ipuFDEC(ipu_cmd.current)) return;
932
933 ipuRegs.topbusy = 0;
934 ipuRegs.cmd.BUSY = 0;
935 break;
936
937 case SCE_IPU_SETIQ:
938 if (!ipuSETIQ(ipu_cmd.current)) return;
939 break;
940
941 case SCE_IPU_SETVQ:
942 if (!ipuSETVQ(ipu_cmd.current)) return;
943 break;
944
945 case SCE_IPU_CSC:
946 if (!ipuCSC(ipu_cmd.current)) return;
947 break;
948
949 case SCE_IPU_PACK:
950 if (!ipuPACK(ipu_cmd.current)) return;
951 break;
952
953 jNO_DEFAULT
954 }
955
956 // success
957 ipuRegs.ctrl.BUSY = 0;
958 ipu_cmd.current = 0xffffffff;
959 hwIntcIrq(INTC_IPU);
960 }

  ViewVC Help
Powered by ViewVC 1.1.22