mirror of https://github.com/YosysHQ/abc.git
Adding check for comb loops in NDR.
This commit is contained in:
parent
d14acd8e2e
commit
d7dfd06ca1
|
|
@ -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 );
|
||||||
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 )
|
||||||
//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 )
|
||||||
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 )
|
||||||
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 );
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue