/[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 191 - (show annotations) (download)
Mon Sep 20 05:35:51 2010 UTC (9 years, 9 months ago) by william
File size: 24008 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.3795 local: v0.9.7.186-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 static __fi void IPU_INT0_FROM()
30 {
31 if (ipu0dma.qwc > 0 && ipu0dma.chcr.STR) ipu0Interrupt();
32 }
33
34 tIPU_cmd ipu_cmd;
35
36 void ReorderBitstream();
37
38 // the BP doesn't advance and returns -1 if there is no data to be read
39 __aligned16 tIPU_BP g_BP;
40
41 void IPUWorker();
42
43 // 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)
45 //char convert_data_buffer[sizeof(convert_rgb_t)];
46 //char convert_data_buffer[0x1C]; // unused?
47 //u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; // unused?
48
49 // Quantization matrix
50 static u16 vqclut[16]; //clut conversion table
51 static u8 s_thresh[2]; //thresholds for color conversions
52 int coded_block_pattern = 0;
53
54
55 u8 indx4[16*16/2];
56 __aligned16 decoder_t decoder;
57
58 __fi void IPUProcessInterrupt()
59 {
60 if (ipuRegs.ctrl.BUSY && g_BP.IFC) 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 IPUProcessInterrupt();
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 return false;
297
298 ipucase(IPU_CTRL): // IPU_CTRL
299 // CTRL = the first 16 bits of ctrl [0x8000ffff], + value for the next 16 bits,
300 // minus the reserved bits. (18-19; 27-29) [0x47f30000]
301 ipuRegs.ctrl.write(value);
302 if (ipuRegs.ctrl.IDP == 3)
303 {
304 Console.WriteLn("IPU Invalid Intra DC Precision, switching to 9 bits");
305 ipuRegs.ctrl.IDP = 1;
306 }
307
308 if (ipuRegs.ctrl.RST) ipuSoftReset(); // RESET
309
310 IPU_LOG("write32: IPU_CTRL=0x%08X", value);
311 return false;
312 }
313 return true;
314 }
315
316 // returns FALSE when the writeback is handled, TRUE if the caller should do the
317 // writeback itself.
318 __fi bool ipuWrite64(u32 mem, u64 value)
319 {
320 // Note: It's assumed that mem's input value is always in the 0x10002000 page
321 // of memory (if not, it's probably bad code).
322
323 pxAssert((mem & ~0xfff) == 0x10002000);
324 mem &= 0xfff;
325
326 IPUProcessInterrupt();
327
328 switch (mem)
329 {
330 ipucase(IPU_CMD):
331 IPU_LOG("write64: IPU_CMD=0x%08X", value);
332 IPUCMD_WRITE((u32)value);
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 bool ipuIDEC(u32 val, bool resume)
356 {
357 tIPU_CMD_IDEC idec(val);
358
359 if (!resume)
360 {
361 idec.log();
362 g_BP.Advance(idec.FB);
363
364 //from IPU_CTRL
365 ipuRegs.ctrl.PCT = I_TYPE; //Intra DECoding;)
366
367 decoder.coding_type = ipuRegs.ctrl.PCT;
368 decoder.mpeg1 = ipuRegs.ctrl.MP1;
369 decoder.q_scale_type = ipuRegs.ctrl.QST;
370 decoder.intra_vlc_format = ipuRegs.ctrl.IVF;
371 decoder.scantype = ipuRegs.ctrl.AS;
372 decoder.intra_dc_precision = ipuRegs.ctrl.IDP;
373
374 //from IDEC value
375 decoder.quantizer_scale = idec.QSC;
376 decoder.frame_pred_frame_dct= !idec.DTD;
377 decoder.sgn = idec.SGN;
378 decoder.dte = idec.DTE;
379 decoder.ofm = idec.OFM;
380
381 //other stuff
382 decoder.dcr = 1; // resets DC prediction value
383 }
384
385 return mpeg2sliceIDEC();
386 }
387
388 static int s_bdec = 0;
389
390 static __fi bool ipuBDEC(u32 val, bool resume)
391 {
392 tIPU_CMD_BDEC bdec(val);
393
394 if (!resume)
395 {
396 bdec.log(s_bdec);
397 if (IsDebugBuild) s_bdec++;
398
399 g_BP.Advance(bdec.FB);
400 decoder.coding_type = I_TYPE;
401 decoder.mpeg1 = ipuRegs.ctrl.MP1;
402 decoder.q_scale_type = ipuRegs.ctrl.QST;
403 decoder.intra_vlc_format = ipuRegs.ctrl.IVF;
404 decoder.scantype = ipuRegs.ctrl.AS;
405 decoder.intra_dc_precision = ipuRegs.ctrl.IDP;
406
407 //from BDEC value
408 decoder.quantizer_scale = decoder.q_scale_type ? non_linear_quantizer_scale [bdec.QSC] : bdec.QSC << 1;
409 decoder.macroblock_modes = bdec.DT ? DCT_TYPE_INTERLACED : 0;
410 decoder.dcr = bdec.DCR;
411 decoder.macroblock_modes |= bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN;
412
413 memzero_sse_a(decoder.mb8);
414 memzero_sse_a(decoder.mb16);
415 }
416
417 return mpeg2_slice();
418 }
419
420 static bool __fastcall ipuVDEC(u32 val)
421 {
422 switch (ipu_cmd.pos[0])
423 {
424 case 0:
425 if (!bitstream_init()) return false;
426
427 switch ((val >> 26) & 3)
428 {
429 case 0://Macroblock Address Increment
430 decoder.mpeg1 = ipuRegs.ctrl.MP1;
431 ipuRegs.cmd.DATA = get_macroblock_address_increment();
432 break;
433
434 case 1://Macroblock Type
435 decoder.frame_pred_frame_dct = 1;
436 decoder.coding_type = ipuRegs.ctrl.PCT;
437 ipuRegs.cmd.DATA = get_macroblock_modes();
438 break;
439
440 case 2://Motion Code
441 ipuRegs.cmd.DATA = get_motion_delta(0);
442 break;
443
444 case 3://DMVector
445 ipuRegs.cmd.DATA = get_dmv();
446 break;
447
448 jNO_DEFAULT
449 }
450
451 ipuRegs.cmd.DATA &= 0xFFFF;
452 ipuRegs.cmd.DATA |= 0x10000;
453
454 //ipuRegs.cmd.DATA = (ipuRegs.cmd.DATA & 0xFFFF) | ((decoder.bitstream_bits + 16) << 16);
455 ipuRegs.ctrl.ECD = (ipuRegs.cmd.DATA == 0);
456
457 case 1:
458 if (!getBits32((u8*)&ipuRegs.top, 0))
459 {
460 ipu_cmd.pos[0] = 1;
461 return false;
462 }
463
464 ipuRegs.top = BigEndian(ipuRegs.top);
465
466 IPU_LOG("VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d",
467 ipuRegs.cmd.DATA, ipuRegs.cmd.DATA >> 16, val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ?
468 ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")), ipuRegs.ctrl.PCT);
469 return true;
470
471 jNO_DEFAULT
472 }
473
474 return false;
475 }
476
477 static __fi bool ipuFDEC(u32 val)
478 {
479 if (!getBits32((u8*)&ipuRegs.cmd.DATA, 0)) return false;
480
481 ipuRegs.cmd.DATA = BigEndian(ipuRegs.cmd.DATA);
482 ipuRegs.top = ipuRegs.cmd.DATA;
483
484 IPU_LOG("FDEC read: 0x%08x", ipuRegs.top);
485
486 return true;
487 }
488
489 static bool ipuSETIQ(u32 val)
490 {
491 int i;
492
493 if ((val >> 27) & 1)
494 {
495 u8 (&niq)[64] = decoder.niq;
496
497 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
498 {
499 if (!getBits64((u8*)niq + 8 * ipu_cmd.pos[0], 1)) return false;
500 }
501
502 IPU_LOG("Read non-intra quantization matrix from FIFO.");
503 for (i = 0; i < 8; i++)
504 {
505 IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
506 niq[i * 8 + 0], niq[i * 8 + 1], niq[i * 8 + 2], niq[i * 8 + 3],
507 niq[i * 8 + 4], niq[i * 8 + 5], niq[i * 8 + 6], niq[i * 8 + 7]);
508 }
509 }
510 else
511 {
512 u8 (&iq)[64] = decoder.iq;
513
514 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
515 {
516 if (!getBits64((u8*)iq + 8 * ipu_cmd.pos[0], 1)) return false;
517 }
518
519 IPU_LOG("Read intra quantization matrix from FIFO.");
520 for (i = 0; i < 8; i++)
521 {
522 IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X",
523 iq[i * 8 + 0], iq[i * 8 + 1], iq[i * 8 + 2], iq[i *8 + 3],
524 iq[i * 8 + 4], iq[i * 8 + 5], iq[i * 8 + 6], iq[i *8 + 7]);
525 }
526 }
527
528 return true;
529 }
530
531 static bool ipuSETVQ(u32 val)
532 {
533 for(;ipu_cmd.pos[0] < 4; ipu_cmd.pos[0]++)
534 {
535 if (!getBits64(((u8*)vqclut) + 8 * ipu_cmd.pos[0], 1)) return false;
536 }
537
538 IPU_LOG("SETVQ command. Read VQCLUT table from FIFO.\n"
539 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
540 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
541 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n"
542 "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d",
543 vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F,
544 vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F,
545 vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F,
546 vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F,
547 vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F,
548 vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F,
549 vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F,
550 vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F,
551 vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F,
552 vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F,
553 vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F,
554 vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F,
555 vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F,
556 vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F,
557 vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F,
558 vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F);
559
560 return true;
561 }
562
563 // IPU Transfers are split into 8Qwords so we need to send ALL the data
564 static bool __fastcall ipuCSC(u32 val)
565 {
566 tIPU_CMD_CSC csc(val);
567 csc.log_from_YCbCr();
568
569 for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
570 {
571 for(;ipu_cmd.pos[0] < 48; ipu_cmd.pos[0]++)
572 {
573 if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
574 }
575
576 ipu_csc(decoder.mb8, decoder.rgb32, 0);
577 if (csc.OFM) ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
578
579 if (csc.OFM)
580 {
581 while (ipu_cmd.pos[1] < 32)
582 {
583 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
584
585 if (ipu_cmd.pos[1] <= 0) return false;
586 }
587 }
588 else
589 {
590 while (ipu_cmd.pos[1] < 64)
591 {
592 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);
593
594 if (ipu_cmd.pos[1] <= 0) return false;
595 }
596 }
597
598 ipu_cmd.pos[0] = 0;
599 ipu_cmd.pos[1] = 0;
600 }
601
602 return true;
603 }
604
605 // Todo - Need to add the same stop and start code as CSC
606 static bool ipuPACK(u32 val)
607 {
608 tIPU_CMD_CSC csc(val);
609 csc.log_from_RGB32();
610
611 for (;ipu_cmd.index < (int)csc.MBC; ipu_cmd.index++)
612 {
613 for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
614 {
615 if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return false;
616 }
617
618 ipu_csc(decoder.mb8, decoder.rgb32, 0);
619 ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
620
621 if (csc.OFM) ipu_vq(decoder.rgb16, indx4);
622
623 if (csc.OFM)
624 {
625 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
626
627 if (ipu_cmd.pos[1] < 32) return false;
628 }
629 else
630 {
631 ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*)indx4) + 4 * ipu_cmd.pos[1], 8 - ipu_cmd.pos[1]);
632
633 if (ipu_cmd.pos[1] < 8) return false;
634 }
635
636 ipu_cmd.pos[0] = 0;
637 ipu_cmd.pos[1] = 0;
638 }
639
640 return TRUE;
641 }
642
643 static void ipuSETTH(u32 val)
644 {
645 s_thresh[0] = (val & 0xff);
646 s_thresh[1] = ((val >> 16) & 0xff);
647 IPU_LOG("SETTH (Set threshold value)command %x.", val&0xff00ff);
648 }
649
650 // --------------------------------------------------------------------------------------
651 // CORE Functions (referenced from MPEG library)
652 // --------------------------------------------------------------------------------------
653 __fi void ipu_csc(macroblock_8& mb8, macroblock_rgb32& rgb32, int sgn)
654 {
655 int i;
656 u8* p = (u8*)&rgb32;
657
658 yuv2rgb();
659
660 if (s_thresh[0] > 0)
661 {
662 for (i = 0; i < 16*16; i++, p += 4)
663 {
664 if ((p[0] < s_thresh[0]) && (p[1] < s_thresh[0]) && (p[2] < s_thresh[0]))
665 *(u32*)p = 0;
666 else if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
667 p[3] = 0x40;
668 }
669 }
670 else if (s_thresh[1] > 0)
671 {
672 for (i = 0; i < 16*16; i++, p += 4)
673 {
674 if ((p[0] < s_thresh[1]) && (p[1] < s_thresh[1]) && (p[2] < s_thresh[1]))
675 p[3] = 0x40;
676 }
677 }
678 if (sgn)
679 {
680 for (i = 0; i < 16*16; i++, p += 4)
681 {
682 *(u32*)p ^= 0x808080;
683 }
684 }
685 }
686
687 __fi void ipu_dither(const macroblock_rgb32& rgb32, macroblock_rgb16& rgb16, int dte)
688 {
689 int i, j;
690 for (i = 0; i < 16; ++i)
691 {
692 for (j = 0; j < 16; ++j)
693 {
694 rgb16.c[i][j].r = rgb32.c[i][j].r >> 3;
695 rgb16.c[i][j].g = rgb32.c[i][j].g >> 3;
696 rgb16.c[i][j].b = rgb32.c[i][j].b >> 3;
697 rgb16.c[i][j].a = rgb32.c[i][j].a == 0x40;
698 }
699 }
700 }
701
702 __fi void ipu_vq(macroblock_rgb16& rgb16, u8* indx4)
703 {
704 Console.Error("IPU: VQ not implemented");
705 }
706
707
708 // --------------------------------------------------------------------------------------
709 // Buffer reader
710 // --------------------------------------------------------------------------------------
711
712 __ri u32 UBITS(uint bits)
713 {
714 uint readpos8 = g_BP.BP/8;
715
716 uint result = BigEndian(*(u32*)( (u8*)g_BP.internal_qwc + readpos8 ));
717 uint bp7 = (g_BP.BP & 7);
718 result <<= bp7;
719 result >>= (32 - bits);
720
721 return result;
722 }
723
724 __ri s32 SBITS(uint bits)
725 {
726 // Read an unaligned 32 bit value and then shift the bits up and then back down.
727
728 uint readpos8 = g_BP.BP/8;
729
730 int result = BigEndian(*(s32*)( (s8*)g_BP.internal_qwc + readpos8 ));
731 uint bp7 = (g_BP.BP & 7);
732 result <<= bp7;
733 result >>= (32 - bits);
734
735 return result;
736 }
737
738 // whenever reading fractions of bytes. The low bits always come from the next byte
739 // while the high bits come from the current byte
740 u8 getBits64(u8 *address, bool advance)
741 {
742 if (!g_BP.FillBuffer(64)) return 0;
743
744 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
745
746 if (uint shift = (g_BP.BP & 7))
747 {
748 u64 mask = (0xff >> shift);
749 mask = mask | (mask << 8) | (mask << 16) | (mask << 24) | (mask << 32) | (mask << 40) | (mask << 48) | (mask << 56);
750
751 *(u64*)address = ((~mask & *(u64*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u64*)readpos) << shift);
752 }
753 else
754 {
755 *(u64*)address = *(u64*)readpos;
756 }
757
758 if (advance) g_BP.Advance(64);
759
760 return 1;
761 }
762
763 // whenever reading fractions of bytes. The low bits always come from the next byte
764 // while the high bits come from the current byte
765 __fi u8 getBits32(u8 *address, bool advance)
766 {
767 if (!g_BP.FillBuffer(32)) return 0;
768
769 const u8* readpos = &g_BP.internal_qwc->_u8[g_BP.BP/8];
770
771 if(uint shift = (g_BP.BP & 7))
772 {
773 u32 mask = (0xff >> shift);
774 mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
775
776 *(u32*)address = ((~mask & *(u32*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u32*)readpos) << shift);
777 }
778 else
779 {
780 // Bit position-aligned -- no masking/shifting necessary
781 *(u32*)address = *(u32*)readpos;
782 }
783
784 if (advance) g_BP.Advance(32);
785
786 return 1;
787 }
788
789 __fi u8 getBits16(u8 *address, bool advance)
790 {
791 if (!g_BP.FillBuffer(16)) return 0;
792
793 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
794
795 if (uint shift = (g_BP.BP & 7))
796 {
797 uint mask = (0xff >> shift);
798 mask = mask | (mask << 8);
799 *(u16*)address = ((~mask & *(u16*)(readpos + 1)) >> (8 - shift)) | (((mask) & *(u16*)readpos) << shift);
800 }
801 else
802 {
803 *(u16*)address = *(u16*)readpos;
804 }
805
806 if (advance) g_BP.Advance(16);
807
808 return 1;
809 }
810
811 u8 getBits8(u8 *address, bool advance)
812 {
813 if (!g_BP.FillBuffer(8)) return 0;
814
815 const u8* readpos = &g_BP.internal_qwc[0]._u8[g_BP.BP/8];
816
817 if (uint shift = (g_BP.BP & 7))
818 {
819 uint mask = (0xff >> shift);
820 *(u8*)address = (((~mask) & readpos[1]) >> (8 - shift)) | (((mask) & *readpos) << shift);
821 }
822 else
823 {
824 *(u8*)address = *(u8*)readpos;
825 }
826
827 if (advance) g_BP.Advance(8);
828
829 return 1;
830 }
831
832 // --------------------------------------------------------------------------------------
833 // IPU Worker / Dispatcher
834 // --------------------------------------------------------------------------------------
835 void IPUCMD_WRITE(u32 val)
836 {
837 // don't process anything if currently busy
838 if (ipuRegs.ctrl.BUSY) Console.WriteLn("IPU BUSY!"); // wait for thread
839
840 ipuRegs.ctrl.ECD = 0;
841 ipuRegs.ctrl.SCD = 0; //clear ECD/SCD
842 ipu_cmd.clear();
843 ipu_cmd.current = val;
844
845 switch (val >> 28)
846 {
847 case SCE_IPU_BCLR:
848 ipuBCLR(val);
849 hwIntcIrq(INTC_IPU); //DMAC_TO_IPU
850 return;
851
852 case SCE_IPU_VDEC:
853
854 g_BP.Advance(val & 0x3F);
855
856 // check if enough data in queue
857 if (ipuVDEC(val)) return;
858
859 ipuRegs.cmd.BUSY = 0x80000000;
860 ipuRegs.topbusy = 0x80000000;
861 break;
862
863 case SCE_IPU_FDEC:
864 IPU_LOG("FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, CHCR 0x%x",
865 val & 0x3f, g_BP.IFC, (int)g_BP.BP, ipu1dma.chcr._u32);
866
867 g_BP.Advance(val & 0x3F);
868
869 if (ipuFDEC(val)) return;
870 ipuRegs.cmd.BUSY = 0x80000000;
871 ipuRegs.topbusy = 0x80000000;
872 break;
873
874 case SCE_IPU_SETTH:
875 ipuSETTH(val);
876 hwIntcIrq(INTC_IPU);
877 return;
878
879 case SCE_IPU_SETIQ:
880 IPU_LOG("SETIQ command.");
881 if (val & 0x3f) IPU_LOG("Skip %d bits.", val & 0x3f);
882 g_BP.Advance(val & 0x3F);
883 if (ipuSETIQ(val)) return;
884 break;
885
886 case SCE_IPU_SETVQ:
887 if (ipuSETVQ(val)) return;
888 break;
889
890 case SCE_IPU_CSC:
891 ipu_cmd.pos[1] = 0;
892 ipu_cmd.index = 0;
893
894 if (ipuCSC(val))
895 {
896 IPU_INT0_FROM();
897 return;
898 }
899 break;
900
901 case SCE_IPU_PACK:
902 ipu_cmd.pos[1] = 0;
903 ipu_cmd.index = 0;
904 if (ipuPACK(val)) return;
905 break;
906
907 case SCE_IPU_IDEC:
908 if (ipuIDEC(val, false))
909 {
910 // idec done, ipu0 done too
911 IPU_INT0_FROM();
912 return;
913 }
914
915 ipuRegs.topbusy = 0x80000000;
916 break;
917
918 case SCE_IPU_BDEC:
919 if (ipuBDEC(val, false))
920 {
921 IPU_INT0_FROM();
922 if (ipuRegs.ctrl.SCD || ipuRegs.ctrl.ECD) hwIntcIrq(INTC_IPU);
923 return;
924 }
925 else
926 {
927 ipuRegs.topbusy = 0x80000000;
928 }
929 break;
930 }
931
932 // have to resort to the thread
933 ipuRegs.ctrl.BUSY = 1;
934 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
935 }
936
937 void IPUWorker()
938 {
939 pxAssert(ipuRegs.ctrl.BUSY);
940
941 switch (ipu_cmd.CMD)
942 {
943 case SCE_IPU_VDEC:
944 if (!ipuVDEC(ipu_cmd.current))
945 {
946 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
947 return;
948 }
949 ipuRegs.cmd.BUSY = 0;
950 ipuRegs.topbusy = 0;
951 break;
952
953 case SCE_IPU_FDEC:
954 if (!ipuFDEC(ipu_cmd.current))
955 {
956 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
957 return;
958 }
959 ipuRegs.cmd.BUSY = 0;
960 ipuRegs.topbusy = 0;
961 break;
962
963 case SCE_IPU_SETIQ:
964 if (!ipuSETIQ(ipu_cmd.current))
965 {
966 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
967 return;
968 }
969 break;
970
971 case SCE_IPU_SETVQ:
972 if (!ipuSETVQ(ipu_cmd.current))
973 {
974 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
975 return;
976 }
977 break;
978
979 case SCE_IPU_CSC:
980 if (!ipuCSC(ipu_cmd.current))
981 {
982 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
983 return;
984 }
985 IPU_INT0_FROM();
986 break;
987
988 case SCE_IPU_PACK:
989 if (!ipuPACK(ipu_cmd.current))
990 {
991 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
992 return;
993 }
994 break;
995
996 case SCE_IPU_IDEC:
997 if (!ipuIDEC(ipu_cmd.current, true))
998 {
999 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1000 return;
1001 }
1002
1003 ipuRegs.ctrl.OFC = 0;
1004 ipuRegs.ctrl.BUSY = 0;
1005 ipuRegs.topbusy = 0;
1006 ipuRegs.cmd.BUSY = 0;
1007 ipu_cmd.current = 0xffffffff;
1008
1009 // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it
1010 IPU_INT0_FROM();
1011 break;
1012
1013 case SCE_IPU_BDEC:
1014 if (!ipuBDEC(ipu_cmd.current, true))
1015 {
1016 if(ipu1dma.chcr.STR == false) hwIntcIrq(INTC_IPU);
1017 return;
1018 }
1019
1020 ipuRegs.ctrl.BUSY = 0;
1021 ipuRegs.topbusy = 0;
1022 ipuRegs.cmd.BUSY = 0;
1023 ipu_cmd.current = 0xffffffff;
1024
1025 IPU_INT0_FROM();
1026 if (ipuRegs.ctrl.SCD || ipuRegs.ctrl.ECD) hwIntcIrq(INTC_IPU);
1027 return;
1028
1029 default:
1030 Console.WriteLn("Unknown IPU command: %08x", ipu_cmd.current);
1031 break;
1032 }
1033
1034 // success
1035 ipuRegs.ctrl.BUSY = 0;
1036 ipu_cmd.current = 0xffffffff;
1037 }

  ViewVC Help
Powered by ViewVC 1.1.22