mirror of
https://github.com/YosysHQ/abc.git
synced 2026-09-08 03:46:07 +02:00
403 lines
13 KiB
C
403 lines
13 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [retLvalue.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Retiming package.]
|
|
|
|
Synopsis [Implementation of Pan's retiming algorithm.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - Oct 31, 2006.]
|
|
|
|
Revision [$Id: retLvalue.c,v 1.00 2006/10/31 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "retInt.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// node status after updating its arrival time
|
|
enum { ABC_RET_UPDATE_FAIL, ABC_RET_UPDATE_NO, ABC_RET_UPDATE_YES };
|
|
|
|
// the internal procedures
|
|
static Vec_Int_t * Abc_NtkRetimeGetLags( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose );
|
|
static int Abc_NtkRetimeSearch_rec( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int FiMin, int FiMax, int nMaxIters, int fVerbose );
|
|
static int Abc_NtkRetimeForPeriod( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi, int nMaxIters, int fVerbose );
|
|
static int Abc_NtkRetimeUpdateLValue( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi );
|
|
static int Abc_NtkRetimePosOverLimit( Abc_Ntk_t * pNtk, int Fi );
|
|
static Vec_Ptr_t * Abc_ManCollectLatches( Abc_Ntk_t * pNtk );
|
|
static int Abc_NtkRetimeUsingLags( Abc_Ntk_t * pNtk, Vec_Int_t * vLags, int fVerbose );
|
|
|
|
static inline int Abc_NodeComputeLag( int LValue, int Fi ) { return (LValue + (1<<16)*Fi)/Fi - (1<<16) - (int)(LValue % Fi == 0); }
|
|
static inline int Abc_NodeGetLValue( Abc_Obj_t * pNode ) { return (int)(ABC_PTRUINT_T)pNode->pCopy; }
|
|
static inline void Abc_NodeSetLValue( Abc_Obj_t * pNode, int Value ) { pNode->pCopy = (Abc_Obj_t *)(ABC_PTRUINT_T)Value; }
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Implements Pan's retiming algorithm.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimeLValue( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose )
|
|
{
|
|
Vec_Int_t * vLags;
|
|
int nLatches = Abc_NtkLatchNum(pNtk);
|
|
assert( Abc_NtkIsLogic( pNtk ) );
|
|
// get the lags
|
|
vLags = Abc_NtkRetimeGetLags( pNtk, nIterLimit, fVerbose );
|
|
// compute the retiming
|
|
// Abc_NtkRetimeUsingLags( pNtk, vLags, fVerbose );
|
|
Vec_IntFree( vLags );
|
|
// fix the COs
|
|
// Abc_NtkLogicMakeSimpleCos( pNtk, 0 );
|
|
// check for correctness
|
|
if ( !Abc_NtkCheck( pNtk ) )
|
|
fprintf( stdout, "Abc_NtkRetimeLValue(): Network check has failed.\n" );
|
|
// return the number of latches saved
|
|
return nLatches - Abc_NtkLatchNum(pNtk);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes the retiming lags.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Int_t * Abc_NtkRetimeGetLags( Abc_Ntk_t * pNtk, int nIterLimit, int fVerbose )
|
|
{
|
|
Vec_Int_t * vLags;
|
|
Vec_Ptr_t * vNodes, * vLatches;
|
|
Abc_Obj_t * pNode;
|
|
int i, FiMax, FiBest, RetValue;
|
|
clock_t clk, clkIter;
|
|
char NodeLag;
|
|
|
|
// get the upper bound on the clock period
|
|
FiMax = Abc_NtkLevel(pNtk);
|
|
|
|
// make sure this clock period is feasible
|
|
vNodes = Abc_NtkDfs( pNtk, 0 );
|
|
vLatches = Abc_ManCollectLatches( pNtk );
|
|
if ( !Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, FiMax, nIterLimit, fVerbose ) )
|
|
{
|
|
Vec_PtrFree( vLatches );
|
|
Vec_PtrFree( vNodes );
|
|
printf( "Abc_NtkRetimeGetLags() error: The upper bound on the clock period cannot be computed.\n" );
|
|
return Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 );
|
|
}
|
|
|
|
// search for the optimal clock period between 0 and nLevelMax
|
|
clk = clock();
|
|
FiBest = Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, 0, FiMax, nIterLimit, fVerbose );
|
|
clkIter = clock() - clk;
|
|
|
|
// recompute the best l-values
|
|
RetValue = Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, FiBest, nIterLimit, fVerbose );
|
|
assert( RetValue );
|
|
|
|
// fix the problem with non-converged delays
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
if ( Abc_NodeGetLValue(pNode) < -ABC_INFINITY/2 )
|
|
Abc_NodeSetLValue( pNode, 0 );
|
|
|
|
// write the retiming lags
|
|
vLags = Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 );
|
|
Abc_NtkForEachNode( pNtk, pNode, i )
|
|
{
|
|
NodeLag = Abc_NodeComputeLag( Abc_NodeGetLValue(pNode), FiBest );
|
|
Vec_IntWriteEntry( vLags, pNode->Id, NodeLag );
|
|
}
|
|
/*
|
|
Abc_NtkForEachPo( pNtk, pNode, i )
|
|
printf( "%d ", Abc_NodeGetLValue(Abc_ObjFanin0(pNode)) );
|
|
printf( "\n" );
|
|
Abc_NtkForEachLatch( pNtk, pNode, i )
|
|
printf( "%d/%d ", Abc_NodeGetLValue(Abc_ObjFanout0(pNode)), Abc_NodeGetLValue(Abc_ObjFanout0(pNode)) + FiBest );
|
|
printf( "\n" );
|
|
*/
|
|
|
|
// print the result
|
|
// if ( fVerbose )
|
|
printf( "The best clock period is %3d. (Currently, network is not modified.)\n", FiBest );
|
|
/*
|
|
{
|
|
FILE * pTable;
|
|
pTable = fopen( "iscas/seqmap__stats2.txt", "a+" );
|
|
fprintf( pTable, "%d ", FiBest );
|
|
fprintf( pTable, "\n" );
|
|
fclose( pTable );
|
|
}
|
|
*/
|
|
Vec_PtrFree( vNodes );
|
|
Vec_PtrFree( vLatches );
|
|
return vLags;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs binary search for the optimal clock period.]
|
|
|
|
Description [Assumes that FiMin is infeasible while FiMax is feasible.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimeSearch_rec( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int FiMin, int FiMax, int nMaxIters, int fVerbose )
|
|
{
|
|
int Median;
|
|
assert( FiMin < FiMax );
|
|
if ( FiMin + 1 == FiMax )
|
|
return FiMax;
|
|
Median = FiMin + (FiMax - FiMin)/2;
|
|
if ( Abc_NtkRetimeForPeriod( pNtk, vNodes, vLatches, Median, nMaxIters, fVerbose ) )
|
|
return Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, FiMin, Median, nMaxIters, fVerbose ); // Median is feasible
|
|
else
|
|
return Abc_NtkRetimeSearch_rec( pNtk, vNodes, vLatches, Median, FiMax, nMaxIters, fVerbose ); // Median is infeasible
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns 1 if retiming with this clock period is feasible.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimeForPeriod( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi, int nMaxIters, int fVerbose )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int c, i, fConverged;
|
|
// set l-values of all nodes to be minus infinity, except PIs and constants
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
if ( Abc_ObjFaninNum(pObj) == 0 )
|
|
Abc_NodeSetLValue( pObj, 0 );
|
|
else
|
|
Abc_NodeSetLValue( pObj, -ABC_INFINITY );
|
|
// update all values iteratively
|
|
fConverged = 0;
|
|
for ( c = 1; c <= nMaxIters; c++ )
|
|
{
|
|
if ( !Abc_NtkRetimeUpdateLValue( pNtk, vNodes, vLatches, Fi ) )
|
|
{
|
|
fConverged = 1;
|
|
break;
|
|
}
|
|
if ( Abc_NtkRetimePosOverLimit(pNtk, Fi) )
|
|
break;
|
|
}
|
|
// report the results
|
|
if ( fVerbose )
|
|
{
|
|
if ( !fConverged )
|
|
printf( "Period = %3d. Iterations = %3d. Infeasible %s\n", Fi, c, (c > nMaxIters)? "(timeout)" : "" );
|
|
else
|
|
printf( "Period = %3d. Iterations = %3d. Feasible\n", Fi, c );
|
|
}
|
|
/*
|
|
// check if any AND gates have infinite delay
|
|
Counter = 0;
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
Counter += (Abc_NodeGetLValue(pObj) < -ABC_INFINITY/2);
|
|
if ( Counter > 0 )
|
|
printf( "Warning: %d internal nodes have wrong l-values!\n", Counter );
|
|
*/
|
|
return fConverged;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs one iteration of l-value computation for the nodes.]
|
|
|
|
Description [Experimentally it was found that checking POs changes
|
|
is not enough to detect the convergence of l-values in the network.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimeUpdateLValue( Abc_Ntk_t * pNtk, Vec_Ptr_t * vNodes, Vec_Ptr_t * vLatches, int Fi )
|
|
{
|
|
Abc_Obj_t * pObj, * pFanin;
|
|
int i, k, lValueNew, fChange;
|
|
// go through the nodes and detect change
|
|
fChange = 0;
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
|
|
{
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
lValueNew = -ABC_INFINITY;
|
|
Abc_ObjForEachFanin( pObj, pFanin, k )
|
|
{
|
|
if ( lValueNew < Abc_NodeGetLValue(pFanin) )
|
|
lValueNew = Abc_NodeGetLValue(pFanin);
|
|
}
|
|
lValueNew++;
|
|
if ( Abc_NodeGetLValue(pObj) < lValueNew )
|
|
{
|
|
Abc_NodeSetLValue( pObj, lValueNew );
|
|
fChange = 1;
|
|
}
|
|
}
|
|
// propagate values through the latches
|
|
Vec_PtrForEachEntry( Abc_Obj_t *, vLatches, pObj, i )
|
|
Abc_NodeSetLValue( Abc_ObjFanout0(pObj), Abc_NodeGetLValue(Abc_ObjFanin0(Abc_ObjFanin0(pObj))) - Fi );
|
|
return fChange;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Detects the case when l-values exceeded the limit.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimePosOverLimit( Abc_Ntk_t * pNtk, int Fi )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
if ( Abc_NodeGetLValue(Abc_ObjFanin0(pObj)) > Fi )
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects latches in the topological order.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_ManCollectLatches_rec( Abc_Obj_t * pObj, Vec_Ptr_t * vLatches )
|
|
{
|
|
Abc_Obj_t * pDriver;
|
|
if ( !Abc_ObjIsLatch(pObj) )
|
|
return;
|
|
// skip already collected latches
|
|
if ( Abc_NodeIsTravIdCurrent(pObj) )
|
|
return;
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
// get the driver node feeding into the latch
|
|
pDriver = Abc_ObjFanin0(Abc_ObjFanin0(pObj));
|
|
// call recursively if the driver looks like a latch output
|
|
if ( Abc_ObjIsBo(pDriver) )
|
|
Abc_ManCollectLatches_rec( Abc_ObjFanin0(pDriver), vLatches );
|
|
// collect the latch
|
|
Vec_PtrPush( vLatches, pObj );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects latches in the topological order.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Ptr_t * Abc_ManCollectLatches( Abc_Ntk_t * pNtk )
|
|
{
|
|
Vec_Ptr_t * vLatches;
|
|
Abc_Obj_t * pObj;
|
|
int i;
|
|
vLatches = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
|
|
Abc_NtkIncrementTravId( pNtk );
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_ManCollectLatches_rec( pObj, vLatches );
|
|
assert( Vec_PtrSize(vLatches) == Abc_NtkLatchNum(pNtk) );
|
|
return vLatches;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Implements the retiming given as the array of retiming lags.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Abc_NtkRetimeUsingLags( Abc_Ntk_t * pNtk, Vec_Int_t * vLags, int fVerbose )
|
|
{
|
|
Abc_Obj_t * pObj;
|
|
int fChanges, fForward, nTotalMoves, Lag, Counter, i;
|
|
// iterate over the nodes
|
|
nTotalMoves = 0;
|
|
do {
|
|
fChanges = 0;
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
{
|
|
Lag = Vec_IntEntry( vLags, pObj->Id );
|
|
if ( !Lag )
|
|
continue;
|
|
fForward = (Lag < 0);
|
|
if ( Abc_NtkRetimeNodeIsEnabled( pObj, fForward ) )
|
|
{
|
|
Abc_NtkRetimeNode( pObj, fForward, 0 );
|
|
fChanges = 1;
|
|
nTotalMoves++;
|
|
Vec_IntAddToEntry( vLags, pObj->Id, fForward? 1 : -1 );
|
|
}
|
|
}
|
|
} while ( fChanges );
|
|
if ( fVerbose )
|
|
printf( "Total latch moves = %d.\n", nTotalMoves );
|
|
// check if there are remaining lags
|
|
Counter = 0;
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
Counter += (Vec_IntEntry( vLags, pObj->Id ) != 0);
|
|
if ( Counter )
|
|
printf( "Warning! The number of nodes with unrealized lag = %d.\n", Counter );
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|