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

  ViewVC Help
Powered by ViewVC 1.1.22