1 /* Mednafen - Multi-system Emulator
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 /*
19 MDEC_READ_FIFO(tfr) vs InCounter vs MDEC_DMACanRead() is a bit fragile right now. Actually, the entire horrible state machine monstrosity is fragile.
20
21 TODO: OutFIFOReady, so <16bpp works right.
22
23 TODO CODE:
24
25 bool InFIFOReady;
26
27 if(InFIFO.CanWrite())
28 {
29 InFIFO.Write(V);
30
31 if(InCommand)
32 {
33 if(InCounter != 0xFFFF)
34 {
35 InCounter--;
36
37 // This condition when InFIFO.CanWrite() != 0 is a bit buggy on real hardware, decoding loop *seems* to be reading too
38 // much and pulling garbage from the FIFO.
39 if(InCounter == 0xFFFF)
40 InFIFOReady = true;
41 }
42
43 if(InFIFO.CanWrite() == 0)
44 InFIFOReady = true;
45 }
46 }
47 */
48
49 // Good test-case games:
50 // Dragon Knight 4(bad disc?)
51 // Final Fantasy 7 intro movie.
52 // GameShark Version 4.0 intro movie; (clever) abuse of DMA channel 0.
53 // SimCity 2000 startup.
54
55
56 #include "psx.h"
57 #include "mdec.h"
58
59 #include "../masmem.h"
60 #include "../math_ops.h"
61 #include "../state_helpers.h"
62
63 #include "FastFIFO.h"
64 #include <math.h>
65
66 #if defined(__SSE2__)
67 #include <xmmintrin.h>
68 #include <emmintrin.h>
69 #endif
70
71 #if defined(ARCH_POWERPC_ALTIVEC) && defined(HAVE_ALTIVEC_H)
72 #include <altivec.h>
73 #endif
74
75 static int32 ClockCounter;
76 static unsigned MDRPhase;
77 static FastFIFO<uint32, 0x20> InFIFO;
78 static FastFIFO<uint32, 0x20> OutFIFO;
79
80 static int8 block_y[8][8];
81 static int8 block_cb[8][8]; // [y >> 1][x >> 1]
82 static int8 block_cr[8][8]; // [y >> 1][x >> 1]
83
84 static uint32 Control;
85 static uint32 Command;
86 static bool InCommand;
87
88 static uint8 QMatrix[2][64];
89 static uint32 QMIndex;
90
91 MDFN_ALIGN(16) static int16 IDCTMatrix[64];
92 static uint32 IDCTMIndex;
93
94 static uint8 QScale;
95
96 MDFN_ALIGN(16) static int16 Coeff[64];
97 static uint32 CoeffIndex;
98 static uint32 DecodeWB;
99
100 static union
101 {
102 uint32 pix32[48];
103 uint16 pix16[96];
104 uint8 pix8[192];
105 } PixelBuffer;
106 static uint32 PixelBufferReadOffset;
107 static uint32 PixelBufferCount32;
108
109 static uint16 InCounter;
110
111 static uint8 RAMOffsetY;
112 static uint8 RAMOffsetCounter;
113 static uint8 RAMOffsetWWS;
114
115 static const uint8 ZigZag[64] =
116 {
117 0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11,
118 0x0a, 0x03, 0x04, 0x0b, 0x12, 0x19, 0x20, 0x28,
119 0x21, 0x1a, 0x13, 0x0c, 0x05, 0x06, 0x0d, 0x14,
120 0x1b, 0x22, 0x29, 0x30, 0x38, 0x31, 0x2a, 0x23,
121 0x1c, 0x15, 0x0e, 0x07, 0x0f, 0x16, 0x1d, 0x24,
122 0x2b, 0x32, 0x39, 0x3a, 0x33, 0x2c, 0x25, 0x1e,
123 0x17, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x3c, 0x35,
124 0x2e, 0x27, 0x2f, 0x36, 0x3d, 0x3e, 0x37, 0x3f,
125 };
126
MDEC_Power(void)127 void MDEC_Power(void)
128 {
129 ClockCounter = 0;
130 MDRPhase = 0;
131
132 InFIFO.Flush();
133 OutFIFO.Flush();
134
135 memset(block_y, 0, sizeof(block_y));
136 memset(block_cb, 0, sizeof(block_cb));
137 memset(block_cr, 0, sizeof(block_cr));
138
139 Control = 0;
140 Command = 0;
141 InCommand = false;
142
143 memset(QMatrix, 0, sizeof(QMatrix));
144 QMIndex = 0;
145
146 memset(IDCTMatrix, 0, sizeof(IDCTMatrix));
147 IDCTMIndex = 0;
148
149 QScale = 0;
150
151 memset(Coeff, 0, sizeof(Coeff));
152 CoeffIndex = 0;
153 DecodeWB = 0;
154
155 memset(PixelBuffer.pix32, 0, sizeof(PixelBuffer.pix32));
156 PixelBufferReadOffset = 0;
157 PixelBufferCount32 = 0;
158
159 InCounter = 0;
160
161 RAMOffsetY = 0;
162 RAMOffsetCounter = 0;
163 RAMOffsetWWS = 0;
164 }
165
MDEC_StateAction(StateMem * sm,int load,int data_only)166 int MDEC_StateAction(StateMem *sm, int load, int data_only)
167 {
168 SFORMAT StateRegs[] =
169 {
170 SFVAR(ClockCounter),
171 SFVAR(MDRPhase),
172
173 #define SFFIFO32(fifoobj) SFARRAY32(&fifoobj.data[0], sizeof(fifoobj.data) / sizeof(fifoobj.data[0])), \
174 SFVAR(fifoobj.read_pos), \
175 SFVAR(fifoobj.write_pos), \
176 SFVAR(fifoobj.in_count)
177
178 SFFIFO32(InFIFO),
179 SFFIFO32(OutFIFO),
180 #undef SFFIFO
181
182 SFARRAY(&block_y[0][0], sizeof(block_y) / sizeof(block_y[0][0])),
183 SFARRAY(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])),
184 SFARRAY(&block_cr[0][0], sizeof(block_cr) / sizeof(block_cr[0][0])),
185
186 SFVAR(Control),
187 SFVAR(Command),
188 SFVAR(InCommand),
189
190 SFARRAY(&QMatrix[0][0], sizeof(QMatrix) / sizeof(QMatrix[0][0])),
191 SFVAR(QMIndex),
192
193 SFARRAY16(&IDCTMatrix[0], sizeof(IDCTMatrix) / sizeof(IDCTMatrix[0])),
194 SFVAR(IDCTMIndex),
195
196 SFVAR(QScale),
197
198 SFARRAY16(&Coeff[0], sizeof(Coeff) / sizeof(Coeff[0])),
199 SFVAR(CoeffIndex),
200 SFVAR(DecodeWB),
201
202 SFARRAY32(&PixelBuffer.pix32[0], sizeof(PixelBuffer.pix32) / sizeof(PixelBuffer.pix32[0])),
203 SFVAR(PixelBufferReadOffset),
204 SFVAR(PixelBufferCount32),
205
206 SFVAR(InCounter),
207
208 SFVAR(RAMOffsetY),
209 SFVAR(RAMOffsetCounter),
210 SFVAR(RAMOffsetWWS),
211
212 SFEND
213 };
214
215 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDEC");
216
217 if(load)
218 {
219 InFIFO.SaveStatePostLoad();
220 OutFIFO.SaveStatePostLoad();
221
222 PixelBufferCount32 %= (sizeof(PixelBuffer.pix32) / sizeof(PixelBuffer.pix32[0])) + 1;
223 }
224
225 return(ret);
226 }
227
Mask9ClampS8(int32 v)228 static INLINE int8 Mask9ClampS8(int32 v)
229 {
230 v = sign_x_to_s32(9, v);
231
232 if(v < -128)
233 v = -128;
234
235 if(v > 127)
236 v = 127;
237
238 return v;
239 }
240
241 template<typename T>
IDCT_1D_Multi(int16 * in_coeff,T * out_coeff)242 static void IDCT_1D_Multi(int16 *in_coeff, T *out_coeff)
243 {
244 unsigned col, x;
245
246 for(col = 0; col < 8; col++)
247 {
248 #if defined(__SSE2__)
249 __m128i c = _mm_load_si128((__m128i *)&in_coeff[(col * 8)]);
250 #endif
251
252 for( x = 0; x < 8; x++)
253 {
254 #ifdef __SSE2__
255 MDFN_ALIGN(16) int32 tmp[4];
256 __m128i m = _mm_load_si128((__m128i *)&IDCTMatrix[(x * 8)]);
257 __m128i sum = _mm_madd_epi16(m, c);
258 sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
259 sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (1 << 0) | (0 << 2)));
260
261 _mm_store_si128((__m128i*)tmp, sum);
262
263 if(sizeof(T) == 1)
264 out_coeff[(col * 8) + x] = Mask9ClampS8((tmp[0] + 0x4000) >> 15);
265 else
266 out_coeff[(x * 8) + col] = (tmp[0] + 0x4000) >> 15;
267 #else
268 int32 sum = 0;
269 unsigned u;
270
271 for(u = 0; u < 8; u++)
272 sum += (in_coeff[(col * 8) + u] * IDCTMatrix[(x * 8) + u]);
273
274 if(sizeof(T) == 1)
275 out_coeff[(col * 8) + x] = Mask9ClampS8((sum + 0x4000) >> 15);
276 else
277 out_coeff[(x * 8) + col] = (sum + 0x4000) >> 15;
278 #endif
279 }
280 }
281 }
282
IDCT(int16 * in_coeff,int8 * out_coeff)283 static void IDCT(int16 *in_coeff, int8 *out_coeff)
284 {
285 MDFN_ALIGN(16) int16 tmpbuf[64];
286
287 IDCT_1D_Multi<int16>(in_coeff, tmpbuf);
288 IDCT_1D_Multi<int8>(tmpbuf, out_coeff);
289 }
290
YCbCr_to_RGB(const int8 y,const int8 cb,const int8 cr,int & r,int & g,int & b)291 static INLINE void YCbCr_to_RGB(const int8 y, const int8 cb, const int8 cr, int &r, int &g, int &b)
292 {
293 // The formula for green is still a bit off(precision/rounding issues when both cb and cr are non-zero).
294 r = Mask9ClampS8(y + (((359 * cr) + 0x80) >> 8));
295 //g = Mask9ClampS8(y + (((-88 * cb) + (-183 * cr) + 0x80) >> 8));
296 g = Mask9ClampS8(y + ((((-88 * cb) &~ 0x1F) + ((-183 * cr) &~ 0x07) + 0x80) >> 8));
297 b = Mask9ClampS8(y + (((454 * cb) + 0x80) >> 8));
298
299 r ^= 0x80;
300 g ^= 0x80;
301 b ^= 0x80;
302 }
303
RGB_to_RGB555(uint8 r,uint8 g,uint8 b)304 static INLINE uint16 RGB_to_RGB555(uint8 r, uint8 g, uint8 b)
305 {
306 r = (r + 4) >> 3;
307 g = (g + 4) >> 3;
308 b = (b + 4) >> 3;
309
310 if(r > 0x1F)
311 r = 0x1F;
312
313 if(g > 0x1F)
314 g = 0x1F;
315
316 if(b > 0x1F)
317 b = 0x1F;
318
319 return((r << 0) | (g << 5) | (b << 10));
320 }
321
EncodeImage(const unsigned ybn)322 static void EncodeImage(const unsigned ybn)
323 {
324 //printf("ENCODE, %d\n", (Command & 0x08000000) ? 256 : 384);
325
326 PixelBufferCount32 = 0;
327
328 switch((Command >> 27) & 0x3)
329 {
330 case 0: // 4bpp
331 {
332 const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x88;
333 uint8* pix_out = PixelBuffer.pix8;
334
335 for(int y = 0; y < 8; y++)
336 {
337 for(int x = 0; x < 8; x += 2)
338 {
339 uint8 p0 = std::min<int>(127, block_y[y][x + 0] + 8);
340 uint8 p1 = std::min<int>(127, block_y[y][x + 1] + 8);
341
342 *pix_out = ((p0 >> 4) | (p1 & 0xF0)) ^ us_xor;
343 pix_out++;
344 }
345 }
346 PixelBufferCount32 = 8;
347 }
348 break;
349
350
351 case 1: // 8bpp
352 {
353 const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x80;
354 uint8* pix_out = PixelBuffer.pix8;
355
356 for(int y = 0; y < 8; y++)
357 {
358 for(int x = 0; x < 8; x++)
359 {
360 *pix_out = (uint8)block_y[y][x] ^ us_xor;
361 pix_out++;
362 }
363 }
364 PixelBufferCount32 = 16;
365 }
366 break;
367
368 case 2: // 24bpp
369 {
370 const uint8 rgb_xor = (Command & (1U << 26)) ? 0x80 : 0x00;
371 uint8* pix_out = PixelBuffer.pix8;
372
373 for(int y = 0; y < 8; y++)
374 {
375 const int8* by = &block_y[y][0];
376 const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
377 const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
378
379 for(int x = 0; x < 8; x++)
380 {
381 int r, g, b;
382
383 YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b);
384
385 pix_out[0] = r ^ rgb_xor;
386 pix_out[1] = g ^ rgb_xor;
387 pix_out[2] = b ^ rgb_xor;
388 pix_out += 3;
389 }
390 }
391 PixelBufferCount32 = 48;
392 }
393 break;
394
395 case 3: // 16bpp
396 {
397 uint16 pixel_xor = ((Command & 0x02000000) ? 0x8000 : 0x0000) | ((Command & (1U << 26)) ? 0x4210 : 0x0000);
398 uint16* pix_out = PixelBuffer.pix16;
399
400 for(int y = 0; y < 8; y++)
401 {
402 const int8* by = &block_y[y][0];
403 const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
404 const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
405
406 for(int x = 0; x < 8; x++)
407 {
408 int r, g, b;
409
410 YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b);
411
412 StoreU16_LE(pix_out, pixel_xor ^ RGB_to_RGB555(r, g, b));
413 pix_out++;
414 }
415 }
416 PixelBufferCount32 = 32;
417 }
418 break;
419
420 }
421 }
422
WriteImageData(uint16 V,int32 * eat_cycles)423 static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
424 {
425 const uint32 qmw = (bool)(DecodeWB < 2);
426
427 //printf("MDEC DMA SubWrite: %04x, %d\n", V, CoeffIndex);
428
429 if(!CoeffIndex)
430 {
431 if(V == 0xFE00)
432 {
433 //printf("FE00 @ %u\n", DecodeWB);
434 return;
435 }
436
437 QScale = V >> 10;
438
439 {
440 int q = QMatrix[qmw][0]; // No QScale here!
441 int ci = sign_10_to_s16(V & 0x3FF);
442 int tmp;
443
444 if(q != 0)
445 tmp = (int32)((uint32)(ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
446 else
447 tmp = (uint32)(ci * 2) << 4;
448
449 // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
450 Coeff[ZigZag[0]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
451 CoeffIndex++;
452 }
453 }
454 else
455 {
456 if(V == 0xFE00)
457 {
458 while(CoeffIndex < 64)
459 Coeff[ZigZag[CoeffIndex++]] = 0;
460 }
461 else
462 {
463 uint32 rlcount = V >> 10;
464
465 for(uint32 i = 0; i < rlcount && CoeffIndex < 64; i++)
466 {
467 Coeff[ZigZag[CoeffIndex]] = 0;
468 CoeffIndex++;
469 }
470
471 if(CoeffIndex < 64)
472 {
473 int q = QScale * QMatrix[qmw][CoeffIndex];
474 int ci = sign_10_to_s16(V & 0x3FF);
475 int tmp;
476
477 if(q != 0)
478 tmp = (int32)((uint32)((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
479 else
480 tmp = (uint32)(ci * 2) << 4;
481
482 // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
483 Coeff[ZigZag[CoeffIndex]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
484 CoeffIndex++;
485 }
486 }
487 }
488
489 if(CoeffIndex == 64)
490 {
491 CoeffIndex = 0;
492
493 //printf("Block %d finished\n", DecodeWB);
494
495 switch(DecodeWB)
496 {
497 case 0:
498 IDCT(Coeff, &block_cr[0][0]);
499 break;
500 case 1:
501 IDCT(Coeff, &block_cb[0][0]);
502 break;
503 case 2:
504 case 3:
505 case 4:
506 case 5:
507 IDCT(Coeff, &block_y[0][0]);
508 break;
509 }
510
511 // Timing in the actual PS1 MDEC is complex due to (apparent) pipelining, but the average when decoding a large number of blocks is
512 // about 512.
513 *eat_cycles += 512;
514
515 if(DecodeWB >= 2)
516 EncodeImage((DecodeWB + 4) % 6);
517
518 DecodeWB++;
519 if(DecodeWB == (((Command >> 27) & 2) ? 6 : 3))
520 DecodeWB = ((Command >> 27) & 2) ? 0 : 2;
521 }
522 }
523
MDEC_Run(int32 clocks)524 void MDEC_Run(int32 clocks)
525 {
526 static const unsigned MDRPhaseBias = 0 + 1;
527
528 ClockCounter += clocks;
529
530 if(ClockCounter > 128)
531 {
532 //if(MDRPhase != 0)
533 // printf("SNORT: %d\n", ClockCounter);
534 ClockCounter = 128;
535 }
536
537 switch(MDRPhase + MDRPhaseBias)
538 {
539 for(;;)
540 {
541 InCommand = false;
542 { { case 1: if(!(InFIFO.in_count)) { MDRPhase = 2 - MDRPhaseBias - 1; return; } }; Command = InFIFO.Read(); };
543 InCommand = true;
544 { ClockCounter -= (1); { case 3: if(!(ClockCounter > 0)) { MDRPhase = 4 - MDRPhaseBias - 1; return; } }; };
545
546 //printf("****************** Command: %08x, %02x\n", Command, Command >> 29);
547
548 //
549 //
550 //
551 if(((Command >> 29) & 0x7) == 1)
552 {
553 InCounter = Command & 0xFFFF;
554 OutFIFO.Flush();
555 //OutBuffer.Flush();
556
557 PixelBufferCount32 = 0;
558 CoeffIndex = 0;
559
560 if((Command >> 27) & 2)
561 DecodeWB = 0;
562 else
563 DecodeWB = 2;
564
565 switch((Command >> 27) & 0x3)
566 {
567 case 0:
568 case 1: RAMOffsetWWS = 0; break;
569 case 2: RAMOffsetWWS = 6; break;
570 case 3: RAMOffsetWWS = 4; break;
571 }
572 RAMOffsetY = 0;
573 RAMOffsetCounter = RAMOffsetWWS;
574
575 InCounter--;
576 do
577 {
578 uint32 tfr;
579 int32 need_eat; // = 0;
580
581 { { case 5: if(!(InFIFO.in_count)) { MDRPhase = 6 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
582 InCounter--;
583
584 // printf("KA: %04x %08x\n", InCounter, tfr);
585
586 need_eat = 0;
587 PixelBufferCount32 = 0;
588 WriteImageData(tfr, &need_eat);
589 WriteImageData(tfr >> 16, &need_eat);
590
591 { ClockCounter -= (need_eat); { case 7: if(!(ClockCounter > 0)) { MDRPhase = 8 - MDRPhaseBias - 1; return; } }; };
592
593 PixelBufferReadOffset = 0;
594
595 while(PixelBufferReadOffset < PixelBufferCount32)
596 {
597 { { case 9: if(!(OutFIFO.CanWrite())) { MDRPhase = 10 - MDRPhaseBias - 1; return; } }; OutFIFO.Write(LoadU32_LE(&PixelBuffer.pix32[PixelBufferReadOffset++])); };
598 }
599 } while(InCounter != 0xFFFF);
600 }
601 //
602 //
603 //
604 else if(((Command >> 29) & 0x7) == 2)
605 {
606 QMIndex = 0;
607 InCounter = 0x10 + ((Command & 0x1) ? 0x10 : 0x00);
608
609 InCounter--;
610 do
611 {
612 uint32 tfr;
613
614 { { case 11: if(!(InFIFO.in_count)) { MDRPhase = 12 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
615 InCounter--;
616
617 //printf("KA: %04x %08x\n", InCounter, tfr);
618
619 for(int i = 0; i < 4; i++)
620 {
621 QMatrix[QMIndex >> 6][QMIndex & 0x3F] = (uint8)tfr;
622 QMIndex = (QMIndex + 1) & 0x7F;
623 tfr >>= 8;
624 }
625 } while(InCounter != 0xFFFF);
626 }
627 //
628 //
629 //
630 else if(((Command >> 29) & 0x7) == 3)
631 {
632 IDCTMIndex = 0;
633 InCounter = 0x20;
634
635 InCounter--;
636 do
637 {
638 uint32 tfr;
639
640 { { case 13: if(!(InFIFO.in_count)) { MDRPhase = 14 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
641 InCounter--;
642
643 for(unsigned i = 0; i < 2; i++)
644 {
645 IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(tfr & 0xFFFF) >> 3;
646 IDCTMIndex = (IDCTMIndex + 1) & 0x3F;
647
648 tfr >>= 16;
649 }
650 } while(InCounter != 0xFFFF);
651 }
652 else
653 {
654 InCounter = Command & 0xFFFF;
655 }
656 } // end for(;;)
657 }
658 }
659
MDEC_DMAWrite(uint32 V)660 void MDEC_DMAWrite(uint32 V)
661 {
662 if(!InFIFO.CanWrite())
663 return;
664
665 InFIFO.Write(V);
666 MDEC_Run(0);
667 }
668
MDEC_DMARead(uint32 * offs)669 uint32 MDEC_DMARead(uint32* offs)
670 {
671 uint32 V = 0;
672
673 *offs = 0;
674
675 if(MDFN_LIKELY(OutFIFO.in_count))
676 {
677 V = OutFIFO.Read();
678
679 *offs = (RAMOffsetY & 0x7) * RAMOffsetWWS;
680
681 if(RAMOffsetY & 0x08)
682 {
683 *offs = (*offs - RAMOffsetWWS*7);
684 }
685
686 RAMOffsetCounter--;
687 if(!RAMOffsetCounter)
688 {
689 RAMOffsetCounter = RAMOffsetWWS;
690 RAMOffsetY++;
691 }
692
693 MDEC_Run(0);
694 }
695
696 return(V);
697 }
698
MDEC_DMACanWrite(void)699 bool MDEC_DMACanWrite(void)
700 {
701 return((InFIFO.CanWrite() >= 0x20) && (Control & (1U << 30)) && InCommand && InCounter != 0xFFFF);
702 }
703
MDEC_DMACanRead(void)704 bool MDEC_DMACanRead(void)
705 {
706 return((OutFIFO.in_count >= 0x20) && (Control & (1U << 29)));
707 }
708
MDEC_Write(const int32_t timestamp,uint32 A,uint32 V)709 void MDEC_Write(const int32_t timestamp, uint32 A, uint32 V)
710 {
711 //PSX_WARNING("[MDEC] Write: 0x%08x 0x%08x, %d --- %u %u", A, V, timestamp, InFIFO.in_count, OutFIFO.in_count);
712 if(A & 4)
713 {
714 if(V & 0x80000000) // Reset?
715 {
716 MDRPhase = 0;
717 InCounter = 0;
718 Command = 0;
719 InCommand = false;
720
721 PixelBufferCount32 = 0;
722 ClockCounter = 0;
723 QMIndex = 0;
724 IDCTMIndex = 0;
725
726 QScale = 0;
727
728 memset(Coeff, 0, sizeof(Coeff));
729 CoeffIndex = 0;
730 DecodeWB = 0;
731
732 InFIFO.Flush();
733 OutFIFO.Flush();
734 }
735 Control = V & 0x7FFFFFFF;
736 }
737 else
738 {
739 if(InFIFO.CanWrite())
740 {
741 InFIFO.Write(V);
742
743 if(!InCommand)
744 {
745 if(ClockCounter < 1)
746 ClockCounter = 1;
747 }
748 MDEC_Run(0);
749 }
750 }
751 }
752
MDEC_Read(const int32_t timestamp,uint32 A)753 uint32 MDEC_Read(const int32_t timestamp, uint32 A)
754 {
755 uint32 ret = 0;
756
757 if(A & 4)
758 {
759 ret = 0;
760
761 ret |= (OutFIFO.in_count == 0) << 31;
762 ret |= (InFIFO.CanWrite() == 0) << 30;
763 ret |= InCommand << 29;
764
765 ret |= MDEC_DMACanWrite() << 28;
766 ret |= MDEC_DMACanRead() << 27;
767
768 ret |= ((Command >> 25) & 0xF) << 23;
769
770 // Needs refactoring elsewhere to work right: ret |= ((DecodeWB + 4) % 6) << 16;
771
772 ret |= InCounter & 0xFFFF;
773 }
774 else
775 {
776 if(OutFIFO.in_count)
777 ret = OutFIFO.Read();
778 }
779
780 //PSX_WARNING("[MDEC] Read: 0x%08x 0x%08x -- %d %d", A, ret, InputBuffer.in_count, InCounter);
781
782 return(ret);
783 }
784