| /**CFile**************************************************************** |
| |
| FileName [abcUtil.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Network and node package.] |
| |
| Synopsis [Various utilities.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: abcUtil.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "abc.h" |
| #include "base/main/main.h" |
| #include "map/mio/mio.h" |
| #include "bool/dec/dec.h" |
| #include "opt/fxu/fxu.h" |
| #include "aig/miniaig/ndr.h" |
| |
| #ifdef ABC_USE_CUDD |
| #include "bdd/extrab/extraBdd.h" |
| #endif |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Frees one attribute manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void * Abc_NtkAttrFree( Abc_Ntk_t * pNtk, int Attr, int fFreeMan ) |
| { |
| void * pUserMan; |
| Vec_Att_t * pAttrMan; |
| pAttrMan = (Vec_Att_t *)Vec_PtrEntry( pNtk->vAttrs, Attr ); |
| Vec_PtrWriteEntry( pNtk->vAttrs, Attr, NULL ); |
| pUserMan = Vec_AttFree( pAttrMan, fFreeMan ); |
| return pUserMan; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Order CI/COs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkOrderCisCos( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj, * pTerm; |
| int i, k; |
| Vec_PtrClear( pNtk->vCis ); |
| Vec_PtrClear( pNtk->vCos ); |
| Abc_NtkForEachPi( pNtk, pObj, i ) |
| Vec_PtrPush( pNtk->vCis, pObj ); |
| Abc_NtkForEachPo( pNtk, pObj, i ) |
| Vec_PtrPush( pNtk->vCos, pObj ); |
| Abc_NtkForEachBox( pNtk, pObj, i ) |
| { |
| if ( Abc_ObjIsLatch(pObj) ) |
| continue; |
| Abc_ObjForEachFanin( pObj, pTerm, k ) |
| Vec_PtrPush( pNtk->vCos, pTerm ); |
| Abc_ObjForEachFanout( pObj, pTerm, k ) |
| Vec_PtrPush( pNtk->vCis, pTerm ); |
| } |
| Abc_NtkForEachBox( pNtk, pObj, i ) |
| { |
| if ( !Abc_ObjIsLatch(pObj) ) |
| continue; |
| Abc_ObjForEachFanin( pObj, pTerm, k ) |
| Vec_PtrPush( pNtk->vCos, pTerm ); |
| Abc_ObjForEachFanout( pObj, pTerm, k ) |
| Vec_PtrPush( pNtk->vCis, pTerm ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of cubes of the node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetCubeNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nCubes = 0; |
| assert( Abc_NtkHasSop(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( Abc_NodeIsConst(pNode) ) |
| continue; |
| assert( pNode->pData ); |
| nCubes += Abc_SopGetCubeNum( (char *)pNode->pData ); |
| } |
| return nCubes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of cubes of the node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetCubePairNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i; |
| word nCubes, nCubePairs = 0; |
| assert( Abc_NtkHasSop(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( Abc_NodeIsConst(pNode) ) |
| continue; |
| assert( pNode->pData ); |
| nCubes = (word)Abc_SopGetCubeNum( (char *)pNode->pData ); |
| if ( nCubes > 1 ) |
| nCubePairs += nCubes * (nCubes - 1) / 2; |
| } |
| return (int)(nCubePairs > (1<<30) ? (1<<30) : nCubePairs); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of literals in the SOPs of the nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetLitNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nLits = 0; |
| assert( Abc_NtkHasSop(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| assert( pNode->pData ); |
| nLits += Abc_SopGetLitNum( (char *)pNode->pData ); |
| } |
| return nLits; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of literals in the factored forms.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetLitFactNum( Abc_Ntk_t * pNtk ) |
| { |
| Dec_Graph_t * pFactor; |
| Abc_Obj_t * pNode; |
| int nNodes, i; |
| assert( Abc_NtkHasSop(pNtk) ); |
| nNodes = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( Abc_NodeIsConst(pNode) ) |
| continue; |
| pFactor = Dec_Factor( (char *)pNode->pData ); |
| nNodes += 1 + Dec_GraphNodeNum(pFactor); |
| Dec_GraphFree( pFactor ); |
| } |
| return nNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of nodes with more than 1 reference.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetMultiRefNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int nNodes, i; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| nNodes = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| nNodes += (int)(Abc_ObjFanoutNum(pNode) > 1); |
| return nNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of BDD nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetBddNodeNum( Abc_Ntk_t * pNtk ) |
| { |
| int nNodes = 0; |
| #ifdef ABC_USE_CUDD |
| Abc_Obj_t * pNode; |
| int i; |
| assert( Abc_NtkIsBddLogic(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| assert( pNode->pData ); |
| if ( Abc_ObjFaninNum(pNode) < 2 ) |
| continue; |
| nNodes += pNode->pData? -1 + Cudd_DagSize( (DdNode *)pNode->pData ) : 0; |
| } |
| #endif |
| return nNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of BDD nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetAigNodeNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nNodes = 0; |
| assert( Abc_NtkIsAigLogic(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| assert( pNode->pData ); |
| if ( Abc_ObjFaninNum(pNode) < 2 ) |
| continue; |
| //printf( "%d ", Hop_DagSize( pNode->pData ) ); |
| nNodes += pNode->pData? Hop_DagSize( (Hop_Obj_t *)pNode->pData ) : 0; |
| } |
| return nNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the number of BDD nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetClauseNum( Abc_Ntk_t * pNtk ) |
| { |
| int nClauses = 0; |
| #ifdef ABC_USE_CUDD |
| extern int Abc_CountZddCubes( DdManager * dd, DdNode * zCover ); |
| Abc_Obj_t * pNode; |
| DdNode * bCover, * zCover, * bFunc; |
| DdManager * dd = (DdManager *)pNtk->pManFunc; |
| int i; |
| assert( Abc_NtkIsBddLogic(pNtk) ); |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| assert( pNode->pData ); |
| bFunc = (DdNode *)pNode->pData; |
| |
| bCover = Cudd_zddIsop( dd, bFunc, bFunc, &zCover ); |
| Cudd_Ref( bCover ); |
| Cudd_Ref( zCover ); |
| nClauses += Abc_CountZddCubes( dd, zCover ); |
| Cudd_RecursiveDeref( dd, bCover ); |
| Cudd_RecursiveDerefZdd( dd, zCover ); |
| |
| bCover = Cudd_zddIsop( dd, Cudd_Not(bFunc), Cudd_Not(bFunc), &zCover ); |
| Cudd_Ref( bCover ); |
| Cudd_Ref( zCover ); |
| nClauses += Abc_CountZddCubes( dd, zCover ); |
| Cudd_RecursiveDeref( dd, bCover ); |
| Cudd_RecursiveDerefZdd( dd, zCover ); |
| } |
| #endif |
| return nClauses; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes the area of the mapped circuit.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| double Abc_NtkGetMappedArea( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| double TotalArea; |
| int i; |
| assert( Abc_NtkHasMapping(pNtk) ); |
| TotalArea = 0.0; |
| Abc_NtkForEachNode( pNtk, pObj, i ) |
| { |
| if ( Abc_ObjIsBarBuf(pObj) ) |
| continue; |
| // assert( pObj->pData ); |
| if ( pObj->pData == NULL ) |
| { |
| printf( "Node without mapping is encountered.\n" ); |
| continue; |
| } |
| TotalArea += Mio_GateReadArea( (Mio_Gate_t *)pObj->pData ); |
| // assuming that twin gates follow each other |
| if ( Abc_NtkFetchTwinNode(pObj) ) |
| i++; |
| } |
| return TotalArea; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of exors.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetExorNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += pNode->fExor; |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of exors.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetMuxNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += Abc_NodeIsMuxType(pNode); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of exors.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetBufNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += (Abc_ObjFaninNum(pNode) == 1); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of exors.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetLargeNodeNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += (Abc_ObjFaninNum(pNode) > 1); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if it is an AIG with choice nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetChoiceNum( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, Counter; |
| if ( !Abc_NtkIsStrash(pNtk) ) |
| return 0; |
| Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += Abc_AigNodeIsChoice( pNode ); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the maximum number of fanins.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetFaninMax( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nFaninsMax = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( nFaninsMax < Abc_ObjFaninNum(pNode) ) |
| nFaninsMax = Abc_ObjFaninNum(pNode); |
| } |
| return nFaninsMax; |
| } |
| int Abc_NtkGetFanoutMax( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nFaninsMax = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| { |
| if ( nFaninsMax < Abc_ObjFanoutNum(pNode) ) |
| nFaninsMax = Abc_ObjFanoutNum(pNode); |
| } |
| return nFaninsMax; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the total number of all fanins.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkGetTotalFanins( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i, nFanins = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| nFanins += Abc_ObjFaninNum(pNode); |
| return nFanins; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanCopy( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->pCopy = NULL; |
| } |
| void Abc_NtkCleanCopy_rec( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkCleanCopy( pNtk ); |
| Abc_NtkForEachBox( pNtk, pObj, i ) |
| Abc_NtkCleanCopy_rec( Abc_ObjModel(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanData( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->pData = NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkFillTemp( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->iTemp = -1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of nodes having non-trivial copies.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkCountCopy( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i, Counter = 0; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| { |
| if ( Abc_ObjIsNode(pObj) ) |
| Counter += (pObj->pCopy != NULL); |
| } |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Saves copy field of the objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Abc_NtkSaveCopy( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vCopies; |
| Abc_Obj_t * pObj; |
| int i; |
| vCopies = Vec_PtrStart( Abc_NtkObjNumMax(pNtk) ); |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| Vec_PtrWriteEntry( vCopies, i, pObj->pCopy ); |
| return vCopies; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Loads copy field of the objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkLoadCopy( Abc_Ntk_t * pNtk, Vec_Ptr_t * vCopies ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->pCopy = (Abc_Obj_t *)Vec_PtrEntry( vCopies, i ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanNext( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->pNext = NULL; |
| } |
| void Abc_NtkCleanNext_rec( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkCleanNext( pNtk ); |
| Abc_NtkForEachBox( pNtk, pObj, i ) |
| Abc_NtkCleanNext_rec( Abc_ObjModel(pObj) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanMarkA( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->fMarkA = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanMarkB( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->fMarkB = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanMarkC( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->fMarkC = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanMarkAB( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->fMarkA = pObj->fMarkB = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Cleans the copy field of all objects.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCleanMarkABC( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| pObj->fMarkA = pObj->fMarkB = pObj->fMarkC = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the index of the given fanin.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeFindFanin( Abc_Obj_t * pNode, Abc_Obj_t * pFanin ) |
| { |
| Abc_Obj_t * pThis; |
| int i; |
| Abc_ObjForEachFanin( pNode, pThis, i ) |
| if ( pThis == pFanin ) |
| return i; |
| return -1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the internal node has CO fanout.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NodeFindCoFanout( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pNode, pFanout, i ) |
| if ( Abc_ObjIsCo(pFanout) ) |
| return pFanout; |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the internal node has CO fanout.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NodeFindNonCoFanout( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pNode, pFanout, i ) |
| if ( !Abc_ObjIsCo(pFanout) ) |
| return pFanout; |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the internal node has CO drivers with the same name.] |
| |
| Description [Checks if the internal node can borrow its name from CO fanouts. |
| This is possible if all COs with non-complemented fanin edge pointing to this |
| node have the same name.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NodeHasUniqueCoFanout( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pFanout, * pFanoutCo; |
| int i; |
| pFanoutCo = NULL; |
| Abc_ObjForEachFanout( pNode, pFanout, i ) |
| { |
| if ( !Abc_ObjIsCo(pFanout) ) |
| continue; |
| if ( Abc_ObjFaninC0(pFanout) ) |
| continue; |
| if ( pFanoutCo == NULL ) |
| { |
| assert( Abc_ObjFaninNum(pFanout) == 1 ); |
| assert( Abc_ObjFanin0(pFanout) == pNode ); |
| pFanoutCo = pFanout; |
| continue; |
| } |
| if ( strcmp( Abc_ObjName(pFanoutCo), Abc_ObjName(pFanout) ) ) // they have diff names |
| return NULL; |
| } |
| return pFanoutCo; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Fixes the CO driver problem.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkFixCoDriverProblem( Abc_Obj_t * pDriver, Abc_Obj_t * pNodeCo, int fDuplicate ) |
| { |
| Abc_Ntk_t * pNtk = pDriver->pNtk; |
| Abc_Obj_t * pDriverNew, * pFanin; |
| int k; |
| if ( fDuplicate && !Abc_ObjIsCi(pDriver) ) |
| { |
| pDriverNew = Abc_NtkDupObj( pNtk, pDriver, 0 ); |
| Abc_ObjForEachFanin( pDriver, pFanin, k ) |
| Abc_ObjAddFanin( pDriverNew, pFanin ); |
| if ( Abc_ObjFaninC0(pNodeCo) ) |
| { |
| // change polarity of the duplicated driver |
| Abc_NodeComplement( pDriverNew ); |
| Abc_ObjXorFaninC( pNodeCo, 0 ); |
| } |
| } |
| else |
| { |
| // add inverters and buffers when necessary |
| if ( Abc_ObjFaninC0(pNodeCo) ) |
| { |
| pDriverNew = Abc_NtkCreateNodeInv( pNtk, pDriver ); |
| Abc_ObjXorFaninC( pNodeCo, 0 ); |
| } |
| else |
| pDriverNew = Abc_NtkCreateNodeBuf( pNtk, pDriver ); |
| } |
| // update the fanin of the PO node |
| Abc_ObjPatchFanin( pNodeCo, pDriver, pDriverNew ); |
| assert( Abc_ObjFanoutNum(pDriverNew) == 1 ); |
| // remove the old driver if it dangles |
| // (this happens when the duplicated driver had only one complemented fanout) |
| if ( Abc_ObjFanoutNum(pDriver) == 0 ) |
| Abc_NtkDeleteObj( pDriver ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if COs of a logic network are simple.] |
| |
| Description [The COs of a logic network are simple under three conditions: |
| (1) The edge from CO to its driver is not complemented. |
| (2) If CI is a driver of a CO, they have the same name.] |
| (3) If two COs share the same driver, they have the same name.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkLogicHasSimpleCos( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode, * pDriver; |
| int i; |
| assert( Abc_NtkIsLogic(pNtk) ); |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| // if the driver is complemented, this is an error |
| pDriver = Abc_ObjFanin0(pNode); |
| if ( Abc_ObjFaninC0(pNode) ) |
| return 0; |
| // if the driver is a CI and has different name, this is an error |
| if ( Abc_ObjIsCi(pDriver) && strcmp(Abc_ObjName(pDriver), Abc_ObjName(pNode)) ) |
| return 0; |
| // if the driver is visited for the first time, remember the CO name |
| if ( !Abc_NodeIsTravIdCurrent(pDriver) ) |
| { |
| pDriver->pNext = (Abc_Obj_t *)Abc_ObjName(pNode); |
| Abc_NodeSetTravIdCurrent(pDriver); |
| continue; |
| } |
| // the driver has second CO - if they have different name, this is an error |
| if ( strcmp((char *)pDriver->pNext, Abc_ObjName(pNode)) ) // diff names |
| return 0; |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Transforms the network to have simple COs.] |
| |
| Description [The COs of a logic network are simple under three conditions: |
| (1) The edge from CO to its driver is not complemented. |
| (2) If CI is a driver of a CO, they have the same name.] |
| (3) If two COs share the same driver, they have the same name. |
| In some cases, such as FPGA mapping, we prevent the increase in delay |
| by duplicating the driver nodes, rather than adding invs/bufs.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkLogicMakeSimpleCos2( Abc_Ntk_t * pNtk, int fDuplicate ) |
| { |
| Abc_Obj_t * pNode, * pDriver; |
| int i, nDupGates = 0; |
| assert( Abc_NtkIsLogic(pNtk) ); |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| // if the driver is complemented, this is an error |
| pDriver = Abc_ObjFanin0(pNode); |
| if ( Abc_ObjFaninC0(pNode) ) |
| { |
| Abc_NtkFixCoDriverProblem( pDriver, pNode, fDuplicate ); |
| nDupGates++; |
| continue; |
| } |
| // if the driver is a CI and has different name, this is an error |
| if ( Abc_ObjIsCi(pDriver) && strcmp(Abc_ObjName(pDriver), Abc_ObjName(pNode)) ) |
| { |
| Abc_NtkFixCoDriverProblem( pDriver, pNode, fDuplicate ); |
| nDupGates++; |
| continue; |
| } |
| // if the driver is visited for the first time, remember the CO name |
| if ( !Abc_NodeIsTravIdCurrent(pDriver) ) |
| { |
| pDriver->pNext = (Abc_Obj_t *)Abc_ObjName(pNode); |
| Abc_NodeSetTravIdCurrent(pDriver); |
| continue; |
| } |
| // the driver has second CO - if they have different name, this is an error |
| if ( strcmp((char *)pDriver->pNext, Abc_ObjName(pNode)) ) // diff names |
| { |
| Abc_NtkFixCoDriverProblem( pDriver, pNode, fDuplicate ); |
| nDupGates++; |
| continue; |
| } |
| } |
| assert( Abc_NtkLogicHasSimpleCos(pNtk) ); |
| return nDupGates; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Transforms the network to have simple COs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkLogicMakeSimpleCosTest( Abc_Ntk_t * pNtk, int fDuplicate ) |
| { |
| int nObjs = Abc_NtkObjNumMax(pNtk); |
| unsigned * pType = ABC_CALLOC( unsigned, nObjs ); |
| Abc_Obj_t * pNode; |
| int i, Counts[4] = {0}, Consts[2] = {0}, Inputs[2] = {0}; |
| // collect info |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| if ( Abc_ObjFaninId0(pNode) == 0 ) |
| Consts[Abc_ObjFaninC0(pNode)]++; |
| if ( Abc_ObjIsCi(Abc_ObjFanin0(pNode)) ) |
| Inputs[Abc_ObjFaninC0(pNode)]++; |
| pType[Abc_ObjFaninId0(pNode)] |= (1 << Abc_ObjFaninC0(pNode)); |
| } |
| // count the numbers |
| for ( i = 0; i < nObjs; i++ ) |
| Counts[pType[i]]++; |
| for ( i = 0; i < 4; i++ ) |
| printf( "%d = %d ", i, Counts[i] ); |
| for ( i = 0; i < 2; i++ ) |
| printf( "c%d = %d ", i, Consts[i] ); |
| for ( i = 0; i < 2; i++ ) |
| printf( "i%d = %d ", i, Inputs[i] ); |
| printf( "\n" ); |
| ABC_FREE( pType ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Transforms the network to have simple COs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkLogicMakeSimpleCos( Abc_Ntk_t * pNtk, int fDuplicate ) |
| { |
| int fAddBuffers = 1; |
| Vec_Ptr_t * vDrivers, * vCoTerms; |
| Abc_Obj_t * pNode, * pDriver, * pDriverNew, * pFanin; |
| int i, k, LevelMax, nTotal = 0; |
| assert( Abc_NtkIsLogic(pNtk) ); |
| LevelMax = Abc_NtkLevel(pNtk); |
| // Abc_NtkLogicMakeSimpleCosTest( pNtk, fDuplicate ); |
| |
| // fix constant drivers |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| pDriver = Abc_ObjFanin0(pNode); |
| if ( !Abc_NodeIsConst(pDriver) ) |
| continue; |
| pDriverNew = (Abc_ObjFaninC0(pNode) == Abc_NodeIsConst0(pDriver)) ? Abc_NtkCreateNodeConst1(pNtk) : Abc_NtkCreateNodeConst0(pNtk); |
| if ( Abc_ObjFaninC0(pNode) ) |
| Abc_ObjXorFaninC( pNode, 0 ); |
| Abc_ObjPatchFanin( pNode, pDriver, pDriverNew ); |
| if ( Abc_ObjFanoutNum(pDriver) == 0 ) |
| Abc_NtkDeleteObj( pDriver ); |
| } |
| |
| // collect drivers pointed by complemented edges |
| vDrivers = Vec_PtrAlloc( 100 ); |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| if ( !Abc_ObjFaninC0(pNode) ) |
| continue; |
| pDriver = Abc_ObjFanin0(pNode); |
| if ( Abc_NodeIsTravIdCurrent(pDriver) ) |
| continue; |
| Abc_NodeSetTravIdCurrent(pDriver); |
| Vec_PtrPush( vDrivers, pDriver ); |
| } |
| // fix complemented drivers |
| if ( Vec_PtrSize(vDrivers) > 0 ) |
| { |
| int nDupGates = 0, nDupInvs = 0, nDupChange = 0; |
| Vec_Ptr_t * vFanouts = Vec_PtrAlloc( 100 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vDrivers, pDriver, i ) |
| { |
| int fHasDir = 0, fHasInv = 0, fHasOther = 0; |
| Abc_ObjForEachFanout( pDriver, pNode, k ) |
| { |
| if ( !Abc_ObjIsCo(pNode) ) |
| { |
| assert( !Abc_ObjFaninC0(pNode) ); |
| fHasOther = 1; |
| continue; |
| } |
| if ( Abc_ObjFaninC0(pNode) ) |
| fHasInv = 1; |
| else //if ( Abc_ObjFaninC0(pNode) ) |
| fHasDir = 1; |
| } |
| assert( fHasInv ); |
| if ( Abc_ObjIsCi(pDriver) || fHasDir || (fHasOther && Abc_NtkHasMapping(pNtk)) ) // cannot change |
| { |
| // duplicate if critical |
| if ( fDuplicate && Abc_ObjIsNode(pDriver) && Abc_ObjLevel(pDriver) == LevelMax ) |
| { |
| pDriverNew = Abc_NtkDupObj( pNtk, pDriver, 0 ); |
| Abc_ObjForEachFanin( pDriver, pFanin, k ) |
| Abc_ObjAddFanin( pDriverNew, pFanin ); |
| Abc_NodeComplement( pDriverNew ); |
| nDupGates++; |
| } |
| else // add inverter |
| { |
| pDriverNew = Abc_NtkCreateNodeInv( pNtk, pDriver ); |
| nDupInvs++; |
| } |
| // collect CO fanouts to be redirected to the new node |
| Vec_PtrClear( vFanouts ); |
| Abc_ObjForEachFanout( pDriver, pNode, k ) |
| if ( Abc_ObjIsCo(pNode) && Abc_ObjFaninC0(pNode) ) |
| Vec_PtrPush( vFanouts, pNode ); |
| assert( Vec_PtrSize(vFanouts) > 0 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vFanouts, pNode, k ) |
| { |
| Abc_ObjXorFaninC( pNode, 0 ); |
| Abc_ObjPatchFanin( pNode, pDriver, pDriverNew ); |
| assert( Abc_ObjIsCi(pDriver) || Abc_ObjFanoutNum(pDriver) > 0 ); |
| } |
| } |
| else // can change |
| { |
| // change polarity of the driver |
| assert( Abc_ObjIsNode(pDriver) ); |
| Abc_NodeComplement( pDriver ); |
| Abc_ObjForEachFanout( pDriver, pNode, k ) |
| { |
| if ( Abc_ObjIsCo(pNode) ) |
| { |
| assert( Abc_ObjFaninC0(pNode) ); |
| Abc_ObjXorFaninC( pNode, 0 ); |
| } |
| else if ( Abc_ObjIsNode(pNode) ) |
| Abc_NodeComplementInput( pNode, pDriver ); |
| else assert( 0 ); |
| } |
| nDupChange++; |
| } |
| } |
| Vec_PtrFree( vFanouts ); |
| // printf( "Resolving inverted CO drivers: Invs = %d. Dups = %d. Changes = %d.\n", |
| // nDupInvs, nDupGates, nDupChange ); |
| nTotal += nDupInvs + nDupGates; |
| } |
| Vec_PtrFree( vDrivers ); |
| |
| // collect COs that needs fixing by adding buffers or duplicating |
| vCoTerms = Vec_PtrAlloc( 100 ); |
| Abc_NtkIncrementTravId( pNtk ); |
| |
| // The following cases should be addressed only if the network is written |
| // into a BLIF file. Otherwise, it is possible to skip them: |
| // (1) if a CO points to a CI with a different name |
| // (2) if an internal node drives more than one CO |
| if ( fAddBuffers ) |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| // if the driver is a CI and has different name, this is an error |
| pDriver = Abc_ObjFanin0(pNode); |
| if ( Abc_ObjIsCi(pDriver) && strcmp(Abc_ObjName(pDriver), Abc_ObjName(pNode)) ) |
| { |
| Vec_PtrPush( vCoTerms, pNode ); |
| continue; |
| } |
| // if the driver is visited for the first time, remember the CO name |
| if ( !Abc_NodeIsTravIdCurrent(pDriver) ) |
| { |
| pDriver->pNext = (Abc_Obj_t *)Abc_ObjName(pNode); |
| Abc_NodeSetTravIdCurrent(pDriver); |
| continue; |
| } |
| // the driver has second CO - if they have different name, this is an error |
| if ( strcmp((char *)pDriver->pNext, Abc_ObjName(pNode)) ) // diff names |
| { |
| Vec_PtrPush( vCoTerms, pNode ); |
| continue; |
| } |
| } |
| // fix duplication problem |
| if ( Vec_PtrSize(vCoTerms) > 0 ) |
| { |
| int nDupBufs = 0, nDupGates = 0; |
| Vec_PtrForEachEntry( Abc_Obj_t *, vCoTerms, pNode, i ) |
| { |
| pDriver = Abc_ObjFanin0(pNode); |
| // duplicate if critical |
| if ( fDuplicate && Abc_ObjIsNode(pDriver) && (Abc_NtkHasMapping(pNtk) || Abc_ObjLevel(pDriver) == LevelMax) ) |
| { |
| pDriverNew = Abc_NtkDupObj( pNtk, pDriver, 0 ); |
| Abc_ObjForEachFanin( pDriver, pFanin, k ) |
| Abc_ObjAddFanin( pDriverNew, pFanin ); |
| nDupGates++; |
| } |
| else // add buffer |
| { |
| pDriverNew = Abc_NtkCreateNodeBuf( pNtk, pDriver ); |
| Abc_ObjAssignName( pDriverNew, Abc_ObjName(pDriver), "_buf" ); |
| nDupBufs++; |
| } |
| // swing the PO |
| Abc_ObjPatchFanin( pNode, pDriver, pDriverNew ); |
| assert( Abc_ObjIsCi(pDriver) || Abc_ObjFanoutNum(pDriver) > 0 ); |
| } |
| // printf( "Resolving shared CO drivers: Bufs = %d. Dups = %d.\n", nDupBufs, nDupGates ); |
| nTotal += nDupBufs + nDupGates; |
| } |
| Vec_PtrFree( vCoTerms ); |
| return nTotal; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Inserts a new node in the order by levels.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_VecObjPushUniqueOrderByLevel( Vec_Ptr_t * p, Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pNode1, * pNode2; |
| int i; |
| if ( Vec_PtrPushUnique(p, pNode) ) |
| return; |
| // find the p of the node |
| for ( i = p->nSize-1; i > 0; i-- ) |
| { |
| pNode1 = (Abc_Obj_t *)p->pArray[i ]; |
| pNode2 = (Abc_Obj_t *)p->pArray[i-1]; |
| if ( Abc_ObjRegular(pNode1)->Level <= Abc_ObjRegular(pNode2)->Level ) |
| break; |
| p->pArray[i ] = pNode2; |
| p->pArray[i-1] = pNode1; |
| } |
| } |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the node is the root of EXOR/NEXOR.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeIsExorType( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pNode0, * pNode1; |
| // check that the node is regular |
| assert( !Abc_ObjIsComplement(pNode) ); |
| // if the node is not AND, this is not EXOR |
| if ( !Abc_AigNodeIsAnd(pNode) ) |
| return 0; |
| // if the children are not complemented, this is not EXOR |
| if ( !Abc_ObjFaninC0(pNode) || !Abc_ObjFaninC1(pNode) ) |
| return 0; |
| // get children |
| pNode0 = Abc_ObjFanin0(pNode); |
| pNode1 = Abc_ObjFanin1(pNode); |
| // if the children are not ANDs, this is not EXOR |
| if ( Abc_ObjFaninNum(pNode0) != 2 || Abc_ObjFaninNum(pNode1) != 2 ) |
| return 0; |
| // this is AIG, which means the fanins should be ordered |
| assert( Abc_ObjFaninId0(pNode0) != Abc_ObjFaninId1(pNode1) || |
| Abc_ObjFaninId0(pNode1) != Abc_ObjFaninId1(pNode0) ); |
| // if grand children are not the same, this is not EXOR |
| if ( Abc_ObjFaninId0(pNode0) != Abc_ObjFaninId0(pNode1) || |
| Abc_ObjFaninId1(pNode0) != Abc_ObjFaninId1(pNode1) ) |
| return 0; |
| // finally, if the complemented edges are matched, this is not EXOR |
| if ( Abc_ObjFaninC0(pNode0) == Abc_ObjFaninC0(pNode1) || |
| Abc_ObjFaninC1(pNode0) == Abc_ObjFaninC1(pNode1) ) |
| return 0; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the node is the root of MUX or EXOR/NEXOR.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeIsMuxType( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pNode0, * pNode1; |
| // check that the node is regular |
| assert( !Abc_ObjIsComplement(pNode) ); |
| // if the node is not AND, this is not MUX |
| if ( !Abc_AigNodeIsAnd(pNode) ) |
| return 0; |
| // if the children are not complemented, this is not MUX |
| if ( !Abc_ObjFaninC0(pNode) || !Abc_ObjFaninC1(pNode) ) |
| return 0; |
| // get children |
| pNode0 = Abc_ObjFanin0(pNode); |
| pNode1 = Abc_ObjFanin1(pNode); |
| // if the children are not ANDs, this is not MUX |
| if ( !Abc_AigNodeIsAnd(pNode0) || !Abc_AigNodeIsAnd(pNode1) ) |
| return 0; |
| // otherwise the node is MUX iff it has a pair of equal grandchildren with opposite polarity |
| return (Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC0(pNode1))) || |
| (Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC1(pNode1))) || |
| (Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC0(pNode1))) || |
| (Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC1(pNode1))); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the node is the root of MUX or EXOR/NEXOR.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkCountMuxes( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pNode; |
| int i; |
| int Counter = 0; |
| Abc_NtkForEachNode( pNtk, pNode, i ) |
| Counter += Abc_NodeIsMuxType( pNode ); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if the node is the control type of the MUX.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeIsMuxControlType( Abc_Obj_t * pNode ) |
| { |
| Abc_Obj_t * pNode0, * pNode1; |
| // check that the node is regular |
| assert( !Abc_ObjIsComplement(pNode) ); |
| // skip the node that do not have two fanouts |
| if ( Abc_ObjFanoutNum(pNode) != 2 ) |
| return 0; |
| // get the fanouts |
| pNode0 = Abc_ObjFanout( pNode, 0 ); |
| pNode1 = Abc_ObjFanout( pNode, 1 ); |
| // if they have more than one fanout, we are not interested |
| if ( Abc_ObjFanoutNum(pNode0) != 1 || Abc_ObjFanoutNum(pNode1) != 1 ) |
| return 0; |
| // if the fanouts have the same fanout, this is MUX or EXOR (or a redundant gate (CA)(CB)) |
| return Abc_ObjFanout0(pNode0) == Abc_ObjFanout0(pNode1); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Recognizes what nodes are control and data inputs of a MUX.] |
| |
| Description [If the node is a MUX, returns the control variable C. |
| Assigns nodes T and E to be the then and else variables of the MUX. |
| Node C is never complemented. Nodes T and E can be complemented. |
| This function also recognizes EXOR/NEXOR gates as MUXes.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NodeRecognizeMux( Abc_Obj_t * pNode, Abc_Obj_t ** ppNodeT, Abc_Obj_t ** ppNodeE ) |
| { |
| Abc_Obj_t * pNode0, * pNode1; |
| assert( !Abc_ObjIsComplement(pNode) ); |
| assert( Abc_NodeIsMuxType(pNode) ); |
| // get children |
| pNode0 = Abc_ObjFanin0(pNode); |
| pNode1 = Abc_ObjFanin1(pNode); |
| // find the control variable |
| // if ( pNode1->p1 == Fraig_Not(pNode2->p1) ) |
| if ( Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC0(pNode1)) ) |
| { |
| // if ( Fraig_IsComplement(pNode1->p1) ) |
| if ( Abc_ObjFaninC0(pNode0) ) |
| { // pNode2->p1 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2); |
| return Abc_ObjChild0(pNode1);//pNode2->p1; |
| } |
| else |
| { // pNode1->p1 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2); |
| return Abc_ObjChild0(pNode0);//pNode1->p1; |
| } |
| } |
| // else if ( pNode1->p1 == Fraig_Not(pNode2->p2) ) |
| else if ( Abc_ObjFaninId0(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC0(pNode0) ^ Abc_ObjFaninC1(pNode1)) ) |
| { |
| // if ( Fraig_IsComplement(pNode1->p1) ) |
| if ( Abc_ObjFaninC0(pNode0) ) |
| { // pNode2->p2 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2); |
| return Abc_ObjChild1(pNode1);//pNode2->p2; |
| } |
| else |
| { // pNode1->p1 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode0));//pNode1->p2); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1); |
| return Abc_ObjChild0(pNode0);//pNode1->p1; |
| } |
| } |
| // else if ( pNode1->p2 == Fraig_Not(pNode2->p1) ) |
| else if ( Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId0(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC0(pNode1)) ) |
| { |
| // if ( Fraig_IsComplement(pNode1->p2) ) |
| if ( Abc_ObjFaninC1(pNode0) ) |
| { // pNode2->p1 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1); |
| return Abc_ObjChild0(pNode1);//pNode2->p1; |
| } |
| else |
| { // pNode1->p2 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild1(pNode1));//pNode2->p2); |
| return Abc_ObjChild1(pNode0);//pNode1->p2; |
| } |
| } |
| // else if ( pNode1->p2 == Fraig_Not(pNode2->p2) ) |
| else if ( Abc_ObjFaninId1(pNode0) == Abc_ObjFaninId1(pNode1) && (Abc_ObjFaninC1(pNode0) ^ Abc_ObjFaninC1(pNode1)) ) |
| { |
| // if ( Fraig_IsComplement(pNode1->p2) ) |
| if ( Abc_ObjFaninC1(pNode0) ) |
| { // pNode2->p2 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1); |
| return Abc_ObjChild1(pNode1);//pNode2->p2; |
| } |
| else |
| { // pNode1->p2 is positive phase of C |
| *ppNodeT = Abc_ObjNot(Abc_ObjChild0(pNode0));//pNode1->p1); |
| *ppNodeE = Abc_ObjNot(Abc_ObjChild0(pNode1));//pNode2->p1); |
| return Abc_ObjChild1(pNode0);//pNode1->p2; |
| } |
| } |
| assert( 0 ); // this is not MUX |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepares two network for a two-argument command similar to "verify".] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkPrepareTwoNtks( FILE * pErr, Abc_Ntk_t * pNtk, char ** argv, int argc, |
| Abc_Ntk_t ** ppNtk1, Abc_Ntk_t ** ppNtk2, int * pfDelete1, int * pfDelete2, int fCheck ) |
| { |
| FILE * pFile; |
| Abc_Ntk_t * pNtk1, * pNtk2, * pNtkTemp; |
| int util_optind = 0; |
| |
| *pfDelete1 = 0; |
| *pfDelete2 = 0; |
| if ( argc == util_optind ) |
| { // use the spec |
| if ( pNtk == NULL ) |
| { |
| fprintf( pErr, "Empty current network.\n" ); |
| return 0; |
| } |
| if ( pNtk->pSpec == NULL ) |
| { |
| fprintf( pErr, "The external spec is not given.\n" ); |
| return 0; |
| } |
| pFile = fopen( pNtk->pSpec, "r" ); |
| if ( pFile == NULL ) |
| { |
| fprintf( pErr, "Cannot open the external spec file \"%s\".\n", pNtk->pSpec ); |
| return 0; |
| } |
| else |
| fclose( pFile ); |
| pNtk1 = Abc_NtkDup(pNtk); |
| pNtk2 = Io_Read( pNtk->pSpec, Io_ReadFileType(pNtk->pSpec), fCheck, 0 ); |
| if ( pNtk2 == NULL ) |
| return 0; |
| *pfDelete1 = 1; |
| *pfDelete2 = 1; |
| } |
| else if ( argc == util_optind + 1 ) |
| { |
| if ( pNtk == NULL ) |
| { |
| fprintf( pErr, "Empty current network.\n" ); |
| return 0; |
| } |
| pNtk1 = Abc_NtkDup(pNtk); |
| pNtk2 = Io_Read( argv[util_optind], Io_ReadFileType(argv[util_optind]), fCheck, 0 ); |
| if ( pNtk2 == NULL ) |
| return 0; |
| *pfDelete1 = 1; |
| *pfDelete2 = 1; |
| } |
| else if ( argc == util_optind + 2 ) |
| { |
| pNtk1 = Io_Read( argv[util_optind], Io_ReadFileType(argv[util_optind]), fCheck, 0 ); |
| if ( pNtk1 == NULL ) |
| return 0; |
| pNtk2 = Io_Read( argv[util_optind+1], Io_ReadFileType(argv[util_optind+1]), fCheck, 0 ); |
| if ( pNtk2 == NULL ) |
| { |
| Abc_NtkDelete( pNtk1 ); |
| return 0; |
| } |
| *pfDelete1 = 1; |
| *pfDelete2 = 1; |
| } |
| else |
| { |
| fprintf( pErr, "Wrong number of arguments.\n" ); |
| return 0; |
| } |
| |
| // make sure the networks are strashed |
| if ( !Abc_NtkIsStrash(pNtk1) ) |
| { |
| pNtkTemp = Abc_NtkStrash( pNtk1, 0, 1, 0 ); |
| if ( *pfDelete1 ) |
| Abc_NtkDelete( pNtk1 ); |
| pNtk1 = pNtkTemp; |
| *pfDelete1 = 1; |
| } |
| if ( !Abc_NtkIsStrash(pNtk2) ) |
| { |
| pNtkTemp = Abc_NtkStrash( pNtk2, 0, 1, 0 ); |
| if ( *pfDelete2 ) |
| Abc_NtkDelete( pNtk2 ); |
| pNtk2 = pNtkTemp; |
| *pfDelete2 = 1; |
| } |
| |
| *ppNtk1 = pNtk1; |
| *ppNtk2 = pNtk2; |
| return 1; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if it is an AIG with choice nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NodeCollectFanins( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ) |
| { |
| Abc_Obj_t * pFanin; |
| int i; |
| Vec_PtrClear(vNodes); |
| Abc_ObjForEachFanin( pNode, pFanin, i ) |
| Vec_PtrPush( vNodes, pFanin ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if it is an AIG with choice nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NodeCollectFanouts( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Vec_PtrClear(vNodes); |
| Abc_ObjForEachFanout( pNode, pFanout, i ) |
| Vec_PtrPush( vNodes, pFanout ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects all latches in the network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Abc_NtkCollectLatches( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vLatches; |
| Abc_Obj_t * pObj; |
| int i; |
| vLatches = Vec_PtrAlloc( 10 ); |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| Vec_PtrPush( vLatches, pObj ); |
| return vLatches; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Procedure used for sorting the nodes in increasing order of levels.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeCompareLevelsIncrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 ) |
| { |
| int Diff = Abc_ObjRegular(*pp1)->Level - Abc_ObjRegular(*pp2)->Level; |
| if ( Diff < 0 ) |
| return -1; |
| if ( Diff > 0 ) |
| return 1; |
| Diff = Abc_ObjRegular(*pp1)->Id - Abc_ObjRegular(*pp2)->Id; |
| if ( Diff < 0 ) |
| return -1; |
| if ( Diff > 0 ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Procedure used for sorting the nodes in decreasing order of levels.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NodeCompareLevelsDecrease( Abc_Obj_t ** pp1, Abc_Obj_t ** pp2 ) |
| { |
| int Diff = Abc_ObjRegular(*pp1)->Level - Abc_ObjRegular(*pp2)->Level; |
| if ( Diff > 0 ) |
| return -1; |
| if ( Diff < 0 ) |
| return 1; |
| Diff = Abc_ObjRegular(*pp1)->Id - Abc_ObjRegular(*pp2)->Id; |
| if ( Diff > 0 ) |
| return -1; |
| if ( Diff < 0 ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates the array of fanout counters.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Int_t * Abc_NtkFanoutCounts( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Int_t * vFanNums; |
| Abc_Obj_t * pObj; |
| int i; |
| vFanNums = Vec_IntAlloc( 0 ); |
| Vec_IntFill( vFanNums, Abc_NtkObjNumMax(pNtk), -1 ); |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( Abc_ObjIsCi(pObj) || Abc_ObjIsNode(pObj) ) |
| Vec_IntWriteEntry( vFanNums, i, Abc_ObjFanoutNum(pObj) ); |
| return vFanNums; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects all objects into one array.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Abc_NtkCollectObjects( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vNodes; |
| Abc_Obj_t * pNode; |
| int i; |
| vNodes = Vec_PtrAlloc( 100 ); |
| Abc_NtkForEachObj( pNtk, pNode, i ) |
| Vec_PtrPush( vNodes, pNode ); |
| return vNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the array of CI IDs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Int_t * Abc_NtkGetCiIds( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Int_t * vCiIds; |
| Abc_Obj_t * pObj; |
| int i; |
| vCiIds = Vec_IntAlloc( Abc_NtkCiNum(pNtk) ); |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| Vec_IntPush( vCiIds, pObj->Id ); |
| return vCiIds; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Puts the nodes into the DFS order and reassign their IDs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkReassignIds( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vNodes; |
| Vec_Ptr_t * vObjsNew; |
| Abc_Obj_t * pNode, * pTemp, * pConst1; |
| int i, k; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| //printf( "Total = %d. Current = %d.\n", Abc_NtkObjNumMax(pNtk), Abc_NtkObjNum(pNtk) ); |
| // start the array of objects with new IDs |
| vObjsNew = Vec_PtrAlloc( pNtk->nObjs ); |
| // put constant node first |
| pConst1 = Abc_AigConst1(pNtk); |
| assert( pConst1->Id == 0 ); |
| Vec_PtrPush( vObjsNew, pConst1 ); |
| // put PI nodes next |
| Abc_NtkForEachPi( pNtk, pNode, i ) |
| { |
| pNode->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pNode ); |
| } |
| // put PO nodes next |
| Abc_NtkForEachPo( pNtk, pNode, i ) |
| { |
| pNode->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pNode ); |
| } |
| // put latches and their inputs/outputs next |
| Abc_NtkForEachBox( pNtk, pNode, i ) |
| { |
| pNode->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pNode ); |
| Abc_ObjForEachFanin( pNode, pTemp, k ) |
| { |
| pTemp->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pTemp ); |
| } |
| Abc_ObjForEachFanout( pNode, pTemp, k ) |
| { |
| pTemp->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pTemp ); |
| } |
| } |
| // finally, internal nodes in the DFS order |
| vNodes = Abc_AigDfs( pNtk, 1, 0 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) |
| { |
| if ( pNode == pConst1 ) |
| continue; |
| pNode->Id = Vec_PtrSize( vObjsNew ); |
| Vec_PtrPush( vObjsNew, pNode ); |
| } |
| Vec_PtrFree( vNodes ); |
| assert( Vec_PtrSize(vObjsNew) == pNtk->nObjs ); |
| |
| // update the fanin/fanout arrays |
| Abc_NtkForEachObj( pNtk, pNode, i ) |
| { |
| Abc_ObjForEachFanin( pNode, pTemp, k ) |
| pNode->vFanins.pArray[k] = pTemp->Id; |
| Abc_ObjForEachFanout( pNode, pTemp, k ) |
| pNode->vFanouts.pArray[k] = pTemp->Id; |
| } |
| |
| // replace the array of objs |
| Vec_PtrFree( pNtk->vObjs ); |
| pNtk->vObjs = vObjsNew; |
| |
| // rehash the AIG |
| Abc_AigRehash( (Abc_Aig_t *)pNtk->pManFunc ); |
| |
| // update the name manager!!! |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Detect cases when non-trivial FF matching is possible.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkDetectMatching( Abc_Ntk_t * pNtk ) |
| { |
| /* |
| Abc_Obj_t * pLatch, * pFanin; |
| int i, nTFFs, nJKFFs; |
| nTFFs = nJKFFs = 0; |
| Abc_NtkForEachLatch( pNtk, pLatch, i ) |
| { |
| pFanin = Abc_ObjFanin0(pLatch); |
| if ( Abc_ObjFaninNum(pFanin) != 2 ) |
| continue; |
| if ( Abc_NodeIsExorType(pLatch) ) |
| { |
| if ( Abc_ObjFanin0(Abc_ObjFanin0(pFanin)) == pLatch || |
| Abc_ObjFanin1(Abc_ObjFanin0(pFanin)) == pLatch ) |
| nTFFs++; |
| } |
| if ( Abc_ObjFaninNum( Abc_ObjFanin0(pFanin) ) != 2 || |
| Abc_ObjFaninNum( Abc_ObjFanin1(pFanin) ) != 2 ) |
| continue; |
| |
| if ( (Abc_ObjFanin0(Abc_ObjFanin0(pFanin)) == pLatch || |
| Abc_ObjFanin1(Abc_ObjFanin0(pFanin)) == pLatch) && |
| (Abc_ObjFanin0(Abc_ObjFanin1(pFanin)) == pLatch || |
| Abc_ObjFanin1(Abc_ObjFanin1(pFanin)) == pLatch) ) |
| { |
| nJKFFs++; |
| } |
| } |
| printf( "D = %6d. T = %6d. JK = %6d. (%6.2f %%)\n", |
| Abc_NtkLatchNum(pNtk), nTFFs, nJKFFs, 100.0 * nJKFFs / Abc_NtkLatchNum(pNtk) ); |
| */ |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Compares the pointers.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_ObjPointerCompare( void ** pp1, void ** pp2 ) |
| { |
| if ( *pp1 < *pp2 ) |
| return -1; |
| if ( *pp1 > *pp2 ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Adjusts the copy pointers.] |
| |
| Description [This procedure assumes that the network was transformed |
| into another network, which was in turn transformed into yet another |
| network. It makes the pCopy pointers of the original network point to |
| the objects of the yet another network.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkTransferCopy( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( !Abc_ObjIsNet(pObj) ) |
| pObj->pCopy = pObj->pCopy? Abc_ObjCopyCond(pObj->pCopy) : NULL; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Increaments the cut counter.] |
| |
| Description [Returns 1 if it becomes equal to the ref counter.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Abc_ObjCrossCutInc( Abc_Obj_t * pObj ) |
| { |
| // pObj->pCopy = (void *)(((int)pObj->pCopy)++); |
| int Value = (int)(ABC_PTRINT_T)pObj->pCopy; |
| pObj->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)(Value + 1); |
| return (int)(ABC_PTRINT_T)pObj->pCopy == Abc_ObjFanoutNum(pObj); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes cross-cut of the circuit.] |
| |
| Description [Returns 1 if it is the last visit to the node.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkCrossCut_rec( Abc_Obj_t * pObj, int * pnCutSize, int * pnCutSizeMax ) |
| { |
| Abc_Obj_t * pFanin; |
| int i, nDecrem = 0; |
| int fReverse = 0; |
| if ( Abc_ObjIsCi(pObj) ) |
| return 0; |
| // if visited, increment visit counter |
| if ( Abc_NodeIsTravIdCurrent( pObj ) ) |
| return Abc_ObjCrossCutInc( pObj ); |
| Abc_NodeSetTravIdCurrent( pObj ); |
| // visit the fanins |
| if ( !Abc_ObjIsCi(pObj) ) |
| { |
| if ( fReverse ) |
| { |
| Abc_ObjForEachFanin( pObj, pFanin, i ) |
| { |
| pFanin = Abc_ObjFanin( pObj, Abc_ObjFaninNum(pObj) - 1 - i ); |
| nDecrem += Abc_NtkCrossCut_rec( pFanin, pnCutSize, pnCutSizeMax ); |
| } |
| } |
| else |
| { |
| Abc_ObjForEachFanin( pObj, pFanin, i ) |
| nDecrem += Abc_NtkCrossCut_rec( pFanin, pnCutSize, pnCutSizeMax ); |
| } |
| } |
| // count the node |
| (*pnCutSize)++; |
| if ( *pnCutSizeMax < *pnCutSize ) |
| *pnCutSizeMax = *pnCutSize; |
| (*pnCutSize) -= nDecrem; |
| return Abc_ObjCrossCutInc( pObj ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes cross-cut of the circuit.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkCrossCut( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int nCutSize = 0, nCutSizeMax = 0; |
| int i; |
| Abc_NtkCleanCopy( pNtk ); |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| { |
| Abc_NtkCrossCut_rec( pObj, &nCutSize, &nCutSizeMax ); |
| nCutSize--; |
| } |
| assert( nCutSize == 0 ); |
| printf( "Max cross cut size = %6d. Ratio = %6.2f %%\n", nCutSizeMax, 100.0 * nCutSizeMax/Abc_NtkObjNum(pNtk) ); |
| return nCutSizeMax; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints all 3-var functions.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkPrint256() |
| { |
| FILE * pFile; |
| unsigned i; |
| pFile = fopen( "4varfs.txt", "w" ); |
| for ( i = 1; i < (1<<16)-1; i++ ) |
| { |
| fprintf( pFile, "read_truth " ); |
| Extra_PrintBinary( pFile, &i, 16 ); |
| fprintf( pFile, "; clp; st; w 1.blif; map; cec 1.blif\n" ); |
| } |
| fclose( pFile ); |
| } |
| |
| |
| static int * pSupps; |
| |
| /**Function************************************************************* |
| |
| Synopsis [Compares the supergates by their level.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkCompareConesCompare( int * pNum1, int * pNum2 ) |
| { |
| if ( pSupps[*pNum1] > pSupps[*pNum2] ) |
| return -1; |
| if ( pSupps[*pNum1] < pSupps[*pNum2] ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Analyze choice node support.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCompareCones( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vSupp, * vNodes, * vReverse; |
| Abc_Obj_t * pObj, * pTemp; |
| int Iter, i, k, Counter, CounterCos, CounterCosNew; |
| int * pPerms; |
| |
| // sort COs by support size |
| pPerms = ABC_ALLOC( int, Abc_NtkCoNum(pNtk) ); |
| pSupps = ABC_ALLOC( int, Abc_NtkCoNum(pNtk) ); |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| { |
| pPerms[i] = i; |
| vSupp = Abc_NtkNodeSupport( pNtk, &pObj, 1 ); |
| pSupps[i] = Vec_PtrSize(vSupp); |
| Vec_PtrFree( vSupp ); |
| } |
| qsort( (void *)pPerms, Abc_NtkCoNum(pNtk), sizeof(int), (int (*)(const void *, const void *)) Abc_NtkCompareConesCompare ); |
| |
| // consider COs in this order |
| Iter = 0; |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| { |
| pObj = Abc_NtkCo( pNtk, pPerms[i] ); |
| if ( pObj->fMarkA ) |
| continue; |
| Iter++; |
| |
| vSupp = Abc_NtkNodeSupport( pNtk, &pObj, 1 ); |
| vNodes = Abc_NtkDfsNodes( pNtk, &pObj, 1 ); |
| vReverse = Abc_NtkDfsReverseNodesContained( pNtk, (Abc_Obj_t **)Vec_PtrArray(vSupp), Vec_PtrSize(vSupp) ); |
| // count the number of nodes in the reverse cone |
| Counter = 0; |
| for ( k = 1; k < Vec_PtrSize(vReverse) - 1; k++ ) |
| for ( pTemp = (Abc_Obj_t *)Vec_PtrEntry(vReverse, k); pTemp; pTemp = (Abc_Obj_t *)pTemp->pCopy ) |
| Counter++; |
| CounterCos = CounterCosNew = 0; |
| for ( pTemp = (Abc_Obj_t *)Vec_PtrEntryLast(vReverse); pTemp; pTemp = (Abc_Obj_t *)pTemp->pCopy ) |
| { |
| assert( Abc_ObjIsCo(pTemp) ); |
| CounterCos++; |
| if ( pTemp->fMarkA == 0 ) |
| CounterCosNew++; |
| pTemp->fMarkA = 1; |
| } |
| // print statistics |
| printf( "%4d CO %5d : Supp = %5d. Lev = %3d. Cone = %5d. Rev = %5d. COs = %3d (%3d).\n", |
| Iter, pPerms[i], Vec_PtrSize(vSupp), Abc_ObjLevel(Abc_ObjFanin0(pObj)), Vec_PtrSize(vNodes), Counter, CounterCos, CounterCosNew ); |
| |
| if ( Vec_PtrSize(vSupp) < 10 ) |
| { |
| // free arrays |
| Vec_PtrFree( vSupp ); |
| Vec_PtrFree( vNodes ); |
| Vec_PtrFree( vReverse ); |
| break; |
| } |
| |
| // free arrays |
| Vec_PtrFree( vSupp ); |
| Vec_PtrFree( vNodes ); |
| Vec_PtrFree( vReverse ); |
| |
| } |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| pObj->fMarkA = 0; |
| |
| ABC_FREE( pPerms ); |
| ABC_FREE( pSupps ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Analyze choice node support.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkCompareSupports( Abc_Ntk_t * pNtk ) |
| { |
| Vec_Ptr_t * vSupp; |
| Abc_Obj_t * pObj, * pTemp; |
| int i, nNodesOld; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| Abc_AigForEachAnd( pNtk, pObj, i ) |
| { |
| if ( !Abc_AigNodeIsChoice(pObj) ) |
| continue; |
| |
| vSupp = Abc_NtkNodeSupport( pNtk, &pObj, 1 ); |
| nNodesOld = Vec_PtrSize(vSupp); |
| Vec_PtrFree( vSupp ); |
| |
| for ( pTemp = (Abc_Obj_t *)pObj->pData; pTemp; pTemp = (Abc_Obj_t *)pTemp->pData ) |
| { |
| vSupp = Abc_NtkNodeSupport( pNtk, &pTemp, 1 ); |
| if ( nNodesOld != Vec_PtrSize(vSupp) ) |
| printf( "Choice orig = %3d Choice new = %3d\n", nNodesOld, Vec_PtrSize(vSupp) ); |
| Vec_PtrFree( vSupp ); |
| } |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Complements the constraint outputs.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkInvertConstraints( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| if ( Abc_NtkConstrNum(pNtk) == 0 ) |
| return; |
| Abc_NtkForEachPo( pNtk, pObj, i ) |
| { |
| if ( i >= Abc_NtkPoNum(pNtk) - Abc_NtkConstrNum(pNtk) ) |
| Abc_ObjXorFaninC( pObj, 0 ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkPrintCiLevels( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| printf( "%c=%d ", 'a'+i, pObj->Level ); |
| printf( "\n" ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if all other fanouts of pFanin are below pNode.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkAddBuffsEval( Abc_Obj_t * pNode, Abc_Obj_t * pFanin ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pFanin, pFanout, i ) |
| if ( pFanout != pNode && pFanout->Level >= pNode->Level ) |
| return 0; |
| return 1; |
| } |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if there exist a fanout of pFanin higher than pNode.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkAddBuffsEval2( Abc_Obj_t * pNode, Abc_Obj_t * pFanin ) |
| { |
| Abc_Obj_t * pFanout; |
| int i; |
| Abc_ObjForEachFanout( pFanin, pFanout, i ) |
| if ( pFanout != pNode && pFanout->Level > pNode->Level ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Obj_t * Abc_NtkAddBuffsOne( Vec_Ptr_t * vBuffs, Abc_Obj_t * pFanin, int Level, int nLevelMax ) |
| { |
| Abc_Obj_t * pBuffer; |
| assert( Level - 1 >= Abc_ObjLevel(pFanin) ); |
| pBuffer = (Abc_Obj_t *)Vec_PtrEntry( vBuffs, Abc_ObjId(pFanin) * nLevelMax + Level ); |
| if ( pBuffer == NULL ) |
| { |
| if ( Level - 1 == Abc_ObjLevel(pFanin) ) |
| pBuffer = pFanin; |
| else |
| pBuffer = Abc_NtkAddBuffsOne( vBuffs, pFanin, Level - 1, nLevelMax ); |
| pBuffer = Abc_NtkCreateNodeBuf( Abc_ObjNtk(pFanin), pBuffer ); |
| Vec_PtrWriteEntry( vBuffs, Abc_ObjId(pFanin) * nLevelMax + Level, pBuffer ); |
| } |
| return pBuffer; |
| } |
| Abc_Ntk_t * Abc_NtkAddBuffsInt( Abc_Ntk_t * pNtkInit, int fReverse, int nImprove, int fVerbose ) |
| { |
| Vec_Ptr_t * vBuffs; |
| Abc_Ntk_t * pNtk = Abc_NtkDup( pNtkInit ); |
| Abc_Obj_t * pObj, * pFanin, * pBuffer; |
| int i, k, Iter, nLevelMax = Abc_NtkLevel( pNtk ); |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| pObj->Level = nLevelMax + 1; |
| if ( fReverse ) |
| { |
| Vec_Ptr_t * vNodes = Abc_NtkDfs( pNtk, 1 ); |
| assert( nLevelMax < (1<<18) ); |
| Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| pObj->Level = (1<<18); |
| Abc_ObjForEachFanout( pObj, pFanin, k ) |
| pObj->Level = Abc_MinInt( pFanin->Level - 1, pObj->Level ); |
| assert( pObj->Level > 0 ); |
| } |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| pObj->Level = 0; |
| |
| // move the nodes down one step at a time |
| for ( Iter = 0; Iter < nImprove; Iter++ ) |
| { |
| int Counter = 0, TotalGain = 0; |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| int CountGain = -1; |
| assert( pObj->Level > 0 ); |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| { |
| assert( pFanin->Level < pObj->Level ); |
| if ( pFanin->Level + 1 == pObj->Level ) |
| break; |
| } |
| if ( k < Abc_ObjFaninNum(pObj) ) // cannot move |
| continue; |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| CountGain += Abc_NtkAddBuffsEval( pObj, pFanin ); |
| if ( CountGain >= 0 ) // can move |
| { |
| pObj->Level--; |
| Counter++; |
| TotalGain += CountGain; |
| } |
| } |
| if ( fVerbose ) |
| printf( "Shifted %5d nodes down with total gain %5d.\n", Counter, TotalGain ); |
| if ( Counter == 0 ) |
| break; |
| } |
| Vec_PtrFree( vNodes ); |
| } |
| else |
| { |
| // move the nodes up one step at a time |
| Vec_Ptr_t * vNodes = Abc_NtkDfs( pNtk, 1 ); |
| for ( Iter = 0; Iter < nImprove; Iter++ ) |
| { |
| int Counter = 0, TotalGain = 0; |
| Vec_PtrForEachEntryReverse( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| int CountGain = 1; |
| assert( pObj->Level <= (unsigned)nLevelMax ); |
| Abc_ObjForEachFanout( pObj, pFanin, k ) |
| { |
| assert( pFanin->Level > pObj->Level ); |
| if ( pFanin->Level == pObj->Level + 1 ) |
| break; |
| } |
| if ( k < Abc_ObjFanoutNum(pObj) ) // cannot move |
| continue; |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| CountGain -= !Abc_NtkAddBuffsEval2( pObj, pFanin ); |
| if ( CountGain >= 0 ) // can move |
| { |
| pObj->Level++; |
| Counter++; |
| TotalGain += CountGain; |
| } |
| } |
| if ( fVerbose ) |
| printf( "Shifted %5d nodes up with total gain %5d.\n", Counter, TotalGain ); |
| if ( Counter == 0 ) |
| break; |
| } |
| Vec_PtrFree( vNodes ); |
| } |
| vBuffs = Vec_PtrStart( Abc_NtkObjNumMax(pNtk) * (nLevelMax + 1) ); |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| { |
| if ( i == Vec_PtrSize(vBuffs) / (nLevelMax + 1) ) |
| break; |
| if ( !Abc_ObjIsNode(pObj) && !Abc_ObjIsCo(pObj) ) |
| continue; |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| { |
| assert( Abc_ObjLevel(pObj) - 1 >= Abc_ObjLevel(pFanin) ); |
| if ( Abc_ObjLevel(pObj) - 1 == Abc_ObjLevel(pFanin) ) |
| continue; |
| pBuffer = Abc_NtkAddBuffsOne( vBuffs, pFanin, Abc_ObjLevel(pObj) - 1, nLevelMax ); |
| Abc_ObjPatchFanin( pObj, pFanin, pBuffer ); |
| } |
| } |
| Vec_PtrFree( vBuffs ); |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| pObj->Level = 0; |
| return pNtk; |
| } |
| Abc_Ntk_t * Abc_NtkAddBuffs( Abc_Ntk_t * pNtkInit, int fDirect, int fReverse, int nImprove, int fVerbose ) |
| { |
| Abc_Ntk_t * pNtkD, * pNtkR; |
| if ( fDirect ) |
| return Abc_NtkAddBuffsInt( pNtkInit, 0, nImprove, fVerbose ); |
| if ( fReverse ) |
| return Abc_NtkAddBuffsInt( pNtkInit, 1, nImprove, fVerbose ); |
| pNtkD = Abc_NtkAddBuffsInt( pNtkInit, 0, nImprove, fVerbose ); |
| pNtkR = Abc_NtkAddBuffsInt( pNtkInit, 1, nImprove, fVerbose ); |
| if ( Abc_NtkNodeNum(pNtkD) < Abc_NtkNodeNum(pNtkR) ) |
| { |
| Abc_NtkDelete( pNtkR ); |
| return pNtkD; |
| } |
| else |
| { |
| Abc_NtkDelete( pNtkD ); |
| return pNtkR; |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes max delay using log(n) delay model.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| float Abc_NtkComputeDelay( Abc_Ntk_t * pNtk ) |
| { |
| static double GateDelays[20] = { 1.00, 1.00, 2.00, 2.58, 3.00, 3.32, 3.58, 3.81, 4.00, 4.17, 4.32, 4.46, 4.58, 4.70, 4.81, 4.91, 5.00, 5.09, 5.17, 5.25 }; |
| Vec_Ptr_t * vNodes; |
| Abc_Obj_t * pObj, * pFanin; |
| float DelayMax, Delays[15] = {0}; |
| int nFaninMax, i, k; |
| // calculate relative gate delays |
| nFaninMax = Abc_NtkGetFaninMax( pNtk ); |
| assert( nFaninMax > 1 && nFaninMax < 15 ); |
| for ( i = 0; i <= nFaninMax; i++ ) |
| Delays[i] = GateDelays[i]/GateDelays[nFaninMax]; |
| // set max CI delay |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| pObj->dTemp = 0.0; |
| // compute delays for each node |
| vNodes = Abc_NtkDfs( pNtk, 1 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| pObj->dTemp = 0.0; |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| pObj->dTemp = Abc_MaxFloat( pObj->dTemp, pFanin->dTemp ); |
| pObj->dTemp += Delays[Abc_ObjFaninNum(pObj)]; |
| } |
| Vec_PtrFree( vNodes ); |
| DelayMax = 0.0; |
| // find max CO delay |
| Abc_NtkForEachCo( pNtk, pObj, i ) |
| DelayMax = Abc_MaxFloat( DelayMax, Abc_ObjFanin0(pObj)->dTemp ); |
| return DelayMax; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NodeSopToCubes( Abc_Obj_t * pNodeOld, Abc_Ntk_t * pNtkNew, int fXor ) |
| { |
| Abc_Obj_t * pNodeOr, * pNodeNew, * pFanin; |
| char * pCube, * pSop = (char *)pNodeOld->pData; |
| int v, Value, nVars = Abc_ObjFaninNum(pNodeOld), nFanins; |
| // create the root node |
| if ( Abc_SopGetCubeNum(pSop) < 2 ) |
| { |
| pNodeNew = Abc_NtkDupObj( pNtkNew, pNodeOld, 0 ); |
| Abc_ObjForEachFanin( pNodeOld, pFanin, v ) |
| Abc_ObjAddFanin( pNodeNew, pFanin->pCopy ); |
| assert( pNodeOld->pCopy == pNodeNew ); |
| return; |
| } |
| // add the OR gate |
| pNodeOr = Abc_NtkCreateNode( pNtkNew ); |
| if ( fXor ) |
| pNodeOr->pData = Abc_SopCreateXorSpecial( (Mem_Flex_t *)pNtkNew->pManFunc, Abc_SopGetCubeNum(pSop) ); |
| else |
| pNodeOr->pData = Abc_SopCreateOr( (Mem_Flex_t *)pNtkNew->pManFunc, Abc_SopGetCubeNum(pSop), NULL ); |
| // check the logic function of the node |
| Abc_SopForEachCube( pSop, nVars, pCube ) |
| { |
| nFanins = 0; |
| Abc_CubeForEachVar( pCube, Value, v ) |
| if ( Value == '0' || Value == '1' ) |
| nFanins++; |
| if ( nFanins == 0 ) // const1 cube in ESOP |
| { |
| pNodeNew = Abc_NtkCreateNodeConst1( pNtkNew ); |
| Abc_ObjAddFanin( pNodeOr, pNodeNew ); |
| continue; |
| } |
| assert( nFanins > 0 ); |
| // create node |
| pNodeNew = Abc_NtkCreateNode( pNtkNew ); |
| pNodeNew->pData = Abc_SopCreateAnd( (Mem_Flex_t *)pNtkNew->pManFunc, nFanins, NULL ); |
| nFanins = 0; |
| Abc_CubeForEachVar( pCube, Value, v ) |
| { |
| if ( Value != '0' && Value != '1' ) |
| continue; |
| Abc_ObjAddFanin( pNodeNew, Abc_ObjFanin(pNodeOld, v)->pCopy ); |
| if ( Value == '0' ) |
| Abc_SopComplementVar( (char *)pNodeNew->pData, nFanins ); |
| nFanins++; |
| } |
| Abc_ObjAddFanin( pNodeOr, pNodeNew ); |
| } |
| // check the complement |
| if ( Abc_SopIsComplement(pSop) ) |
| Abc_SopComplement( (char *)pNodeOr->pData ); |
| // mark the old node with the new one |
| assert( pNodeOld->pCopy == NULL ); |
| pNodeOld->pCopy = pNodeOr; |
| } |
| Abc_Ntk_t * Abc_NtkSopToCubes( Abc_Ntk_t * pNtk, int fXor ) |
| { |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pNode; |
| Vec_Ptr_t * vNodes; |
| int i; |
| assert( Abc_NtkIsSopLogic(pNtk) ); |
| Abc_NtkCleanCopy( pNtk ); |
| pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_SOP ); |
| // perform conversion in the topological order |
| vNodes = Abc_NtkDfs( pNtk, 0 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) |
| Abc_NodeSopToCubes( pNode, pNtkNew, fXor ); |
| Vec_PtrFree( vNodes ); |
| // make sure everything is okay |
| Abc_NtkFinalize( pNtk, pNtkNew ); |
| if ( !Abc_NtkCheck( pNtkNew ) ) |
| { |
| printf( "Abc_NtkSopToCubes: The network check has failed.\n" ); |
| Abc_NtkDelete( pNtkNew ); |
| return NULL; |
| } |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates precomputed reverse topological order for each node.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Abc_NtkTopoHasBeg( Abc_Obj_t * p ) { return Vec_IntEntry(p->pNtk->vTopo, 2*Abc_ObjId(p) ); } |
| static inline int Abc_NtkTopoHasEnd( Abc_Obj_t * p ) { return Vec_IntEntry(p->pNtk->vTopo, 2*Abc_ObjId(p)+1); } |
| |
| static inline void Abc_NtkTopoSetBeg( Abc_Obj_t * p ) { Vec_IntWriteEntry(p->pNtk->vTopo, 2*Abc_ObjId(p) , Vec_IntSize(p->pNtk->vTopo)); } |
| static inline void Abc_NtkTopoSetEnd( Abc_Obj_t * p ) { Vec_IntWriteEntry(p->pNtk->vTopo, 2*Abc_ObjId(p)+1, Vec_IntSize(p->pNtk->vTopo)); } |
| |
| void Abc_NtkReverseTopoOrder_rec( Abc_Obj_t * pObj, int fThisIsPivot ) |
| { |
| Abc_Obj_t * pNext, * pPivot = NULL; |
| int i; |
| if ( Abc_NodeIsTravIdCurrent( pObj ) ) |
| return; |
| Abc_NodeSetTravIdCurrent( pObj ); |
| if ( Abc_ObjIsPo(pObj) ) |
| { |
| Vec_IntPush( pObj->pNtk->vTopo, Abc_ObjId(pObj) ); |
| return; |
| } |
| assert( Abc_ObjIsNode(pObj) ); |
| // mark begining |
| if ( fThisIsPivot ) |
| Abc_NtkTopoSetBeg( pObj ); |
| // find fanout without topo |
| Abc_ObjForEachFanout( pObj, pNext, i ) |
| if ( !Abc_NtkTopoHasBeg(pNext) ) |
| { |
| assert( !Abc_NtkTopoHasEnd(pNext) ); |
| Abc_NtkReverseTopoOrder_rec( pNext, 1 ); |
| pPivot = pNext; |
| break; |
| } |
| Abc_ObjForEachFanout( pObj, pNext, i ) |
| if ( pNext != pPivot ) |
| Abc_NtkReverseTopoOrder_rec( pNext, 0 ); |
| // mark end |
| if ( fThisIsPivot ) |
| Abc_NtkTopoSetEnd( pObj ); |
| // save current node |
| Vec_IntPush( pObj->pNtk->vTopo, Abc_ObjId(pObj) ); |
| } |
| void Abc_NtkReverseTopoOrder( Abc_Ntk_t * p ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| assert( p->vTopo == NULL ); |
| p->vTopo = Vec_IntAlloc( 10 * Abc_NtkObjNumMax(p) ); |
| Vec_IntFill( p->vTopo, 2 * Abc_NtkObjNumMax(p), 0 ); |
| Abc_NtkForEachNode( p, pObj, i ) |
| { |
| if ( Abc_NtkTopoHasBeg(pObj) ) |
| continue; |
| Abc_NtkIncrementTravId( p ); |
| Abc_NtkReverseTopoOrder_rec( pObj, 1 ); |
| } |
| printf( "Nodes = %d. Size = %d. Ratio = %f.\n", |
| Abc_NtkNodeNum(p), Vec_IntSize(p->vTopo), 1.0*Vec_IntSize(p->vTopo)/Abc_NtkNodeNum(p) ); |
| } |
| |
| void Abc_NtkReverse_rec( Abc_Obj_t * pObj, Vec_Int_t * vVisited ) |
| { |
| Abc_Obj_t * pNext; |
| int i; |
| if ( Abc_NodeIsTravIdCurrent( pObj ) ) |
| return; |
| Abc_NodeSetTravIdCurrent( pObj ); |
| Abc_ObjForEachFanout( pObj, pNext, i ) |
| Abc_NtkReverse_rec( pNext, vVisited ); |
| Vec_IntPush( vVisited, Abc_ObjId(pObj) ); |
| } |
| void Abc_NtkReverseTopoOrderTest( Abc_Ntk_t * p ) |
| { |
| Vec_Int_t * vVisited; |
| Abc_Obj_t * pObj; |
| int i;//, k, iBeg, iEnd; |
| abctime clk = Abc_Clock(); |
| Abc_NtkReverseTopoOrder( p ); |
| /* |
| printf( "Reverse topological order for nodes:\n" ); |
| Abc_NtkForEachNode( p, pObj, i ) |
| { |
| iBeg = Abc_NtkTopoHasBeg( pObj ); |
| iEnd = Abc_NtkTopoHasEnd( pObj ); |
| printf( "Node %4d : ", Abc_ObjId(pObj) ); |
| for ( k = iEnd - 1; k >= iBeg; k-- ) |
| printf( "%d ", Vec_IntEntry(p->vTopo, k) ); |
| printf( "\n" ); |
| } |
| */ |
| Vec_IntFreeP( &p->vTopo ); |
| Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); |
| // compute regular fanout orders |
| clk = Abc_Clock(); |
| vVisited = Vec_IntAlloc( 1000 ); |
| Abc_NtkForEachNode( p, pObj, i ) |
| { |
| Vec_IntClear( vVisited ); |
| Abc_NtkIncrementTravId( p ); |
| Abc_NtkReverse_rec( pObj, vVisited ); |
| } |
| Vec_IntFree( vVisited ); |
| Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Converts multi-output PLA into an AIG with logic sharing.] |
| |
| Description [The first argument is an array of char*-strings representing |
| individual output of a multi-output PLA. The number of inputs (nInputs) |
| and the number of outputs (nOutputs) are the second and third arguments. |
| This procedure returns the AIG manager with the given number of inputs |
| and outputs representing the PLA as a logic network with sharing. |
| |
| For example, if the original PLA is |
| 1000 10 |
| 0110 01 |
| 0011 01 |
| the individual PLA for each the two outputs should be |
| 1000 1 |
| and |
| 0110 1 |
| 0011 1 |
| |
| Reprsentation in terms of two char*-strings will be: |
| char * pPlas[2] = { "1000 1\n", "0110 1\n0011 1\n" }; |
| The call to the procedure may look as follows: |
| Abc_Ntk_t * pNtkAig = Abc_NtkFromPla( pPlas, 4, 2 );] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkFromPla( char ** pPlas, int nInputs, int nOutputs ) |
| { |
| Fxu_Data_t Params, * p = &Params; |
| Abc_Ntk_t * pNtkSop, * pNtkAig; |
| Abc_Obj_t * pNode, * pFanin; |
| int i, k; |
| // allocate logic network with SOP local functions |
| pNtkSop = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_SOP, 1 ); |
| pNtkSop->pName = Extra_FileNameGeneric("pla"); |
| // create primary inputs/outputs |
| for ( i = 0; i < nInputs; i++ ) |
| Abc_NtkCreatePi( pNtkSop ); |
| for ( i = 0; i < nOutputs; i++ ) |
| Abc_NtkCreatePo( pNtkSop ); |
| Abc_NtkAddDummyPiNames( pNtkSop ); |
| Abc_NtkAddDummyPoNames( pNtkSop ); |
| // create internal nodes |
| for ( i = 0; i < nOutputs; i++ ) |
| { |
| pNode = Abc_NtkCreateNode( pNtkSop ); |
| Abc_NtkForEachPi( pNtkSop, pFanin, k ) |
| Abc_ObjAddFanin( pNode, pFanin ); |
| pNode->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkSop->pManFunc, pPlas[i] ); |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkSop, i), pNode ); |
| // check that the number of inputs is the same |
| assert( Abc_SopGetVarNum((char*)pNode->pData) == nInputs ); |
| } |
| if ( !Abc_NtkCheck( pNtkSop ) ) |
| fprintf( stdout, "Abc_NtkFromPla(): Network check has failed.\n" ); |
| // perform fast_extract |
| Abc_NtkSetDefaultFxParams( p ); |
| Abc_NtkFastExtract( pNtkSop, p ); |
| Abc_NtkFxuFreeInfo( p ); |
| // convert to an AIG |
| pNtkAig = Abc_NtkStrash( pNtkSop, 0, 1, 0 ); |
| Abc_NtkDelete( pNtkSop ); |
| return pNtkAig; |
| } |
| void Abc_NtkFromPlaTest() |
| { |
| char * pPlas[2] = { "1000 1\n", "0110 1\n0011 1\n" }; |
| Abc_Ntk_t * pNtkAig = Abc_NtkFromPla( pPlas, 4, 2 ); |
| Io_WriteBlifLogic( pNtkAig, "temp.blif", 0 ); |
| Abc_NtkDelete( pNtkAig ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the logic network is in the topological order.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkSplitSop( Abc_Ntk_t * pNtk, int nCubesMax, int fVerbose ) |
| { |
| Vec_Ptr_t * vNodes; |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pFanin, * pObjNew, * pObjNewRoot; |
| int i, k, j, nCubes, nCubesThis, nSplits; |
| char * pSopStr, * pSopStr2, * pTempSop, Symb; |
| if ( pNtk == NULL ) |
| return NULL; |
| assert( !Abc_NtkIsStrash(pNtk) && !Abc_NtkIsNetlist(pNtk) ); |
| // start the network |
| pNtkNew = Abc_NtkStartFrom( pNtk, pNtk->ntkType, pNtk->ntkFunc ); |
| // copy the internal nodes |
| vNodes = Abc_NtkDfs( pNtk, 0 ); |
| Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i ) |
| { |
| assert( Abc_ObjIsNode(pObj) ); |
| pObjNewRoot = Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| nCubes = Abc_SopGetCubeNum( (char *)pObj->pData ); |
| if ( nCubes <= nCubesMax ) |
| { |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy ); |
| continue; |
| } |
| nSplits = (nCubes / nCubesMax) + (int)(nCubes % nCubesMax > 0); |
| pSopStr = (char *)pObjNewRoot->pData; |
| pObjNewRoot->pData = Abc_SopCreateOr((Mem_Flex_t *)pNtkNew->pManFunc, nSplits, NULL); |
| if ( Abc_SopIsComplement(pSopStr) ) |
| { |
| Abc_SopComplement( pSopStr ); |
| Abc_SopComplement( (char *)pObjNewRoot->pData ); |
| } |
| pTempSop = (char *)pObj->pData; pObj->pData = (char *)"?"; |
| for ( j = 0; j < nSplits; j++ ) |
| { |
| // clone the node |
| pObjNew = Abc_NtkDupObj( pNtkNew, pObj, 0 ); |
| Abc_ObjAddFanin( pObjNewRoot, pObjNew ); |
| // get its cubes |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy ); |
| // create SOP for this node |
| nCubesThis = (j < nCubes / nCubesMax) ? nCubesMax : nCubes % nCubesMax; |
| pSopStr2 = pSopStr + (Abc_ObjFaninNum(pObj) + 3) * nCubesThis; |
| Symb = *pSopStr2; *pSopStr2 = 0; |
| pObjNew->pData = Abc_SopRegister( (Mem_Flex_t *)pNtkNew->pManFunc, pSopStr ); |
| *pSopStr2 = Symb; |
| pSopStr = pSopStr2; |
| } |
| // update |
| pObj->pData = pTempSop; |
| pObj->pCopy = pObjNewRoot; |
| } |
| Vec_PtrFree( vNodes ); |
| Abc_NtkFinalize( pNtk, pNtkNew ); |
| // check correctness |
| if ( !Abc_NtkCheck( pNtkNew ) ) |
| fprintf( stdout, "Abc_NtkDup(): Network check has failed.\n" ); |
| pNtk->pCopy = pNtkNew; |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks if the logic network is in the topological order.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkIsTopo( Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj, * pFanin; |
| int i, k, Counter = 0; |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCi( pNtk, pObj, i ) |
| Abc_NodeSetTravIdCurrent(pObj); |
| Abc_NtkForEachNode( pNtk, pObj, i ) |
| { |
| // check if fanins are in the topo order |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| if ( !Abc_NodeIsTravIdCurrent(pFanin) ) |
| break; |
| if ( k != Abc_ObjFaninNum(pObj) ) |
| { |
| if ( Counter++ == 0 ) |
| printf( "Node %d is out of topo order.\n", Abc_ObjId(pObj) ); |
| } |
| Abc_NodeSetTravIdCurrent(pObj); |
| } |
| if ( Counter ) |
| printf( "Topological order does not hold for %d internal nodes.\n", Counter ); |
| return (int)(Counter == 0); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Transfers phase information to the new network.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Abc_NtkTransferPhases( Abc_Ntk_t * pNtkNew, Abc_Ntk_t * pNtk ) |
| { |
| Abc_Obj_t * pObj; |
| int i; |
| assert( pNtk->vPhases != NULL ); |
| assert( Vec_IntSize(pNtk->vPhases) == Abc_NtkObjNumMax(pNtk) ); |
| assert( pNtkNew->vPhases == NULL ); |
| pNtkNew->vPhases = Vec_IntStart( Abc_NtkObjNumMax(pNtkNew) ); |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( pObj->pCopy && !Abc_ObjIsNone( (Abc_Obj_t *)pObj->pCopy ) ) |
| Vec_IntWriteEntry( pNtkNew->vPhases, Abc_ObjId( (Abc_Obj_t *)pObj->pCopy ), Vec_IntEntry(pNtk->vPhases, i) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts a new network using existing network as a model.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkDeriveWithOnePo( Abc_Ntk_t * pNtk, Vec_Int_t * vNodeIds, Vec_Int_t * vNodeValues ) |
| { |
| int fCopyNames = 1; |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pFanin, * pObjNew, * pOutputNew; |
| Vec_Ptr_t * vFanins = Vec_PtrAlloc( 100 ); |
| int i, k, Id, Value; |
| // start the network |
| pNtkNew = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 ); |
| // duplicate the name and the spec |
| pNtkNew->pName = Extra_UtilStrsav(pNtk->pName); |
| pNtkNew->pSpec = Extra_UtilStrsav(pNtk->pSpec); |
| // clean the node copy fields |
| Abc_NtkCleanCopy( pNtk ); |
| // map the constant nodes |
| if ( Abc_NtkIsStrash(pNtk) && Abc_NtkIsStrash(pNtkNew) ) |
| Abc_AigConst1(pNtk)->pCopy = Abc_AigConst1(pNtkNew); |
| // clone CIs/CIs/boxes |
| Abc_NtkForEachPi( pNtk, pObj, i ) |
| Abc_NtkDupObj( pNtkNew, pObj, fCopyNames ); |
| //Abc_NtkForEachPo( pNtk, pObj, i ) |
| // Abc_NtkDupObj( pNtkNew, pObj, fCopyNames ); |
| // create one PO |
| pObjNew = Abc_NtkCreateObj( pNtkNew, ABC_OBJ_PO ); |
| Abc_ObjAssignName( pObjNew, "monitor", NULL ); |
| // create boxes |
| Abc_NtkForEachBox( pNtk, pObj, i ) |
| Abc_NtkDupBox( pNtkNew, pObj, fCopyNames ); |
| |
| // duplicate nodes (CIs/COs/latches are already duplicated) |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( pObj->pCopy == NULL && !Abc_ObjIsPo(pObj) ) |
| Abc_NtkDupObj(pNtkNew, pObj, 0); |
| // reconnect all objects except boxes (they are already connected) and POs (they will be connected later) |
| Abc_NtkForEachObj( pNtk, pObj, i ) |
| if ( !Abc_ObjIsPo(pObj) && !Abc_ObjIsBox(pObj) && !Abc_ObjIsBo(pObj) ) |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| Abc_ObjAddFanin( pObj->pCopy, pFanin->pCopy ); |
| |
| // AND nodes (with interters if needed) |
| pOutputNew = NULL; |
| Vec_IntForEachEntryTwo( vNodeIds, vNodeValues, Id, Value, i ) |
| { |
| pObjNew = Abc_NtkObj( pNtk, Id )->pCopy; |
| if ( Value == 0 ) // negative polarity - add inverter |
| pObjNew = Abc_NtkCreateNodeInv( pNtkNew, pObjNew ); |
| if ( pOutputNew == NULL ) |
| pOutputNew = pObjNew; |
| else |
| { |
| Vec_PtrFillTwo( vFanins, 2, pOutputNew, pObjNew ); |
| pOutputNew = Abc_NtkCreateNodeAnd( pNtkNew, vFanins ); |
| } |
| } |
| Vec_PtrFree( vFanins ); |
| // create the only POs, which is the AND of the corresponding nodes |
| Abc_ObjAddFanin( Abc_NtkPo(pNtkNew, 0), pOutputNew ); |
| |
| // check that the CI/CO/latches are copied correctly |
| assert( Abc_NtkPoNum(pNtkNew) == 1 ); |
| assert( Abc_NtkCiNum(pNtkNew) == Abc_NtkCiNum(pNtk) ); |
| assert( Abc_NtkLatchNum(pNtkNew) == Abc_NtkLatchNum(pNtk) ); |
| return pNtkNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Derives the AIG representing a property.] |
| |
| Description [Given is a sequential logic network (Abc_Ntk_t) and |
| an array of nodes (vector of object IDs) and their values (vector of 0s or 1s). |
| This procedure creates a sequential AIG (Abc_Ntk_t), which can be given to a |
| sequential model checker (in particular "pdr") to prove that the given |
| combination of values never appears at the intenal nodes of the network, |
| or produce a counter-example showing that it can appear.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkCreatePropertyMonitor( Abc_Ntk_t * p, Vec_Int_t * vNodeIds, Vec_Int_t * vNodeValues ) |
| { |
| Abc_Ntk_t * pMonitor, * pStrashed, * pResult; |
| // sequential cleanup parameters |
| int fLatchConst = 1; |
| int fLatchEqual = 1; |
| int fSaveNames = 1; |
| int fUseMvSweep = 0; |
| int nFramesSymb = 1; |
| int nFramesSatur = 512; |
| int fVerbose = 0; |
| int fVeryVerbose = 0; |
| // expecting sequential logic network |
| assert( Abc_NtkIsLogic(p) ); |
| assert( Abc_NtkLatchNum(p) > 0 ); |
| assert( Vec_IntSize(vNodeIds) > 0 ); |
| assert( Vec_IntSize(vNodeIds) == Vec_IntSize(vNodeValues) ); |
| // derive ABC network whose only output is 1 iff the given nodes have the given values |
| pMonitor = Abc_NtkDeriveWithOnePo( p, vNodeIds, vNodeValues ); |
| // perform structural hashing |
| pStrashed = Abc_NtkStrash( pMonitor, 0, 1, 0 ); |
| Abc_NtkDelete( pMonitor ); |
| // it is a good idea to run sequential cleanup before giving the network to PDR |
| pResult = Abc_NtkDarLatchSweep( pStrashed, fLatchConst, fLatchEqual, fSaveNames, fUseMvSweep, nFramesSymb, nFramesSatur, fVerbose, fVeryVerbose ); |
| Abc_NtkDelete( pStrashed ); |
| return pResult; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Testbench.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Abc_Ntk_t * Abc_NtkCreatePropertyMonitorTest( Abc_Ntk_t * p ) |
| { |
| Abc_Ntk_t * pNtk; |
| Vec_Int_t * vNodeIds = Vec_IntAlloc( 100 ); |
| Vec_Int_t * vNodeValues = Vec_IntAlloc( 100 ); |
| |
| // this test will only work for the network, which has nodes with internal IDs such as these |
| Vec_IntPush( vNodeIds, 90 ); |
| Vec_IntPush( vNodeIds, 80 ); |
| Vec_IntPush( vNodeIds, 100 ); |
| |
| Vec_IntPush( vNodeValues, 1 ); |
| Vec_IntPush( vNodeValues, 0 ); |
| Vec_IntPush( vNodeValues, 1 ); |
| |
| pNtk = Abc_NtkCreatePropertyMonitor( p, vNodeIds, vNodeValues ); |
| |
| Vec_IntFree( vNodeIds ); |
| Vec_IntFree( vNodeValues ); |
| |
| return pNtk; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_GateToType( Abc_Obj_t * pObj ) |
| { |
| char * pGateName = Mio_GateReadName((Mio_Gate_t *)pObj->pData); |
| if ( !strncmp(pGateName, "buf", 3) ) return ABC_OPER_BIT_BUF; |
| if ( !strncmp(pGateName, "inv", 3) ) return ABC_OPER_BIT_INV; |
| if ( !strncmp(pGateName, "and", 3) ) return ABC_OPER_BIT_AND; |
| if ( !strncmp(pGateName, "nand", 4) ) return ABC_OPER_BIT_NAND; |
| if ( !strncmp(pGateName, "or", 2) ) return ABC_OPER_BIT_OR; |
| if ( !strncmp(pGateName, "nor", 3) ) return ABC_OPER_BIT_NOR; |
| if ( !strncmp(pGateName, "xor", 3) ) return ABC_OPER_BIT_XOR; |
| if ( !strncmp(pGateName, "xnor", 4) ) return ABC_OPER_BIT_NXOR; |
| if ( !strncmp(pGateName, "zero", 4) ) return ABC_OPER_CONST_F; |
| if ( !strncmp(pGateName, "one", 3) ) return ABC_OPER_CONST_T; |
| assert( 0 ); |
| return -1; |
| } |
| Vec_Wec_t * Abc_SopSynthesize( Vec_Ptr_t * vSops ) |
| { |
| Vec_Wec_t * vRes = NULL; |
| Abc_Ntk_t * pNtk = Abc_NtkCreateFromSops( "top", vSops ); |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pFanin; |
| int i, k, iNode = 0; |
| Abc_FrameReplaceCurrentNetwork( Abc_FrameReadGlobalFrame(), pNtk ); |
| Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "fx; strash; balance; dc2; map -a" ); |
| pNtkNew = Abc_FrameReadNtk( Abc_FrameReadGlobalFrame() ); |
| vRes = Vec_WecStart( Abc_NtkPiNum(pNtkNew) + Abc_NtkNodeNum(pNtkNew) + Abc_NtkPoNum(pNtkNew) ); |
| Abc_NtkForEachPi( pNtkNew, pObj, i ) |
| pObj->iTemp = iNode++; |
| Abc_NtkForEachNode( pNtkNew, pObj, i ) |
| { |
| Vec_Int_t * vNode = Vec_WecEntry(vRes, iNode); |
| Vec_IntPush( vNode, Abc_GateToType(pObj) ); |
| Vec_IntPush( vNode, iNode ); |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| Vec_IntPush( vNode, pFanin->iTemp ); |
| pObj->iTemp = iNode++; |
| } |
| Abc_NtkForEachPo( pNtkNew, pObj, i ) |
| Vec_IntPushTwo( Vec_WecEntry(vRes, iNode++), ABC_OPER_BIT_BUF, Abc_ObjFanin0(pObj)->iTemp ); |
| assert( Vec_WecSize(vRes) == iNode ); |
| return vRes; |
| } |
| Vec_Wec_t * Abc_GiaSynthesize( Vec_Ptr_t * vGias ) |
| { |
| Vec_Wec_t * vRes = NULL; |
| Abc_Ntk_t * pNtk = Abc_NtkCreateFromGias( "top", vGias ); |
| Abc_Ntk_t * pNtkNew; |
| Abc_Obj_t * pObj, * pFanin; |
| int i, k, iNode = 0; |
| Abc_FrameReplaceCurrentNetwork( Abc_FrameReadGlobalFrame(), pNtk ); |
| Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "compress2rs; dch; map -a; strash; compress2rs; dch; map -a; strash; compress2rs; dch; map -a" ); |
| pNtkNew = Abc_FrameReadNtk( Abc_FrameReadGlobalFrame() ); |
| vRes = Vec_WecStart( Abc_NtkPiNum(pNtkNew) + Abc_NtkNodeNum(pNtkNew) + Abc_NtkPoNum(pNtkNew) ); |
| Abc_NtkForEachPi( pNtkNew, pObj, i ) |
| pObj->iTemp = iNode++; |
| Abc_NtkForEachNode( pNtkNew, pObj, i ) |
| { |
| Vec_Int_t * vNode = Vec_WecEntry(vRes, iNode); |
| Vec_IntPush( vNode, Abc_GateToType(pObj) ); |
| Vec_IntPush( vNode, iNode ); |
| Abc_ObjForEachFanin( pObj, pFanin, k ) |
| Vec_IntPush( vNode, pFanin->iTemp ); |
| pObj->iTemp = iNode++; |
| } |
| Abc_NtkForEachPo( pNtkNew, pObj, i ) |
| Vec_IntPushTwo( Vec_WecEntry(vRes, iNode++), ABC_OPER_BIT_BUF, Abc_ObjFanin0(pObj)->iTemp ); |
| assert( Vec_WecSize(vRes) == iNode ); |
| return vRes; |
| } |
| Gia_Man_t * Abc_GiaSynthesizeInter( Gia_Man_t * p ) |
| { |
| Abc_Ntk_t * pNtkNew, * pNtk; |
| Vec_Ptr_t * vGias = Vec_PtrAlloc( 1 ); |
| Vec_PtrPush( vGias, p ); |
| pNtk = Abc_NtkCreateFromGias( "top", vGias ); |
| Vec_PtrFree( vGias ); |
| Abc_FrameReplaceCurrentNetwork( Abc_FrameReadGlobalFrame(), pNtk ); |
| Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "balance; collapse; muxes; strash; dc2" ); |
| pNtkNew = Abc_FrameReadNtk( Abc_FrameReadGlobalFrame() ); |
| return Abc_NtkClpGia( pNtkNew ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Abc_NtkClpOneGia_rec( Gia_Man_t * pNew, Abc_Obj_t * pNode ) |
| { |
| int iLit0, iLit1; |
| if ( Abc_NodeIsTravIdCurrent(pNode) || Abc_ObjFaninNum(pNode) == 0 || Abc_ObjIsCi(pNode) ) |
| return pNode->iTemp; |
| assert( Abc_ObjIsNode( pNode ) ); |
| Abc_NodeSetTravIdCurrent( pNode ); |
| iLit0 = Abc_NtkClpOneGia_rec( pNew, Abc_ObjFanin0(pNode) ); |
| iLit1 = Abc_NtkClpOneGia_rec( pNew, Abc_ObjFanin1(pNode) ); |
| iLit0 = Abc_LitNotCond( iLit0, Abc_ObjFaninC0(pNode) ); |
| iLit1 = Abc_LitNotCond( iLit1, Abc_ObjFaninC1(pNode) ); |
| return (pNode->iTemp = Gia_ManHashAnd(pNew, iLit0, iLit1)); |
| } |
| Gia_Man_t * Abc_NtkStrashToGia( Abc_Ntk_t * pNtk ) |
| { |
| int i, iLit; |
| Abc_Obj_t * pNode; |
| Gia_Man_t * pNew, * pTemp; |
| assert( Abc_NtkIsStrash(pNtk) ); |
| Abc_NtkForEachObj( pNtk, pNode, i ) |
| pNode->iTemp = -1; |
| // start new manager |
| pNew = Gia_ManStart( Abc_NtkObjNum(pNtk) ); |
| pNew->pName = Abc_UtilStrsav( pNtk->pName ); |
| pNew->pSpec = Abc_UtilStrsav( pNtk->pSpec ); |
| Gia_ManHashStart( pNew ); |
| // primary inputs |
| Abc_AigConst1(pNtk)->iTemp = 1; |
| Abc_NtkForEachCi( pNtk, pNode, i ) |
| pNode->iTemp = Gia_ManAppendCi(pNew); |
| // create the first cone |
| Abc_NtkIncrementTravId( pNtk ); |
| Abc_NtkForEachCo( pNtk, pNode, i ) |
| { |
| iLit = Abc_NtkClpOneGia_rec( pNew, Abc_ObjFanin0(pNode) ); |
| iLit = Abc_LitNotCond( iLit, Abc_ObjFaninC0(pNode) ); |
| Gia_ManAppendCo( pNew, iLit ); |
| } |
| // perform cleanup |
| pNew = Gia_ManCleanup( pTemp = pNew ); |
| Gia_ManStop( pTemp ); |
| return pNew; |
| } |
| Gia_Man_t * Abc_SopSynthesizeOne( char * pSop, int fClp ) |
| { |
| Abc_Ntk_t * pNtkNew, * pNtk; |
| Vec_Ptr_t * vSops; |
| if ( strlen(pSop) == 3 ) |
| { |
| Gia_Man_t * pNew = Gia_ManStart( 1 ); |
| pNew->pName = Abc_UtilStrsav( "top" ); |
| //Gia_ManAppendCi( pNew ); |
| assert( pSop[1] == '0' || pSop[1] == '1' ); |
| Gia_ManAppendCo( pNew, pSop[1] == '1' ); |
| return pNew; |
| } |
| vSops = Vec_PtrAlloc( 1 ); |
| Vec_PtrPush( vSops, pSop ); |
| pNtk = Abc_NtkCreateFromSops( "top", vSops ); |
| Vec_PtrFree( vSops ); |
| Abc_FrameReplaceCurrentNetwork( Abc_FrameReadGlobalFrame(), pNtk ); |
| if ( fClp ) |
| Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "clp; sop" ); |
| Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), "fx; strash; balance; dc2" ); |
| pNtkNew = Abc_FrameReadNtk( Abc_FrameReadGlobalFrame() ); |
| return Abc_NtkStrashToGia( pNtkNew ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |