522 lines
17 KiB
C
522 lines
17 KiB
C
//----------------------------------------------------------------------------
|
|
// STISR.C
|
|
//----------------------------------------------------------------------------
|
|
// Description : small description of the goal of the module
|
|
//----------------------------------------------------------------------------
|
|
// Copyright SGS Thomson Microelectronics ! Version alpha ! Jan 1st, 1995
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Include files
|
|
//----------------------------------------------------------------------------
|
|
#include "stdefs.h"
|
|
#include "common.h"
|
|
#include "STllapi.h"
|
|
#include "stvideo.h"
|
|
#include "debug.h"
|
|
#include "error.h"
|
|
#ifdef STi3520A
|
|
#include "STi3520A.h"
|
|
#else
|
|
#include "STi3520.h"
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// GLOBAL Variables (avoid as possible)
|
|
//----------------------------------------------------------------------------
|
|
U8 Sequence = 1;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private Constants
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private Types
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Private GLOBAL Variables (static)
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Functions (statics one are private)
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Mask Video Interrupts
|
|
//----------------------------------------------------------------------------
|
|
void VideoMaskInt ( PVIDEO pVideo )
|
|
{
|
|
VideoWrite( ITM, 0 ); // mask chip interrupts before reading the status
|
|
VideoWrite( ITM + 1, 0 ); // avoids possible gliches on the IRQ line
|
|
#ifdef STi3520A
|
|
VideoWrite( VID_ITM1, 0 ); // mask chip interrupts before
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Restore Video Interrupts Mask
|
|
//----------------------------------------------------------------------------
|
|
void VideoRestoreInt ( PVIDEO pVideo )
|
|
{
|
|
VideoWrite( ITM, ( pVideo->intMask >> 8 ) );
|
|
VideoWrite( ITM + 1, ( pVideo->intMask & 0xFF ) );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Interrupt routine (All the control is made in this routine)
|
|
//----------------------------------------------------------------------------
|
|
BOOLEAN VideoVideoInt(PVIDEO pVideo)
|
|
{
|
|
BOOLEAN VideoITOccured = FALSE;
|
|
U16 compute;
|
|
pVideo->VsyncInterrupt = FALSE;
|
|
pVideo->FirstDTS = FALSE;
|
|
#ifdef STi3520A
|
|
VideoRead ( ITS1 );
|
|
#endif
|
|
/* All interrupts except the first one are computed in this area */
|
|
pVideo->intStatus = VideoRead ( ITS ) << 8;
|
|
// Reading the interrupt status register
|
|
pVideo->intStatus = VideoRead ( ITS + 1 ) | pVideo->intStatus;
|
|
// All the STI3500 interrupts are cleared */
|
|
pVideo->intStatus = pVideo->intStatus & pVideo->intMask;
|
|
// To mask the IT not used */
|
|
|
|
while ( pVideo->intStatus ) // stay into interrupt routine
|
|
// until all the bits have not
|
|
// been tested
|
|
{
|
|
VideoITOccured = TRUE;
|
|
|
|
|
|
/******************************************************/
|
|
/** BOTTOM VSYNC INTERRUPT **/
|
|
/******************************************************/
|
|
if ( ( pVideo->intStatus & BOT ) != 0x0 )
|
|
{
|
|
DBG1('B');
|
|
pVideo->intStatus = pVideo->intStatus & ~BOT;
|
|
// clear BOT bit
|
|
VideoChooseField ( pVideo);
|
|
pVideo->currField = BOT;
|
|
if(pVideo->InvertedField)
|
|
pVideo->currField = TOP;
|
|
VideoVsyncRout ( pVideo );
|
|
}
|
|
/******************************************************/
|
|
/** TOP VSYNC INTERRUPT **/
|
|
/******************************************************/
|
|
if ( ( pVideo->intStatus & TOP ) != 0x0 )
|
|
{
|
|
DBG1('T');
|
|
pVideo->intStatus = pVideo->intStatus & ~TOP;
|
|
// clear TOP bit
|
|
|
|
VideoChooseField ( pVideo );
|
|
pVideo->currField = TOP;
|
|
if(pVideo->InvertedField)
|
|
pVideo->currField = BOT;
|
|
VideoVsyncRout ( pVideo );
|
|
|
|
}
|
|
/******************************************************/
|
|
/** DSYNC INTERRUPT **/
|
|
/******************************************************/
|
|
/***************************************************************/
|
|
/* The DSYNC interrupt is generated on each VSYNC (RPT = 0) */
|
|
/* if the next INStrucztion has the EXE bit set. */
|
|
/* On each DSYNC a new Header Search is automatically started. */
|
|
/***************************************************************/
|
|
|
|
if ( ( pVideo->intStatus & PSD ) != 0x0 )
|
|
{
|
|
DBG1('d');
|
|
pVideo->intStatus = pVideo->intStatus & ~PSD;
|
|
// clear PSD bit
|
|
pVideo->VsyncNumber = 0; /* clear software watch-dog */
|
|
/* check if we have reached the first picture with a PTS */
|
|
|
|
|
|
if ( pVideo->NextInstr.Seq ) // first interrupt enabled (Searching Sequence)
|
|
{
|
|
VideoWaitDec ( pVideo ); // put decoder in Wait mode
|
|
pVideo->intMask = 0x1; /* enable header hit interrupt */
|
|
pVideo->NextInstr.Seq = 0;
|
|
pVideo->NextInstr.Exe = 0;
|
|
}
|
|
else
|
|
{
|
|
Sequence = 0;
|
|
if ( VideoGetState ( pVideo ) == VIDEO_START_UP )
|
|
{
|
|
if ( pVideo->pDecodedPict->validPTS == TRUE )
|
|
{
|
|
pVideo->FirstDTS = TRUE;
|
|
pVideo->VideoState = VIDEO_DECODE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Check bit buffer level consistency with pVideo->vbveDelay */
|
|
/* of the picture that the STi3500 starts to decode */
|
|
if ( ( pVideo->fieldMode == 0 ) || ( pVideo->fieldMode == 2 ) )
|
|
// frame picture or first field of a field picture
|
|
{
|
|
compute = VideoGetBBL();
|
|
if ( compute < ( 4 * pVideo->vbvDelay / 5) ) // 0.8 is 4/5 !
|
|
// bit buffer level is not high enough for the next
|
|
// picture: wait !!!
|
|
{ // we stop the current decoding
|
|
// process for two fields
|
|
DBG1('<');
|
|
VideoEnableDecoding(pVideo, OFF);
|
|
pVideo->needDataInBuff = pVideo->currField;
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************/
|
|
/*
|
|
* We put the decoder in wait mode on DSYNC: EXE bit reset
|
|
* into INS.
|
|
*/
|
|
/*
|
|
* In normal case the DSYNC interrupt is quickly followed
|
|
* by a
|
|
*/
|
|
/*
|
|
* Header Hit int. during which the next INS is written
|
|
* with EXE=1.
|
|
*/
|
|
/*
|
|
* If for any reason the header hit is delayed, the STi3500
|
|
* will
|
|
*/
|
|
/* see the notEXE and stay in WAIT mode without crashing... */
|
|
/* this can typically appear if the bit buffer gets empty. */
|
|
/********************************************************************/
|
|
if ( !pVideo->needDataInBuff )
|
|
{
|
|
VideoWaitDec ( pVideo ); // put decoder in Wait mode
|
|
pVideo->NextInstr.Exe = 0;
|
|
// reset EXE bit.
|
|
}
|
|
|
|
/* update the display frame pointer for the next VSYNC */
|
|
if ( ( pVideo->fieldMode == 0 ) || ( pVideo->fieldMode == 2 ) )
|
|
// frame picture or first field of a field picture
|
|
{
|
|
pVideo->pCurrDisplay = pVideo->pNextDisplay;
|
|
// preset the VSYNC counter
|
|
pVideo->pictDispIndex = 0 - ( 2 * pVideo->decSlowDown );
|
|
if ( pVideo->DecodeMode != SLOW_MODE )
|
|
pVideo->decSlowDown = 0; /* allows to do the repeat
|
|
* function */
|
|
VideoWrite( DFP, ( pVideo->pCurrDisplay->buffer >> 8 ) );
|
|
VideoWrite( DFP + 1, ( pVideo->pCurrDisplay->buffer & 0xFF ) );
|
|
|
|
pVideo->displaySecondField = 0;
|
|
VideoChooseField ( pVideo );
|
|
}
|
|
VideoSetPSV ( pVideo ); // update the next pan vector
|
|
// frame picture or second field of field picture */
|
|
// if ( ( pVideo->VideoState == VIDEO_PAUSE ) && ( pVideo->fieldMode != 2 ) )
|
|
// pVideo->pictureDecoded = 1;
|
|
// to know that in step by step, the picture is decoded
|
|
}
|
|
}
|
|
/******************************************************/
|
|
/** HEADER HIT INTERRUPT **/
|
|
/******************************************************/
|
|
if ( ( pVideo->intStatus & HIT ) != 0 )
|
|
// Test Header hit interrupt
|
|
{
|
|
U16 temp = 0;
|
|
|
|
pVideo->intStatus = pVideo->intStatus & ~HIT;
|
|
// clear HIT bit
|
|
while ( VideoHeaderFifoEmpty())
|
|
/* Header fifo not available */
|
|
{
|
|
temp++;
|
|
if ( temp == 0xFFFF )
|
|
{
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = BUF_EMPTY;
|
|
SetErrorCode(ERR_HEADER_FIFO_EMPTY);
|
|
break;
|
|
}
|
|
} /* Waiting... */
|
|
compute = VideoRead(HDF);
|
|
//compute = VideoRead ( HDF );
|
|
/* load MSB */
|
|
pVideo->hdrPos = 0; /* start code is MSB */
|
|
if ( compute == 0x01 )
|
|
{
|
|
pVideo->hdrPos = 8; /* start code value is in LSB */
|
|
#ifndef STi3520A
|
|
pVideo->hdrNextWord = VideoRead ( HDF + 1 ) << 8;
|
|
#else
|
|
pVideo->hdrNextWord = VideoRead(HDF)<<8;//VideoRead ( HDF ) << 8;
|
|
#endif
|
|
VideoReadHeaderDataFifo ( pVideo );
|
|
/* Result in pVideo->hdrFirstWord */
|
|
}
|
|
else
|
|
{
|
|
pVideo->hdrNextWord = 0;
|
|
#ifndef STi3520A
|
|
pVideo->hdrFirstWord = VideoRead ( HDF + 1 );
|
|
#else
|
|
pVideo->hdrFirstWord = VideoRead(HDF);
|
|
#endif
|
|
pVideo->hdrFirstWord = pVideo->hdrFirstWord | ( compute << 8 );
|
|
}
|
|
/*
|
|
* on that point the start code value is always the MSByte of
|
|
* pVideo->hdrFirstWord
|
|
*/
|
|
|
|
switch ( pVideo->hdrFirstWord & 0xFF00 )
|
|
{
|
|
U32 buf_control;
|
|
U32 size_of_pict;
|
|
|
|
case SEQ:
|
|
DBG1('s');
|
|
VideoSequenceHeader ( pVideo );
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
break;
|
|
case EXT:
|
|
VideoExtensionHeader ( pVideo );
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
break;
|
|
case GOP:
|
|
DBG1('g');
|
|
VideoGopHeader ( pVideo );
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
break;
|
|
case PICT:
|
|
DBG1('h');
|
|
VideoPictureHeader ( pVideo );
|
|
//**********************************
|
|
//* This part of the code
|
|
//* Computes the size of last picture
|
|
//* and substracts it to lastbuffer level
|
|
//* This allows to track if pipe/scd are misalined
|
|
//**********************************
|
|
buf_control = VideoReadSCDCount ( pVideo );
|
|
if ( pVideo->LastScdCount > buf_control )
|
|
size_of_pict = ( 0x1000000L - pVideo->LastScdCount ) + buf_control;
|
|
else
|
|
size_of_pict = buf_control - pVideo->LastScdCount;
|
|
|
|
pVideo->LastScdCount = buf_control;
|
|
if ( pVideo->fastForward )
|
|
pVideo->LastPipeReset = 3;
|
|
pVideo->LastBufferLevel -= ( U16 ) ( size_of_pict >> 7 );
|
|
//******************************
|
|
//End of misalined pb tracking
|
|
//******************************
|
|
/* don't restart header search !!! */
|
|
if ( pVideo->skipMode ) // restart search only if we
|
|
// skip this picture
|
|
{
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
}
|
|
break;
|
|
case USER: // We don't care about user
|
|
// fields
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
break;
|
|
case SEQ_END: // end of sequence code
|
|
compute = VideoRead ( ITS ) << 8;
|
|
// this start code can be back to back with next one
|
|
compute = ( compute | VideoRead ( ITS + 1 ) );
|
|
// in such case the HDS bit can be set
|
|
pVideo->intStatus = ( pVideo->intStatus | compute ) & pVideo->intMask;
|
|
if ( !( pVideo->intStatus & HIT ) )
|
|
{
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
}
|
|
break;
|
|
case SEQ_ERR: // the chip will enter the
|
|
// automatic error concealment
|
|
// mode
|
|
compute = VideoRead ( ITS ) << 8;
|
|
// this start code can be back to back with next one
|
|
compute = ( compute | VideoRead ( ITS + 1 ) );
|
|
// in such case the HDS bit can be set
|
|
pVideo->intStatus = ( pVideo->intStatus | compute ) & pVideo->intMask;
|
|
if ( !( pVideo->intStatus & HIT ) )
|
|
{
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
/* Restart Header Search */
|
|
}
|
|
break;
|
|
default:
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = S_C_ERR;
|
|
SetErrorCode(ERR_UNKNOWN_SC);
|
|
// non video start code
|
|
break;
|
|
}
|
|
|
|
} // end of header hit interrupt
|
|
|
|
|
|
/******************************************************/
|
|
/** BIT BUFFER FULL INTERRUPT **/
|
|
/******************************************************/
|
|
if ( ( pVideo->intStatus & BBF ) != 0x0 )
|
|
/* Bit buffer full */
|
|
{
|
|
DBG1('*');
|
|
pVideo->intStatus = pVideo->intStatus & ~BBF;
|
|
// clear BBF bit
|
|
if ( pVideo->vbvReached == 1 ) /* bit buffer level too high */
|
|
{
|
|
if ( !pVideo->errCode )
|
|
pVideo->errCode = FULL_BUF; /* mention of the error */
|
|
SetErrorCode(ERR_BIT_BUFFER_FULL);
|
|
VideoWaitDec ( pVideo ); // put decoder in Wait mode
|
|
pVideo->NextInstr = pVideo->ZeroInstr;
|
|
}
|
|
else
|
|
{
|
|
S16 BitBufferLevel;
|
|
|
|
BitBufferLevel = BUF_FULL - 2;
|
|
VideoSetBBThresh(BitBufferLevel);
|
|
pVideo->intMask = PID | SER | PER | PSD | BOT | TOP | BBE | HIT;
|
|
/* enable all interrupts that may be used */
|
|
VideoRead ( ITS );
|
|
#ifdef STi3520A
|
|
VideoRead ( ITS + 1);
|
|
#endif
|
|
// to clear previous TOP VSYNC flag
|
|
pVideo->NextInstr.Exe = 1;; // decoding will start on
|
|
// next "good" Vsync */
|
|
pVideo->VsyncNumber = 0;
|
|
pVideo->pictDispIndex = 1;
|
|
pVideo->pCurrDisplay->nb_display_field = 1;
|
|
pVideo->vbvReached = 1;
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************/
|
|
//* pipeline ERROR **/
|
|
//*****************************************************/
|
|
// The pipeline reset is made here by software */
|
|
// It is also possible to enable the automatic */
|
|
// Pipeline reset by setting bit EPR of CTL reg. */
|
|
// This could be done in the Reset3500 routine */
|
|
// In this case the pipeline error interrupt is */
|
|
// only used as a flag for the external micro. */
|
|
//*****************************************************/
|
|
if ( ( pVideo->intStatus & PER ) != 0x0 )
|
|
{
|
|
DBG1('p');
|
|
|
|
pVideo->intStatus = pVideo->intStatus & ~PER;
|
|
// clear PER bit
|
|
// VideoPipeReset ( pVideo );
|
|
|
|
}
|
|
|
|
|
|
/******************************************************/
|
|
/** serious ERROR **/
|
|
/******************************************************/
|
|
if ( ( pVideo->intStatus & SER ) != 0x0 )
|
|
{
|
|
DBG1('s');
|
|
|
|
pVideo->intStatus = pVideo->intStatus & ~SER;
|
|
// clear SER bit
|
|
VideoPipeReset ( pVideo );
|
|
}
|
|
|
|
/********************************/
|
|
/* bit buffer empty interrupt */
|
|
/********************************/
|
|
if ( ( pVideo->intStatus & BBE ) != 0x0 )
|
|
// bit buffer empty
|
|
{
|
|
pVideo->intStatus = pVideo->intStatus & ~BBE;
|
|
// clear BBE bit
|
|
}
|
|
|
|
|
|
/********************************/
|
|
/* pipeline idle interrupt */
|
|
/********************************/
|
|
if ( ( pVideo->intStatus & PID ) != 0x0 )
|
|
// pipeline idle
|
|
{
|
|
//***************************************
|
|
// Check If pipe is misalined with scd
|
|
// and restart header search if it is
|
|
// the case
|
|
//***************************************
|
|
U32 NewCd;
|
|
U32 EnterBitBuffer;
|
|
U16 NewBbl;
|
|
U16 ExpectedBbl;
|
|
// clear PID bit
|
|
pVideo->intStatus = pVideo->intStatus & ~PID;
|
|
/* read BBL level */
|
|
NewBbl = VideoGetBBL();
|
|
/* Read number of compressed data loaded into the chip */
|
|
NewCd = VideoReadCDCount ( pVideo );
|
|
|
|
if ( NewCd < pVideo->LastCdCount )
|
|
EnterBitBuffer = ( 0x1000000L - pVideo->LastCdCount ) + NewCd;
|
|
else
|
|
EnterBitBuffer = ( NewCd - pVideo->LastCdCount );
|
|
|
|
//Expected Bitbuffer level is Old bbl + what enterred - what left
|
|
//pVideo->LastBufferLevel holds Old bbl + what enterred and has been
|
|
// updated in picture hit interrupt.
|
|
ExpectedBbl = pVideo->LastBufferLevel + ( EnterBitBuffer >> 8 ) - 2;
|
|
if ( pVideo->LastPipeReset == 0 )
|
|
{
|
|
/* BBL is lower than it should be !!! */
|
|
if ( NewBbl < ExpectedBbl )
|
|
{
|
|
DBG1('#');
|
|
/* here we force manually a new header search because */
|
|
/* the pipeline is supposed to have skipped a picture */
|
|
/* i.e. the start code detector and the pipeline are */
|
|
/* not synchronised on the same picture */
|
|
VideoLaunchHeadSearch ( pVideo );
|
|
pVideo->LastPipeReset = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pVideo->LastPipeReset--;
|
|
}
|
|
pVideo->LastCdCount = NewCd;
|
|
pVideo->LastBufferLevel = NewBbl;
|
|
}
|
|
|
|
/******************************************************/
|
|
/** END OF INTERRUPT ROUTINE **/
|
|
/******************************************************/
|
|
/* common to all interrupts */
|
|
/* set interrupt mask to the correct value */
|
|
} // end of while
|
|
return VideoITOccured;
|
|
}
|
|
|
|
//------------------------------- End of File --------------------------------
|