| /**CFile**************************************************************** |
| |
| FileName [saigRetMin.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Sequential AIG package.] |
| |
| Synopsis [Min-area retiming for the AIG.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: saigRetMin.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "saig.h" |
| |
| #include "opt/nwk/nwk.h" |
| #include "sat/cnf/cnf.h" |
| #include "sat/bsat/satSolver.h" |
| #include "sat/bsat/satStore.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives the initial state after backward retiming.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Int_t * Saig_ManRetimeInitState( Aig_Man_t * p ) |
| { |
| int nConfLimit = 1000000; |
| Vec_Int_t * vCiIds, * vInit = NULL; |
| Cnf_Dat_t * pCnf; |
| sat_solver * pSat; |
| Aig_Obj_t * pObj; |
| int i, RetValue, * pModel; |
| // solve the SAT problem |
| pCnf = Cnf_DeriveSimpleForRetiming( p ); |
| pSat = (sat_solver *)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); |
| if ( pSat == NULL ) |
| { |
| Cnf_DataFree( pCnf ); |
| return NULL; |
| } |
| RetValue = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfLimit, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 ); |
| assert( RetValue != l_Undef ); |
| // create counter-example |
| if ( RetValue == l_True ) |
| { |
| // accumulate SAT variables of the CIs |
| vCiIds = Vec_IntAlloc( Aig_ManCiNum(p) ); |
| Aig_ManForEachCi( p, pObj, i ) |
| Vec_IntPush( vCiIds, pCnf->pVarNums[pObj->Id] ); |
| // create the model |
| pModel = Sat_SolverGetModel( pSat, vCiIds->pArray, vCiIds->nSize ); |
| vInit = Vec_IntAllocArray( pModel, Aig_ManCiNum(p) ); |
| Vec_IntFree( vCiIds ); |
| } |
| sat_solver_delete( pSat ); |
| Cnf_DataFree( pCnf ); |
| return vInit; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Uses UNSAT core to find the part of AIG to be excluded.] |
| |
| Description [Returns the number of the PO that appears in the UNSAT core.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Saig_ManRetimeUnsatCore( Aig_Man_t * p, int fVerbose ) |
| { |
| int fVeryVerbose = 0; |
| int nConfLimit = 1000000; |
| void * pSatCnf = NULL; |
| Intp_Man_t * pManProof; |
| Vec_Int_t * vCore = NULL; |
| Cnf_Dat_t * pCnf; |
| sat_solver * pSat; |
| Aig_Obj_t * pObj; |
| int * pClause1, * pClause2, * pLit, * pVars; |
| int i, RetValue, iBadPo, iClause, nVars, nPos; |
| // create the SAT solver |
| pCnf = Cnf_DeriveSimpleForRetiming( p ); |
| pSat = sat_solver_new(); |
| sat_solver_store_alloc( pSat ); |
| sat_solver_setnvars( pSat, pCnf->nVars ); |
| for ( i = 0; i < pCnf->nClauses; i++ ) |
| { |
| if ( !sat_solver_addclause( pSat, pCnf->pClauses[i], pCnf->pClauses[i+1] ) ) |
| { |
| Cnf_DataFree( pCnf ); |
| sat_solver_delete( pSat ); |
| return -1; |
| } |
| } |
| sat_solver_store_mark_roots( pSat ); |
| // solve the problem |
| RetValue = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfLimit, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 ); |
| assert( RetValue != l_Undef ); |
| assert( RetValue == l_False ); |
| pSatCnf = sat_solver_store_release( pSat ); |
| sat_solver_delete( pSat ); |
| // derive the UNSAT core |
| pManProof = Intp_ManAlloc(); |
| vCore = (Vec_Int_t *)Intp_ManUnsatCore( pManProof, (Sto_Man_t *)pSatCnf, 0, fVeryVerbose ); |
| Intp_ManFree( pManProof ); |
| Sto_ManFree( (Sto_Man_t *)pSatCnf ); |
| // derive the set of variables on which the core depends |
| // collect the variable numbers |
| nVars = 0; |
| pVars = ABC_ALLOC( int, pCnf->nVars ); |
| memset( pVars, 0, sizeof(int) * pCnf->nVars ); |
| Vec_IntForEachEntry( vCore, iClause, i ) |
| { |
| pClause1 = pCnf->pClauses[iClause]; |
| pClause2 = pCnf->pClauses[iClause+1]; |
| for ( pLit = pClause1; pLit < pClause2; pLit++ ) |
| { |
| if ( pVars[ (*pLit) >> 1 ] == 0 ) |
| nVars++; |
| pVars[ (*pLit) >> 1 ] = 1; |
| if ( fVeryVerbose ) |
| printf( "%s%d ", ((*pLit) & 1)? "-" : "+", (*pLit) >> 1 ); |
| } |
| if ( fVeryVerbose ) |
| printf( "\n" ); |
| } |
| // collect the nodes |
| if ( fVeryVerbose ) { |
| Aig_ManForEachObj( p, pObj, i ) |
| if ( pCnf->pVarNums[pObj->Id] >= 0 && pVars[ pCnf->pVarNums[pObj->Id] ] == 1 ) |
| { |
| Aig_ObjPrint( p, pObj ); |
| printf( "\n" ); |
| } |
| } |
| // pick the first PO in the list |
| nPos = 0; |
| iBadPo = -1; |
| Aig_ManForEachCo( p, pObj, i ) |
| if ( pCnf->pVarNums[pObj->Id] >= 0 && pVars[ pCnf->pVarNums[pObj->Id] ] == 1 ) |
| { |
| if ( iBadPo == -1 ) |
| iBadPo = i; |
| nPos++; |
| } |
| if ( fVerbose ) |
| printf( "UNSAT core: %d clauses, %d variables, %d POs. ", Vec_IntSize(vCore), nVars, nPos ); |
| ABC_FREE( pVars ); |
| Vec_IntFree( vCore ); |
| Cnf_DataFree( pCnf ); |
| return iBadPo; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Marks the TFI cone with the current traversal ID.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Saig_ManMarkCone_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) |
| { |
| if ( pObj == NULL ) |
| return; |
| if ( Aig_ObjIsTravIdCurrent( p, pObj ) ) |
| return; |
| Aig_ObjSetTravIdCurrent( p, pObj ); |
| Saig_ManMarkCone_rec( p, Aig_ObjFanin0(pObj) ); |
| Saig_ManMarkCone_rec( p, Aig_ObjFanin1(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of nodes to get registers after retiming.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Saig_ManRetimeCountCut( Aig_Man_t * p, Vec_Ptr_t * vCut ) |
| { |
| Vec_Ptr_t * vNodes; |
| Aig_Obj_t * pObj, * pFanin; |
| int i, RetValue; |
| // mark the cones |
| Aig_ManIncrementTravId( p ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| Saig_ManMarkCone_rec( p, pObj ); |
| // collect the new cut |
| vNodes = Vec_PtrAlloc( 1000 ); |
| Aig_ManForEachObj( p, pObj, i ) |
| { |
| if ( Aig_ObjIsTravIdCurrent(p, pObj) ) |
| continue; |
| pFanin = Aig_ObjFanin0( pObj ); |
| if ( pFanin && !pFanin->fMarkA && Aig_ObjIsTravIdCurrent(p, pFanin) ) |
| { |
| Vec_PtrPush( vNodes, pFanin ); |
| pFanin->fMarkA = 1; |
| } |
| pFanin = Aig_ObjFanin1( pObj ); |
| if ( pFanin && !pFanin->fMarkA && Aig_ObjIsTravIdCurrent(p, pFanin) ) |
| { |
| Vec_PtrPush( vNodes, pFanin ); |
| pFanin->fMarkA = 1; |
| } |
| } |
| Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) |
| pObj->fMarkA = 0; |
| RetValue = Vec_PtrSize( vNodes ); |
| Vec_PtrFree( vNodes ); |
| return RetValue; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Duplicates the AIG recursively.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Saig_ManRetimeDup_rec( Aig_Man_t * pNew, Aig_Obj_t * pObj ) |
| { |
| if ( pObj->pData ) |
| return; |
| assert( Aig_ObjIsNode(pObj) ); |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin0(pObj) ); |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin1(pObj) ); |
| pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Duplicates the AIG while retiming the registers to the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Man_t * Saig_ManRetimeDupForward( Aig_Man_t * p, Vec_Ptr_t * vCut ) |
| { |
| Aig_Man_t * pNew; |
| Aig_Obj_t * pObj, * pObjLi, * pObjLo; |
| int i; |
| // mark the cones under the cut |
| // assert( Vec_PtrSize(vCut) == Saig_ManRetimeCountCut(p, vCut) ); |
| // create the new manager |
| pNew = Aig_ManStart( Aig_ManObjNumMax(p) ); |
| pNew->pName = Abc_UtilStrsav( p->pName ); |
| pNew->pSpec = Abc_UtilStrsav( p->pSpec ); |
| pNew->nRegs = Vec_PtrSize(vCut); |
| pNew->nTruePis = p->nTruePis; |
| pNew->nTruePos = p->nTruePos; |
| // create the true PIs |
| Aig_ManCleanData( p ); |
| Aig_ManConst1(p)->pData = Aig_ManConst1(pNew); |
| Saig_ManForEachPi( p, pObj, i ) |
| pObj->pData = Aig_ObjCreateCi( pNew ); |
| // create the registers |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| pObj->pData = Aig_NotCond( Aig_ObjCreateCi(pNew), pObj->fPhase ); |
| // duplicate logic above the cut |
| Aig_ManForEachCo( p, pObj, i ) |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin0(pObj) ); |
| // create the true POs |
| Saig_ManForEachPo( p, pObj, i ) |
| Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) ); |
| // remember value in LI |
| Saig_ManForEachLi( p, pObj, i ) |
| pObj->pData = Aig_ObjChild0Copy(pObj); |
| // transfer values from the LIs to the LOs |
| Saig_ManForEachLiLo( p, pObjLi, pObjLo, i ) |
| pObjLo->pData = pObjLi->pData; |
| // erase the data values on the internal nodes of the cut |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| if ( Aig_ObjIsNode(pObj) ) |
| pObj->pData = NULL; |
| // duplicate logic below the cut |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| { |
| Saig_ManRetimeDup_rec( pNew, pObj ); |
| Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)pObj->pData, pObj->fPhase) ); |
| } |
| Aig_ManCleanup( pNew ); |
| return pNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Duplicates the AIG while retiming the registers to the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Man_t * Saig_ManRetimeDupBackward( Aig_Man_t * p, Vec_Ptr_t * vCut, Vec_Int_t * vInit ) |
| { |
| Aig_Man_t * pNew; |
| Aig_Obj_t * pObj, * pObjLi, * pObjLo; |
| int i; |
| // mark the cones under the cut |
| // assert( Vec_PtrSize(vCut) == Saig_ManRetimeCountCut(p, vCut) ); |
| // create the new manager |
| pNew = Aig_ManStart( Aig_ManObjNumMax(p) ); |
| pNew->pName = Abc_UtilStrsav( p->pName ); |
| pNew->pSpec = Abc_UtilStrsav( p->pSpec ); |
| pNew->nRegs = Vec_PtrSize(vCut); |
| pNew->nTruePis = p->nTruePis; |
| pNew->nTruePos = p->nTruePos; |
| // create the true PIs |
| Aig_ManCleanData( p ); |
| Aig_ManConst1(p)->pData = Aig_ManConst1(pNew); |
| Saig_ManForEachPi( p, pObj, i ) |
| pObj->pData = Aig_ObjCreateCi( pNew ); |
| // create the registers |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| pObj->pData = Aig_NotCond( Aig_ObjCreateCi(pNew), vInit?Vec_IntEntry(vInit,i):0 ); |
| // duplicate logic above the cut and remember values |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin0(pObj) ); |
| pObj->pData = Aig_ObjChild0Copy(pObj); |
| } |
| // transfer values from the LIs to the LOs |
| Saig_ManForEachLiLo( p, pObjLi, pObjLo, i ) |
| pObjLo->pData = pObjLi->pData; |
| // erase the data values on the internal nodes of the cut |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| if ( Aig_ObjIsNode(pObj) ) |
| pObj->pData = NULL; |
| // replicate the data on the constant node and the PIs |
| pObj = Aig_ManConst1(p); |
| pObj->pData = Aig_ManConst1(pNew); |
| Saig_ManForEachPi( p, pObj, i ) |
| pObj->pData = Aig_ManCi( pNew, i ); |
| // duplicate logic below the cut |
| Saig_ManForEachPo( p, pObj, i ) |
| { |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin0(pObj) ); |
| Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) ); |
| } |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| { |
| Saig_ManRetimeDup_rec( pNew, pObj ); |
| Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)pObj->pData, vInit?Vec_IntEntry(vInit,i):0) ); |
| } |
| Aig_ManCleanup( pNew ); |
| return pNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives AIG for the initial state computation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Man_t * Saig_ManRetimeDupInitState( Aig_Man_t * p, Vec_Ptr_t * vCut ) |
| { |
| Aig_Man_t * pNew; |
| Aig_Obj_t * pObj; |
| int i; |
| // mark the cones under the cut |
| // assert( Vec_PtrSize(vCut) == Saig_ManRetimeCountCut(p, vCut) ); |
| // create the new manager |
| pNew = Aig_ManStart( Aig_ManObjNumMax(p) ); |
| // create the true PIs |
| Aig_ManCleanData( p ); |
| Aig_ManConst1(p)->pData = Aig_ManConst1(pNew); |
| // create the registers |
| Vec_PtrForEachEntry( Aig_Obj_t *, vCut, pObj, i ) |
| pObj->pData = Aig_ObjCreateCi(pNew); |
| // duplicate logic above the cut and create POs |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| Saig_ManRetimeDup_rec( pNew, Aig_ObjFanin0(pObj) ); |
| Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) ); |
| } |
| return pNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the array of bad registers.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Saig_ManGetRegistersToExclude( Aig_Man_t * p ) |
| { |
| Vec_Ptr_t * vNodes; |
| Aig_Obj_t * pObj, * pFanin; |
| int i, Diffs; |
| assert( Saig_ManRegNum(p) > 0 ); |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| pFanin = Aig_ObjFanin0(pObj); |
| if ( !Aig_ObjFaninC0(pObj) ) |
| pFanin->fMarkA = 1; |
| else |
| pFanin->fMarkB = 1; |
| } |
| Diffs = 0; |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| pFanin = Aig_ObjFanin0(pObj); |
| Diffs += pFanin->fMarkA && pFanin->fMarkB; |
| } |
| vNodes = Vec_PtrAlloc( 100 ); |
| if ( Diffs > 0 ) |
| { |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| pFanin = Aig_ObjFanin0(pObj); |
| if ( pFanin->fMarkA && pFanin->fMarkB ) |
| Vec_PtrPush( vNodes, pObj ); |
| } |
| assert( Vec_PtrSize(vNodes) == Diffs ); |
| } |
| Saig_ManForEachLi( p, pObj, i ) |
| { |
| pFanin = Aig_ObjFanin0(pObj); |
| pFanin->fMarkA = pFanin->fMarkB = 0; |
| } |
| return vNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Hides the registers that cannot be backward retimed.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Saig_ManHideBadRegs( Aig_Man_t * p, Vec_Ptr_t * vBadRegs ) |
| { |
| Vec_Ptr_t * vPisNew, * vPosNew; |
| Aig_Obj_t * pObjLi, * pObjLo; |
| int nTruePi, nTruePo, nBadRegs, i; |
| if ( Vec_PtrSize(vBadRegs) == 0 ) |
| return 0; |
| // attached LOs to LIs |
| Saig_ManForEachLiLo( p, pObjLi, pObjLo, i ) |
| pObjLi->pData = pObjLo; |
| // reorder them by putting bad registers first |
| vPisNew = Vec_PtrDup( p->vCis ); |
| vPosNew = Vec_PtrDup( p->vCos ); |
| nTruePi = Aig_ManCiNum(p) - Aig_ManRegNum(p); |
| nTruePo = Aig_ManCoNum(p) - Aig_ManRegNum(p); |
| assert( nTruePi == p->nTruePis ); |
| assert( nTruePo == p->nTruePos ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vBadRegs, pObjLi, i ) |
| { |
| Vec_PtrWriteEntry( vPisNew, nTruePi++, pObjLi->pData ); |
| Vec_PtrWriteEntry( vPosNew, nTruePo++, pObjLi ); |
| pObjLi->fMarkA = 1; |
| } |
| Saig_ManForEachLiLo( p, pObjLi, pObjLo, i ) |
| { |
| if ( pObjLi->fMarkA ) |
| { |
| pObjLi->fMarkA = 0; |
| continue; |
| } |
| Vec_PtrWriteEntry( vPisNew, nTruePi++, pObjLo ); |
| Vec_PtrWriteEntry( vPosNew, nTruePo++, pObjLi ); |
| } |
| // check the sizes |
| assert( nTruePi == Aig_ManCiNum(p) ); |
| assert( nTruePo == Aig_ManCoNum(p) ); |
| // transfer the arrays |
| Vec_PtrFree( p->vCis ); p->vCis = vPisNew; |
| Vec_PtrFree( p->vCos ); p->vCos = vPosNew; |
| // update the PIs |
| nBadRegs = Vec_PtrSize(vBadRegs); |
| p->nRegs -= nBadRegs; |
| p->nTruePis += nBadRegs; |
| p->nTruePos += nBadRegs; |
| return nBadRegs; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Exposes bad registers.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Saig_ManExposeBadRegs( Aig_Man_t * p, int nBadRegs ) |
| { |
| p->nRegs += nBadRegs; |
| p->nTruePis -= nBadRegs; |
| p->nTruePos -= nBadRegs; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs min-area retiming backward with initial state.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Man_t * Saig_ManRetimeMinAreaBackward( Aig_Man_t * pNew, int fVerbose ) |
| { |
| Aig_Man_t * pInit, * pFinal; |
| Vec_Ptr_t * vBadRegs, * vCut; |
| Vec_Int_t * vInit; |
| int iBadReg; |
| // transform the AIG to have no bad registers |
| vBadRegs = Saig_ManGetRegistersToExclude( pNew ); |
| if ( fVerbose && Vec_PtrSize(vBadRegs) ) |
| printf( "Excluding %d registers that cannot be backward retimed.\n", Vec_PtrSize(vBadRegs) ); |
| while ( 1 ) |
| { |
| Saig_ManHideBadRegs( pNew, vBadRegs ); |
| Vec_PtrFree( vBadRegs ); |
| // compute cut |
| vCut = Nwk_ManDeriveRetimingCut( pNew, 0, fVerbose ); |
| if ( Vec_PtrSize(vCut) >= Aig_ManRegNum(pNew) ) |
| { |
| Vec_PtrFree( vCut ); |
| return NULL; |
| } |
| // derive the initial state |
| pInit = Saig_ManRetimeDupInitState( pNew, vCut ); |
| vInit = Saig_ManRetimeInitState( pInit ); |
| if ( vInit != NULL ) |
| { |
| pFinal = Saig_ManRetimeDupBackward( pNew, vCut, vInit ); |
| Vec_IntFree( vInit ); |
| Vec_PtrFree( vCut ); |
| Aig_ManStop( pInit ); |
| return pFinal; |
| } |
| Vec_PtrFree( vCut ); |
| // there is no initial state - find the offending output |
| iBadReg = Saig_ManRetimeUnsatCore( pInit, fVerbose ); |
| Aig_ManStop( pInit ); |
| if ( fVerbose ) |
| printf( "Excluding register %d.\n", iBadReg ); |
| // prepare to remove this output |
| vBadRegs = Vec_PtrAlloc( 1 ); |
| Vec_PtrPush( vBadRegs, Aig_ManCo( pNew, Saig_ManPoNum(pNew) + iBadReg ) ); |
| } |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs min-area retiming.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Aig_Man_t * Saig_ManRetimeMinArea( Aig_Man_t * p, int nMaxIters, int fForwardOnly, int fBackwardOnly, int fInitial, int fVerbose ) |
| { |
| Vec_Ptr_t * vCut; |
| Aig_Man_t * pNew, * pTemp, * pCopy; |
| int i, fChanges; |
| pNew = Aig_ManDupSimple( p ); |
| // perform several iterations of forward retiming |
| fChanges = 0; |
| if ( !fBackwardOnly ) |
| for ( i = 0; i < nMaxIters; i++ ) |
| { |
| if ( Saig_ManRegNum(pNew) == 0 ) |
| break; |
| vCut = Nwk_ManDeriveRetimingCut( pNew, 1, fVerbose ); |
| if ( Vec_PtrSize(vCut) >= Aig_ManRegNum(pNew) ) |
| { |
| if ( fVerbose && !fChanges ) |
| printf( "Forward retiming cannot reduce registers.\n" ); |
| Vec_PtrFree( vCut ); |
| break; |
| } |
| pNew = Saig_ManRetimeDupForward( pTemp = pNew, vCut ); |
| Aig_ManStop( pTemp ); |
| Vec_PtrFree( vCut ); |
| if ( fVerbose ) |
| Aig_ManReportImprovement( p, pNew ); |
| fChanges = 1; |
| } |
| // perform several iterations of backward retiming |
| fChanges = 0; |
| if ( !fForwardOnly && !fInitial ) |
| for ( i = 0; i < nMaxIters; i++ ) |
| { |
| if ( Saig_ManRegNum(pNew) == 0 ) |
| break; |
| vCut = Nwk_ManDeriveRetimingCut( pNew, 0, fVerbose ); |
| if ( Vec_PtrSize(vCut) >= Aig_ManRegNum(pNew) ) |
| { |
| if ( fVerbose && !fChanges ) |
| printf( "Backward retiming cannot reduce registers.\n" ); |
| Vec_PtrFree( vCut ); |
| break; |
| } |
| pNew = Saig_ManRetimeDupBackward( pTemp = pNew, vCut, NULL ); |
| Aig_ManStop( pTemp ); |
| Vec_PtrFree( vCut ); |
| if ( fVerbose ) |
| Aig_ManReportImprovement( p, pNew ); |
| fChanges = 1; |
| } |
| else if ( !fForwardOnly && fInitial ) |
| for ( i = 0; i < nMaxIters; i++ ) |
| { |
| if ( Saig_ManRegNum(pNew) == 0 ) |
| break; |
| pCopy = Aig_ManDupSimple( pNew ); |
| pTemp = Saig_ManRetimeMinAreaBackward( pCopy, fVerbose ); |
| Aig_ManStop( pCopy ); |
| if ( pTemp == NULL ) |
| { |
| if ( fVerbose && !fChanges ) |
| printf( "Backward retiming cannot reduce registers.\n" ); |
| break; |
| } |
| Saig_ManExposeBadRegs( pTemp, Saig_ManPoNum(pTemp) - Saig_ManPoNum(pNew) ); |
| Aig_ManStop( pNew ); |
| pNew = pTemp; |
| if ( fVerbose ) |
| Aig_ManReportImprovement( p, pNew ); |
| fChanges = 1; |
| } |
| if ( !fForwardOnly && !fInitial && fChanges ) |
| printf( "Assuming const-0 init-state after backward retiming. Result will not verify.\n" ); |
| return pNew; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |