Commit d7dfd06c by Alan Mishchenko

Adding check for comb loops in NDR.

parent d14acd8e
...@@ -163,6 +163,7 @@ static inline void Wln_ObjSetFanout( Wln_Ntk_t * p, int i, int f, int v ...@@ -163,6 +163,7 @@ static inline void Wln_ObjSetFanout( Wln_Ntk_t * p, int i, int f, int v
static inline void Wln_NtkIncrementTravId( Wln_Ntk_t * p ) { if (!p->nTravIds++) Vec_IntFill(&p->vTravIds, Vec_IntCap(&p->vTypes), 0); } static inline void Wln_NtkIncrementTravId( Wln_Ntk_t * p ) { if (!p->nTravIds++) Vec_IntFill(&p->vTravIds, Vec_IntCap(&p->vTypes), 0); }
static inline void Wln_ObjSetTravIdCurrent( Wln_Ntk_t * p, int i ) { Vec_IntWriteEntry( &p->vTravIds, i, p->nTravIds ); } static inline void Wln_ObjSetTravIdCurrent( Wln_Ntk_t * p, int i ) { Vec_IntWriteEntry( &p->vTravIds, i, p->nTravIds ); }
static inline void Wln_ObjSetTravIdPrevious( Wln_Ntk_t * p, int i ) { Vec_IntWriteEntry( &p->vTravIds, i, p->nTravIds-1 ); }
static inline int Wln_ObjIsTravIdCurrent( Wln_Ntk_t * p, int i ) { return (Vec_IntEntry(&p->vTravIds, i) == p->nTravIds); } static inline int Wln_ObjIsTravIdCurrent( Wln_Ntk_t * p, int i ) { return (Vec_IntEntry(&p->vTravIds, i) == p->nTravIds); }
static inline int Wln_ObjIsTravIdPrevious( Wln_Ntk_t * p, int i ) { return (Vec_IntEntry(&p->vTravIds, i) == p->nTravIds-1); } static inline int Wln_ObjIsTravIdPrevious( Wln_Ntk_t * p, int i ) { return (Vec_IntEntry(&p->vTravIds, i) == p->nTravIds-1); }
static inline int Wln_ObjCheckTravId( Wln_Ntk_t * p, int i ) { if ( Wln_ObjIsTravIdCurrent(p, i) ) return 1; Wln_ObjSetTravIdCurrent(p, i); return 0; } static inline int Wln_ObjCheckTravId( Wln_Ntk_t * p, int i ) { if ( Wln_ObjIsTravIdCurrent(p, i) ) return 1; Wln_ObjSetTravIdCurrent(p, i); return 0; }
...@@ -225,6 +226,7 @@ extern void Wln_NtkFree( Wln_Ntk_t * p ); ...@@ -225,6 +226,7 @@ extern void Wln_NtkFree( Wln_Ntk_t * p );
extern int Wln_NtkMemUsage( Wln_Ntk_t * p ); extern int Wln_NtkMemUsage( Wln_Ntk_t * p );
extern void Wln_NtkPrint( Wln_Ntk_t * p ); extern void Wln_NtkPrint( Wln_Ntk_t * p );
extern Wln_Ntk_t * Wln_NtkDupDfs( Wln_Ntk_t * p ); extern Wln_Ntk_t * Wln_NtkDupDfs( Wln_Ntk_t * p );
extern int Wln_NtkIsAcyclic( Wln_Ntk_t * p );
extern void Wln_NtkCreateRefs( Wln_Ntk_t * p ); extern void Wln_NtkCreateRefs( Wln_Ntk_t * p );
extern void Wln_NtkStartFaninMap( Wln_Ntk_t * p, Vec_Int_t * vFaninMap, int nMulti ); extern void Wln_NtkStartFaninMap( Wln_Ntk_t * p, Vec_Int_t * vFaninMap, int nMulti );
extern void Wln_NtkStartFanoutMap( Wln_Ntk_t * p, Vec_Int_t * vFanoutMap, Vec_Int_t * vFanoutNums, int nMulti ); extern void Wln_NtkStartFanoutMap( Wln_Ntk_t * p, Vec_Int_t * vFanoutMap, Vec_Int_t * vFanoutNums, int nMulti );
......
...@@ -270,6 +270,11 @@ Wln_Ntk_t * Wln_NtkFromNdr( void * pData ) ...@@ -270,6 +270,11 @@ Wln_Ntk_t * Wln_NtkFromNdr( void * pData )
//Ndr_NtkPrintObjects( pNtk ); //Ndr_NtkPrintObjects( pNtk );
Wln_WriteVer( pNtk, "temp_ndr.v" ); Wln_WriteVer( pNtk, "temp_ndr.v" );
printf( "Dumped design \"%s\" into file \"temp_ndr.v\".\n", pNtk->pName ); printf( "Dumped design \"%s\" into file \"temp_ndr.v\".\n", pNtk->pName );
if ( !Wln_NtkIsAcyclic(pNtk) )
{
Wln_NtkFree(pNtk);
return NULL;
}
// derive topological order // derive topological order
pNtk = Wln_NtkDupDfs( pTemp = pNtk ); pNtk = Wln_NtkDupDfs( pTemp = pNtk );
Wln_NtkFree( pTemp ); Wln_NtkFree( pTemp );
......
...@@ -129,6 +129,139 @@ void Wln_NtkPrint( Wln_Ntk_t * p ) ...@@ -129,6 +129,139 @@ void Wln_NtkPrint( Wln_Ntk_t * p )
printf( "\n" ); printf( "\n" );
} }
/**Function*************************************************************
Synopsis [Detects combinational loops.]
Description [This procedure is based on the idea suggested by Donald Chai.
As we traverse the network and visit the nodes, we need to distinquish
three types of nodes: (1) those that are visited for the first time,
(2) those that have been visited in this traversal but are currently not
on the traversal path, (3) those that have been visited and are currently
on the travesal path. When the node of type (3) is encountered, it means
that there is a combinational loop. To mark the three types of nodes,
two new values of the traversal IDs are used.]
SideEffects []
SeeAlso []
***********************************************************************/
int Wln_NtkIsAcyclic_rec( Wln_Ntk_t * p, int iObj )
{
int i, iFanin;
//printf( "Visiting node %d\n", iObj );
if ( 43309 == iObj )
{
int s = 0;
}
// skip the node if it is already visited
if ( Wln_ObjIsTravIdPrevious(p, iObj) )
return 1;
// check if the node is part of the combinational loop
if ( Wln_ObjIsTravIdCurrent(p, iObj) )
{
fprintf( stdout, "Network contains combinational loop!\n" );
fprintf( stdout, "Node %16s is encountered twice on the following path:\n", Wln_ObjName(p, iObj) );
fprintf( stdout, "Node %16s (ID %6d) of type %5s (type ID %2d) ->\n",
Wln_ObjName(p, iObj), iObj, Abc_OperName(Wln_ObjType(p, iObj)), Wln_ObjType(p, iObj) );
return 0;
}
// mark this node as a node on the current path
Wln_ObjSetTravIdCurrent( p, iObj );
// quit if it is a CI or constant node
if ( Wln_ObjIsCi(p, iObj) || Wln_ObjIsFf(p, iObj) || Wln_ObjFaninNum(p, iObj) == 0 )
{
// mark this node as a visited node
Wln_ObjSetTravIdPrevious( p, iObj );
return 1;
}
// traverse the fanin's cone searching for the loop
Wln_ObjForEachFanin( p, iObj, iFanin, i )
{
if ( !Wln_NtkIsAcyclic_rec(p, iFanin) )
{
// return as soon as the loop is detected
fprintf( stdout, "Node %16s (ID %6d) of type %5s (type ID %2d) ->\n",
Wln_ObjName(p, iObj), iObj, Abc_OperName(Wln_ObjType(p, iObj)), Wln_ObjType(p, iObj) );
return 0;
}
}
// mark this node as a visited node
Wln_ObjSetTravIdPrevious( p, iObj );
return 1;
}
int Wln_NtkIsAcyclic( Wln_Ntk_t * p )
{
int fAcyclic, i, iObj, nUnvisited = 0 ;
// set the traversal ID for this DFS ordering
Wln_NtkIncrementTravId( p );
Wln_NtkIncrementTravId( p );
// iObj->TravId == pNet->nTravIds means "iObj is on the path"
// iObj->TravId == pNet->nTravIds - 1 means "iObj is visited but is not on the path"
// iObj->TravId < pNet->nTravIds - 1 means "iObj is not visited"
// traverse the network to detect cycles
fAcyclic = 1;
Wln_NtkForEachCo( p, iObj, i )
{
// traverse the output logic cone
if ( (fAcyclic = Wln_NtkIsAcyclic_rec(p, iObj)) )
continue;
// stop as soon as the first loop is detected
fprintf( stdout, "Primary output %16s (ID %6d)\n", Wln_ObjName(p, iObj), iObj );
break;
}
Wln_NtkForEachFf( p, iObj, i )
{
// traverse the output logic cone
if ( (fAcyclic = Wln_NtkIsAcyclic_rec(p, iObj)) )
continue;
// stop as soon as the first loop is detected
fprintf( stdout, "Flip-flop %16s (ID %6d)\n", Wln_ObjName(p, iObj), iObj );
break;
}
Wln_NtkForEachObj( p, iObj )
nUnvisited += !Wln_ObjIsTravIdPrevious(p, iObj) && !Wln_ObjIsCi(p, iObj);
if ( nUnvisited )
{
int nSinks = 0;
Wln_NtkCreateRefs(p);
printf( "The network has %d objects and %d (%6.2f %%) of them are not connected to the outputs.\n",
Wln_NtkObjNum(p), nUnvisited, 100.0*nUnvisited/Wln_NtkObjNum(p) );
Wln_NtkForEachObj( p, iObj )
if ( !Wln_ObjRefs(p, iObj) && !Wln_ObjIsCi(p, iObj) && !Wln_ObjIsFf(p, iObj) )
nSinks++;
if ( nSinks )
{
int nPrinted = 0;
printf( "These unconnected objects feed into %d sink objects without fanout:\n", nSinks );
Wln_NtkForEachObj( p, iObj )
if ( !Wln_ObjRefs(p, iObj) && !Wln_ObjIsCi(p, iObj) && !Wln_ObjIsFf(p, iObj) )
{
fprintf( stdout, "Node %16s (ID %6d) of type %5s (type ID %2d)\n",
Wln_ObjName(p, iObj), iObj, Abc_OperName(Wln_ObjType(p, iObj)), Wln_ObjType(p, iObj) );
if ( ++nPrinted == 5 )
break;
}
if ( nPrinted < nSinks )
printf( "...\n" );
}
Wln_NtkForEachObj( p, iObj )
if ( /*!Wln_ObjRefs(p, iObj) &&*/ !Wln_ObjIsTravIdPrevious(p, iObj) && !Wln_ObjIsCi(p, iObj) )
{
// traverse the output logic cone
if ( (fAcyclic = Wln_NtkIsAcyclic_rec(p, iObj)) )
continue;
// stop as soon as the first loop is detected
fprintf( stdout, "Unconnected object %s\n", Wln_ObjName(p, iObj) );
break;
}
}
return fAcyclic;
}
/**Function************************************************************* /**Function*************************************************************
Synopsis [Duplicating network.] Synopsis [Duplicating network.]
...@@ -186,7 +319,7 @@ int Wln_NtkDupDfs_rec( Wln_Ntk_t * pNew, Wln_Ntk_t * p, int iObj ) ...@@ -186,7 +319,7 @@ int Wln_NtkDupDfs_rec( Wln_Ntk_t * pNew, Wln_Ntk_t * p, int iObj )
return 0; return 0;
if ( Wln_ObjCopy(p, iObj) ) if ( Wln_ObjCopy(p, iObj) )
return Wln_ObjCopy(p, iObj); return Wln_ObjCopy(p, iObj);
//printf( "Visiting node %d\n", iObj ); //printf( "Visiting node %16s (ID %6d) of type %5s (type ID %2d)\n", Wln_ObjName(p, iObj), iObj, Abc_OperName(Wln_ObjType(p, iObj)), Wln_ObjType(p, iObj) );
assert( !Wln_ObjIsFf(p, iObj) ); assert( !Wln_ObjIsFf(p, iObj) );
Wln_ObjForEachFanin( p, iObj, iFanin, i ) Wln_ObjForEachFanin( p, iObj, iFanin, i )
Wln_NtkDupDfs_rec( pNew, p, iFanin ); Wln_NtkDupDfs_rec( pNew, p, iFanin );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment