1 /******************************************************************************/
2 /* Mednafen Virtual Boy Emulation Module                                      */
3 /******************************************************************************/
4 /* vip.cpp:
5 **  Copyright (C) 2010-2017 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #include "vb.h"
23 #include "vip.h"
24 
25 #define VIP_DBGMSG(...) { }
26 //#define VIP_DBGMSG(...) printf(__VA_ARGS__)
27 
28 namespace MDFN_IEN_VB
29 {
30 
31 static uint8 FB[2][2][0x6000];
32 static uint16 CHR_RAM[0x8000 / sizeof(uint16)];
33 static uint16 DRAM[0x20000 / sizeof(uint16)];
34 
35 #define INT_SCAN_ERR	0x0001
36 #define INT_LFB_END	0x0002
37 #define INT_RFB_END	0x0004
38 #define INT_GAME_START	0x0008
39 #define INT_FRAME_START	0x0010
40 
41 #define INT_SB_HIT	0x2000
42 #define INT_XP_END	0x4000
43 #define INT_TIME_ERR	0x8000
44 
45 static uint16 InterruptPending;
46 static uint16 InterruptEnable;
47 
48 static uint8 BRTA, BRTB, BRTC, REST;
49 static uint8 Repeat;
50 
51 static NO_INLINE void CopyFBColumnToTarget_Anaglyph(void);
52 static NO_INLINE void CopyFBColumnToTarget_AnaglyphSlow(void);
53 static NO_INLINE void CopyFBColumnToTarget_CScope(void);
54 static NO_INLINE void CopyFBColumnToTarget_SideBySide(void);
55 static NO_INLINE void CopyFBColumnToTarget_VLI(void);
56 static NO_INLINE void CopyFBColumnToTarget_HLI(void);
57 static void (*CopyFBColumnToTarget)(void) = NULL;
58 static float VBLEDOnScale;
59 static uint32 VB3DMode;
60 static uint32 VB3DReverse;
61 static uint32 VBPrescale;
62 static uint32 VBSBS_Separation;
63 static uint32 HLILUT[256];
64 static uint32 ColorLUT[2][256];
65 static int32 BrightnessCache[4];
66 static uint32 BrightCLUT[2][4];
67 
68 static float ColorLUTNoGC[2][256][3];
69 static uint32 AnaSlowColorLUT[256][256];
70 
71 // A few settings:
72 static bool InstantDisplayHack;
73 static bool AllowDrawSkip;
74 
75 static bool VidSettingsDirty;
76 static bool ParallaxDisabled;
77 static uint32 Anaglyph_Colors[2];
78 static uint32 Default_Color;
79 
80 const CustomPalette_Spec VIP_CPInfo[] =
81 {
82  { gettext_noop("VB LED Active Time; 256 left, 256 right.  If only 256 triplets are present, then they will be used for both left and right views.  When the custom palette's right view colors are the same as the left view colors(either explicitly, or when using a 256-entry custom palette), and anaglyph 3D mode is active, then the custom palette will not be used."), NULL, { 256, 256 * 2, 0 } },
83 
84  { NULL, NULL }
85 };
86 
MakeColorLUT(const MDFN_PixelFormat & format,const uint8 * const CustomPalette,const uint32 CustomPaletteNumEntries)87 static void MakeColorLUT(const MDFN_PixelFormat& format, const uint8* const CustomPalette, const uint32 CustomPaletteNumEntries)
88 {
89  //
90  // TODO: Use correct CRT/sRGB gamma curve, instead of approximation.
91  //
92  const bool cprunique = CustomPalette && (CustomPaletteNumEntries == 512) && memcmp(CustomPalette + 0 * 3, CustomPalette + 256 * 3, 256 * 3);
93 
94  for(int lr = 0; lr < 2; lr++)
95  {
96   for(int i = 0; i < 256; i++)
97   {
98    float r, g, b;
99    uint32 modcolor_prime;
100 
101    if(VB3DMode == VB3DMODE_ANAGLYPH)
102     modcolor_prime = Anaglyph_Colors[lr ^ VB3DReverse];
103    else
104     modcolor_prime = Default_Color;
105 
106    if(CustomPalette && (VB3DMode != VB3DMODE_ANAGLYPH || cprunique))
107    {
108     r = g = b = 1.0;
109     // Don't ^ VB3DReverse here.
110     modcolor_prime = MDFN_de24msb(CustomPalette + ((lr & cprunique) * 256 + i) * 3);
111    }
112    else
113     r = g = b = std::min<float>(1.0, i * VBLEDOnScale / 255.0);
114 
115    // Modulate.
116    r = r * pow(((modcolor_prime >> 16) & 0xFF) / 255.0, 2.2 / 1.0);
117    g = g * pow(((modcolor_prime >>  8) & 0xFF) / 255.0, 2.2 / 1.0);
118    b = b * pow(((modcolor_prime >>  0) & 0xFF) / 255.0, 2.2 / 1.0);
119 
120    ColorLUTNoGC[lr][i][0] = r;
121    ColorLUTNoGC[lr][i][1] = g;
122    ColorLUTNoGC[lr][i][2] = b;
123 
124    // Apply gamma correction
125    const float r_prime = pow(r, 1.0 / 2.2);
126    const float g_prime = pow(g, 1.0 / 2.2);
127    const float b_prime = pow(b, 1.0 / 2.2);
128 
129    ColorLUT[lr][i] = format.MakeColor((int)(r_prime * 255), (int)(g_prime * 255), (int)(b_prime * 255), 0);
130   }
131  }
132 
133  // Anaglyph slow-mode LUT calculation
134  for(int l_b = 0; l_b < 256; l_b++)
135  {
136   for(int r_b = 0; r_b < 256; r_b++)
137   {
138    float r, g, b;
139    float r_prime, g_prime, b_prime;
140 
141    r = ColorLUTNoGC[0][l_b][0] + ColorLUTNoGC[1][r_b][0];
142    g = ColorLUTNoGC[0][l_b][1] + ColorLUTNoGC[1][r_b][1];
143    b = ColorLUTNoGC[0][l_b][2] + ColorLUTNoGC[1][r_b][2];
144 
145    if(r > 1.0)
146     r = 1.0;
147    if(g > 1.0)
148     g = 1.0;
149    if(b > 1.0)
150     b = 1.0;
151 
152    r_prime = pow(r, 1.0 / 2.2);
153    g_prime = pow(g, 1.0 / 2.2);
154    b_prime = pow(b, 1.0 / 2.2);
155 
156    AnaSlowColorLUT[l_b][r_b] = format.MakeColor((int)(r_prime * 255), (int)(g_prime * 255), (int)(b_prime * 255), 0);
157   }
158  }
159 }
160 
RecalcBrightnessCache(void)161 static void RecalcBrightnessCache(void)
162 {
163  static const int32 MaxTime = 255;
164  int32 CumulativeTime = (BRTA + 1 + BRTB + 1 + BRTC + 1 + REST + 1) + 1;
165 
166  //printf("BRTA: %d, BRTB: %d, BRTC: %d, Rest: %d --- %d\n", BRTA, BRTB, BRTC, REST, BRTA + 1 + BRTB + 1 + BRTC);
167 
168  BrightnessCache[0] = 0;
169  BrightnessCache[1] = 0;
170  BrightnessCache[2] = 0;
171  BrightnessCache[3] = 0;
172 
173  for(int i = 0; i < Repeat + 1; i++)
174  {
175   int32 btemp[4];
176 
177   if((i * CumulativeTime) >= MaxTime)
178    break;
179 
180   btemp[1] = (i * CumulativeTime) + BRTA;
181   if(btemp[1] > MaxTime)
182    btemp[1] = MaxTime;
183   btemp[1] -= (i * CumulativeTime);
184   if(btemp[1] < 0)
185    btemp[1] = 0;
186 
187 
188   btemp[2] = (i * CumulativeTime) + BRTA + 1 + BRTB;
189   if(btemp[2] > MaxTime)
190    btemp[2] = MaxTime;
191   btemp[2] -= (i * CumulativeTime) + BRTA + 1;
192   if(btemp[2] < 0)
193    btemp[2] = 0;
194 
195   //btemp[3] = (i * CumulativeTime) + BRTA + 1 + BRTB + 1 + BRTC;
196   //if(btemp[3] > MaxTime)
197   // btemp[3] = MaxTime;
198   //btemp[3] -= (i * CumulativeTime);
199   //if(btemp[3] < 0)
200   // btemp[3] = 0;
201 
202   btemp[3] = (i * CumulativeTime) + BRTA + BRTB + BRTC + 1;
203   if(btemp[3] > MaxTime)
204    btemp[3] = MaxTime;
205   btemp[3] -= (i * CumulativeTime) + 1;
206   if(btemp[3] < 0)
207    btemp[3] = 0;
208 
209   BrightnessCache[1] += btemp[1];
210   BrightnessCache[2] += btemp[2];
211   BrightnessCache[3] += btemp[3];
212  }
213 
214  //printf("BC: %d %d %d %d\n", BrightnessCache[0], BrightnessCache[1], BrightnessCache[2], BrightnessCache[3]);
215 
216  for(int lr = 0; lr < 2; lr++)
217   for(int i = 0; i < 4; i++)
218   {
219    BrightCLUT[lr][i] = ColorLUT[lr][BrightnessCache[i]];
220    //printf("%d %d, %08x\n", lr, i, BrightCLUT[lr][i]);
221   }
222 }
223 
Recalc3DModeStuff(bool non_rgb_output=false)224 static void Recalc3DModeStuff(bool non_rgb_output = false)
225 {
226  switch(VB3DMode)
227  {
228   default:
229 	   if(((Anaglyph_Colors[0] & 0xFF) && (Anaglyph_Colors[1] & 0xFF)) ||
230 		((Anaglyph_Colors[0] & 0xFF00) && (Anaglyph_Colors[1] & 0xFF00)) ||
231 		((Anaglyph_Colors[0] & 0xFF0000) && (Anaglyph_Colors[1] & 0xFF0000)) ||
232 		non_rgb_output)
233 	   {
234             CopyFBColumnToTarget = CopyFBColumnToTarget_AnaglyphSlow;
235 	   }
236            else
237             CopyFBColumnToTarget = CopyFBColumnToTarget_Anaglyph;
238            break;
239 
240   case VB3DMODE_CSCOPE:
241            CopyFBColumnToTarget = CopyFBColumnToTarget_CScope;
242            break;
243 
244   case VB3DMODE_SIDEBYSIDE:
245            CopyFBColumnToTarget = CopyFBColumnToTarget_SideBySide;
246            break;
247 
248   case VB3DMODE_VLI:
249            CopyFBColumnToTarget = CopyFBColumnToTarget_VLI;
250            break;
251 
252   case VB3DMODE_HLI:
253            CopyFBColumnToTarget = CopyFBColumnToTarget_HLI;
254            break;
255  }
256  RecalcBrightnessCache();
257 }
258 
VIP_Set3DMode(uint32 mode,bool reverse,uint32 prescale,uint32 sbs_separation)259 void VIP_Set3DMode(uint32 mode, bool reverse, uint32 prescale, uint32 sbs_separation)
260 {
261  VB3DMode = mode;
262  VB3DReverse = reverse ? 1 : 0;
263  VBPrescale = prescale;
264  VBSBS_Separation = sbs_separation;
265 
266  VidSettingsDirty = true;
267 
268  for(uint32 p = 0; p < 256; p++)
269  {
270   uint32 v;
271   uint8 s[4];
272 
273   s[0] = (p >> 0) & 0x3;
274   s[1] = (p >> 2) & 0x3;
275   s[2] = (p >> 4) & 0x3;
276   s[3] = (p >> 6) & 0x3;
277 
278   v = 0;
279   for(unsigned int i = 0, shifty = 0; i < 4; i++)
280   {
281    for(unsigned int ps = 0; ps < prescale; ps++)
282    {
283     v |= s[i] << shifty;
284     shifty += 2;
285    }
286   }
287 
288   HLILUT[p] = v;
289  }
290 }
291 
VIP_SetParallaxDisable(bool disabled)292 void VIP_SetParallaxDisable(bool disabled)
293 {
294  ParallaxDisabled = disabled;
295 }
296 
VIP_SetDefaultColor(uint32 default_color)297 void VIP_SetDefaultColor(uint32 default_color)
298 {
299  Default_Color = default_color;
300 
301  VidSettingsDirty = true;
302 }
303 
VIP_SetLEDOnScale(float coeff)304 void VIP_SetLEDOnScale(float coeff)
305 {
306  VBLEDOnScale = coeff;
307 }
308 
VIP_SetAnaglyphColors(uint32 lcolor,uint32 rcolor)309 void VIP_SetAnaglyphColors(uint32 lcolor, uint32 rcolor)
310 {
311  Anaglyph_Colors[0] = lcolor;
312  Anaglyph_Colors[1] = rcolor;
313 
314  VidSettingsDirty = true;
315 }
316 
VIP_SetInstantDisplayHack(bool val)317 void VIP_SetInstantDisplayHack(bool val)
318 {
319  InstantDisplayHack = val;
320 }
321 
VIP_SetAllowDrawSkip(bool val)322 void VIP_SetAllowDrawSkip(bool val)
323 {
324  AllowDrawSkip = val;
325 }
326 
327 
328 static uint16 FRMCYC;
329 
330 static uint16 DPCTRL;
331 static bool DisplayActive;
332 
333 #define XPCTRL_XP_RST	0x0001
334 #define XPCTRL_XP_EN	0x0002
335 static uint16 XPCTRL;
336 static uint16 SBCMP;	// Derived from XPCTRL
337 
338 static uint16 SPT[4];	// SPT0~SPT3, 5f848~5f84e
339 static uint16 GPLT[4];
340 static uint8 GPLT_Cache[4][4];
341 
Recalc_GPLT_Cache(int which)342 static INLINE void Recalc_GPLT_Cache(int which)
343 {
344  for(int i = 0; i < 4; i++)
345   GPLT_Cache[which][i] = (GPLT[which] >> (i * 2)) & 3;
346 }
347 
348 static uint16 JPLT[4];
349 static uint8 JPLT_Cache[4][4];
350 
Recalc_JPLT_Cache(int which)351 static INLINE void Recalc_JPLT_Cache(int which)
352 {
353  for(int i = 0; i < 4; i++)
354   JPLT_Cache[which][i] = (JPLT[which] >> (i * 2)) & 3;
355 }
356 
357 
358 static uint16 BKCOL;
359 
360 //
361 //
362 //
363 static int32 CalcNextEvent(void);
364 
365 static int32 last_ts;
366 
367 static uint32 Column;
368 static int32 ColumnCounter;
369 
370 static int32 DisplayRegion;
371 static bool DisplayFB;
372 
373 static int32 GameFrameCounter;
374 
375 static int32 DrawingCounter;
376 static bool DrawingActive;
377 static bool DrawingFB;
378 static uint32 DrawingBlock;
379 static int32 SB_Latch;
380 static int32 SBOUT_InactiveTime;
381 
382 //static uint8 CTA_L, CTA_R;
383 
CheckIRQ(void)384 static void CheckIRQ(void)
385 {
386  VBIRQ_Assert(VBIRQ_SOURCE_VIP, (bool)(InterruptEnable & InterruptPending));
387 
388  #if 0
389  printf("%08x\n", InterruptEnable & InterruptPending);
390  if((bool)(InterruptEnable & InterruptPending))
391   puts("IRQ asserted");
392  else
393   puts("IRQ not asserted");
394  #endif
395 }
396 
397 
VIP_Init(void)398 void VIP_Init(void)
399 {
400  InstantDisplayHack = false;
401  AllowDrawSkip = false;
402  ParallaxDisabled = false;
403  Anaglyph_Colors[0] = 0xFF0000;
404  Anaglyph_Colors[1] = 0x0000FF;
405  VB3DMode = VB3DMODE_ANAGLYPH;
406  Default_Color = 0xFFFFFF;
407  VB3DReverse = 0;
408  VBPrescale = 1;
409  VBSBS_Separation = 0;
410 
411  VidSettingsDirty = true;
412 }
413 
VIP_Kill(void)414 void VIP_Kill(void)
415 {
416 
417 
418 }
419 
VIP_Power(void)420 void VIP_Power(void)
421 {
422  Repeat = 0;
423  SB_Latch = 0;
424  SBOUT_InactiveTime = -1;
425  last_ts = 0;
426 
427  Column = 0;
428  ColumnCounter = 259;
429 
430  DisplayRegion = 0;
431  DisplayFB = 0;
432 
433  GameFrameCounter = 0;
434 
435  DrawingCounter = 0;
436  DrawingActive = false;
437  DrawingFB = 0;
438  DrawingBlock = 0;
439 
440  DPCTRL = 2;
441  DisplayActive = false;
442 
443 
444 
445  memset(FB, 0, 0x6000 * 2 * 2);
446  memset(CHR_RAM, 0, 0x8000);
447  memset(DRAM, 0, 0x20000);
448 
449  InterruptPending = 0;
450  InterruptEnable = 0;
451 
452  BRTA = 0;
453  BRTB = 0;
454  BRTC = 0;
455  REST = 0;
456 
457  FRMCYC = 0;
458 
459  XPCTRL = 0;
460  SBCMP = 0;
461 
462  for(int i = 0; i < 4; i++)
463  {
464   SPT[i] = 0;
465   GPLT[i] = 0;
466   JPLT[i] = 0;
467 
468   Recalc_GPLT_Cache(i);
469   Recalc_JPLT_Cache(i);
470  }
471 
472  BKCOL = 0;
473 }
474 
ReadRegister(int32 & timestamp,uint32 A)475 static INLINE uint16 ReadRegister(int32 &timestamp, uint32 A)
476 {
477  uint16 ret = 0;	//0xFFFF;
478 
479  if(A & 1)
480   VIP_DBGMSG("Misaligned VIP Read: %08x\n", A);
481 
482  switch(A & 0xFE)
483  {
484   default: VIP_DBGMSG("Unknown VIP register read: %08x\n", A);
485 	   break;
486 
487   case 0x00: ret = InterruptPending;
488 	     break;
489 
490   case 0x02: ret = InterruptEnable;
491 	     break;
492 
493   case 0x20: //printf("Read DPSTTS at %d\n", timestamp);
494 	     ret = DPCTRL & 0x702;
495 	     if((DisplayRegion & 1) && DisplayActive)
496 	     {
497 	      unsigned int DPBSY = 1 << ((DisplayRegion >> 1) & 1);
498 
499 	      if(DisplayFB)
500 	       DPBSY <<= 2;
501 
502 	      ret |= DPBSY << 2;
503 	     }
504 	     //if(!(DisplayRegion & 1))	// FIXME? (Had to do it this way for Galactic Pinball...)
505               ret |= 1 << 6;
506 	     break;
507 
508   // Note: Upper bits of BRTA, BRTB, BRTC, and REST(?) are 0 when read(on real hardware)
509   case 0x24: ret = BRTA;
510              break;
511 
512   case 0x26: ret = BRTB;
513              break;
514 
515   case 0x28: ret = BRTC;
516              break;
517 
518   case 0x2A: ret = REST;
519              break;
520 
521   case 0x30: ret = 0xFFFF;
522 	     break;
523 
524   case 0x40: ret = XPCTRL & 0x2;
525 	     if(DrawingActive)
526 	     {
527 	      ret |= (1 + DrawingFB) << 2;
528 	     }
529 	     if(timestamp < SBOUT_InactiveTime)
530 	     {
531 	      ret |= 0x8000;
532 	      ret |= /*DrawingBlock*/SB_Latch << 8;
533 	     }
534 	     break;     // XPSTTS, read-only
535 
536   case 0x44: ret = 2;	// VIP version.  2 is a known valid version, while the validity of other numbers is unknown, so we'll just go with 2.
537 	     break;
538 
539   case 0x48:
540   case 0x4a:
541   case 0x4c:
542   case 0x4e: ret = SPT[(A >> 1) & 3];
543              break;
544 
545   case 0x60:
546   case 0x62:
547   case 0x64:
548   case 0x66: ret = GPLT[(A >> 1) & 3];
549              break;
550 
551   case 0x68:
552   case 0x6a:
553   case 0x6c:
554   case 0x6e: ret = JPLT[(A >> 1) & 3];
555              break;
556 
557   case 0x70: ret = BKCOL;
558              break;
559  }
560 
561  return(ret);
562 }
563 
WriteRegister(int32 & timestamp,uint32 A,uint16 V)564 static INLINE void WriteRegister(int32 &timestamp, uint32 A, uint16 V)
565 {
566  if(A & 1)
567   VIP_DBGMSG("Misaligned VIP Write: %08x %04x\n", A, V);
568 
569  switch(A & 0xFE)
570  {
571   default: VIP_DBGMSG("Unknown VIP register write: %08x %04x\n", A, V);
572            break;
573 
574   case 0x00: break; // Interrupt pending, read-only
575 
576   case 0x02: {
577 	      InterruptEnable = V & 0xE01F;
578 
579 	      VIP_DBGMSG("Interrupt Enable: %04x\n", V);
580 
581 	      if(V & 0x2000)
582 	       VIP_DBGMSG("Warning: VIP SB Hit Interrupt enable: %04x\n", V);
583 	      CheckIRQ();
584 	     }
585 	     break;
586 
587   case 0x04: InterruptPending &= ~V;
588 	     CheckIRQ();
589 	     break;
590 
591   case 0x20: break; // Display control, read-only.
592 
593   case 0x22: DPCTRL = V & (0x703); // Display-control, write-only
594 	     if(V & 1)
595 	     {
596 	      DisplayActive = false;
597 	      InterruptPending &= ~(INT_TIME_ERR | INT_FRAME_START | INT_GAME_START | INT_RFB_END | INT_LFB_END | INT_SCAN_ERR);
598 	      CheckIRQ();
599 	     }
600 	     break;
601 
602   case 0x24: BRTA = V & 0xFF;	// BRTA
603 	     RecalcBrightnessCache();
604 	     break;
605 
606   case 0x26: BRTB = V & 0xFF;	// BRTB
607 	     RecalcBrightnessCache();
608 	     break;
609 
610   case 0x28: BRTC = V & 0xFF;	// BRTC
611 	     RecalcBrightnessCache();
612 	     break;
613 
614   case 0x2A: REST = V & 0xFF;	// REST
615 	     RecalcBrightnessCache();
616 	     break;
617 
618   case 0x2E: FRMCYC = V & 0xF;	// FRMCYC, write-only?
619 	     break;
620 
621   case 0x30: break;	// CTA, read-only(
622 
623   case 0x40: break;	// XPSTTS, read-only
624 
625   case 0x42: XPCTRL = V & 0x0002;	// XPCTRL, write-only
626 	     SBCMP = (V >> 8) & 0x1F;
627 
628 	     if(V & 1)
629 	     {
630 	      VIP_DBGMSG("XPRST\n");
631 	      DrawingActive = 0;
632 	      DrawingCounter = 0;
633               InterruptPending &= ~(INT_SB_HIT | INT_XP_END | INT_TIME_ERR);
634 	      CheckIRQ();
635 	     }
636 	     break;
637 
638   case 0x44: break;	// Version Control, read-only?
639 
640   case 0x48:
641   case 0x4a:
642   case 0x4c:
643   case 0x4e: SPT[(A >> 1) & 3] = V & 0x3FF;
644 	     break;
645 
646   case 0x60:
647   case 0x62:
648   case 0x64:
649   case 0x66: GPLT[(A >> 1) & 3] = V & 0xFC;
650 	     Recalc_GPLT_Cache((A >> 1) & 3);
651 	     break;
652 
653   case 0x68:
654   case 0x6a:
655   case 0x6c:
656   case 0x6e: JPLT[(A >> 1) & 3] = V & 0xFC;
657              Recalc_JPLT_Cache((A >> 1) & 3);
658              break;
659 
660   case 0x70: BKCOL = V & 0x3;
661 	     break;
662 
663  }
664 }
665 
666 //
667 // Don't update the VIP state on reads/writes, the event system will update it with enough precision as far as VB software cares.
668 //
669 
VIP_Read8(int32 & timestamp,uint32 A)670 MDFN_FASTCALL uint8 VIP_Read8(int32 &timestamp, uint32 A)
671 {
672  uint8 ret = 0; //0xFF;
673 
674  //VIP_Update(timestamp);
675 
676  switch(A >> 16)
677  {
678   case 0x0:
679   case 0x1:
680            if((A & 0x7FFF) >= 0x6000)
681            {
682             ret = ne16_rbo_le<uint8>(CHR_RAM, (A & 0x1FFF) | ((A >> 2) & 0x6000));
683            }
684            else
685            {
686             ret = FB[(A >> 15) & 1][(A >> 16) & 1][A & 0x7FFF];
687            }
688            break;
689 
690   case 0x2:
691   case 0x3: ret = ne16_rbo_le<uint8>(DRAM, A & 0x1FFFF);
692             break;
693 
694   case 0x4:
695   case 0x5: if(A >= 0x5E000)
696 	     ret = ReadRegister(timestamp, A);
697 	    else
698 	     VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
699             break;
700 
701   case 0x6: break;
702 
703   case 0x7: if(A >= 0x8000)
704             {
705              ret = ne16_rbo_le<uint8>(CHR_RAM, A & 0x7FFF);
706             }
707 	    else
708 	     VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
709             break;
710 
711   default: VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
712 	   break;
713  }
714 
715 
716  //VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
717 
718  return(ret);
719 }
720 
VIP_Read16(int32 & timestamp,uint32 A)721 MDFN_FASTCALL uint16 VIP_Read16(int32 &timestamp, uint32 A)
722 {
723  uint16 ret = 0; //0xFFFF;
724 
725  //VIP_Update(timestamp);
726 
727  switch(A >> 16)
728  {
729   case 0x0:
730   case 0x1:
731            if((A & 0x7FFF) >= 0x6000)
732            {
733             ret = ne16_rbo_le<uint16>(CHR_RAM, (A & 0x1FFF) | ((A >> 2) & 0x6000));
734            }
735            else
736            {
737             ret = MDFN_de16lsb<true>(&FB[(A >> 15) & 1][(A >> 16) & 1][A & 0x7FFF]);
738            }
739            break;
740 
741   case 0x2:
742   case 0x3: ret = ne16_rbo_le<uint16>(DRAM, A & 0x1FFFF);
743             break;
744 
745   case 0x4:
746   case 0x5:
747 	    if(A >= 0x5E000)
748 	     ret = ReadRegister(timestamp, A);
749             else
750              VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
751             break;
752 
753   case 0x6: break;
754 
755   case 0x7: if(A >= 0x8000)
756             {
757              ret = ne16_rbo_le<uint16>(CHR_RAM, A & 0x7FFF);
758             }
759 	    else
760 	     VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
761             break;
762 
763   default: VIP_DBGMSG("Unknown VIP Read: %08x\n", A);
764            break;
765  }
766 
767 
768  //VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
769  return(ret);
770 }
771 
VIP_Write8(int32 & timestamp,uint32 A,uint8 V)772 MDFN_FASTCALL void VIP_Write8(int32 &timestamp, uint32 A, uint8 V)
773 {
774  //VIP_Update(timestamp);
775 
776  //if(A >= 0x3DC00 && A < 0x3E000)
777  // printf("%08x %02x\n", A, V);
778 
779  switch(A >> 16)
780  {
781   case 0x0:
782   case 0x1:
783 	   if((A & 0x7FFF) >= 0x6000)
784 	    ne16_wbo_le<uint8>(CHR_RAM, (A & 0x1FFF) | ((A >> 2) & 0x6000), V);
785 	   else
786 	    FB[(A >> 15) & 1][(A >> 16) & 1][A & 0x7FFF] = V;
787 	   break;
788 
789   case 0x2:
790   case 0x3: ne16_wbo_le<uint8>(DRAM, A & 0x1FFFF, V);
791 	    break;
792 
793   case 0x4:
794   case 0x5: if(A >= 0x5E000)
795  	     WriteRegister(timestamp, A, V);
796             else
797              VIP_DBGMSG("Unknown VIP Write: %08x %02x\n", A, V);
798 	    break;
799 
800   case 0x6: VIP_DBGMSG("Unknown VIP Write: %08x %02x\n", A, V);
801 	    break;
802 
803   case 0x7: if(A >= 0x8000)
804 	     ne16_wbo_le<uint8>(CHR_RAM, A & 0x7FFF, V);
805 	    else
806 	     VIP_DBGMSG("Unknown VIP Write: %08x %02x\n", A, V);
807 	    break;
808 
809   default: VIP_DBGMSG("Unknown VIP Write: %08x %02x\n", A, V);
810            break;
811  }
812 
813  //VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
814 }
815 
VIP_Write16(int32 & timestamp,uint32 A,uint16 V)816 MDFN_FASTCALL void VIP_Write16(int32 &timestamp, uint32 A, uint16 V)
817 {
818  //VIP_Update(timestamp);
819 
820  //if(A >= 0x3DC00 && A < 0x3E000)
821  // printf("%08x %04x\n", A, V);
822 
823  switch(A >> 16)
824  {
825   case 0x0:
826   case 0x1:
827            if((A & 0x7FFF) >= 0x6000)
828             ne16_wbo_le<uint16>(CHR_RAM, (A & 0x1FFF) | ((A >> 2) & 0x6000), V);
829            else
830             MDFN_en16lsb<true>(&FB[(A >> 15) & 1][(A >> 16) & 1][A & 0x7FFF], V);
831            break;
832 
833   case 0x2:
834   case 0x3: ne16_wbo_le<uint16>(DRAM, A & 0x1FFFF, V);
835             break;
836 
837   case 0x4:
838   case 0x5: if(A >= 0x5E000)
839  	     WriteRegister(timestamp, A, V);
840             else
841              VIP_DBGMSG("Unknown VIP Write: %08x %04x\n", A, V);
842             break;
843 
844   case 0x6: VIP_DBGMSG("Unknown VIP Write: %08x %04x\n", A, V);
845 	    break;
846 
847   case 0x7: if(A >= 0x8000)
848              ne16_wbo_le<uint16>(CHR_RAM, A & 0x7FFF, V);
849 	    else
850 	     VIP_DBGMSG("Unknown VIP Write: %08x %04x\n", A, V);
851             break;
852 
853   default: VIP_DBGMSG("Unknown VIP Write: %08x %04x\n", A, V);
854            break;
855  }
856 
857 
858  //VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
859 }
860 
861 static MDFN_Surface *surface;
862 static bool skip;
863 
VIP_StartFrame(EmulateSpecStruct * espec)864 void VIP_StartFrame(EmulateSpecStruct *espec)
865 {
866 // puts("Start frame");
867 
868  if(espec->VideoFormatChanged || VidSettingsDirty)
869  {
870   MakeColorLUT(espec->surface->format, espec->CustomPalette, espec->CustomPaletteNumEntries);
871   Recalc3DModeStuff(espec->surface->format.colorspace != MDFN_COLORSPACE_RGB);
872 
873   VidSettingsDirty = false;
874  }
875 
876  espec->DisplayRect.x = 0;
877  espec->DisplayRect.y = 0;
878 
879  switch(VB3DMode)
880  {
881   default:
882 	espec->DisplayRect.w = 384;
883 	espec->DisplayRect.h = 224;
884 	break;
885 
886   case VB3DMODE_VLI:
887 	espec->DisplayRect.w = 768 * VBPrescale;
888 	espec->DisplayRect.h = 224;
889 	break;
890 
891   case VB3DMODE_HLI:
892         espec->DisplayRect.w = 384;
893         espec->DisplayRect.h = 448 * VBPrescale;
894         break;
895 
896   case VB3DMODE_CSCOPE:
897 	espec->DisplayRect.w = 512;
898 	espec->DisplayRect.h = 384;
899 	break;
900 
901   case VB3DMODE_SIDEBYSIDE:
902 	espec->DisplayRect.w = 768 + VBSBS_Separation;
903 	espec->DisplayRect.h = 224;
904 	break;
905  }
906 
907  surface = espec->surface;
908  skip = espec->skip;
909 }
910 
VIP_ResetTS(void)911 void VIP_ResetTS(void)
912 {
913  if(SBOUT_InactiveTime >= 0)
914   SBOUT_InactiveTime -= last_ts;
915  last_ts = 0;
916 }
917 
CalcNextEvent(void)918 static int32 CalcNextEvent(void)
919 {
920  return(ColumnCounter);
921 }
922 
923 #include "vip_draw.inc"
924 
CopyFBColumnToTarget_Anaglyph_BASE(const bool DisplayActive_arg,const int lr)925 static INLINE void CopyFBColumnToTarget_Anaglyph_BASE(const bool DisplayActive_arg, const int lr)
926 {
927      const int fb = DisplayFB;
928      uint32 *target = surface->pixels + Column;
929      const int32 pitch32 = surface->pitch32;
930      const uint8 *fb_source = &FB[fb][lr][64 * Column];
931 
932      for(int y = 56; y; y--)
933      {
934       uint32 source_bits = *fb_source;
935 
936       for(int y_sub = 4; y_sub; y_sub--)
937       {
938        uint32 pixel = BrightCLUT[lr][source_bits & 3];
939 
940        if(!DisplayActive_arg)
941         pixel = 0;
942 
943        if(lr)
944 	*target |= pixel;
945        else
946         *target = pixel;
947 
948        source_bits >>= 2;
949        target += pitch32;
950       }
951       fb_source++;
952      }
953 }
954 
CopyFBColumnToTarget_Anaglyph(void)955 static void CopyFBColumnToTarget_Anaglyph(void)
956 {
957  const int lr = (DisplayRegion & 2) >> 1;
958 
959  if(!DisplayActive)
960  {
961   if(!lr)
962    CopyFBColumnToTarget_Anaglyph_BASE(0, 0);
963   else
964    CopyFBColumnToTarget_Anaglyph_BASE(0, 1);
965  }
966  else
967  {
968   if(!lr)
969    CopyFBColumnToTarget_Anaglyph_BASE(1, 0);
970   else
971    CopyFBColumnToTarget_Anaglyph_BASE(1, 1);
972  }
973 }
974 
975 static uint32 AnaSlowBuf[384][224];
976 
CopyFBColumnToTarget_AnaglyphSlow_BASE(const bool DisplayActive_arg,const int lr)977 static INLINE void CopyFBColumnToTarget_AnaglyphSlow_BASE(const bool DisplayActive_arg, const int lr)
978 {
979      const int fb = DisplayFB;
980      const uint8 *fb_source = &FB[fb][lr][64 * Column];
981 
982      if(!lr)
983      {
984       uint32 *target = AnaSlowBuf[Column];
985 
986       for(int y = 56; y; y--)
987       {
988        uint32 source_bits = *fb_source;
989 
990        for(int y_sub = 4; y_sub; y_sub--)
991        {
992         uint32 pixel = BrightnessCache[source_bits & 3];
993 
994         if(!DisplayActive_arg)
995          pixel = 0;
996 
997         *target = pixel;
998         source_bits >>= 2;
999         target++;
1000        }
1001        fb_source++;
1002       }
1003 
1004      }
1005      else
1006      {
1007       uint32 *target = surface->pixels + Column;
1008       const uint32 *left_src = AnaSlowBuf[Column];
1009       const int32 pitch32 = surface->pitch32;
1010 
1011       for(int y = 56; y; y--)
1012       {
1013        uint32 source_bits = *fb_source;
1014 
1015        for(int y_sub = 4; y_sub; y_sub--)
1016        {
1017         uint32 pixel = AnaSlowColorLUT[*left_src][DisplayActive_arg ? BrightnessCache[source_bits & 3] : 0];
1018 
1019         *target = pixel;
1020 
1021         source_bits >>= 2;
1022         target += pitch32;
1023         left_src++;
1024        }
1025        fb_source++;
1026       }
1027      }
1028 }
1029 
CopyFBColumnToTarget_AnaglyphSlow(void)1030 static void CopyFBColumnToTarget_AnaglyphSlow(void)
1031 {
1032  const int lr = (DisplayRegion & 2) >> 1;
1033 
1034  if(!DisplayActive)
1035  {
1036   if(!lr)
1037    CopyFBColumnToTarget_AnaglyphSlow_BASE(0, 0);
1038   else
1039    CopyFBColumnToTarget_AnaglyphSlow_BASE(0, 1);
1040  }
1041  else
1042  {
1043   if(!lr)
1044    CopyFBColumnToTarget_AnaglyphSlow_BASE(1, 0);
1045   else
1046    CopyFBColumnToTarget_AnaglyphSlow_BASE(1, 1);
1047  }
1048 }
1049 
1050 
CopyFBColumnToTarget_CScope_BASE(const bool DisplayActive_arg,const int lr,const int dest_lr)1051 static void CopyFBColumnToTarget_CScope_BASE(const bool DisplayActive_arg, const int lr, const int dest_lr)
1052 {
1053      const int fb = DisplayFB;
1054      uint32 *target = surface->pixels + (dest_lr ? 512 - 16 - 1 : 16) + (dest_lr ? Column : 383 - Column) * surface->pitch32;
1055      const uint8 *fb_source = &FB[fb][lr][64 * Column];
1056 
1057      for(int y = 56; y; y--)
1058      {
1059       uint32 source_bits = *fb_source;
1060 
1061       for(int y_sub = 4; y_sub; y_sub--)
1062       {
1063        if(DisplayActive_arg)
1064         *target = BrightCLUT[lr][source_bits & 3];
1065        else
1066 	*target = 0;
1067 
1068        source_bits >>= 2;
1069        if(dest_lr)
1070         target--;
1071        else
1072 	target++;
1073       }
1074       fb_source++;
1075      }
1076 }
1077 
CopyFBColumnToTarget_CScope(void)1078 static void CopyFBColumnToTarget_CScope(void)
1079 {
1080  const int lr = (DisplayRegion & 2) >> 1;
1081 
1082  if(!DisplayActive)
1083  {
1084   if(!lr)
1085    CopyFBColumnToTarget_CScope_BASE(0, 0, 0 ^ VB3DReverse);
1086   else
1087    CopyFBColumnToTarget_CScope_BASE(0, 1, 1 ^ VB3DReverse);
1088  }
1089  else
1090  {
1091   if(!lr)
1092    CopyFBColumnToTarget_CScope_BASE(1, 0, 0 ^ VB3DReverse);
1093   else
1094    CopyFBColumnToTarget_CScope_BASE(1, 1, 1 ^ VB3DReverse);
1095  }
1096 }
1097 
CopyFBColumnToTarget_SideBySide_BASE(const bool DisplayActive_arg,const int lr,const int dest_lr)1098 static void CopyFBColumnToTarget_SideBySide_BASE(const bool DisplayActive_arg, const int lr, const int dest_lr)
1099 {
1100      const int fb = DisplayFB;
1101      uint32 *target = surface->pixels + Column + (dest_lr ? (384 + VBSBS_Separation) : 0);
1102      const int32 pitch32 = surface->pitch32;
1103      const uint8 *fb_source = &FB[fb][lr][64 * Column];
1104 
1105      for(int y = 56; y; y--)
1106      {
1107       uint32 source_bits = *fb_source;
1108 
1109       for(int y_sub = 4; y_sub; y_sub--)
1110       {
1111        if(DisplayActive_arg)
1112         *target = BrightCLUT[lr][source_bits & 3];
1113        else
1114 	*target = 0;
1115        source_bits >>= 2;
1116        target += pitch32;
1117       }
1118       fb_source++;
1119      }
1120 }
1121 
CopyFBColumnToTarget_SideBySide(void)1122 static void CopyFBColumnToTarget_SideBySide(void)
1123 {
1124  const int lr = (DisplayRegion & 2) >> 1;
1125 
1126  if(!DisplayActive)
1127  {
1128   if(!lr)
1129    CopyFBColumnToTarget_SideBySide_BASE(0, 0, 0 ^ VB3DReverse);
1130   else
1131    CopyFBColumnToTarget_SideBySide_BASE(0, 1, 1 ^ VB3DReverse);
1132  }
1133  else
1134  {
1135   if(!lr)
1136    CopyFBColumnToTarget_SideBySide_BASE(1, 0, 0 ^ VB3DReverse);
1137   else
1138    CopyFBColumnToTarget_SideBySide_BASE(1, 1, 1 ^ VB3DReverse);
1139  }
1140 }
1141 
CopyFBColumnToTarget_VLI_BASE(const bool DisplayActive_arg,const int lr,const int dest_lr)1142 static INLINE void CopyFBColumnToTarget_VLI_BASE(const bool DisplayActive_arg, const int lr, const int dest_lr)
1143 {
1144      const int fb = DisplayFB;
1145      uint32 *target = surface->pixels + Column * 2 * VBPrescale + dest_lr;
1146      const int32 pitch32 = surface->pitch32;
1147      const uint8 *fb_source = &FB[fb][lr][64 * Column];
1148 
1149      for(int y = 56; y; y--)
1150      {
1151       uint32 source_bits = *fb_source;
1152 
1153       for(int y_sub = 4; y_sub; y_sub--)
1154       {
1155        uint32 tv;
1156 
1157        if(DisplayActive_arg)
1158         tv = BrightCLUT[lr][source_bits & 3];
1159        else
1160         tv = 0;
1161 
1162        for(uint32 ps = 0; ps < VBPrescale; ps++)
1163 	target[ps * 2] = tv;
1164 
1165        source_bits >>= 2;
1166        target += pitch32;
1167       }
1168       fb_source++;
1169      }
1170 }
1171 
CopyFBColumnToTarget_VLI(void)1172 static void CopyFBColumnToTarget_VLI(void)
1173 {
1174  const int lr = (DisplayRegion & 2) >> 1;
1175 
1176  if(!DisplayActive)
1177  {
1178   if(!lr)
1179    CopyFBColumnToTarget_VLI_BASE(0, 0, 0 ^ VB3DReverse);
1180   else
1181    CopyFBColumnToTarget_VLI_BASE(0, 1, 1 ^ VB3DReverse);
1182  }
1183  else
1184  {
1185   if(!lr)
1186    CopyFBColumnToTarget_VLI_BASE(1, 0, 0 ^ VB3DReverse);
1187   else
1188    CopyFBColumnToTarget_VLI_BASE(1, 1, 1 ^ VB3DReverse);
1189  }
1190 }
1191 
CopyFBColumnToTarget_HLI_BASE(const bool DisplayActive_arg,const int lr,const int dest_lr)1192 static INLINE void CopyFBColumnToTarget_HLI_BASE(const bool DisplayActive_arg, const int lr, const int dest_lr)
1193 {
1194      const int fb = DisplayFB;
1195      const int32 pitch32 = surface->pitch32;
1196      uint32 *target = surface->pixels + Column + dest_lr * pitch32;
1197      const uint8 *fb_source = &FB[fb][lr][64 * Column];
1198 
1199 if(VBPrescale <= 4)
1200      for(int y = 56; y; y--)
1201      {
1202       uint32 source_bits = HLILUT[*fb_source];
1203 
1204       for(int y_sub = 4 * VBPrescale; y_sub; y_sub--)
1205       {
1206        if(DisplayActive_arg)
1207         *target = BrightCLUT[lr][source_bits & 3];
1208        else
1209         *target = 0;
1210 
1211        target += pitch32 * 2;
1212        source_bits >>= 2;
1213       }
1214       fb_source++;
1215      }
1216 else
1217      for(int y = 56; y; y--)
1218      {
1219       uint32 source_bits = *fb_source;
1220 
1221       for(int y_sub = 4; y_sub; y_sub--)
1222       {
1223        for(uint32 ps = 0; ps < VBPrescale; ps++)
1224        {
1225         if(DisplayActive_arg)
1226          *target = BrightCLUT[lr][source_bits & 3];
1227         else
1228          *target = 0;
1229 
1230         target += pitch32 * 2;
1231        }
1232 
1233        source_bits >>= 2;
1234       }
1235       fb_source++;
1236      }
1237 }
1238 
CopyFBColumnToTarget_HLI(void)1239 static void CopyFBColumnToTarget_HLI(void)
1240 {
1241  const int lr = (DisplayRegion & 2) >> 1;
1242 
1243  if(!DisplayActive)
1244  {
1245   if(!lr)
1246    CopyFBColumnToTarget_HLI_BASE(0, 0, 0 ^ VB3DReverse);
1247   else
1248    CopyFBColumnToTarget_HLI_BASE(0, 1, 1 ^ VB3DReverse);
1249  }
1250  else
1251  {
1252   if(!lr)
1253    CopyFBColumnToTarget_HLI_BASE(1, 0, 0 ^ VB3DReverse);
1254   else
1255    CopyFBColumnToTarget_HLI_BASE(1, 1, 1 ^ VB3DReverse);
1256  }
1257 }
1258 
1259 
VIP_Update(const v810_timestamp_t timestamp)1260 v810_timestamp_t MDFN_FASTCALL VIP_Update(const v810_timestamp_t timestamp)
1261 {
1262  int32 clocks = timestamp - last_ts;
1263  int32 running_timestamp = timestamp;
1264 
1265  while(clocks > 0)
1266  {
1267   int32 chunk_clocks = clocks;
1268 
1269   if(DrawingCounter > 0 && chunk_clocks > DrawingCounter)
1270    chunk_clocks = DrawingCounter;
1271   if(chunk_clocks > ColumnCounter)
1272    chunk_clocks = ColumnCounter;
1273 
1274   running_timestamp += chunk_clocks;
1275 
1276   if(DrawingCounter > 0)
1277   {
1278    DrawingCounter -= chunk_clocks;
1279    if(DrawingCounter <= 0)
1280    {
1281     alignas(8) uint8 DrawingBuffers[2][512 * 8];	// Don't decrease this from 512 unless you adjust vip_draw.inc(including areas that draw off-visible >= 384 and >= -7 for speed reasons)
1282 
1283     if(skip && InstantDisplayHack && AllowDrawSkip)
1284     {
1285 #if 0
1286      for(int lr = 0; lr < 2; lr++)
1287      {
1288       uint8 *FB_Target = FB[DrawingFB][lr] + DrawingBlock * 2;
1289       for(int x = 0; x < 384; x++)
1290       {
1291        FB_Target[64 * x + 0] = BKCOL;
1292        FB_Target[64 * x + 1] = BKCOL;
1293       }
1294      }
1295 #endif
1296     }
1297     else
1298     {
1299      VIP_DrawBlock(DrawingBlock, DrawingBuffers[0] + 8, DrawingBuffers[1] + 8);
1300 
1301      for(int lr = 0; lr < 2; lr++)
1302      {
1303       uint8 *FB_Target = FB[DrawingFB][lr] + DrawingBlock * 2;
1304 
1305       for(int x = 0; x < 384; x++)
1306       {
1307        FB_Target[64 * x + 0] = (DrawingBuffers[lr][8 + x + 512 * 0] << 0)
1308 				  | (DrawingBuffers[lr][8 + x + 512 * 1] << 2)
1309 				  | (DrawingBuffers[lr][8 + x + 512 * 2] << 4)
1310 				  | (DrawingBuffers[lr][8 + x + 512 * 3] << 6);
1311 
1312        FB_Target[64 * x + 1] = (DrawingBuffers[lr][8 + x + 512 * 4] << 0)
1313                                   | (DrawingBuffers[lr][8 + x + 512 * 5] << 2)
1314                                   | (DrawingBuffers[lr][8 + x + 512 * 6] << 4)
1315                                   | (DrawingBuffers[lr][8 + x + 512 * 7] << 6);
1316 
1317       }
1318      }
1319     }
1320 
1321     SBOUT_InactiveTime = running_timestamp + 1120;
1322     SB_Latch = DrawingBlock;	// Not exactly correct, but probably doesn't matter.
1323 
1324     DrawingBlock++;
1325     if(DrawingBlock == 28)
1326     {
1327      DrawingActive = false;
1328 
1329      InterruptPending |= INT_XP_END;
1330      CheckIRQ();
1331     }
1332     else
1333      DrawingCounter += 1120 * 4;
1334    }
1335   }
1336 
1337   ColumnCounter -= chunk_clocks;
1338   if(ColumnCounter == 0)
1339   {
1340    if(DisplayRegion & 1)
1341    {
1342     if(!(Column & 3))
1343     {
1344      const int lr = (DisplayRegion & 2) >> 1;
1345      uint16 ctdata = ne16_rbo_le<uint16>(DRAM, 0x1DFFE - ((Column >> 2) * 2) - (lr ? 0 : 0x200));
1346 
1347      //printf("%02x, repeat: %02x\n", ctdata & 0xFF, ctdata >> 8);
1348 
1349      if((ctdata >> 8) != Repeat)
1350      {
1351       Repeat = ctdata >> 8;
1352       RecalcBrightnessCache();
1353      }
1354     }
1355     if(!skip && !InstantDisplayHack)
1356      CopyFBColumnToTarget();
1357    }
1358 
1359    ColumnCounter = 259;
1360    Column++;
1361    if(Column == 384)
1362    {
1363     Column = 0;
1364 
1365     if(DisplayActive)
1366     {
1367      if(DisplayRegion & 1)	// Did we just finish displaying an active region?
1368      {
1369       if(DisplayRegion & 2)	// finished displaying right eye
1370        InterruptPending |= INT_RFB_END;
1371       else		// Otherwise, left eye
1372        InterruptPending |= INT_LFB_END;
1373 
1374       CheckIRQ();
1375      }
1376     }
1377 
1378     DisplayRegion = (DisplayRegion + 1) & 3;
1379 
1380     if(DisplayRegion == 0)	// New frame start
1381     {
1382      DisplayActive = DPCTRL & 0x2;
1383 
1384      if(DisplayActive)
1385      {
1386       InterruptPending |= INT_FRAME_START;
1387       CheckIRQ();
1388      }
1389      GameFrameCounter++;
1390      if(GameFrameCounter > FRMCYC) // New game frame start?
1391      {
1392       InterruptPending |= INT_GAME_START;
1393       CheckIRQ();
1394 
1395       if(XPCTRL & XPCTRL_XP_EN)
1396       {
1397        DisplayFB ^= 1;
1398 
1399        DrawingBlock = 0;
1400        DrawingActive = true;
1401        DrawingCounter = 1120 * 4;
1402        DrawingFB = DisplayFB ^ 1;
1403       }
1404 
1405       GameFrameCounter = 0;
1406      }
1407 
1408      if(!skip && InstantDisplayHack)
1409      {
1410 	// Ugly kludge, fix in the future.
1411 	int32 save_DisplayRegion = DisplayRegion;
1412 	uint32 save_Column = Column;
1413 	uint8 save_Repeat = Repeat;
1414 
1415 	for(int lr = 0; lr < 2; lr++)
1416 	{
1417 	 DisplayRegion = lr << 1;
1418 	 for(Column = 0; Column < 384; Column++)
1419 	 {
1420 	  if(!(Column & 3))
1421 	  {
1422 	   uint16 ctdata = ne16_rbo_le<uint16>(DRAM, 0x1DFFE - ((Column >> 2) * 2) - (lr ? 0 : 0x200));
1423 
1424 	   if((ctdata >> 8) != Repeat)
1425 	   {
1426 	    Repeat = ctdata >> 8;
1427 	    RecalcBrightnessCache();
1428 	   }
1429 	  }
1430 
1431           CopyFBColumnToTarget();
1432 	 }
1433 	}
1434 	DisplayRegion = save_DisplayRegion;
1435 	Column = save_Column;
1436 	Repeat = save_Repeat;
1437 	RecalcBrightnessCache();
1438      }
1439 
1440      VB_ExitLoop();
1441     }
1442    }
1443   }
1444 
1445   clocks -= chunk_clocks;
1446  }
1447 
1448  last_ts = timestamp;
1449 
1450  return(timestamp + CalcNextEvent());
1451 }
1452 
1453 
VIP_StateAction(StateMem * sm,const unsigned load,const bool data_only)1454 void VIP_StateAction(StateMem *sm, const unsigned load, const bool data_only)
1455 {
1456  SFORMAT StateRegs[] =
1457  {
1458   SFVARN(FB, "FB[0][0]"),
1459   SFVAR(CHR_RAM),
1460   SFVAR(DRAM),
1461 
1462   SFVAR(InterruptPending),
1463   SFVAR(InterruptEnable),
1464 
1465   SFVAR(BRTA),
1466   SFVAR(BRTB),
1467   SFVAR(BRTC),
1468   SFVAR(REST),
1469 
1470   SFVAR(FRMCYC),
1471   SFVAR(DPCTRL),
1472 
1473   SFVAR(DisplayActive),
1474 
1475   SFVAR(XPCTRL),
1476   SFVAR(SBCMP),
1477   SFVAR(SPT),
1478   SFVAR(GPLT),	// FIXME
1479   SFVAR(JPLT),
1480 
1481   SFVAR(BKCOL),
1482 
1483   SFVAR(Column),
1484   SFVAR(ColumnCounter),
1485 
1486   SFVAR(DisplayRegion),
1487   SFVAR(DisplayFB),
1488 
1489   SFVAR(GameFrameCounter),
1490 
1491   SFVAR(DrawingCounter),
1492 
1493   SFVAR(DrawingActive),
1494   SFVAR(DrawingFB),
1495   SFVAR(DrawingBlock),
1496 
1497   SFVAR(SB_Latch),
1498   SFVAR(SBOUT_InactiveTime),
1499 
1500   SFVAR(Repeat),
1501   SFEND
1502  };
1503 
1504  MDFNSS_StateAction(sm, load, data_only, StateRegs, "VIP");
1505 
1506  if(load)
1507  {
1508   Column %= 384;
1509 
1510   if(ColumnCounter < 1)
1511    ColumnCounter = 1;
1512   else if(ColumnCounter > 1000)
1513    ColumnCounter = 1000;
1514 
1515   //
1516   //
1517   //
1518   RecalcBrightnessCache();
1519   for(int i = 0; i < 4; i++)
1520   {
1521    Recalc_GPLT_Cache(i);
1522    Recalc_JPLT_Cache(i);
1523   }
1524  }
1525 }
1526 
VIP_GetRegister(const unsigned int id,char * special,const uint32 special_len)1527 uint32 VIP_GetRegister(const unsigned int id, char *special, const uint32 special_len)
1528 {
1529  uint32 ret = 0xDEADBEEF;
1530 
1531  switch(id)
1532  {
1533   case VIP_GSREG_IPENDING:
1534 	ret = InterruptPending;
1535 	break;
1536 
1537   case VIP_GSREG_IENABLE:
1538 	ret = InterruptEnable;
1539 	break;
1540 
1541   case VIP_GSREG_DPCTRL:
1542 	ret = DPCTRL;
1543 	break;
1544 
1545   case VIP_GSREG_BRTA:
1546 	ret = BRTA;
1547 	break;
1548 
1549   case VIP_GSREG_BRTB:
1550 	ret = BRTB;
1551 	break;
1552 
1553   case VIP_GSREG_BRTC:
1554 	ret = BRTC;
1555 	break;
1556 
1557   case VIP_GSREG_REST:
1558 	ret = REST;
1559 	break;
1560 
1561   case VIP_GSREG_FRMCYC:
1562 	ret = FRMCYC;
1563 	break;
1564 
1565   case VIP_GSREG_XPCTRL:
1566 	ret = XPCTRL | (SBCMP << 8);
1567 	break;
1568 
1569   case VIP_GSREG_SPT0:
1570   case VIP_GSREG_SPT1:
1571   case VIP_GSREG_SPT2:
1572   case VIP_GSREG_SPT3:
1573 	ret = SPT[id - VIP_GSREG_SPT0];
1574 	break;
1575 
1576   case VIP_GSREG_GPLT0:
1577   case VIP_GSREG_GPLT1:
1578   case VIP_GSREG_GPLT2:
1579   case VIP_GSREG_GPLT3:
1580 	ret = GPLT[id - VIP_GSREG_GPLT0];
1581 	break;
1582 
1583   case VIP_GSREG_JPLT0:
1584   case VIP_GSREG_JPLT1:
1585   case VIP_GSREG_JPLT2:
1586   case VIP_GSREG_JPLT3:
1587 	ret = JPLT[id - VIP_GSREG_JPLT0];
1588 	break;
1589 
1590   case VIP_GSREG_BKCOL:
1591 	ret = BKCOL;
1592 	break;
1593 
1594  }
1595 
1596  if(id == VIP_GSREG_IPENDING || id == VIP_GSREG_IENABLE)
1597  {
1598         if(special)
1599          trio_snprintf(special, special_len, "%s: %s%s%s%s%s%s%s%s",
1600 		(id == VIP_GSREG_IPENDING) ? "Interrupts Pending" : "Interrupts Enabled",
1601                 (ret & INT_SCAN_ERR) ? "SCAN_ERR " : "",
1602                 (ret & INT_LFB_END) ? "LFB_END " : "",
1603                 (ret & INT_RFB_END) ? "RFB_END " : "",
1604                 (ret & INT_GAME_START) ? "GAME_START " : "",
1605                 (ret & INT_FRAME_START) ? "FRAME_START " : "",
1606                 (ret & INT_SB_HIT) ? "SB_HIT " : "",
1607                 (ret & INT_XP_END) ? "XP_END " : "",
1608                 (ret & INT_TIME_ERR) ? "TIME_ERR " : "");
1609 
1610  }
1611 
1612  return(ret);
1613 }
1614 
VIP_SetRegister(const unsigned int id,const uint32 value)1615 void VIP_SetRegister(const unsigned int id, const uint32 value)
1616 {
1617  switch(id)
1618  {
1619   case VIP_GSREG_IPENDING:
1620         InterruptPending = value & 0xE01F;
1621 	CheckIRQ();
1622         break;
1623 
1624   case VIP_GSREG_IENABLE:
1625         InterruptEnable = value & 0xE01F;
1626 	CheckIRQ();
1627         break;
1628 
1629   case VIP_GSREG_DPCTRL:
1630 	DPCTRL = value & 0x703;	// FIXME(Lower bit?)
1631         break;
1632 
1633   case VIP_GSREG_BRTA:
1634         BRTA = value & 0xFF;
1635         RecalcBrightnessCache();
1636         break;
1637 
1638   case VIP_GSREG_BRTB:
1639         BRTB = value & 0xFF;
1640         RecalcBrightnessCache();
1641         break;
1642 
1643   case VIP_GSREG_BRTC:
1644         BRTC = value & 0xFF;
1645         RecalcBrightnessCache();
1646         break;
1647 
1648   case VIP_GSREG_REST:
1649         REST = value & 0xFF;
1650         RecalcBrightnessCache();
1651         break;
1652 
1653   case VIP_GSREG_FRMCYC:
1654         FRMCYC = value & 0xF;
1655         break;
1656 
1657   case VIP_GSREG_XPCTRL:
1658 	XPCTRL = value & 0x2;
1659 	SBCMP = (value >> 8) & 0x1f;
1660         break;
1661 
1662   case VIP_GSREG_SPT0:
1663   case VIP_GSREG_SPT1:
1664   case VIP_GSREG_SPT2:
1665   case VIP_GSREG_SPT3:
1666         SPT[id - VIP_GSREG_SPT0] = value & 0x3FF;
1667         break;
1668 
1669   case VIP_GSREG_GPLT0:
1670   case VIP_GSREG_GPLT1:
1671   case VIP_GSREG_GPLT2:
1672   case VIP_GSREG_GPLT3:
1673         GPLT[id - VIP_GSREG_GPLT0] = value & 0xFC;
1674 	Recalc_GPLT_Cache(id - VIP_GSREG_GPLT0);
1675         break;
1676 
1677   case VIP_GSREG_JPLT0:
1678   case VIP_GSREG_JPLT1:
1679   case VIP_GSREG_JPLT2:
1680   case VIP_GSREG_JPLT3:
1681         JPLT[id - VIP_GSREG_JPLT0] = value & 0xFC;
1682 	Recalc_JPLT_Cache(id - VIP_GSREG_JPLT0);
1683         break;
1684 
1685   case VIP_GSREG_BKCOL:
1686         BKCOL = value & 0x03;
1687         break;
1688  }
1689 }
1690 
1691 
1692 }
1693