/**CFile**************************************************************** FileName [dchChoice.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Choice computation for tech-mapping.] Synopsis [Contrustion of choices.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 29, 2008.] Revision [$Id: dchChoice.c,v 1.00 2008/07/29 00:00:00 alanmi Exp $] ***********************************************************************/ #include "dchInt.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Counts support nodes.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Dch_ObjCountSupp_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) { int Count; if ( Aig_ObjIsTravIdCurrent( p, pObj ) ) return 0; Aig_ObjSetTravIdCurrent( p, pObj ); if ( Aig_ObjIsCi(pObj) ) return 1; assert( Aig_ObjIsNode(pObj) ); Count = Dch_ObjCountSupp_rec( p, Aig_ObjFanin0(pObj) ); Count += Dch_ObjCountSupp_rec( p, Aig_ObjFanin1(pObj) ); return Count; } int Dch_ObjCountSupp( Aig_Man_t * p, Aig_Obj_t * pObj ) { Aig_ManIncrementTravId( p ); return Dch_ObjCountSupp_rec( p, pObj ); } /**Function************************************************************* Synopsis [Counts the number of representatives.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Dch_DeriveChoiceCountReprs( Aig_Man_t * pAig ) { Aig_Obj_t * pObj, * pRepr; int i, nReprs = 0; Aig_ManForEachObj( pAig, pObj, i ) { pRepr = Aig_ObjRepr( pAig, pObj ); if ( pRepr == NULL ) continue; assert( pRepr->Id < pObj->Id ); nReprs++; } return nReprs; } int Dch_DeriveChoiceCountEquivs( Aig_Man_t * pAig ) { Aig_Obj_t * pObj, * pEquiv; int i, nEquivs = 0; Aig_ManForEachObj( pAig, pObj, i ) { pEquiv = Aig_ObjEquiv( pAig, pObj ); if ( pEquiv == NULL ) continue; assert( pEquiv->Id < pObj->Id ); nEquivs++; } return nEquivs; } /**Function************************************************************* Synopsis [Marks the TFI of the node.] Description [Returns 1 if there is a CI not marked with previous ID.] SideEffects [] SeeAlso [] ***********************************************************************/ int Dch_ObjMarkTfi_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) { int RetValue; if ( pObj == NULL ) return 0; if ( Aig_ObjIsTravIdCurrent( p, pObj ) ) return 0; if ( Aig_ObjIsCi(pObj) ) { RetValue = !Aig_ObjIsTravIdPrevious( p, pObj ); Aig_ObjSetTravIdCurrent( p, pObj ); return RetValue; } assert( Aig_ObjIsNode(pObj) ); Aig_ObjSetTravIdCurrent( p, pObj ); RetValue = Dch_ObjMarkTfi_rec( p, Aig_ObjFanin0(pObj) ); RetValue += Dch_ObjMarkTfi_rec( p, Aig_ObjFanin1(pObj) ); // RetValue += Dch_ObjMarkTfi_rec( p, Aig_ObjEquiv(p, pObj) ); return (RetValue > 0); } int Dch_ObjCheckSuppRed( Aig_Man_t * p, Aig_Obj_t * pObj, Aig_Obj_t * pRepr ) { // mark support of the representative node (pRepr) Aig_ManIncrementTravId( p ); Dch_ObjMarkTfi_rec( p, pRepr ); // detect if the new node (pObj) depends on additional variables Aig_ManIncrementTravId( p ); if ( Dch_ObjMarkTfi_rec( p, pObj ) ) return 1;//, printf( "1" ); // detect if the representative node (pRepr) depends on additional variables Aig_ManIncrementTravId( p ); if ( Dch_ObjMarkTfi_rec( p, pRepr ) ) return 1;//, printf( "2" ); // skip the choice if this is what is happening return 0; } /**Function************************************************************* Synopsis [Make sure reprsentative nodes do not have representatives.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Aig_ManCheckReprs( Aig_Man_t * p ) { int fPrintConst = 0; Aig_Obj_t * pObj; int i, fProb = 0; int Class0 = 0, ClassCi = 0; Aig_ManForEachObj( p, pObj, i ) { if ( Aig_ObjRepr(p, pObj) == NULL ) continue; if ( !Aig_ObjIsNode(pObj) ) printf( "Obj %d is not an AND but it has a repr %d.\n", i, Aig_ObjId(Aig_ObjRepr(p, pObj)) ), fProb = 1; else if ( Aig_ObjRepr(p, Aig_ObjRepr(p, pObj)) ) printf( "Obj %d has repr %d with a repr %d.\n", i, Aig_ObjId(Aig_ObjRepr(p, pObj)), Aig_ObjId(Aig_ObjRepr(p, Aig_ObjRepr(p, pObj))) ), fProb = 1; } if ( !fProb ) printf( "Representive verification successful.\n" ); else printf( "Representive verification FAILED.\n" ); if ( !fPrintConst ) return; // count how many representatives are const0 or a CI Aig_ManForEachObj( p, pObj, i ) { if ( Aig_ObjRepr(p, pObj) == Aig_ManConst1(p) ) Class0++; if ( Aig_ObjRepr(p, pObj) && Aig_ObjIsCi(Aig_ObjRepr(p, pObj)) ) ClassCi++; } printf( "Const0 nodes = %d. ConstCI nodes = %d.\n", Class0, ClassCi ); } /**Function************************************************************* Synopsis [Verify correctness of choices.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Dch_CheckChoices( Aig_Man_t * p, int fSkipRedSupps ) { Aig_Obj_t * pObj; int i, fProb = 0; Aig_ManCleanMarkA( p ); Aig_ManForEachNode( p, pObj, i ) { if ( p->pEquivs[i] != NULL ) { if ( pObj->fMarkA == 1 ) printf( "node %d participates in more than one choice class\n", i ), fProb = 1; pObj->fMarkA = 1; // check redundancy if ( fSkipRedSupps && Dch_ObjCheckSuppRed( p, pObj, p->pEquivs[i]) ) printf( "node %d and repr %d have diff supports\n", pObj->Id, p->pEquivs[i]->Id ); // consider the next one pObj = p->pEquivs[i]; if ( p->pEquivs[Aig_ObjId(pObj)] == NULL ) { if ( pObj->fMarkA == 1 ) printf( "repr %d has final node %d participates in more than one choice class\n", i, pObj->Id ), fProb = 1; pObj->fMarkA = 1; } // consider the non-head ones if ( pObj->nRefs > 0 ) printf( "node %d belonging to choice has fanout %d\n", pObj->Id, pObj->nRefs ); } if ( p->pReprs && p->pReprs[i] != NULL ) { if ( pObj->nRefs > 0 ) printf( "node %d has representative %d and fanout count %d\n", pObj->Id, p->pReprs[i]->Id, pObj->nRefs ), fProb = 1; } } Aig_ManCleanMarkA( p ); if ( !fProb ) printf( "Verification of choice AIG succeeded.\n" ); else printf( "Verification of choice AIG FAILED.\n" ); } /**Function************************************************************* Synopsis [Checks for combinational loops in the AIG.] Description [Returns 1 if combinational loop is detected.] SideEffects [] SeeAlso [] ***********************************************************************/ int Aig_ManCheckAcyclic_rec( Aig_Man_t * p, Aig_Obj_t * pNode, int fVerbose ) { Aig_Obj_t * pFanin; int fAcyclic; if ( Aig_ObjIsCi(pNode) || Aig_ObjIsConst1(pNode) ) return 1; assert( Aig_ObjIsNode(pNode) ); // make sure the node is not visited assert( !Aig_ObjIsTravIdPrevious(p, pNode) ); // check if the node is part of the combinational loop if ( Aig_ObjIsTravIdCurrent(p, pNode) ) { if ( fVerbose ) Abc_Print( 1, "Network \"%s\" contains combinational loop!\n", p->pSpec? p->pSpec : NULL ); if ( fVerbose ) Abc_Print( 1, "Node \"%d\" is encountered twice on the following path to the COs:\n", Aig_ObjId(pNode) ); return 0; } // mark this node as a node on the current path Aig_ObjSetTravIdCurrent( p, pNode ); // visit the transitive fanin pFanin = Aig_ObjFanin0(pNode); // check if the fanin is visited if ( !Aig_ObjIsTravIdPrevious(p, pFanin) ) { // traverse the fanin's cone searching for the loop if ( !(fAcyclic = Aig_ManCheckAcyclic_rec(p, pFanin, fVerbose)) ) { // return as soon as the loop is detected if ( fVerbose ) Abc_Print( 1, " %d ->", Aig_ObjId(pFanin) ); return 0; } } // visit the transitive fanin pFanin = Aig_ObjFanin1(pNode); // check if the fanin is visited if ( !Aig_ObjIsTravIdPrevious(p, pFanin) ) { // traverse the fanin's cone searching for the loop if ( !(fAcyclic = Aig_ManCheckAcyclic_rec(p, pFanin, fVerbose)) ) { // return as soon as the loop is detected if ( fVerbose ) Abc_Print( 1, " %d ->", Aig_ObjId(pFanin) ); return 0; } } // visit choices if ( Aig_ObjRepr(p, pNode) == NULL && Aig_ObjEquiv(p, pNode) != NULL ) { for ( pFanin = Aig_ObjEquiv(p, pNode); pFanin; pFanin = Aig_ObjEquiv(p, pFanin) ) { // check if the fanin is visited if ( Aig_ObjIsTravIdPrevious(p, pFanin) ) continue; // traverse the fanin's cone searching for the loop if ( (fAcyclic = Aig_ManCheckAcyclic_rec(p, pFanin, fVerbose)) ) continue; // return as soon as the loop is detected if ( fVerbose ) Abc_Print( 1, " %d", Aig_ObjId(pFanin) ); if ( fVerbose ) Abc_Print( 1, " (choice of %d) -> ", Aig_ObjId(pNode) ); return 0; } } // mark this node as a visited node Aig_ObjSetTravIdPrevious( p, pNode ); return 1; } int Aig_ManCheckAcyclic( Aig_Man_t * p, int fVerbose ) { Aig_Obj_t * pNode; int fAcyclic; int i; // set the traversal ID for this DFS ordering Aig_ManIncrementTravId( p ); Aig_ManIncrementTravId( p ); // pNode->TravId == pNet->nTravIds means "pNode is on the path" // pNode->TravId == pNet->nTravIds - 1 means "pNode is visited but is not on the path" // pNode->TravId < pNet->nTravIds - 1 means "pNode is not visited" // traverse the network to detect cycles fAcyclic = 1; Aig_ManForEachCo( p, pNode, i ) { pNode = Aig_ObjFanin0(pNode); if ( Aig_ObjIsTravIdPrevious(p, pNode) ) continue; // traverse the output logic cone if ( (fAcyclic = Aig_ManCheckAcyclic_rec(p, pNode, fVerbose)) ) continue; // stop as soon as the first loop is detected if ( fVerbose ) Abc_Print( 1, " CO %d\n", i ); break; } return fAcyclic; } /**Function************************************************************* Synopsis [Returns 1 if the choice node of pRepr is in the TFI of pObj.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Dch_ObjCheckTfi_rec( Aig_Man_t * p, Aig_Obj_t * pObj ) { // check the trivial cases if ( pObj == NULL ) return 0; if ( Aig_ObjIsCi(pObj) ) return 0; if ( pObj->fMarkA ) return 1; // skip the visited node if ( Aig_ObjIsTravIdCurrent( p, pObj ) ) return 0; Aig_ObjSetTravIdCurrent( p, pObj ); // check the children if ( Dch_ObjCheckTfi_rec( p, Aig_ObjFanin0(pObj) ) ) return 1; if ( Dch_ObjCheckTfi_rec( p, Aig_ObjFanin1(pObj) ) ) return 1; // check equivalent nodes return Dch_ObjCheckTfi_rec( p, Aig_ObjEquiv(p, pObj) ); } int Dch_ObjCheckTfi( Aig_Man_t * p, Aig_Obj_t * pObj, Aig_Obj_t * pRepr ) { Aig_Obj_t * pTemp; int RetValue; assert( !Aig_IsComplement(pObj) ); assert( !Aig_IsComplement(pRepr) ); // mark nodes of the choice node for ( pTemp = pRepr; pTemp; pTemp = Aig_ObjEquiv(p, pTemp) ) pTemp->fMarkA = 1; // traverse the new node Aig_ManIncrementTravId( p ); RetValue = Dch_ObjCheckTfi_rec( p, pObj ); // unmark nodes of the choice node for ( pTemp = pRepr; pTemp; pTemp = Aig_ObjEquiv(p, pTemp) ) pTemp->fMarkA = 0; return RetValue; } /**Function************************************************************* Synopsis [Returns representatives of fanin in approapriate polarity.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline Aig_Obj_t * Aig_ObjGetRepr( Aig_Man_t * p, Aig_Obj_t * pObj ) { Aig_Obj_t * pRepr; if ( (pRepr = Aig_ObjRepr(p, Aig_Regular(pObj))) ) return Aig_NotCond( pRepr, Aig_Regular(pObj)->fPhase ^ pRepr->fPhase ^ Aig_IsComplement(pObj) ); return pObj; } static inline Aig_Obj_t * Aig_ObjChild0CopyRepr( Aig_Man_t * p, Aig_Obj_t * pObj ) { return Aig_ObjGetRepr( p, Aig_ObjChild0Copy(pObj) ); } static inline Aig_Obj_t * Aig_ObjChild1CopyRepr( Aig_Man_t * p, Aig_Obj_t * pObj ) { return Aig_ObjGetRepr( p, Aig_ObjChild1Copy(pObj) ); } /**Function************************************************************* Synopsis [Derives the AIG with choices from representatives.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Dch_DeriveChoiceAigNode( Aig_Man_t * pAigNew, Aig_Man_t * pAigOld, Aig_Obj_t * pObj, int fSkipRedSupps ) { Aig_Obj_t * pRepr, * pObjNew, * pReprNew; assert( !Aig_IsComplement(pObj) ); // get the representative pRepr = Aig_ObjRepr( pAigOld, pObj ); if ( pRepr != NULL && (Aig_ObjIsConst1(pRepr) || Aig_ObjIsCi(pRepr)) ) { assert( pRepr->pData != NULL ); pObj->pData = Aig_NotCond( (Aig_Obj_t *)pRepr->pData, pObj->fPhase ^ pRepr->fPhase ); return; } // get the new node pObjNew = Aig_And( pAigNew, Aig_ObjChild0CopyRepr(pAigNew, pObj), Aig_ObjChild1CopyRepr(pAigNew, pObj) ); pObjNew = Aig_ObjGetRepr( pAigNew, pObjNew ); // assert( Aig_ObjRepr( pAigNew, pObjNew ) == NULL ); // assign the copy assert( pObj->pData == NULL ); pObj->pData = pObjNew; // skip those without reprs if ( pRepr == NULL ) return; assert( pRepr->Id < pObj->Id ); assert( Aig_ObjIsNode(pRepr) ); // get the corresponding new nodes pObjNew = Aig_Regular((Aig_Obj_t *)pObj->pData); pReprNew = Aig_Regular((Aig_Obj_t *)pRepr->pData); // skip earlier nodes if ( pReprNew->Id >= pObjNew->Id ) return; assert( pReprNew->Id < pObjNew->Id ); // set the representatives Aig_ObjSetRepr( pAigNew, pObjNew, pReprNew ); // skip used nodes if ( pObjNew->nRefs > 0 ) return; assert( pObjNew->nRefs == 0 ); // skip choices that can lead to combo loops if ( Dch_ObjCheckTfi( pAigNew, pObjNew, pReprNew ) ) return; // don't add choice if structural support of pObjNew and pReprNew differ if ( fSkipRedSupps && Dch_ObjCheckSuppRed(pAigNew, pObjNew, pReprNew) ) return; // add choice to the end of the list while ( pAigNew->pEquivs[pReprNew->Id] != NULL ) pReprNew = pAigNew->pEquivs[pReprNew->Id]; assert( pAigNew->pEquivs[pReprNew->Id] == NULL ); pAigNew->pEquivs[pReprNew->Id] = pObjNew; } Aig_Man_t * Dch_DeriveChoiceAigInt( Aig_Man_t * pAig, int fSkipRedSupps ) { Aig_Man_t * pChoices; Aig_Obj_t * pObj; int i; // start recording equivalences pChoices = Aig_ManStart( Aig_ManObjNumMax(pAig) ); pChoices->pEquivs = ABC_CALLOC( Aig_Obj_t *, Aig_ManObjNumMax(pAig) ); pChoices->pReprs = ABC_CALLOC( Aig_Obj_t *, Aig_ManObjNumMax(pAig) ); // map constants and PIs Aig_ManCleanData( pAig ); Aig_ManConst1(pAig)->pData = Aig_ManConst1(pChoices); Aig_ManForEachCi( pAig, pObj, i ) pObj->pData = Aig_ObjCreateCi( pChoices ); // construct choices for the internal nodes assert( pAig->pReprs != NULL ); Aig_ManForEachNode( pAig, pObj, i ) Dch_DeriveChoiceAigNode( pChoices, pAig, pObj, fSkipRedSupps ); Aig_ManForEachCo( pAig, pObj, i ) Aig_ObjCreateCo( pChoices, Aig_ObjChild0CopyRepr(pChoices, pObj) ); Aig_ManSetRegNum( pChoices, Aig_ManRegNum(pAig) ); return pChoices; } Aig_Man_t * Dch_DeriveChoiceAig( Aig_Man_t * pAig, int fSkipRedSupps ) { int fCheck = 0; Aig_Man_t * pChoices, * pTemp; // verify if ( fCheck ) Aig_ManCheckReprs( pAig ); // compute choices pChoices = Dch_DeriveChoiceAigInt( pAig, fSkipRedSupps ); ABC_FREE( pChoices->pReprs ); // verify if ( fCheck ) Dch_CheckChoices( pChoices, fSkipRedSupps ); // find correct topo order with choices pChoices = Aig_ManDupDfs( pTemp = pChoices ); Aig_ManStop( pTemp ); // verify if ( fCheck ) Dch_CheckChoices( pChoices, fSkipRedSupps ); return pChoices; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END