// $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? 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 ); }