2017-06-17 19:30:03 +00:00
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* vdp2.cpp - VDP2 Emulation
* * Copyright ( C ) 2015 - 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 .
*/
// TODO: Emulate brokenness(missing vblank) that occurs when switching from 240-height mode to 224-height mode around lines 224-239.
// TODO: Update output signals on Reset()? Might have to call VDP2::Reset() before other _Reset() then...and take special care in the
// SMPC clock change code.
# include "ss.h"
# include "vdp1.h"
# include "vdp2.h"
# include "scu.h"
# include "smpc.h"
# include "vdp2_common.h"
# include "vdp2_render.h"
namespace MDFN_IEN_SS
{
namespace VDP2
{
static bool PAL ;
static sscpu_timestamp_t lastts ;
//
//
//
static uint16 RawRegs [ 0x100 ] ; // For debugging
static bool DisplayOn ;
static bool BorderMode ;
static bool ExLatchEnable ;
static bool ExSyncEnable ;
static bool ExBGEnable ;
static bool DispAreaSelect ;
static bool VRAMSize ;
static uint8 HRes , VRes ;
static uint8 InterlaceMode ;
enum { IM_NONE , IM_ILLEGAL , IM_SINGLE , IM_DOUBLE } ;
static uint16 RAMCTL_Raw ;
static uint8 CRAM_Mode ;
enum
{
CRAM_MODE_RGB555_1024 = 0 ,
CRAM_MODE_RGB555_2048 = 1 ,
CRAM_MODE_RGB888_1024 = 2 ,
CRAM_MODE_ILLEGAL = 3
} ;
static uint16 BGON ;
static uint8 VCPRegs [ 4 ] [ 8 ] ;
static uint32 VRAMPenalty [ 4 ] ;
static uint32 RPTA ;
static uint8 RPRCTL [ 2 ] ;
static uint8 KTAOF [ 2 ] ;
static uint16 VRAM [ 262144 ] ;
static uint16 CRAM [ 2048 ] ;
static struct
{
// Signed values are stored sign-extended to the full 32 bits.
int32 Xst , Yst , Zst ; // 1.12.10
int32 DXst , DYst ; // 1. 2.10
int32 DX , DY ; // 1. 2.10
int32 RotMatrix [ 6 ] ; // 1. 3.10
int32 Px , Py , Pz ; // 1.13. 0
int32 Cx , Cy , Cz ; // 1.13. 0
int32 Mx , My ; // 1.13.10
int32 kx , ky ; // 1. 7.16
uint32 KAst ; // 0.16.10
uint32 DKAst ; // 1. 9.10
uint32 DKAx ; // 1. 9.10
//
//
//
uint32 XstAccum , YstAccum ; // 1.12.10 (sorta)
uint32 KAstAccum ; // .10
} RotParams [ 2 ] ;
static void FetchRotParams ( const bool field )
{
uint32 a = RPTA & 0x7FFBE ;
for ( unsigned i = 0 ; i < 2 ; i + + )
{
auto & rp = RotParams [ i ] ;
rp . Xst = sign_x_to_s32 ( 23 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x00 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . Yst = sign_x_to_s32 ( 23 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x02 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . Zst = sign_x_to_s32 ( 23 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x04 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . DXst = sign_x_to_s32 ( 13 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x06 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . DYst = sign_x_to_s32 ( 13 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x08 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . DX = sign_x_to_s32 ( 13 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x0A ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . DY = sign_x_to_s32 ( 13 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x0C ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
for ( unsigned m = 0 ; m < 6 ; m + + )
{
rp . RotMatrix [ m ] = sign_x_to_s32 ( 14 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x0E + ( m < < 1 ) ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
}
rp . Px = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x1A ) & 0x3FFFF ] ) ;
rp . Py = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x1B ) & 0x3FFFF ] ) ;
rp . Pz = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x1C ) & 0x3FFFF ] ) ;
rp . Cx = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x1E ) & 0x3FFFF ] ) ;
rp . Cy = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x1F ) & 0x3FFFF ] ) ;
rp . Cz = sign_x_to_s32 ( 14 , VRAM [ ( a + 0x20 ) & 0x3FFFF ] ) ;
rp . Mx = sign_x_to_s32 ( 24 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x22 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . My = sign_x_to_s32 ( 24 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x24 ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . kx = sign_x_to_s32 ( 24 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x26 ) & 0x3FFFF ) < < 1 ) ) ;
rp . ky = sign_x_to_s32 ( 24 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x28 ) & 0x3FFFF ) < < 1 ) ) ;
rp . KAst = ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x2A ) & 0x3FFFF ) < < 1 ) > > 6 ;
rp . DKAst = sign_x_to_s32 ( 20 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x2C ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
rp . DKAx = sign_x_to_s32 ( 20 , ne16_rbo_be < uint32 > ( VRAM , ( ( a + 0x2E ) & 0x3FFFF ) < < 1 ) > > 6 ) ;
a + = 0x40 ;
//
// Interlace mode doesn't seem to affect operation?
//
// const bool imft = (InterlaceMode == IM_DOUBLE && field);
if ( RPRCTL [ i ] & 0x01 )
rp . XstAccum = rp . Xst ; // + rp.DXst * imft;
else
rp . XstAccum + = rp . DXst ; // << (InterlaceMode == IM_DOUBLE);
if ( RPRCTL [ i ] & 0x02 )
rp . YstAccum = rp . Yst ; // + rp.DYst * imft;
else
rp . YstAccum + = rp . DYst ; // << (InterlaceMode == IM_DOUBLE);
if ( RPRCTL [ i ] & 0x04 )
rp . KAstAccum = ( KTAOF [ i ] < < 26 ) + rp . KAst ; // + rp.DKAst * imft;
else
rp . KAstAccum + = rp . DKAst ; // << (InterlaceMode == IM_DOUBLE);
}
}
enum
{
VPHASE_ACTIVE = 0 ,
VPHASE_BOTTOM_BORDER ,
VPHASE_BOTTOM_BLANKING ,
VPHASE_VSYNC ,
VPHASE_TOP_BLANKING ,
VPHASE_TOP_BORDER ,
VPHASE__COUNT
} ;
static const int32 VTimings [ 2 ] [ 4 ] [ VPHASE__COUNT ] = // End lines
{
{ // NTSC:
{ 0x0E0 , 0xE8 , 0xED , 0xF0 , 0x0FF , 0x107 } ,
{ 0x0F0 , 0xF0 , 0xF5 , 0xF8 , 0x107 , 0x107 } ,
{ 0x0E0 , 0xE8 , 0xED , 0xF0 , 0x0FF , 0x107 } ,
{ 0x0F0 , 0xF0 , 0xF5 , 0xF8 , 0x107 , 0x107 } ,
} ,
{ // PAL:
// btm brdr begin, btm blnk begin, vsync begin, /***/ top blnk begin, top brdr begin, total
{ 0x0E0 , 0x100 , 0x103 , /***/ 0x103 + 3 /*?*/ , 0x119 , 0x139 } ,
{ 0x0F0 , 0x108 , 0x10B , /***/ 0x10B + 3 /*?*/ , 0x121 , 0x139 } ,
{ 0x100 , 0x110 , 0x113 , /***/ 0x113 + 3 /*?*/ , 0x129 , 0x139 } ,
{ 0x100 , 0x110 , 0x113 , /***/ 0x113 + 3 /*?*/ , 0x129 , 0x139 } ,
} ,
} ;
static bool Out_VB ; // VB output signal
static uint32 VPhase ;
/*static*/ int32 VCounter ;
static bool InternalVB ;
static bool Odd ;
//
static int SurfInterlaceField ;
//
//
//
// (No 0) 8 accesses, No split: 0 added cycles
// (No 4) 4 accesses, No split: 1 added cycles
// (No 6) 2 accesses, No split: 2 added cycles
// (No 7) 1 accesses, No split: 3, Split: 3.51? added cycles
// (No 8) 0 accesses, No split: 4, Split: 5.34? added cycles
static INLINE void RecalcVRAMPenalty ( void )
{
if ( InternalVB )
VRAMPenalty [ 0 ] = VRAMPenalty [ 1 ] = VRAMPenalty [ 2 ] = VRAMPenalty [ 3 ] = 0 ;
else
{
const unsigned VRAM_Mode = ( RAMCTL_Raw > > 8 ) & 0x3 ;
const unsigned RDBS_Mode = ( RAMCTL_Raw & 0xFF ) ;
const size_t sh = ( ( HRes & 0x6 ) ? 0 : 4 ) ;
uint8 vcp_type_penalty [ 0x10 ] ;
for ( unsigned vcp_type = 0 ; vcp_type < 0x10 ; vcp_type + + )
{
bool penalty ;
if ( ( vcp_type < 0x8 ) | | vcp_type = = 0xC | | vcp_type = = 0xD )
penalty = ( bool ) ( BGON & ( 1U < < ( vcp_type & 0x3 ) ) ) ;
else
penalty = false ;
vcp_type_penalty [ vcp_type ] = penalty ;
}
for ( unsigned bank = 0 ; bank < 4 ; bank + + )
{
const unsigned esb = bank & ( 2 | ( ( VRAM_Mode > > ( bank > > 1 ) ) & 1 ) ) ;
const uint8 rdbs = ( RDBS_Mode > > ( esb < < 1 ) ) & 0x3 ;
uint32 tmp = 0 ;
if ( BGON & 0x20 )
{
if ( bank > = 2 | | ( ( BGON & 0x10 ) & & rdbs ! = RDBS_UNUSED ) )
tmp = 8 ;
}
else
{
if ( ( BGON & 0x10 ) & & rdbs ! = RDBS_UNUSED )
tmp = 8 ;
else if ( BGON & 0x0F )
{
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ 0 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ 1 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ 2 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ 3 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ sh + 0 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ sh + 1 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ sh + 2 ] ] ;
tmp + = vcp_type_penalty [ VCPRegs [ esb ] [ sh + 3 ] ] ;
}
}
static const uint8 tab [ 9 ] = { 0 , 0 , 0 , 0 , 1 , 1 , 2 , 3 , 4 } ;
VRAMPenalty [ bank ] = tab [ tmp ] ;
//printf("%d, %d\n", bank, tmp);
}
}
}
enum
{
HPHASE_ACTIVE = 0 ,
HPHASE_RIGHT_BORDER ,
HPHASE_HSYNC ,
// ... ? ? ?
HPHASE__COUNT
} ;
static const int32 HTimings [ 2 ] [ HPHASE__COUNT ] =
{
{ 0x140 , 0x15B , 0x1AB } ,
{ 0x160 , 0x177 , 0x1C7 } ,
} ;
static uint32 HPhase ;
/*static*/ int32 HCounter ;
static uint16 Latched_VCNT , Latched_HCNT ;
static bool HVIsExLatched ;
static void LatchHV ( void )
{
{
unsigned vtmp ;
if ( VPhase > = VPHASE_VSYNC )
vtmp = VCounter + ( 0x200 - VTimings [ PAL ] [ VRes ] [ VPHASE__COUNT - 1 ] ) ;
else
vtmp = VCounter ;
if ( InterlaceMode = = IM_DOUBLE )
vtmp = ( vtmp < < 1 ) | ! Odd ;
Latched_VCNT = vtmp ;
}
if ( HPhase > = HPHASE_HSYNC )
Latched_HCNT = ( HCounter + ( 0x200 - HTimings [ HRes & 1 ] [ HPHASE__COUNT - 1 ] ) ) < < 1 ;
else
Latched_HCNT = HCounter < < 1 ;
//HVIsLatched = true; // Only on external signal-induced latching?
}
//
//
void StartFrame ( EmulateSpecStruct * espec , const bool clock28m )
{
//printf("StartFrame: %d\n", SurfInterlaceField);
VDP2REND_StartFrame ( espec , clock28m , SurfInterlaceField ) ;
}
//
//
static INLINE void IncVCounter ( const sscpu_timestamp_t event_timestamp )
{
VCounter = ( VCounter + 1 ) & 0x1FF ;
if ( VCounter = = ( VTimings [ PAL ] [ VRes ] [ VPHASE__COUNT - 1 ] - 1 ) )
Out_VB = false ;
// - 1, so the CPU loop will have plenty of time to exit before we reach non-hblank top border area
// (exit granularity could be large if program is executing from SCSP RAM space, for example).
if ( VCounter = = ( VTimings [ PAL ] [ VRes ] [ VPHASE_TOP_BLANKING ] - 1 ) )
{
#if 0
for ( unsigned bank = 0 ; bank < 4 ; bank + + )
{
printf ( " Bank %d: " , bank ) ;
for ( unsigned vc = 0 ; vc < 8 ; vc + + )
printf ( " %01x " , VCPRegs [ bank ] [ vc ] ) ;
printf ( " \n " ) ;
}
# endif
SS_RequestMLExit ( ) ;
VDP2REND_EndFrame ( ) ;
//printf("Meow: %d\n", VCounter);
}
while ( VCounter > = VTimings [ PAL ] [ VRes ] [ VPhase ] - ( ( VPhase = = VPHASE_VSYNC - 1 ) & & InterlaceMode ) )
{
VPhase + + ;
if ( VPhase = = VPHASE__COUNT )
{
VPhase = 0 ;
VCounter - = VTimings [ PAL ] [ VRes ] [ VPHASE__COUNT - 1 ] ;
}
if ( VPhase = = VPHASE_ACTIVE )
InternalVB = ! DisplayOn ;
else if ( VPhase = = VPHASE_BOTTOM_BORDER )
{
SS_SetEventNT ( & events [ SS_EVENT_MIDSYNC ] , event_timestamp + 1 ) ;
InternalVB = true ;
Out_VB = true ;
}
else if ( VPhase = = VPHASE_VSYNC )
{
if ( InterlaceMode )
{
Odd = ! Odd ;
VCounter + = Odd ;
SurfInterlaceField = ! Odd ;
}
else
{
SurfInterlaceField = - 1 ;
Odd = true ;
}
}
}
RecalcVRAMPenalty ( ) ;
SMPC_SetVB ( event_timestamp , Out_VB ) ;
}
static INLINE int32 AddHCounter ( const sscpu_timestamp_t event_timestamp , int32 count )
{
HCounter + = count ;
//if(HCounter > HTimings[HRes & 1][HPhase])
// printf("VDP2 oops: %d %d\n", HCounter, HTimings[HRes & 1][HPhase]);
while ( HCounter > = HTimings [ HRes & 1 ] [ HPhase ] )
{
HPhase + + ;
if ( HPhase = = HPHASE__COUNT )
{
HPhase = 0 ;
HCounter - = HTimings [ HRes & 1 ] [ HPHASE__COUNT - 1 ] ;
}
//
//
//
if ( HPhase = = HPHASE_ACTIVE )
{
if ( VPhase = = VPHASE_ACTIVE )
{
VDP2Rend_LIB * lib = VDP2REND_GetLIB ( VCounter ) ;
if ( ! InternalVB )
{
if ( BGON & 0x30 )
{
if ( VCounter = = 0 )
RPRCTL [ 0 ] = RPRCTL [ 1 ] = 0x07 ;
FetchRotParams ( false /*field*/ ) ;
RPRCTL [ 0 ] = RPRCTL [ 1 ] = 0 ;
}
for ( unsigned i = 0 ; i < 2 ; i + + )
{
auto const & rp = RotParams [ i ] ;
auto & r = lib - > rv [ i ] ;
r . Xsp = ( ( int64 ) rp . RotMatrix [ 0 ] * ( ( int32 ) rp . XstAccum - ( rp . Px * 1024 ) ) +
( int64 ) rp . RotMatrix [ 1 ] * ( ( int32 ) rp . YstAccum - ( rp . Py * 1024 ) ) +
( int64 ) rp . RotMatrix [ 2 ] * ( rp . Zst - ( rp . Pz * 1024 ) ) ) > > 10 ;
r . Ysp = ( ( int64 ) rp . RotMatrix [ 3 ] * ( ( int32 ) rp . XstAccum - ( rp . Px * 1024 ) ) +
( int64 ) rp . RotMatrix [ 4 ] * ( ( int32 ) rp . YstAccum - ( rp . Py * 1024 ) ) +
( int64 ) rp . RotMatrix [ 5 ] * ( rp . Zst - ( rp . Pz * 1024 ) ) ) > > 10 ;
r . Xp = rp . RotMatrix [ 0 ] * ( rp . Px - rp . Cx ) +
rp . RotMatrix [ 1 ] * ( rp . Py - rp . Cy ) +
rp . RotMatrix [ 2 ] * ( rp . Pz - rp . Cz ) +
( rp . Cx * 1024 ) + rp . Mx ;
r . Yp = rp . RotMatrix [ 3 ] * ( rp . Px - rp . Cx ) +
rp . RotMatrix [ 4 ] * ( rp . Py - rp . Cy ) +
rp . RotMatrix [ 5 ] * ( rp . Pz - rp . Cz ) +
( rp . Cy * 1024 ) + rp . My ;
r . dX = ( rp . RotMatrix [ 0 ] * rp . DX + rp . RotMatrix [ 1 ] * rp . DY ) > > 10 ;
r . dY = ( rp . RotMatrix [ 3 ] * rp . DX + rp . RotMatrix [ 4 ] * rp . DY ) > > 10 ;
r . kx = rp . kx ;
r . ky = rp . ky ;
r . KAstAccum = rp . KAstAccum ;
r . DKAx = rp . DKAx ;
}
}
//printf("%d, 0x%08x(%f) 0x%08x(%f)\n", VCounter, RotParams[0].KAstAccum >> 10, (int32)RotParams[0].DKAst / 1024.0, RotParams[1].KAstAccum >> 10, (int32)RotParams[1].DKAst / 1024.0);
//printf("DL: %d\n", VCounter);
lib - > vdp1_hires8 = VDP1 : : GetLine ( VCounter , lib - > vdp1_line , ( HRes & 1 ) ? 352 : 320 , ( int32 ) RotParams [ 0 ] . XstAccum > > 1 , ( int32 ) RotParams [ 0 ] . YstAccum > > 1 , ( int32 ) RotParams [ 0 ] . DX > > 1 , ( int32 ) RotParams [ 0 ] . DY > > 1 ) ; // Always call, has side effects.
VDP2REND_DrawLine ( InternalVB ? - 1 : VCounter , ! Odd ) ;
}
else if ( VPhase = = VPHASE_TOP_BORDER | | VPhase = = VPHASE_BOTTOM_BORDER )
VDP2REND_DrawLine ( - 1 , ! Odd ) ;
}
else if ( HPhase = = HPHASE_HSYNC )
{
IncVCounter ( event_timestamp ) ;
}
}
return ( HTimings [ HRes & 1 ] [ HPhase ] - HCounter ) ;
}
sscpu_timestamp_t Update ( sscpu_timestamp_t timestamp )
{
int32 clocks = ( timestamp - lastts ) > > 2 ;
if ( MDFN_UNLIKELY ( timestamp < lastts ) )
{
SS_DBGTI ( SS_DBG_WARNING | SS_DBG_VDP2 , " [VDP2] [BUG] timestamp(%d) < lastts(%d) " , timestamp , lastts ) ;
clocks = 0 ;
}
lastts + = clocks < < 2 ;
//
//
int32 ne ;
int32 tmp ;
ne = AddHCounter ( timestamp , clocks ) ;
VDP1 : : SetHBVB ( timestamp , HPhase > HPHASE_ACTIVE , Out_VB ) ;
tmp = SCU_SetHBVB ( clocks , HPhase > HPHASE_ACTIVE , Out_VB ) ;
if ( tmp < ne )
ne = tmp ;
return lastts + ( ne < < 2 ) ;
}
//
// Register writes seem to always be 16-bit
//
static INLINE void RegsWrite ( uint32 A , uint16 V )
{
A & = 0x1FE ;
RawRegs [ A > > 1 ] = V ;
SS_DBGTI ( SS_DBG_VDP2_REGW , " [VDP2] Register write 0x%03x: 0x%04x " , A , V ) ;
switch ( A )
{
default :
// SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown write to register at 0x%08x of value 0x%04x", A, V);
break ;
case 0x00 :
Update ( SH7095_mem_timestamp ) ;
//
DisplayOn = ( V > > 15 ) & 0x1 ;
BorderMode = ( V > > 8 ) & 0x1 ;
InterlaceMode = ( V > > 6 ) & 0x3 ;
VRes = ( V > > 4 ) & 0x3 ;
HRes = ( V > > 0 ) & 0x7 ;
//
InternalVB | = ! DisplayOn ;
//
SS_SetEventNT ( & events [ SS_EVENT_VDP2 ] , Update ( SH7095_mem_timestamp ) ) ;
break ;
case 0x02 :
ExLatchEnable = ( V > > 9 ) & 0x1 ;
ExSyncEnable = ( V > > 8 ) & 0x1 ;
DispAreaSelect = ( V > > 1 ) & 0x1 ;
ExBGEnable = ( V > > 0 ) & 0x1 ;
break ;
case 0x06 :
VRAMSize = ( V > > 15 ) & 0x1 ;
if ( VRAMSize )
SS_DBGTI ( SS_DBG_WARNING | SS_DBG_VDP2 , " [VDP2] VRAMSize=%d (unemulated) " , VRAMSize ) ;
break ;
case 0x0E :
RAMCTL_Raw = V & 0xB3FF ;
CRAM_Mode = ( V > > 12 ) & 0x3 ;
break ;
case 0x10 :
case 0x12 :
case 0x14 :
case 0x16 :
case 0x18 :
case 0x1A :
case 0x1C :
case 0x1E :
{
uint8 * const b = & VCPRegs [ ( A > > 2 ) & 3 ] [ ( A & 0x2 ) < < 1 ] ;
b [ 0 ] = ( V > > 12 ) & 0xF ;
b [ 1 ] = ( V > > 8 ) & 0xF ;
b [ 2 ] = ( V > > 4 ) & 0xF ;
b [ 3 ] = ( V > > 0 ) & 0xF ;
}
break ;
case 0x20 :
BGON = V & 0x1F3F ;
break ;
case 0xB2 :
RPRCTL [ 0 ] = ( V > > 0 ) & 0x7 ;
RPRCTL [ 1 ] = ( V > > 8 ) & 0x7 ;
break ;
case 0xB6 :
KTAOF [ 0 ] = ( V > > 0 ) & 0x7 ;
KTAOF [ 1 ] = ( V > > 8 ) & 0x7 ;
break ;
case 0xBC :
RPTA = ( RPTA & 0xFFFF ) | ( ( V & 0x7 ) < < 16 ) ;
break ;
case 0xBE :
RPTA = ( RPTA & ~ 0xFFFF ) | ( V & 0xFFFE ) ;
break ;
}
}
static INLINE uint16 RegsRead ( uint32 A )
{
switch ( A & 0x1FE )
{
default :
SS_DBGTI ( SS_DBG_WARNING | SS_DBG_VDP2 , " [VDP2] Unknown read from 0x%08x " , A ) ;
return 0 ;
case 0x00 :
return ( DisplayOn < < 15 ) | ( BorderMode < < 8 ) | ( InterlaceMode < < 6 ) | ( VRes < < 4 ) | ( HRes < < 0 ) ;
case 0x02 :
if ( ! ExLatchEnable )
{
SS_SetEventNT ( & events [ SS_EVENT_VDP2 ] , Update ( SH7095_mem_timestamp ) ) ;
LatchHV ( ) ;
}
return ( ExLatchEnable < < 9 ) | ( ExSyncEnable < < 8 ) | ( DispAreaSelect < < 1 ) | ( ExBGEnable < < 0 ) ;
case 0x04 :
SS_SetEventNT ( & events [ SS_EVENT_VDP2 ] , Update ( SH7095_mem_timestamp ) ) ;
{
// TODO: EXSYFG
uint16 ret = ( HVIsExLatched < < 9 ) | ( InternalVB < < 3 ) | ( ( HPhase > HPHASE_ACTIVE ) < < 2 ) | ( Odd < < 1 ) | ( PAL < < 0 ) ;
HVIsExLatched = false ;
return ret ;
}
case 0x06 :
return VRAMSize < < 15 ;
case 0x08 :
return Latched_HCNT ;
case 0x0A :
return Latched_VCNT ;
case 0x0E :
return RAMCTL_Raw ;
}
}
template < typename T , bool IsWrite >
static INLINE uint32 RW ( uint32 A , uint16 * DB )
{
static_assert ( IsWrite | | sizeof ( T ) = = 2 , " Wrong type for read. " ) ;
A & = 0x1FFFFF ;
//
// VRAM
//
if ( A < 0x100000 )
{
const size_t vri = ( A & 0x7FFFF ) > > 1 ;
if ( IsWrite )
{
const unsigned mask = ( sizeof ( T ) = = 2 ) ? 0xFFFF : ( 0xFF00 > > ( ( A & 1 ) < < 3 ) ) ;
VRAM [ vri ] = ( VRAM [ vri ] & ~ mask ) | ( * DB & mask ) ;
}
else
* DB = VRAM [ vri ] ;
return VRAMPenalty [ vri > > 16 ] ;
}
//
// CRAM
//
if ( A < 0x180000 )
{
const unsigned cri = ( A & 0xFFF ) > > 1 ;
if ( IsWrite )
{
switch ( CRAM_Mode )
{
case CRAM_MODE_RGB555_1024 :
( CRAM + 0x000 ) [ cri & 0x3FF ] = * DB ;
( CRAM + 0x400 ) [ cri & 0x3FF ] = * DB ;
break ;
case CRAM_MODE_RGB555_2048 :
CRAM [ cri ] = * DB ;
break ;
case CRAM_MODE_RGB888_1024 :
case CRAM_MODE_ILLEGAL :
default :
CRAM [ ( ( cri > > 1 ) & 0x3FF ) | ( ( cri & 1 ) < < 10 ) ] = * DB ;
break ;
}
}
else
{
switch ( CRAM_Mode )
{
case CRAM_MODE_RGB555_1024 :
case CRAM_MODE_RGB555_2048 :
* DB = CRAM [ cri ] ;
break ;
case CRAM_MODE_RGB888_1024 :
case CRAM_MODE_ILLEGAL :
default :
* DB = CRAM [ ( ( cri > > 1 ) & 0x3FF ) | ( ( cri & 1 ) < < 10 ) ] ;
break ;
}
}
return 0 ;
}
//
// Registers
//
if ( A < 0x1C0000 )
{
if ( IsWrite )
{
if ( sizeof ( T ) = = 1 )
SS_DBGTI ( SS_DBG_WARNING | SS_DBG_VDP2 , " [VDP2] Byte-write to register at 0x%08x(DB=0x%04x) " , A , * DB ) ;
RegsWrite ( A , * DB ) ;
}
else
* DB = RegsRead ( A ) ;
return 0 ;
}
if ( IsWrite )
{
//SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte write to 0x%08x(DB=0x%04x)", sizeof(T), A, *DB);
}
else
{
//SS_DBGTI(SS_DBG_WARNING | SS_DBG_VDP2, "[VDP2] Unknown %zu-byte read from 0x%08x", sizeof(T), A);
* DB = 0 ;
}
return 0 ;
}
uint16 Read16_DB ( uint32 A )
{
uint16 DB ;
RW < uint16 , false > ( A , & DB ) ;
return DB ;
}
uint32 Write8_DB ( uint32 A , uint16 DB )
{
VDP2REND_Write8_DB ( A , DB ) ;
return RW < uint8 , true > ( A , & DB ) ;
}
uint32 Write16_DB ( uint32 A , uint16 DB )
{
VDP2REND_Write16_DB ( A , DB ) ;
return RW < uint16 , true > ( A , & DB ) ;
}
//
//
//
void AdjustTS ( const int32 delta )
{
lastts + = delta ;
}
void Init ( const bool IsPAL )
{
SurfInterlaceField = - 1 ;
PAL = IsPAL ;
lastts = 0 ;
SS_SetPhysMemMap ( 0x05E00000 , 0x05EFFFFF , VRAM , 0x80000 , true ) ;
AddMemoryDomain ( " VDP2 Ram " , VRAM , sizeof ( VRAM ) , MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2 ) ;
AddMemoryDomain ( " VDP2 CRam " , CRAM , sizeof ( CRAM ) , MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2 ) ;
VDP2REND_Init ( IsPAL ) ;
}
void Reset ( bool powering_up )
{
DisplayOn = false ;
BorderMode = false ;
ExLatchEnable = false ;
ExSyncEnable = false ;
ExBGEnable = false ;
DispAreaSelect = false ;
HRes = 0 ;
VRes = 0 ;
InterlaceMode = 0 ;
VRAMSize = 0 ;
InternalVB = true ;
Out_VB = false ;
VPhase = VPHASE_ACTIVE ;
VCounter = 0 ;
Odd = true ;
RAMCTL_Raw = 0 ;
CRAM_Mode = 0 ;
BGON = 0 ;
memset ( VCPRegs , 0 , sizeof ( VCPRegs ) ) ;
for ( unsigned i = 0 ; i < 2 ; i + + )
{
KTAOF [ i ] = 0 ;
RPRCTL [ i ] = 0 ;
}
RPTA = 0 ;
memset ( RotParams , 0 , sizeof ( RotParams ) ) ;
//
// FIXME(init values), also in VDP2REND.
if ( powering_up )
{
memset ( VRAM , 0 , sizeof ( VRAM ) ) ;
memset ( CRAM , 0 , sizeof ( CRAM ) ) ;
}
//
RecalcVRAMPenalty ( ) ;
//
//
VDP2REND_Reset ( powering_up ) ;
}
//
//
//
//
uint32 GetRegister ( const unsigned id , char * const special , const uint32 special_len )
{
uint32 ret = 0xDEADBEEF ;
switch ( id )
{
case GSREG_LINE :
ret = VCounter ;
break ;
case GSREG_DON :
ret = DisplayOn ;
break ;
case GSREG_BM :
ret = BorderMode ;
break ;
case GSREG_IM :
ret = InterlaceMode ;
break ;
case GSREG_VRES :
ret = VRes ;
break ;
case GSREG_HRES :
ret = HRes ;
break ;
}
return ret ;
}
void SetRegister ( const unsigned id , const uint32 value )
{
}
uint8 PeekVRAM ( const uint32 addr )
{
return ne16_rbo_be < uint8 > ( VRAM , addr & 0x7FFFF ) ;
}
void PokeVRAM ( const uint32 addr , const uint8 val )
{
ne16_wbo_be < uint8 > ( VRAM , addr & 0x7FFFF , val ) ;
//VDP2REND_Write8_DB(addr, val << (((A & 1) ^ 1) << 3));
}
void SetLayerEnableMask ( uint64 mask )
{
VDP2REND_SetLayerEnableMask ( mask ) ;
}
/*void MakeDump(const std::string& path)
{
FileStream fp ( path , FileStream : : MODE_WRITE ) ;
fp . print_format ( " { " ) ;
for ( unsigned i = 0 ; i < 0x100 ; i + + )
fp . print_format ( " 0x%04x, " , RawRegs [ i ] ) ;
fp . print_format ( " }, \n " ) ;
fp . print_format ( " { " ) ;
for ( unsigned i = 0 ; i < 2048 ; i + + )
fp . print_format ( " 0x%04x, " , CRAM [ i ] ) ;
fp . print_format ( " }, \n " ) ;
fp . print_format ( " { " ) ;
for ( unsigned i = 0 ; i < 0x40000 ; i + + )
fp . print_format ( " 0x%04x, " , VRAM [ i ] ) ;
fp . print_format ( " }, \n " ) ;
fp . close ( ) ;
} */
}
}