2025-04-27 07:49:33 -04:00

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 --------------------------------