2017-06-17 14:07:02 +00:00
/******************************************************************************/
/* Mednafen Virtual Boy Emulation Module */
/******************************************************************************/
/* vip.cpp:
* * Copyright ( C ) 2010 - 2016 Mednafen Team
* *
* * This program is free software ; you can redistribute it and / or
* * modify it under the terms of the GNU General Public License
* * as published by the Free Software Foundation ; either version 2
* * of the License , or ( at your option ) any later version .
* *
* * This program is distributed in the hope that it will be useful ,
* * but WITHOUT ANY WARRANTY ; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* * GNU General Public License for more details .
* *
* * You should have received a copy of the GNU General Public License
* * along with this program ; if not , write to the Free Software Foundation , Inc . ,
* * 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
# include "vb.h"
# include <cmath>
2017-07-20 21:22:40 +00:00
# include "../emulibc/emulibc.h"
2017-06-17 14:07:02 +00:00
# define VIP_DBGMSG(format, ...) \
{ \
}
//#define VIP_DBGMSG(format, ...) printf(format "\n", ## __VA_ARGS__)
namespace MDFN_IEN_VB
{
static uint8 FB [ 2 ] [ 2 ] [ 0x6000 ] ;
static uint16 CHR_RAM [ 0x8000 / sizeof ( uint16 ) ] ;
static uint16 DRAM [ 0x20000 / sizeof ( uint16 ) ] ;
# define INT_SCAN_ERR 0x0001
# define INT_LFB_END 0x0002
# define INT_RFB_END 0x0004
# define INT_GAME_START 0x0008
# define INT_FRAME_START 0x0010
# define INT_SB_HIT 0x2000
# define INT_XP_END 0x4000
# define INT_TIME_ERR 0x8000
static uint16 InterruptPending ;
static uint16 InterruptEnable ;
static uint8 BRTA , BRTB , BRTC , REST ;
static uint8 Repeat ;
static void CopyFBColumnToTarget_Anaglyph ( void ) NO_INLINE ;
static void CopyFBColumnToTarget_AnaglyphSlow ( void ) NO_INLINE ;
static void CopyFBColumnToTarget_CScope ( void ) NO_INLINE ;
static void CopyFBColumnToTarget_SideBySide ( void ) NO_INLINE ;
static void CopyFBColumnToTarget_VLI ( void ) NO_INLINE ;
static void CopyFBColumnToTarget_HLI ( void ) NO_INLINE ;
static void ( * CopyFBColumnToTarget ) ( void ) = NULL ;
static float VBLEDOnScale ;
static uint32 VB3DMode ;
static uint32 VB3DReverse ;
static uint32 VBPrescale ;
static uint32 VBSBS_Separation ;
static uint32 HLILUT [ 256 ] ;
static uint32 ColorLUT [ 2 ] [ 256 ] ;
static int32 BrightnessCache [ 4 ] ;
static uint32 BrightCLUT [ 2 ] [ 4 ] ;
2017-07-20 21:22:40 +00:00
static float ECL_INVISIBLE ColorLUTNoGC [ 2 ] [ 256 ] [ 3 ] ;
static uint32 ECL_INVISIBLE AnaSlowColorLUT [ 256 ] [ 256 ] ;
2017-06-17 14:07:02 +00:00
static bool VidSettingsDirty ;
static bool ParallaxDisabled ;
static uint32 Anaglyph_Colors [ 2 ] ;
static uint32 Default_Color ;
static void MakeColorLUT ( )
{
for ( int lr = 0 ; lr < 2 ; lr + + )
{
for ( int i = 0 ; i < 256 ; i + + )
{
float r , g , b ;
uint32 modcolor_prime ;
if ( VB3DMode = = VB3DMODE_ANAGLYPH )
modcolor_prime = Anaglyph_Colors [ lr ^ VB3DReverse ] ;
else
modcolor_prime = Default_Color ;
r = g = b = std : : min < float > ( 1.0 , i * VBLEDOnScale / 255.0 ) ;
// Modulate.
r = r * pow ( ( ( modcolor_prime > > 16 ) & 0xFF ) / 255.0 , 2.2 / 1.0 ) ;
g = g * pow ( ( ( modcolor_prime > > 8 ) & 0xFF ) / 255.0 , 2.2 / 1.0 ) ;
b = b * pow ( ( ( modcolor_prime > > 0 ) & 0xFF ) / 255.0 , 2.2 / 1.0 ) ;
ColorLUTNoGC [ lr ] [ i ] [ 0 ] = r ;
ColorLUTNoGC [ lr ] [ i ] [ 1 ] = g ;
ColorLUTNoGC [ lr ] [ i ] [ 2 ] = b ;
// Apply gamma correction
const float r_prime = pow ( r , 1.0 / 2.2 ) ;
const float g_prime = pow ( g , 1.0 / 2.2 ) ;
const float b_prime = pow ( b , 1.0 / 2.2 ) ;
ColorLUT [ lr ] [ i ] = ( int ) ( b_prime * 255 ) & 0xff | ( int ) ( g_prime * 255 ) < < 8 & 0xff00 | ( int ) ( r_prime * 255 ) < < 16 & 0xff0000 | 0xff000000 ;
}
}
// Anaglyph slow-mode LUT calculation
for ( int l_b = 0 ; l_b < 256 ; l_b + + )
{
for ( int r_b = 0 ; r_b < 256 ; r_b + + )
{
float r , g , b ;
float r_prime , g_prime , b_prime ;
r = ColorLUTNoGC [ 0 ] [ l_b ] [ 0 ] + ColorLUTNoGC [ 1 ] [ r_b ] [ 0 ] ;
g = ColorLUTNoGC [ 0 ] [ l_b ] [ 1 ] + ColorLUTNoGC [ 1 ] [ r_b ] [ 1 ] ;
b = ColorLUTNoGC [ 0 ] [ l_b ] [ 2 ] + ColorLUTNoGC [ 1 ] [ r_b ] [ 2 ] ;
if ( r > 1.0 )
r = 1.0 ;
if ( g > 1.0 )
g = 1.0 ;
if ( b > 1.0 )
b = 1.0 ;
r_prime = pow ( r , 1.0 / 2.2 ) ;
g_prime = pow ( g , 1.0 / 2.2 ) ;
b_prime = pow ( b , 1.0 / 2.2 ) ;
AnaSlowColorLUT [ l_b ] [ r_b ] = ( int ) ( b_prime * 255 ) & 0xff | ( int ) ( g_prime * 255 ) < < 8 & 0xff00 | ( int ) ( r_prime * 255 ) < < 16 & 0xff0000 | 0xff000000 ;
}
}
}
static void RecalcBrightnessCache ( void )
{
static const int32 MaxTime = 255 ;
int32 CumulativeTime = ( BRTA + 1 + BRTB + 1 + BRTC + 1 + REST + 1 ) + 1 ;
//printf("BRTA: %d, BRTB: %d, BRTC: %d, Rest: %d --- %d\n", BRTA, BRTB, BRTC, REST, BRTA + 1 + BRTB + 1 + BRTC);
BrightnessCache [ 0 ] = 0 ;
BrightnessCache [ 1 ] = 0 ;
BrightnessCache [ 2 ] = 0 ;
BrightnessCache [ 3 ] = 0 ;
for ( int i = 0 ; i < Repeat + 1 ; i + + )
{
int32 btemp [ 4 ] ;
if ( ( i * CumulativeTime ) > = MaxTime )
break ;
btemp [ 1 ] = ( i * CumulativeTime ) + BRTA ;
if ( btemp [ 1 ] > MaxTime )
btemp [ 1 ] = MaxTime ;
btemp [ 1 ] - = ( i * CumulativeTime ) ;
if ( btemp [ 1 ] < 0 )
btemp [ 1 ] = 0 ;
btemp [ 2 ] = ( i * CumulativeTime ) + BRTA + 1 + BRTB ;
if ( btemp [ 2 ] > MaxTime )
btemp [ 2 ] = MaxTime ;
btemp [ 2 ] - = ( i * CumulativeTime ) + BRTA + 1 ;
if ( btemp [ 2 ] < 0 )
btemp [ 2 ] = 0 ;
//btemp[3] = (i * CumulativeTime) + BRTA + 1 + BRTB + 1 + BRTC;
//if(btemp[3] > MaxTime)
// btemp[3] = MaxTime;
//btemp[3] -= (i * CumulativeTime);
//if(btemp[3] < 0)
// btemp[3] = 0;
btemp [ 3 ] = ( i * CumulativeTime ) + BRTA + BRTB + BRTC + 1 ;
if ( btemp [ 3 ] > MaxTime )
btemp [ 3 ] = MaxTime ;
btemp [ 3 ] - = ( i * CumulativeTime ) + 1 ;
if ( btemp [ 3 ] < 0 )
btemp [ 3 ] = 0 ;
BrightnessCache [ 1 ] + = btemp [ 1 ] ;
BrightnessCache [ 2 ] + = btemp [ 2 ] ;
BrightnessCache [ 3 ] + = btemp [ 3 ] ;
}
//printf("BC: %d %d %d %d\n", BrightnessCache[0], BrightnessCache[1], BrightnessCache[2], BrightnessCache[3]);
for ( int lr = 0 ; lr < 2 ; lr + + )
for ( int i = 0 ; i < 4 ; i + + )
{
BrightCLUT [ lr ] [ i ] = ColorLUT [ lr ] [ BrightnessCache [ i ] ] ;
//printf("%d %d, %08x\n", lr, i, BrightCLUT[lr][i]);
}
}
static void Recalc3DModeStuff ( bool non_rgb_output = false )
{
switch ( VB3DMode )
{
default :
if ( ( ( Anaglyph_Colors [ 0 ] & 0xFF ) & & ( Anaglyph_Colors [ 1 ] & 0xFF ) ) | |
( ( Anaglyph_Colors [ 0 ] & 0xFF00 ) & & ( Anaglyph_Colors [ 1 ] & 0xFF00 ) ) | |
( ( Anaglyph_Colors [ 0 ] & 0xFF0000 ) & & ( Anaglyph_Colors [ 1 ] & 0xFF0000 ) ) | |
non_rgb_output )
{
CopyFBColumnToTarget = CopyFBColumnToTarget_AnaglyphSlow ;
}
else
CopyFBColumnToTarget = CopyFBColumnToTarget_Anaglyph ;
break ;
case VB3DMODE_CSCOPE :
CopyFBColumnToTarget = CopyFBColumnToTarget_CScope ;
break ;
case VB3DMODE_SIDEBYSIDE :
CopyFBColumnToTarget = CopyFBColumnToTarget_SideBySide ;
break ;
case VB3DMODE_VLI :
CopyFBColumnToTarget = CopyFBColumnToTarget_VLI ;
break ;
case VB3DMODE_HLI :
CopyFBColumnToTarget = CopyFBColumnToTarget_HLI ;
break ;
}
RecalcBrightnessCache ( ) ;
}
void VIP_Set3DMode ( uint32 mode , bool reverse , uint32 prescale , uint32 sbs_separation )
{
VB3DMode = mode ;
VB3DReverse = reverse ? 1 : 0 ;
VBPrescale = prescale ;
VBSBS_Separation = sbs_separation ;
VidSettingsDirty = true ;
for ( uint32 p = 0 ; p < 256 ; p + + )
{
uint32 v ;
uint8 s [ 4 ] ;
s [ 0 ] = ( p > > 0 ) & 0x3 ;
s [ 1 ] = ( p > > 2 ) & 0x3 ;
s [ 2 ] = ( p > > 4 ) & 0x3 ;
s [ 3 ] = ( p > > 6 ) & 0x3 ;
v = 0 ;
for ( unsigned int i = 0 , shifty = 0 ; i < 4 ; i + + )
{
for ( unsigned int ps = 0 ; ps < prescale ; ps + + )
{
v | = s [ i ] < < shifty ;
shifty + = 2 ;
}
}
HLILUT [ p ] = v ;
}
}
void VIP_SetParallaxDisable ( bool disabled )
{
ParallaxDisabled = disabled ;
}
void VIP_SetDefaultColor ( uint32 default_color )
{
Default_Color = default_color ;
VidSettingsDirty = true ;
}
void VIP_SetLEDOnScale ( float coeff )
{
VBLEDOnScale = coeff ;
}
void VIP_SetAnaglyphColors ( uint32 lcolor , uint32 rcolor )
{
Anaglyph_Colors [ 0 ] = lcolor ;
Anaglyph_Colors [ 1 ] = rcolor ;
VidSettingsDirty = true ;
}
static uint16 FRMCYC ;
static uint16 DPCTRL ;
static bool DisplayActive ;
# define XPCTRL_XP_RST 0x0001
# define XPCTRL_XP_EN 0x0002
static uint16 XPCTRL ;
static uint16 SBCMP ; // Derived from XPCTRL
static uint16 SPT [ 4 ] ; // SPT0~SPT3, 5f848~5f84e
static uint16 GPLT [ 4 ] ;
static uint8 GPLT_Cache [ 4 ] [ 4 ] ;
static INLINE void Recalc_GPLT_Cache ( int which )
{
for ( int i = 0 ; i < 4 ; i + + )
GPLT_Cache [ which ] [ i ] = ( GPLT [ which ] > > ( i * 2 ) ) & 3 ;
}
static uint16 JPLT [ 4 ] ;
static uint8 JPLT_Cache [ 4 ] [ 4 ] ;
static INLINE void Recalc_JPLT_Cache ( int which )
{
for ( int i = 0 ; i < 4 ; i + + )
JPLT_Cache [ which ] [ i ] = ( JPLT [ which ] > > ( i * 2 ) ) & 3 ;
}
static uint16 BKCOL ;
//
//
//
static int32 CalcNextEvent ( void ) ;
static int32 last_ts ;
static uint32 Column ;
static int32 ColumnCounter ;
static int32 DisplayRegion ;
static bool DisplayFB ;
static int32 GameFrameCounter ;
static int32 DrawingCounter ;
static bool DrawingActive ;
static bool DrawingFB ;
static uint32 DrawingBlock ;
static int32 SB_Latch ;
static int32 SBOUT_InactiveTime ;
//static uint8 CTA_L, CTA_R;
static void CheckIRQ ( void )
{
VBIRQ_Assert ( VBIRQ_SOURCE_VIP , ( bool ) ( InterruptEnable & InterruptPending ) ) ;
#if 0
printf ( " %08x \n " , InterruptEnable & InterruptPending ) ;
if ( ( bool ) ( InterruptEnable & InterruptPending ) )
puts ( " IRQ asserted " ) ;
else
puts ( " IRQ not asserted " ) ;
# endif
}
void VIP_Init ( void )
{
ParallaxDisabled = false ;
Anaglyph_Colors [ 0 ] = 0xFF0000 ;
Anaglyph_Colors [ 1 ] = 0x0000FF ;
VB3DMode = VB3DMODE_ANAGLYPH ;
Default_Color = 0xFFFFFF ;
VB3DReverse = 0 ;
VBPrescale = 1 ;
VBSBS_Separation = 0 ;
VidSettingsDirty = true ;
}
void VIP_Power ( void )
{
Repeat = 0 ;
SB_Latch = 0 ;
SBOUT_InactiveTime = - 1 ;
last_ts = 0 ;
Column = 0 ;
ColumnCounter = 259 ;
DisplayRegion = 0 ;
DisplayFB = 0 ;
GameFrameCounter = 0 ;
DrawingCounter = 0 ;
DrawingActive = false ;
DrawingFB = 0 ;
DrawingBlock = 0 ;
DPCTRL = 2 ;
DisplayActive = false ;
memset ( FB , 0 , 0x6000 * 2 * 2 ) ;
memset ( CHR_RAM , 0 , 0x8000 ) ;
memset ( DRAM , 0 , 0x20000 ) ;
InterruptPending = 0 ;
InterruptEnable = 0 ;
BRTA = 0 ;
BRTB = 0 ;
BRTC = 0 ;
REST = 0 ;
FRMCYC = 0 ;
XPCTRL = 0 ;
SBCMP = 0 ;
for ( int i = 0 ; i < 4 ; i + + )
{
SPT [ i ] = 0 ;
GPLT [ i ] = 0 ;
JPLT [ i ] = 0 ;
Recalc_GPLT_Cache ( i ) ;
Recalc_JPLT_Cache ( i ) ;
}
BKCOL = 0 ;
}
static INLINE uint16 ReadRegister ( int32 & timestamp , uint32 A )
{
uint16 ret = 0 ; //0xFFFF;
if ( A & 1 )
VIP_DBGMSG ( " Misaligned VIP Read: %08x " , A ) ;
switch ( A & 0xFE )
{
default :
VIP_DBGMSG ( " Unknown VIP register read: %08x " , A ) ;
break ;
case 0x00 :
ret = InterruptPending ;
break ;
case 0x02 :
ret = InterruptEnable ;
break ;
case 0x20 : //printf("Read DPSTTS at %d\n", timestamp);
ret = DPCTRL & 0x702 ;
if ( ( DisplayRegion & 1 ) & & DisplayActive )
{
unsigned int DPBSY = 1 < < ( ( DisplayRegion > > 1 ) & 1 ) ;
if ( DisplayFB )
DPBSY < < = 2 ;
ret | = DPBSY < < 2 ;
}
//if(!(DisplayRegion & 1)) // FIXME? (Had to do it this way for Galactic Pinball...)
ret | = 1 < < 6 ;
break ;
// Note: Upper bits of BRTA, BRTB, BRTC, and REST(?) are 0 when read(on real hardware)
case 0x24 :
ret = BRTA ;
break ;
case 0x26 :
ret = BRTB ;
break ;
case 0x28 :
ret = BRTC ;
break ;
case 0x2A :
ret = REST ;
break ;
case 0x30 :
ret = 0xFFFF ;
break ;
case 0x40 :
ret = XPCTRL & 0x2 ;
if ( DrawingActive )
{
ret | = ( 1 + DrawingFB ) < < 2 ;
}
if ( timestamp < SBOUT_InactiveTime )
{
ret | = 0x8000 ;
ret | = /*DrawingBlock*/ SB_Latch < < 8 ;
}
break ; // XPSTTS, read-only
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.
break ;
case 0x48 :
case 0x4a :
case 0x4c :
case 0x4e :
ret = SPT [ ( A > > 1 ) & 3 ] ;
break ;
case 0x60 :
case 0x62 :
case 0x64 :
case 0x66 :
ret = GPLT [ ( A > > 1 ) & 3 ] ;
break ;
case 0x68 :
case 0x6a :
case 0x6c :
case 0x6e :
ret = JPLT [ ( A > > 1 ) & 3 ] ;
break ;
case 0x70 :
ret = BKCOL ;
break ;
}
return ( ret ) ;
}
static INLINE void WriteRegister ( int32 & timestamp , uint32 A , uint16 V )
{
if ( A & 1 )
VIP_DBGMSG ( " Misaligned VIP Write: %08x %04x " , A , V ) ;
switch ( A & 0xFE )
{
default :
VIP_DBGMSG ( " Unknown VIP register write: %08x %04x " , A , V ) ;
break ;
case 0x00 :
break ; // Interrupt pending, read-only
case 0x02 :
{
InterruptEnable = V & 0xE01F ;
VIP_DBGMSG ( " Interrupt Enable: %04x " , V ) ;
if ( V & 0x2000 )
VIP_DBGMSG ( " Warning: VIP SB Hit Interrupt enable: %04x \n " , V ) ;
CheckIRQ ( ) ;
}
break ;
case 0x04 :
InterruptPending & = ~ V ;
CheckIRQ ( ) ;
break ;
case 0x20 :
break ; // Display control, read-only.
case 0x22 :
DPCTRL = V & ( 0x703 ) ; // Display-control, write-only
if ( V & 1 )
{
DisplayActive = false ;
InterruptPending & = ~ ( INT_TIME_ERR | INT_FRAME_START | INT_GAME_START | INT_RFB_END | INT_LFB_END | INT_SCAN_ERR ) ;
CheckIRQ ( ) ;
}
break ;
case 0x24 :
BRTA = V & 0xFF ; // BRTA
RecalcBrightnessCache ( ) ;
break ;
case 0x26 :
BRTB = V & 0xFF ; // BRTB
RecalcBrightnessCache ( ) ;
break ;
case 0x28 :
BRTC = V & 0xFF ; // BRTC
RecalcBrightnessCache ( ) ;
break ;
case 0x2A :
REST = V & 0xFF ; // REST
RecalcBrightnessCache ( ) ;
break ;
case 0x2E :
FRMCYC = V & 0xF ; // FRMCYC, write-only?
break ;
case 0x30 :
break ; // CTA, read-only(
case 0x40 :
break ; // XPSTTS, read-only
case 0x42 :
XPCTRL = V & 0x0002 ; // XPCTRL, write-only
SBCMP = ( V > > 8 ) & 0x1F ;
if ( V & 1 )
{
VIP_DBGMSG ( " XPRST " ) ;
DrawingActive = 0 ;
DrawingCounter = 0 ;
InterruptPending & = ~ ( INT_SB_HIT | INT_XP_END | INT_TIME_ERR ) ;
CheckIRQ ( ) ;
}
break ;
case 0x44 :
break ; // Version Control, read-only?
case 0x48 :
case 0x4a :
case 0x4c :
case 0x4e :
SPT [ ( A > > 1 ) & 3 ] = V & 0x3FF ;
break ;
case 0x60 :
case 0x62 :
case 0x64 :
case 0x66 :
GPLT [ ( A > > 1 ) & 3 ] = V & 0xFC ;
Recalc_GPLT_Cache ( ( A > > 1 ) & 3 ) ;
break ;
case 0x68 :
case 0x6a :
case 0x6c :
case 0x6e :
JPLT [ ( A > > 1 ) & 3 ] = V & 0xFC ;
Recalc_JPLT_Cache ( ( A > > 1 ) & 3 ) ;
break ;
case 0x70 :
BKCOL = V & 0x3 ;
break ;
}
}
//
// Don't update the VIP state on reads/writes, the event system will update it with enough precision as far as VB software cares.
//
MDFN_FASTCALL uint8 VIP_Read8 ( int32 & timestamp , uint32 A )
{
uint8 ret = 0 ; //0xFF;
//VIP_Update(timestamp);
switch ( A > > 16 )
{
case 0x0 :
case 0x1 :
if ( ( A & 0x7FFF ) > = 0x6000 )
{
ret = ne16_rbo_le < uint8 > ( CHR_RAM , ( A & 0x1FFF ) | ( ( A > > 2 ) & 0x6000 ) ) ;
}
else
{
ret = FB [ ( A > > 15 ) & 1 ] [ ( A > > 16 ) & 1 ] [ A & 0x7FFF ] ;
}
break ;
case 0x2 :
case 0x3 :
ret = ne16_rbo_le < uint8 > ( DRAM , A & 0x1FFFF ) ;
break ;
case 0x4 :
case 0x5 :
if ( A > = 0x5E000 )
ret = ReadRegister ( timestamp , A ) ;
else
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
case 0x6 :
break ;
case 0x7 :
if ( A > = 0x8000 )
{
ret = ne16_rbo_le < uint8 > ( CHR_RAM , A & 0x7FFF ) ;
}
else
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
default :
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
}
//VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
return ( ret ) ;
}
MDFN_FASTCALL uint16 VIP_Read16 ( int32 & timestamp , uint32 A )
{
uint16 ret = 0 ; //0xFFFF;
//VIP_Update(timestamp);
switch ( A > > 16 )
{
case 0x0 :
case 0x1 :
if ( ( A & 0x7FFF ) > = 0x6000 )
{
ret = ne16_rbo_le < uint16 > ( CHR_RAM , ( A & 0x1FFF ) | ( ( A > > 2 ) & 0x6000 ) ) ;
}
else
{
ret = MDFN_de16lsb < true > ( & FB [ ( A > > 15 ) & 1 ] [ ( A > > 16 ) & 1 ] [ A & 0x7FFF ] ) ;
}
break ;
case 0x2 :
case 0x3 :
ret = ne16_rbo_le < uint16 > ( DRAM , A & 0x1FFFF ) ;
break ;
case 0x4 :
case 0x5 :
if ( A > = 0x5E000 )
ret = ReadRegister ( timestamp , A ) ;
else
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
case 0x6 :
break ;
case 0x7 :
if ( A > = 0x8000 )
{
ret = ne16_rbo_le < uint16 > ( CHR_RAM , A & 0x7FFF ) ;
}
else
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
default :
VIP_DBGMSG ( " Unknown VIP Read: %08x " , A ) ;
break ;
}
//VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
return ( ret ) ;
}
MDFN_FASTCALL void VIP_Write8 ( int32 & timestamp , uint32 A , uint8 V )
{
//VIP_Update(timestamp);
//if(A >= 0x3DC00 && A < 0x3E000)
// printf("%08x %02x\n", A, V);
switch ( A > > 16 )
{
case 0x0 :
case 0x1 :
if ( ( A & 0x7FFF ) > = 0x6000 )
ne16_wbo_le < uint8 > ( CHR_RAM , ( A & 0x1FFF ) | ( ( A > > 2 ) & 0x6000 ) , V ) ;
else
FB [ ( A > > 15 ) & 1 ] [ ( A > > 16 ) & 1 ] [ A & 0x7FFF ] = V ;
break ;
case 0x2 :
case 0x3 :
ne16_wbo_le < uint8 > ( DRAM , A & 0x1FFFF , V ) ;
break ;
case 0x4 :
case 0x5 :
if ( A > = 0x5E000 )
WriteRegister ( timestamp , A , V ) ;
else
VIP_DBGMSG ( " Unknown VIP Write: %08x %02x " , A , V ) ;
break ;
case 0x6 :
VIP_DBGMSG ( " Unknown VIP Write: %08x %02x " , A , V ) ;
break ;
case 0x7 :
if ( A > = 0x8000 )
ne16_wbo_le < uint8 > ( CHR_RAM , A & 0x7FFF , V ) ;
else
VIP_DBGMSG ( " Unknown VIP Write: %08x %02x " , A , V ) ;
break ;
default :
VIP_DBGMSG ( " Unknown VIP Write: %08x %02x " , A , V ) ;
break ;
}
//VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
}
MDFN_FASTCALL void VIP_Write16 ( int32 & timestamp , uint32 A , uint16 V )
{
//VIP_Update(timestamp);
//if(A >= 0x3DC00 && A < 0x3E000)
// printf("%08x %04x\n", A, V);
switch ( A > > 16 )
{
case 0x0 :
case 0x1 :
if ( ( A & 0x7FFF ) > = 0x6000 )
ne16_wbo_le < uint16 > ( CHR_RAM , ( A & 0x1FFF ) | ( ( A > > 2 ) & 0x6000 ) , V ) ;
else
MDFN_en16lsb < true > ( & FB [ ( A > > 15 ) & 1 ] [ ( A > > 16 ) & 1 ] [ A & 0x7FFF ] , V ) ;
break ;
case 0x2 :
case 0x3 :
ne16_wbo_le < uint16 > ( DRAM , A & 0x1FFFF , V ) ;
break ;
case 0x4 :
case 0x5 :
if ( A > = 0x5E000 )
WriteRegister ( timestamp , A , V ) ;
else
VIP_DBGMSG ( " Unknown VIP Write: %08x %04x " , A , V ) ;
break ;
case 0x6 :
VIP_DBGMSG ( " Unknown VIP Write: %08x %04x " , A , V ) ;
break ;
case 0x7 :
if ( A > = 0x8000 )
ne16_wbo_le < uint16 > ( CHR_RAM , A & 0x7FFF , V ) ;
else
VIP_DBGMSG ( " Unknown VIP Write: %08x %04x " , A , V ) ;
break ;
default :
VIP_DBGMSG ( " Unknown VIP Write: %08x %04x " , A , V ) ;
break ;
}
//VB_SetEvent(VB_EVENT_VIP, timestamp + CalcNextEvent());
}
static MDFN_Surface real_surface ;
static MDFN_Surface * surface ;
2017-06-26 21:34:01 +00:00
void VIP_CalcFrameSize ( MyFrameInfo * frame )
2017-06-17 14:07:02 +00:00
{
switch ( VB3DMode )
{
default :
frame - > Width = 384 ;
frame - > Height = 224 ;
break ;
case VB3DMODE_VLI :
frame - > Width = 768 * VBPrescale ;
frame - > Height = 224 ;
break ;
case VB3DMODE_HLI :
frame - > Width = 384 ;
frame - > Height = 448 * VBPrescale ;
break ;
case VB3DMODE_CSCOPE :
frame - > Width = 512 ;
frame - > Height = 384 ;
break ;
case VB3DMODE_SIDEBYSIDE :
frame - > Width = 768 + VBSBS_Separation ;
frame - > Height = 224 ;
break ;
}
2017-06-26 21:34:01 +00:00
}
void VIP_StartFrame ( MyFrameInfo * frame )
{
// puts("Start frame");
if ( VidSettingsDirty )
{
MakeColorLUT ( ) ;
Recalc3DModeStuff ( ) ;
VidSettingsDirty = false ;
}
VIP_CalcFrameSize ( frame ) ;
2017-06-17 14:07:02 +00:00
surface = & real_surface ;
real_surface . pixels = frame - > VideoBuffer ;
real_surface . pitch32 = frame - > Width ;
}
void VIP_ResetTS ( void )
{
if ( SBOUT_InactiveTime > = 0 )
SBOUT_InactiveTime - = last_ts ;
last_ts = 0 ;
}
static int32 CalcNextEvent ( void )
{
return ( ColumnCounter ) ;
}
# include "vip_draw.inc"
static INLINE void CopyFBColumnToTarget_Anaglyph_BASE ( const bool DisplayActive_arg , const int lr )
{
const int fb = DisplayFB ;
uint32 * target = surface - > pixels + Column ;
const int32 pitch32 = surface - > pitch32 ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
uint32 pixel = BrightCLUT [ lr ] [ source_bits & 3 ] ;
if ( ! DisplayActive_arg )
pixel = 0 ;
if ( lr )
* target | = pixel ;
else
* target = pixel ;
source_bits > > = 2 ;
target + = pitch32 ;
}
fb_source + + ;
}
}
static void CopyFBColumnToTarget_Anaglyph ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_Anaglyph_BASE ( 0 , 0 ) ;
else
CopyFBColumnToTarget_Anaglyph_BASE ( 0 , 1 ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_Anaglyph_BASE ( 1 , 0 ) ;
else
CopyFBColumnToTarget_Anaglyph_BASE ( 1 , 1 ) ;
}
}
static uint32 AnaSlowBuf [ 384 ] [ 224 ] ;
static INLINE void CopyFBColumnToTarget_AnaglyphSlow_BASE ( const bool DisplayActive_arg , const int lr )
{
const int fb = DisplayFB ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
if ( ! lr )
{
uint32 * target = AnaSlowBuf [ Column ] ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
uint32 pixel = BrightnessCache [ source_bits & 3 ] ;
if ( ! DisplayActive_arg )
pixel = 0 ;
* target = pixel ;
source_bits > > = 2 ;
target + + ;
}
fb_source + + ;
}
}
else
{
uint32 * target = surface - > pixels + Column ;
const uint32 * left_src = AnaSlowBuf [ Column ] ;
const int32 pitch32 = surface - > pitch32 ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
uint32 pixel = AnaSlowColorLUT [ * left_src ] [ DisplayActive_arg ? BrightnessCache [ source_bits & 3 ] : 0 ] ;
* target = pixel ;
source_bits > > = 2 ;
target + = pitch32 ;
left_src + + ;
}
fb_source + + ;
}
}
}
static void CopyFBColumnToTarget_AnaglyphSlow ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_AnaglyphSlow_BASE ( 0 , 0 ) ;
else
CopyFBColumnToTarget_AnaglyphSlow_BASE ( 0 , 1 ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_AnaglyphSlow_BASE ( 1 , 0 ) ;
else
CopyFBColumnToTarget_AnaglyphSlow_BASE ( 1 , 1 ) ;
}
}
static void CopyFBColumnToTarget_CScope_BASE ( const bool DisplayActive_arg , const int lr , const int dest_lr )
{
const int fb = DisplayFB ;
uint32 * target = surface - > pixels + ( dest_lr ? 512 - 16 - 1 : 16 ) + ( dest_lr ? Column : 383 - Column ) * surface - > pitch32 ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
if ( DisplayActive_arg )
* target = BrightCLUT [ lr ] [ source_bits & 3 ] ;
else
* target = 0 ;
source_bits > > = 2 ;
if ( dest_lr )
target - - ;
else
target + + ;
}
fb_source + + ;
}
}
static void CopyFBColumnToTarget_CScope ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_CScope_BASE ( 0 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_CScope_BASE ( 0 , 1 , 1 ^ VB3DReverse ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_CScope_BASE ( 1 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_CScope_BASE ( 1 , 1 , 1 ^ VB3DReverse ) ;
}
}
static void CopyFBColumnToTarget_SideBySide_BASE ( const bool DisplayActive_arg , const int lr , const int dest_lr )
{
const int fb = DisplayFB ;
uint32 * target = surface - > pixels + Column + ( dest_lr ? ( 384 + VBSBS_Separation ) : 0 ) ;
const int32 pitch32 = surface - > pitch32 ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
if ( DisplayActive_arg )
* target = BrightCLUT [ lr ] [ source_bits & 3 ] ;
else
* target = 0 ;
source_bits > > = 2 ;
target + = pitch32 ;
}
fb_source + + ;
}
}
static void CopyFBColumnToTarget_SideBySide ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_SideBySide_BASE ( 0 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_SideBySide_BASE ( 0 , 1 , 1 ^ VB3DReverse ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_SideBySide_BASE ( 1 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_SideBySide_BASE ( 1 , 1 , 1 ^ VB3DReverse ) ;
}
}
static INLINE void CopyFBColumnToTarget_VLI_BASE ( const bool DisplayActive_arg , const int lr , const int dest_lr )
{
const int fb = DisplayFB ;
uint32 * target = surface - > pixels + Column * 2 * VBPrescale + dest_lr ;
const int32 pitch32 = surface - > pitch32 ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
uint32 tv ;
if ( DisplayActive_arg )
tv = BrightCLUT [ lr ] [ source_bits & 3 ] ;
else
tv = 0 ;
for ( uint32 ps = 0 ; ps < VBPrescale ; ps + + )
target [ ps * 2 ] = tv ;
source_bits > > = 2 ;
target + = pitch32 ;
}
fb_source + + ;
}
}
static void CopyFBColumnToTarget_VLI ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_VLI_BASE ( 0 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_VLI_BASE ( 0 , 1 , 1 ^ VB3DReverse ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_VLI_BASE ( 1 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_VLI_BASE ( 1 , 1 , 1 ^ VB3DReverse ) ;
}
}
static INLINE void CopyFBColumnToTarget_HLI_BASE ( const bool DisplayActive_arg , const int lr , const int dest_lr )
{
const int fb = DisplayFB ;
const int32 pitch32 = surface - > pitch32 ;
uint32 * target = surface - > pixels + Column + dest_lr * pitch32 ;
const uint8 * fb_source = & FB [ fb ] [ lr ] [ 64 * Column ] ;
if ( VBPrescale < = 4 )
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = HLILUT [ * fb_source ] ;
for ( int y_sub = 4 * VBPrescale ; y_sub ; y_sub - - )
{
if ( DisplayActive_arg )
* target = BrightCLUT [ lr ] [ source_bits & 3 ] ;
else
* target = 0 ;
target + = pitch32 * 2 ;
source_bits > > = 2 ;
}
fb_source + + ;
}
else
for ( int y = 56 ; y ; y - - )
{
uint32 source_bits = * fb_source ;
for ( int y_sub = 4 ; y_sub ; y_sub - - )
{
for ( uint32 ps = 0 ; ps < VBPrescale ; ps + + )
{
if ( DisplayActive_arg )
* target = BrightCLUT [ lr ] [ source_bits & 3 ] ;
else
* target = 0 ;
target + = pitch32 * 2 ;
}
source_bits > > = 2 ;
}
fb_source + + ;
}
}
static void CopyFBColumnToTarget_HLI ( void )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
if ( ! DisplayActive )
{
if ( ! lr )
CopyFBColumnToTarget_HLI_BASE ( 0 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_HLI_BASE ( 0 , 1 , 1 ^ VB3DReverse ) ;
}
else
{
if ( ! lr )
CopyFBColumnToTarget_HLI_BASE ( 1 , 0 , 0 ^ VB3DReverse ) ;
else
CopyFBColumnToTarget_HLI_BASE ( 1 , 1 , 1 ^ VB3DReverse ) ;
}
}
v810_timestamp_t MDFN_FASTCALL VIP_Update ( const v810_timestamp_t timestamp )
{
int32 clocks = timestamp - last_ts ;
int32 running_timestamp = timestamp ;
while ( clocks > 0 )
{
int32 chunk_clocks = clocks ;
if ( DrawingCounter > 0 & & chunk_clocks > DrawingCounter )
chunk_clocks = DrawingCounter ;
if ( chunk_clocks > ColumnCounter )
chunk_clocks = ColumnCounter ;
running_timestamp + = chunk_clocks ;
if ( DrawingCounter > 0 )
{
DrawingCounter - = chunk_clocks ;
if ( DrawingCounter < = 0 )
{
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)
VIP_DrawBlock ( DrawingBlock , DrawingBuffers [ 0 ] + 8 , DrawingBuffers [ 1 ] + 8 ) ;
for ( int lr = 0 ; lr < 2 ; lr + + )
{
uint8 * FB_Target = FB [ DrawingFB ] [ lr ] + DrawingBlock * 2 ;
for ( int x = 0 ; x < 384 ; x + + )
{
FB_Target [ 64 * x + 0 ] = ( DrawingBuffers [ lr ] [ 8 + x + 512 * 0 ] < < 0 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 1 ] < < 2 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 2 ] < < 4 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 3 ] < < 6 ) ;
FB_Target [ 64 * x + 1 ] = ( DrawingBuffers [ lr ] [ 8 + x + 512 * 4 ] < < 0 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 5 ] < < 2 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 6 ] < < 4 ) | ( DrawingBuffers [ lr ] [ 8 + x + 512 * 7 ] < < 6 ) ;
}
}
SBOUT_InactiveTime = running_timestamp + 1120 ;
SB_Latch = DrawingBlock ; // Not exactly correct, but probably doesn't matter.
DrawingBlock + + ;
if ( DrawingBlock = = 28 )
{
DrawingActive = false ;
InterruptPending | = INT_XP_END ;
CheckIRQ ( ) ;
}
else
DrawingCounter + = 1120 * 4 ;
}
}
ColumnCounter - = chunk_clocks ;
if ( ColumnCounter = = 0 )
{
if ( DisplayRegion & 1 )
{
if ( ! ( Column & 3 ) )
{
const int lr = ( DisplayRegion & 2 ) > > 1 ;
uint16 ctdata = ne16_rbo_le < uint16 > ( DRAM , 0x1DFFE - ( ( Column > > 2 ) * 2 ) - ( lr ? 0 : 0x200 ) ) ;
//printf("%02x, repeat: %02x\n", ctdata & 0xFF, ctdata >> 8);
if ( ( ctdata > > 8 ) ! = Repeat )
{
Repeat = ctdata > > 8 ;
RecalcBrightnessCache ( ) ;
}
}
CopyFBColumnToTarget ( ) ;
}
ColumnCounter = 259 ;
Column + + ;
if ( Column = = 384 )
{
Column = 0 ;
if ( DisplayActive )
{
if ( DisplayRegion & 1 ) // Did we just finish displaying an active region?
{
if ( DisplayRegion & 2 ) // finished displaying right eye
InterruptPending | = INT_RFB_END ;
else // Otherwise, left eye
InterruptPending | = INT_LFB_END ;
CheckIRQ ( ) ;
}
}
DisplayRegion = ( DisplayRegion + 1 ) & 3 ;
if ( DisplayRegion = = 0 ) // New frame start
{
DisplayActive = DPCTRL & 0x2 ;
if ( DisplayActive )
{
InterruptPending | = INT_FRAME_START ;
CheckIRQ ( ) ;
}
GameFrameCounter + + ;
if ( GameFrameCounter > FRMCYC ) // New game frame start?
{
InterruptPending | = INT_GAME_START ;
CheckIRQ ( ) ;
if ( XPCTRL & XPCTRL_XP_EN )
{
DisplayFB ^ = 1 ;
DrawingBlock = 0 ;
DrawingActive = true ;
DrawingCounter = 1120 * 4 ;
DrawingFB = DisplayFB ^ 1 ;
}
GameFrameCounter = 0 ;
}
VB_ExitLoop ( ) ;
}
}
}
clocks - = chunk_clocks ;
}
last_ts = timestamp ;
return ( timestamp + CalcNextEvent ( ) ) ;
}
}