You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
813 lines
25 KiB
813 lines
25 KiB
// $Header: G:/SwDev/WDM/Video/bt848/rcs/Riscprog.cpp 1.14 1998/05/04 17:53:37 tomz Exp $
|
|
|
|
#include "riscprog.h"
|
|
#include "physaddr.h"
|
|
|
|
#define ClearMem( a ) memset( &##a, '\0', sizeof( a ) )
|
|
|
|
|
|
DWORD RISCProgram::GetDataBuffer( )
|
|
{
|
|
return dwLinBufAddr_;
|
|
}
|
|
|
|
void RISCProgram::SetDataBuffer( DWORD addr )
|
|
{
|
|
dwLinBufAddr_ = addr;
|
|
}
|
|
|
|
void RISCProgram::Dump( )
|
|
{
|
|
if( bAlreadyDumped_ ) {
|
|
return;
|
|
}
|
|
|
|
DebugOut((0, "; RiscProgram(%x) ProgAddr(%x) PhysProgAddr(%x)\n",
|
|
this,
|
|
GetProgAddress( ),
|
|
GetPhysProgAddr( )));
|
|
|
|
DebugOut((0, " RiscProgram(%x) dwBufAddr_(%x) dwLinBufAddr_(%x)\n",
|
|
this,
|
|
dwBufAddr_,
|
|
dwLinBufAddr_));
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
dwSize_ = 0;
|
|
DWORD* pProgLoc = (DWORD*) GetProgAddress( );
|
|
while( *pProgLoc++ != PROGRAM_TERMINATOR ) {
|
|
dwSize_++;
|
|
if( dwSize_ > 1024 ) {
|
|
dwSize_ = 0;
|
|
break;
|
|
}
|
|
}
|
|
DWORD dwTmpSize_ = dwSize_;
|
|
DebugOut((0, "; size = %d\n", dwSize_));
|
|
|
|
if( dwSize_ ) {
|
|
DebugOut((0, "%x ", GetPhysProgAddr( )));
|
|
}
|
|
|
|
PULONG pulProg = (PULONG) (ProgramSpace_->getLinearBase());
|
|
while( dwTmpSize_ >= 4 ) {
|
|
DebugOut((0, " %08x %08x %08x %08x\n",
|
|
pulProg[0],
|
|
pulProg[1],
|
|
pulProg[2],
|
|
pulProg[3]));
|
|
pulProg += 4;
|
|
dwTmpSize_ -= 4;
|
|
}
|
|
switch( dwTmpSize_ ) {
|
|
case 3:
|
|
DebugOut((0, " %08x %08x %08x\n",
|
|
pulProg[0],
|
|
pulProg[1],
|
|
pulProg[2]
|
|
));
|
|
break;
|
|
case 2:
|
|
DebugOut((0, " %08x %08x\n",
|
|
pulProg[0],
|
|
pulProg[1]
|
|
));
|
|
break;
|
|
case 1:
|
|
DebugOut((0, " %08x\n",
|
|
pulProg[0]
|
|
));
|
|
break;
|
|
}
|
|
|
|
bAlreadyDumped_ = TRUE;
|
|
|
|
#if 0
|
|
if( pChild_ != NULL ) {
|
|
// *** warning - recursion ***
|
|
pChild_->Dump();
|
|
}
|
|
#endif
|
|
|
|
bAlreadyDumped_ = FALSE;
|
|
}
|
|
|
|
/*
|
|
{
|
|
// Input
|
|
// DWORD : RiscProg ndx
|
|
// CreatedProgs : 12 elements ndx 0..11
|
|
// ActiveProgs : 12 elements ndx 12..23
|
|
// Skippers : 8 elements ndx 24..31
|
|
// Output
|
|
// Buffer filled with riscprog
|
|
int i = 0;
|
|
|
|
if ( !pDIOCParams->dioc_cbOutBuf || (pDIOCParams->dioc_cbInBuf != 4))
|
|
return -1; // invalid parameters
|
|
|
|
// pause
|
|
// CaptureContrll_->Pause() ;
|
|
|
|
// dump a prog
|
|
DWORD WhichProg = *((PDWORD) pDIOCParams->dioc_InBuf);
|
|
|
|
RiscPrgHandle hProg ;
|
|
|
|
if (WhichProg < 12) // CreatedProgs
|
|
{
|
|
hProg = CaptureContrll_->CreatedProgs_[WhichProg] ;
|
|
}
|
|
else if (WhichProg < 24) // Active
|
|
{
|
|
hProg = CaptureContrll_->ActiveProgs_[WhichProg % 12] ;
|
|
}
|
|
else // Skippers
|
|
{
|
|
hProg = CaptureContrll_->Skippers_[WhichProg % 12] ;
|
|
}
|
|
|
|
if(hProg)
|
|
{
|
|
char * pRetAddr = (char *)pDIOCParams->dioc_OutBuf;
|
|
DWORD physAddr = hProg->GetPhysProgAddr() ;
|
|
DWORD progSize = hProg->GetProgramSize();
|
|
char * linBuf = (char *) MapPhysToLinear((void *)physAddr, progSize, 0) ;
|
|
|
|
*((DWORD *) pRetAddr) = physAddr ;
|
|
pRetAddr+=4 ;
|
|
for (i = 0 ; i < progSize && i < pDIOCParams->dioc_cbOutBuf ; i++)
|
|
{
|
|
*pRetAddr++ = linBuf[i] ;
|
|
}
|
|
}
|
|
if ( pDIOCParams->dioc_bytesret )
|
|
*pDIOCParams->dioc_bytesret = i;
|
|
|
|
// and resume
|
|
// CaptureContrll_->Continue() ;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
/* Method: RISCProgram::ChangeAddress
|
|
* Purpose: Modifies existing program to use new destination address
|
|
* Input: dwNewAddr: DWORD - new buffer address
|
|
* Output: None
|
|
*/
|
|
void RISCProgram::ChangeAddress( DataBuf &buf )
|
|
{
|
|
Trace t("RISCProgram::ChangeAddress()");
|
|
//DebugOut((1, "RISCProgram::ChangeAddress(): this(%x), buf.pData_(%x)\n", this, buf.pData_));
|
|
Create( Interrupting_, buf, dwPlanarAdjust_, GenerateResync_, false );
|
|
}
|
|
|
|
/* Function: CreatePrologEpilog
|
|
* Purpose: Called from Create function to put proper sync codes at the beginning
|
|
* and at the end of a RISC program
|
|
* Input: pProgLoc: PDWORD - pointer to the instruction memory
|
|
* SyncBits: SyncCode
|
|
* CurCommand: Command & - reference to a command object
|
|
* Output: PDWORD - address of the next instruction
|
|
*/
|
|
inline PDWORD RISCProgram::CreatePrologEpilog( PDWORD pProgLoc, SyncCode SyncBits,
|
|
Command &CurCommand, bool Resync )
|
|
{
|
|
Trace t("RISCProgram::CreatePrologEpilog()");
|
|
|
|
CurCommand.Create( pProgLoc, SYNC, NULL, NULL, false );//, false, false );
|
|
CurCommand.SetSync( pProgLoc, SyncBits, Resync );
|
|
// advance to the next command's position
|
|
return pProgLoc + CurCommand.GetInstrSize();
|
|
}
|
|
|
|
inline bool IsWithin( int coord, int top, int bot )
|
|
{
|
|
Trace t("IsWithin()");
|
|
return bool( coord >= top && coord < bot );
|
|
}
|
|
|
|
inline PDWORD FinishWithSkip( int pixels, int bpp, PDWORD pProgLoc, Command &com )
|
|
{
|
|
Trace t("FinishWithSkip()");
|
|
|
|
WORD awByteCounts [1];
|
|
awByteCounts [0] = WORD( pixels * bpp );
|
|
return (LPDWORD)com.Create( pProgLoc, SKIP, awByteCounts, NULL,
|
|
true, false, true, false ); // safety, SOL, EOL, Intr
|
|
}
|
|
|
|
ErrorCode RISCProgram::GetDataBufPhys( DataBuf &buf )
|
|
{
|
|
Trace t("RISCProgram::GetDataBufPhys()");
|
|
|
|
dwBufAddr_ = GetPhysAddr( buf );
|
|
if ( dwBufAddr_ == (DWORD)-1 ) {
|
|
return Fail;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
/* Method: RISCProgram::AllocateStorage
|
|
* Purpose: Allocates a number of pages ( locked and physically contiguous ) to
|
|
* hold the new program
|
|
* Input: None
|
|
* Output: ErrorCode
|
|
*/
|
|
ErrorCode RISCProgram::AllocateStorage( bool extra, int )
|
|
{
|
|
Trace t("RISCProgram::AllocateStorage()");
|
|
|
|
if ( ProgramSpace_ )
|
|
return Success;
|
|
|
|
// figure out size of the memory to hold the program
|
|
// at least as many DWORDs as lines
|
|
DWORD dwProgramSize = ImageSize_.cy * sizeof( DWORD );
|
|
|
|
// scale up according to the data format
|
|
switch ( BufFormat_.GetColorFormat() ) {
|
|
case CF_RGB32:
|
|
case CF_RGB24:
|
|
case CF_RGB16:
|
|
case CF_RGB15:
|
|
case CF_Y8:
|
|
case CF_YUY2:
|
|
case CF_UYVY:
|
|
case CF_BTYUV:
|
|
case CF_RGB8:
|
|
case CF_RAW:
|
|
case CF_VBI:
|
|
dwProgramSize *= 2; // size of 'Write' command is 2 DWORDs
|
|
if ( extra == true ) // doing clipping
|
|
dwProgramSize *= 3;
|
|
break;
|
|
case CF_PL_422:
|
|
case CF_PL_411:
|
|
case CF_YUV9:
|
|
case CF_YUV12:
|
|
case CF_I420:
|
|
dwProgramSize *= 5; // Planar WRITE is 5 DWORDs
|
|
}
|
|
// add extra for page crossings
|
|
dwProgramSize += ImageSize_.cx * ImageSize_.cy * BufFormat_.GetBitCount() / 8
|
|
/ PAGE_SIZE * sizeof( DWORD ) * 5;
|
|
|
|
ProgramSpace_ = new PsPageBlock( dwProgramSize );
|
|
|
|
if ( ProgramSpace_ && ProgramSpace_->getLinearBase() != 0 )
|
|
return Success;
|
|
return Fail;
|
|
}
|
|
|
|
/* Function: GetAlternateSwitch
|
|
* Purpose: Chooses alternative instruction frequency
|
|
* Input: AlternateSwitch: int
|
|
* col: ColFmt, color format
|
|
* Output: None
|
|
*/
|
|
inline void GetAlternateSwitch( int &AlternateSwitch, ColFmt col )
|
|
{
|
|
Trace t("GetAlternateSwitch()");
|
|
|
|
AlternateSwitch = col == CF_YUV9 ? 4 :
|
|
col == CF_YUV12 ? 2 : 1;
|
|
}
|
|
|
|
/* Function: GetSplitAddr
|
|
* Purpose: Calculates page-aligned address
|
|
* Input: dwLinBufAddr: DWORD - linear address
|
|
* Output: DWORD
|
|
*/
|
|
inline DWORD GetSplitAddr( DWORD dwLinBufAddr )
|
|
{
|
|
Trace t("GetSplitAddr()");
|
|
return ( dwLinBufAddr + PAGE_SIZE ) & ~( PAGE_SIZE - 1 );//0xFFFFF000L;
|
|
// return ( dwLinBufAddr + 0x1000 ) & 0xFFFFF000L;
|
|
}
|
|
|
|
/* Function: GetSplitByteCount
|
|
* Purpose: Calculates number of bytes before the page boundary
|
|
* Input: dwLinBufAddr: DWORD, address
|
|
* Output: WORD, byte count
|
|
*/
|
|
inline WORD GetSplitByteCount( DWORD dwLinBufAddr )
|
|
{
|
|
Trace t("GetSplitByteCount()");
|
|
return WORD( PAGE_SIZE - BYTE_OFFSET( dwLinBufAddr ) );
|
|
// return WORD( 0x1000 - ( dwLinBufAddr & 0xFFF ) );
|
|
}
|
|
|
|
/* Function: GetSplitNumbers
|
|
* Purpose: Calculates addresses and byte counts when scan line crosses a page boundary
|
|
* Input: dwLinAddr: DWORD, starting linear address
|
|
* wByteCount: WORD &, number of bytes to move before page crossing
|
|
* wByteCSplit: WORD &, number of bytes to move after page crossing
|
|
* SecondAddr: DWORD &, reference to the DWORD contatining address of the starting
|
|
* address for the second 'write' instruction
|
|
* FirstAddr: DWORD &,
|
|
*/
|
|
void GetSplitNumbers( DataBuf buf, WORD &wFirstByteCount, WORD &wSecondByteCount,
|
|
DWORD &SecondAddr, DWORD &FirstAddr )
|
|
{
|
|
Trace t("GetSplitNumbers()");
|
|
|
|
// maybe can have some optimization here: if within the same page as previous
|
|
// call ( no split ), don't call out for the physical address - just
|
|
// increment the old physical address by difference in virtual addresses
|
|
FirstAddr = GetPhysAddr( buf );
|
|
|
|
if ( Need2Split( buf, wFirstByteCount ) ) {
|
|
|
|
wSecondByteCount = wFirstByteCount;
|
|
|
|
// lin address of the second write command ( page aligned )
|
|
SecondAddr = GetSplitAddr( DWORD( buf.pData_ ) );
|
|
|
|
// byte count of first write command
|
|
wFirstByteCount = GetSplitByteCount( DWORD( buf.pData_ ) );
|
|
wSecondByteCount -= wFirstByteCount;
|
|
|
|
// get the physical addresses
|
|
buf.pData_ = PBYTE( SecondAddr );
|
|
SecondAddr = GetPhysAddr( buf );
|
|
} else {
|
|
wSecondByteCount = 0;
|
|
SecondAddr = 0;
|
|
}
|
|
}
|
|
|
|
/* Function: AdjustByteCounts
|
|
* Purpose: This function is used to calculate 2 byte counts based on the given ratio
|
|
* Purpose:
|
|
*/
|
|
void AdjustByteCounts( WORD &smaller, WORD &larger, WORD total, WORD ratio )
|
|
{
|
|
Trace t("AdjustByteCounts()");
|
|
|
|
if ( ratio <= 1 ) {
|
|
smaller = WORD( total >> 1 );
|
|
} else
|
|
smaller = WORD( total / ratio );
|
|
smaller += (WORD)3;
|
|
smaller &= ~3;
|
|
larger = WORD( total - smaller );
|
|
}
|
|
|
|
/* Method: RISCProgram::Create
|
|
* Purpose: Creates a RISC program
|
|
* Input: NeedInterrupt: bool - flag
|
|
* Output: None
|
|
* Note: It is likely this function is used to simply change dst addresses of
|
|
* an already existing program. It does not seem to make much sense to write
|
|
* basically the same function ( or the one that has to parse existing program)
|
|
* to change addresses
|
|
*/
|
|
ErrorCode RISCProgram::Create( bool NeedInterrupt, DataBuf buf, DWORD dwPlanrAdjust,
|
|
bool rsync, bool LoopOnItself )
|
|
{
|
|
Trace t("RISCProgram::Create(2)");
|
|
|
|
dwPlanarAdjust_ = dwPlanrAdjust;
|
|
Interrupting_ = NeedInterrupt;
|
|
GenerateResync_ = rsync;
|
|
|
|
// allocate memory for the program first
|
|
if ( AllocateStorage() != Success )
|
|
return Fail;
|
|
|
|
// store the buffer address in case somebody will want to change clipping
|
|
if ( buf.pData_ && GetDataBufPhys( buf ) != Success )
|
|
return Fail;
|
|
|
|
// keep the linear address around
|
|
dwLinBufAddr_ = DWORD( buf.pData_ );
|
|
pSrb_ = buf.pSrb_;
|
|
DebugOut((1, "dwLinBufAddr_ = %x\n", dwLinBufAddr_));
|
|
|
|
// bad naming ?
|
|
DWORD dwLinBufAddr = dwLinBufAddr_;
|
|
|
|
// probably should create a class to handle these arrays
|
|
WORD awByteCounts [3];
|
|
DWORD adwAddresses [3];
|
|
|
|
Instruction MainInstrToUse, AltInstrToUse;
|
|
|
|
int AlternateSwitch = 1;
|
|
|
|
// used to increment planes' addresses
|
|
LONG PlanePitch1 = dwBufPitch_, ChromaPitch = dwBufPitch_;
|
|
|
|
// get size in bytes
|
|
DWORD dwYPlaneSize = ImageSize_.cy * dwBufPitch_;
|
|
|
|
// DebugOut((1, "buf addr = %x\n", dwLinBufAddr ) );
|
|
|
|
// this is a physical address
|
|
DWORD Plane1 = dwLinBufAddr_ + dwYPlaneSize, Plane2;
|
|
|
|
// initialize byte count for all planar modes
|
|
awByteCounts [0] = (WORD)ImageSize_.cx;
|
|
|
|
if ( !dwLinBufAddr_ ) { // hack to handle special case of creating a skipper for VBI streams
|
|
MainInstrToUse = SKIP123;
|
|
AltInstrToUse = SKIP123;
|
|
} else {
|
|
MainInstrToUse = WRITE1S23;
|
|
AltInstrToUse = WRITE123;
|
|
}
|
|
// handle all planar modes here
|
|
SyncCode SyncBits = SC_FM3;
|
|
|
|
// these guys used for the calculation of addresses
|
|
// for different planar mode combinations ( pitch > witdh, interleaving )
|
|
DWORD dwEqualPitchDivider = 1;
|
|
DWORD dwByteCountDivider = 1;
|
|
|
|
bool flip = false;
|
|
|
|
// prepare all the ugly things
|
|
switch ( BufFormat_.GetColorFormat() ) {
|
|
case CF_RGB32:
|
|
case CF_RGB24:
|
|
case CF_RGB16:
|
|
case CF_RGB15:
|
|
case CF_BTYUV:
|
|
case CF_RGB8:
|
|
flip = Interrupting_;
|
|
case CF_Y8:
|
|
case CF_YUY2:
|
|
case CF_UYVY:
|
|
case CF_RAW:
|
|
case CF_VBI:
|
|
if ( !dwLinBufAddr_ ) { // hack to handle special case of creating a skipper for VBI streams
|
|
MainInstrToUse = SKIP;
|
|
AltInstrToUse = SKIP;
|
|
} else {
|
|
MainInstrToUse = WRIT;
|
|
AltInstrToUse = WRIT;
|
|
}
|
|
awByteCounts [0] = (WORD)(ImageSize_.cx * BufFormat_.GetBitCount() / 8 );
|
|
// packed data to follow
|
|
SyncBits = SC_FM1;
|
|
break;
|
|
case CF_PL_422:
|
|
dwEqualPitchDivider = 2;
|
|
dwByteCountDivider = 2;
|
|
break;
|
|
case CF_PL_411:
|
|
dwEqualPitchDivider = 4;
|
|
dwByteCountDivider = 4;
|
|
break;
|
|
case CF_YUV9:
|
|
AlternateSwitch = 4;
|
|
dwEqualPitchDivider = 16;
|
|
dwByteCountDivider = 4;
|
|
break;
|
|
case CF_I420:
|
|
case CF_YUV12:
|
|
AlternateSwitch = 2;
|
|
dwEqualPitchDivider = 4;
|
|
dwByteCountDivider = 2;
|
|
} /*endswitch*/
|
|
|
|
awByteCounts [1] = awByteCounts [2] =
|
|
WORD( awByteCounts [0] / dwByteCountDivider );
|
|
|
|
Plane2 = Plane1 + dwYPlaneSize / dwEqualPitchDivider;
|
|
ChromaPitch /= dwByteCountDivider;
|
|
|
|
// need to adjust if doing a full-size planar capture.
|
|
Plane2 -= dwPlanarAdjust_;
|
|
Plane1 -= dwPlanarAdjust_;
|
|
Plane2 += dwPlanarAdjust_ / dwByteCountDivider;
|
|
Plane1 += dwPlanarAdjust_ / dwByteCountDivider;
|
|
|
|
// U goes first for this color format
|
|
if ( BufFormat_.GetColorFormat() == CF_I420 ) {
|
|
DWORD dwTmp = Plane1;
|
|
Plane1 = Plane2;
|
|
Plane2 = dwTmp;
|
|
}
|
|
// that's were the instructions are going
|
|
LPDWORD pProgLoc = (LPDWORD)(DWORD)ProgramSpace_->getLinearBase();
|
|
LPDWORD pProgStart = pProgLoc;
|
|
|
|
Command CurCommand; // this will create every command we need - yahoo !
|
|
|
|
// put one of the FM codes here if this program is for image data only
|
|
pProgLoc = CreatePrologEpilog( pProgLoc, SyncBits, CurCommand );
|
|
|
|
// init the destination address
|
|
if ( flip ) {
|
|
dwLinBufAddr += dwYPlaneSize;
|
|
PlanePitch1 = -PlanePitch1;
|
|
} else {
|
|
dwLinBufAddr -= PlanePitch1;
|
|
;
|
|
}
|
|
// initial adjustment of chroma pointers
|
|
Plane1 -= ChromaPitch;
|
|
Plane2 -= ChromaPitch;
|
|
|
|
// now go into a loop (up to the hight of the image) and create
|
|
// a command for every line. Commands depend on the data format
|
|
unsigned int i = 0;
|
|
while ( i < (unsigned)ImageSize_.cy ) {
|
|
|
|
Instruction CurInstr;
|
|
|
|
// now take care of vertically sub-sampled planar modes
|
|
if ( i % AlternateSwitch != 0 ) {
|
|
CurInstr = AltInstrToUse;
|
|
} else {
|
|
CurInstr = MainInstrToUse;
|
|
Plane2 += ChromaPitch;
|
|
Plane1 += ChromaPitch;
|
|
}
|
|
// advance the linear address to the next scan line
|
|
dwLinBufAddr += PlanePitch1;
|
|
|
|
// these arrays contain values for the second instruction
|
|
DWORD adwSecondAddr [3];
|
|
WORD FirstByteCount [3];
|
|
WORD SecondByteCount [3];
|
|
|
|
adwSecondAddr [0] = adwSecondAddr [1] = adwSecondAddr [2] =
|
|
SecondByteCount [0] = SecondByteCount [1] = SecondByteCount [2] = 0;
|
|
|
|
// initialize byte counts
|
|
memmove( FirstByteCount, awByteCounts, sizeof( FirstByteCount ) );
|
|
|
|
buf.pData_ = PBYTE( dwLinBufAddr );
|
|
if ( dwLinBufAddr_ ) // don't bother with the addresses, if we are SKIPping them !
|
|
GetSplitNumbers( buf, FirstByteCount [0], SecondByteCount [0],
|
|
adwSecondAddr [0], adwAddresses [0] );
|
|
|
|
PVOID pEOLLoc; // this is needed to set EOL bit in split instructions
|
|
|
|
if ( AlternateSwitch > 1 && dwLinBufAddr_ ) {
|
|
|
|
int split = 1;
|
|
// Y plane is already done
|
|
// now check if we better split instructions
|
|
// just make width half of original and create 2 instructions
|
|
if ( ImageSize_.cx > 320 && SecondByteCount [0 ] )
|
|
split = 2;
|
|
|
|
// temps for the loop
|
|
DWORD dwYPlane = dwLinBufAddr;
|
|
DWORD dwVPlane = Plane2;
|
|
DWORD dwUPlane = Plane1;
|
|
|
|
for ( int k = 0; k < split; k++ ) {
|
|
|
|
// initialize byte counts
|
|
memmove( FirstByteCount, awByteCounts, sizeof( FirstByteCount ) );
|
|
// and split them in half
|
|
for ( int l = 0; l < sizeof FirstByteCount / sizeof FirstByteCount [0]; l++ )
|
|
FirstByteCount [l] = WORD (FirstByteCount [l] / split); //create 2 instructions with half the pixels
|
|
|
|
// see if any of the planes crosses a page boundary
|
|
// very ugly... must use the bad structure
|
|
buf.pData_ = PBYTE( dwYPlane );
|
|
GetSplitNumbers( buf, FirstByteCount [0], SecondByteCount [0],
|
|
adwSecondAddr [0], adwAddresses [0] );
|
|
// V plane
|
|
buf.pData_ = PBYTE( dwVPlane );
|
|
GetSplitNumbers( buf, FirstByteCount [1], SecondByteCount [1],
|
|
adwSecondAddr [1], adwAddresses [1] );
|
|
// U plane
|
|
buf.pData_ = PBYTE( dwUPlane );
|
|
GetSplitNumbers( buf, FirstByteCount [2], SecondByteCount [2],
|
|
adwSecondAddr [2], adwAddresses [2] );
|
|
|
|
// can not have zero Y byte count
|
|
if ( !SecondByteCount [0] && ( SecondByteCount [1] || SecondByteCount [2] ) ) {
|
|
FirstByteCount [0] -= max( SecondByteCount [1], SecondByteCount [2] );
|
|
FirstByteCount [0] &= ~3; // need to align for the second address
|
|
SecondByteCount [0] = WORD( awByteCounts [0] / split - FirstByteCount [0] );
|
|
// second addr starts where first ends; no page crossing
|
|
adwSecondAddr [0] = adwAddresses [0] + FirstByteCount [0];
|
|
}
|
|
// now make sure that there are no zero chroma byte counts
|
|
// adjust chroma byte counts in proportion to luma byte counts split
|
|
if ( SecondByteCount [0] ) {
|
|
if ( !SecondByteCount [1] ) {
|
|
if ( SecondByteCount [0] > FirstByteCount [0] )
|
|
AdjustByteCounts( FirstByteCount [1], SecondByteCount [1], FirstByteCount [1],
|
|
WORD( SecondByteCount [0] / FirstByteCount [0] ) );
|
|
else
|
|
AdjustByteCounts( SecondByteCount [1], FirstByteCount [1], FirstByteCount [1],
|
|
WORD( FirstByteCount [0] / SecondByteCount [0] ) );
|
|
adwSecondAddr [1] = adwAddresses [1] + FirstByteCount [1];
|
|
}
|
|
if ( !SecondByteCount [2] ) {
|
|
if ( SecondByteCount [0] > FirstByteCount [0] )
|
|
AdjustByteCounts( FirstByteCount [2], SecondByteCount [2], FirstByteCount [2],
|
|
WORD( SecondByteCount [0] / FirstByteCount [0] ) );
|
|
else
|
|
AdjustByteCounts( SecondByteCount [2], FirstByteCount [2], FirstByteCount [2],
|
|
WORD( FirstByteCount [0] / SecondByteCount [0] ) );
|
|
adwSecondAddr [2] = adwAddresses [2] + FirstByteCount [2];
|
|
}
|
|
}
|
|
// now write out the instructions
|
|
// first command. SOL==true, EOL==false
|
|
pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
|
|
FirstByteCount, adwAddresses, LoopOnItself, k == 0, false );
|
|
pEOLLoc = CurCommand.GetInstrAddr();
|
|
|
|
if ( SecondByteCount [0] || SecondByteCount [1] || SecondByteCount [2] ) {
|
|
// second command
|
|
pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
|
|
SecondByteCount, adwSecondAddr, LoopOnItself, false, false );
|
|
pEOLLoc = CurCommand.GetInstrAddr();
|
|
}
|
|
// adjust starting addresses
|
|
dwYPlane += awByteCounts [0] / 2;
|
|
dwVPlane += awByteCounts [1] / 2;
|
|
dwUPlane += awByteCounts [2] / 2;
|
|
} /* endfor */
|
|
// do not forget the EOL bit !
|
|
CurCommand.SetEOL( pEOLLoc );
|
|
|
|
} else {
|
|
// first command. SOL==true, EOL==false
|
|
pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
|
|
FirstByteCount, adwAddresses, LoopOnItself, true, false );
|
|
pEOLLoc = CurCommand.GetInstrAddr();
|
|
|
|
if ( SecondByteCount [0] || SecondByteCount [1] || SecondByteCount [2] ) {
|
|
// second command
|
|
pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
|
|
SecondByteCount, adwSecondAddr, LoopOnItself, false );
|
|
} else
|
|
CurCommand.SetEOL( pEOLLoc );
|
|
} /* endif */
|
|
i++;
|
|
} /* endwhile */
|
|
|
|
pChainAddress_ = pProgLoc;
|
|
pIRQAddress_ = pProgLoc;
|
|
|
|
PutInChain();
|
|
|
|
Skipped_ = false;
|
|
dwSize_ = (DWORD)pProgLoc - (DWORD)pProgStart;
|
|
|
|
return Success;
|
|
}
|
|
|
|
/* Method: RISCProgram::PutInChain
|
|
* Purpose: Restores the chain of programs this program was in.
|
|
* Input: None
|
|
* Output: None
|
|
* Note: The chain is destroyed when clipping is set or buffer address is changed
|
|
*/
|
|
void RISCProgram::PutInChain()
|
|
{
|
|
Trace t("RISCProgram::PutInChain()");
|
|
|
|
if ( pChild_ )
|
|
SetChain( pChild_ );
|
|
|
|
if ( pParent_ )
|
|
pParent_->SetChain( this );
|
|
}
|
|
|
|
/* Method: RISCProgram::SetChain
|
|
* Purpose: Chains this program to another one
|
|
* Input: dwProgAddr: DWORD - address of a first instruction in the next program
|
|
* Output: None
|
|
*/
|
|
void RISCProgram::SetChain( RISCProgram *ChainTo )
|
|
{
|
|
Trace t("RISCProgram::SetChain()");
|
|
|
|
if ( !ChainTo )
|
|
return;
|
|
|
|
// now we know where we are chaining to
|
|
pChild_ = ChainTo;
|
|
|
|
// now child knows who chains to it.Does it really want to know its parent?<g>
|
|
pChild_->SetParent( this );
|
|
|
|
SetJump( (PDWORD)pChild_->GetPhysProgAddr() );
|
|
}
|
|
|
|
/* Method: RISCProgram::Skip
|
|
* Purpose: Changes first instruction so program jumps over itself and to the child
|
|
* Input: None
|
|
* Output: None
|
|
* Note: This functionality is useful when there are not enough data buffers
|
|
* to supply for this program
|
|
*/
|
|
void RISCProgram::Skip()
|
|
{
|
|
Trace t("RISCProgram::Skip()");
|
|
|
|
// change first SYNC into JUMP
|
|
PDWORD pTmpAddr = pChainAddress_;
|
|
pChainAddress_ = (PDWORD)GetProgAddress();
|
|
ULONG len;
|
|
DWORD PhysAddr = StreamClassGetPhysicalAddress( gpHwDeviceExtension, NULL,
|
|
pTmpAddr, DmaBuffer, &len ).LowPart;
|
|
|
|
SetJump( (PDWORD)PhysAddr );
|
|
pChainAddress_ = pTmpAddr;
|
|
|
|
Skipped_ = true;
|
|
}
|
|
|
|
/* Method: RISCProgram::SetJump
|
|
* Purpose: Creates a JUMP instruction to chain some place
|
|
* Input: JumpAddr: PDWORD - target address
|
|
* Output: None
|
|
*/
|
|
void RISCProgram::SetJump( PDWORD JumpAddr )
|
|
{
|
|
Trace t("RISCProgram::SetJump()");
|
|
|
|
Command JumpCommand;
|
|
DWORD adwAddresses [1];
|
|
adwAddresses [0] = (DWORD)JumpAddr;
|
|
JumpCommand.Create( pChainAddress_, JUMP, NULL, adwAddresses, false );
|
|
// make the last JUMP interrupt
|
|
if ( Interrupting_ ) {
|
|
JumpCommand.SetIRQ( pIRQAddress_ );
|
|
if ( Counting_ )
|
|
SetToCount();
|
|
else
|
|
ResetStatus();
|
|
}
|
|
}
|
|
|
|
/* Method: RISCProgram::CreateLoop
|
|
* Purpose: Creates a closed loop at the end of a RISC program
|
|
* Input: resync: bool - value of the resync bit
|
|
* Output: None
|
|
*/
|
|
void RISCProgram::CreateLoop( bool resync )
|
|
{
|
|
Trace t("RISCProgram::CreateLoop()");
|
|
|
|
Command SyncCommand( SYNC );
|
|
SyncCommand.SetResync( pChainAddress_, resync );
|
|
if ( resync == true ) {
|
|
DWORD adwAddresses [1];
|
|
ULONG len;
|
|
DWORD PhysAddr = StreamClassGetPhysicalAddress( gpHwDeviceExtension, NULL,
|
|
pChainAddress_, DmaBuffer, &len ).LowPart;
|
|
|
|
adwAddresses [0] = PhysAddr;
|
|
SyncCommand.Create( pChainAddress_, JUMP, NULL, adwAddresses );
|
|
}
|
|
}
|
|
|
|
/* Method: RISCProgram::Create
|
|
* Purpose: Creates a simple SYNC and JUMP program
|
|
* Input: SyncBits: SyncCode - defines what code to do resync with
|
|
* Output: None
|
|
*/
|
|
ErrorCode RISCProgram::Create( SyncCode SyncBits, bool resync )
|
|
{
|
|
Trace t("RISCProgram::Create(3)");
|
|
|
|
// allocate memory for the program first
|
|
if ( AllocateStorage() != Success )
|
|
return Fail;
|
|
|
|
Command CurCommand; // this will create every command we need - yahoo !
|
|
|
|
// that's were the instructions are going
|
|
LPDWORD pProgLoc = (LPDWORD)ProgramSpace_->getLinearBase();
|
|
LPDWORD pProgStart = pProgLoc;
|
|
|
|
// put one of the FM or VRx codes here
|
|
pProgLoc = CreatePrologEpilog( pProgLoc, SyncBits, CurCommand, resync );
|
|
pChainAddress_ = pProgLoc;
|
|
CreateLoop( true );
|
|
|
|
dwSize_ = (DWORD)pProgLoc - (DWORD)pProgStart;
|
|
|
|
return Success;
|
|
}
|
|
|
|
RISCProgram::~RISCProgram()
|
|
{
|
|
Trace t("RISCProgram::~RISCProgram(3)");
|
|
delete ProgramSpace_;
|
|
ProgramSpace_ = NULL;
|
|
if ( pParent_ )
|
|
pParent_->SetChild( NULL );
|
|
}
|
|
|
|
|