abc/src/base/seq/seqRetIter.c

409 lines
13 KiB
C

/**CFile****************************************************************
FileName [seqRetIter.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Construction and manipulation of sequential AIGs.]
Synopsis [Iterative delay computation in FPGA mapping/retiming package.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: seqRetIter.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "seqInt.h"
#include "main.h"
#include "fpga.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static float Seq_NtkMappingSearch_rec( Abc_Ntk_t * pNtk, float FiMin, float FiMax, float Delta, int fVerbose );
static int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose );
static int Seq_NtkNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vDelays );
static void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag );
static void Seq_NodePrintInfo( Abc_Obj_t * pNode );
static void Seq_NodePrintInfoPlus( Abc_Obj_t * pNode );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Computes the retiming lags for arbitrary network.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Seq_NtkRetimeDelayLags( Abc_Ntk_t * pNtkOld, Abc_Ntk_t * pNtk, int fVerbose )
{
Abc_Seq_t * p = pNtk->pManFunc;
Abc_Obj_t * pNode;
float FiMax, Delta;
int i, RetValue;
char NodeLag;
assert( Abc_NtkIsSeq( pNtk ) );
// the root AND gates and node delay should be assigned
assert( p->vMapAnds );
assert( p->vMapCuts );
assert( p->vMapDelays );
assert( p->vMapFanins );
// guess the upper bound on the clock period
if ( Abc_NtkHasMapping(pNtkOld) )
{
// assign the accuracy for min-period computation
Delta = Mio_LibraryReadDelayNand2Max(Abc_FrameReadLibGen());
if ( Delta == 0.0 )
{
Delta = Mio_LibraryReadDelayAnd2Max(Abc_FrameReadLibGen());
if ( Delta == 0.0 )
{
printf( "Cannot retime/map if the library does not have NAND2 or AND2.\n" );
return 0;
}
}
// get the upper bound on the clock period
FiMax = Delta * 2 + Abc_NtkDelayTrace(pNtkOld);
Delta /= 2;
}
else
{
FiMax = (float)2.0 + Abc_NtkGetLevelNum(pNtkOld);
Delta = 1;
}
// make sure this clock period is feasible
if ( !Seq_NtkMappingForPeriod( pNtk, FiMax, fVerbose ) )
{
printf( "Error: The upper bound on the clock period cannot be computed.\n" );
printf( "The reason for this error may be the presence in the circuit of logic\n" );
printf( "that is not reachable from the PIs. Mapping/retiming is not performed.\n" );
return 0;
}
// search for the optimal clock period between 0 and nLevelMax
p->FiBestFloat = Seq_NtkMappingSearch_rec( pNtk, 0.0, FiMax, Delta, fVerbose );
// recompute the best l-values
RetValue = Seq_NtkMappingForPeriod( pNtk, p->FiBestFloat, fVerbose );
assert( RetValue );
// fix the problem with non-converged delays
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pNode, i )
if ( Seq_NodeGetLValueP(pNode) < -ABC_INFINITY/2 )
Seq_NodeSetLValueP( pNode, 0 );
// experiment by adding an epsilon to all LValues
// Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pNode, i )
// Seq_NodeSetLValueP( pNode, Seq_NodeGetLValueP(pNode) - p->fEpsilon );
// save the retiming lags
// mark the nodes
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pNode, i )
pNode->fMarkA = 1;
// process the nodes
Vec_StrFill( p->vLags, p->nSize, 0 );
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pNode, i )
{
if ( Vec_PtrSize( Vec_VecEntry(p->vMapCuts, i) ) == 0 )
{
Seq_NodeSetLag( pNode, 0 );
continue;
}
NodeLag = Seq_NodeComputeLagFloat( Seq_NodeGetLValueP(pNode), p->FiBestFloat );
Seq_NodeRetimeSetLag_rec( pNode, NodeLag );
}
// unmark the nodes
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pNode, i )
pNode->fMarkA = 0;
// print the result
if ( fVerbose )
printf( "The best clock period is %6.2f.\n", p->FiBestFloat );
/*
{
FILE * pTable;
pTable = fopen( "stats.txt", "a+" );
fprintf( pTable, "%s ", pNtk->pName );
fprintf( pTable, "%.2f ", FiBest );
fprintf( pTable, "\n" );
fclose( pTable );
}
*/
// Seq_NodePrintInfo( Abc_NtkObj(pNtk, 847) );
return 1;
}
/**Function*************************************************************
Synopsis [Performs binary search for the optimal clock period.]
Description [Assumes that FiMin is infeasible while FiMax is feasible.]
SideEffects []
SeeAlso []
***********************************************************************/
float Seq_NtkMappingSearch_rec( Abc_Ntk_t * pNtk, float FiMin, float FiMax, float Delta, int fVerbose )
{
float Median;
assert( FiMin < FiMax );
if ( FiMin + Delta >= FiMax )
return FiMax;
Median = FiMin + (FiMax - FiMin)/2;
if ( Seq_NtkMappingForPeriod( pNtk, Median, fVerbose ) )
return Seq_NtkMappingSearch_rec( pNtk, FiMin, Median, Delta, fVerbose ); // Median is feasible
else
return Seq_NtkMappingSearch_rec( pNtk, Median, FiMax, Delta, fVerbose ); // Median is infeasible
}
/**Function*************************************************************
Synopsis [Returns 1 if retiming with this clock period is feasible.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Seq_NtkMappingForPeriod( Abc_Ntk_t * pNtk, float Fi, int fVerbose )
{
Abc_Seq_t * p = pNtk->pManFunc;
Vec_Ptr_t * vLeaves, * vDelays;
Abc_Obj_t * pObj;
int i, c, RetValue, fChange, Counter;
char * pReason = "";
// set l-values of all nodes to be minus infinity
Vec_IntFill( p->vLValues, p->nSize, Abc_Float2Int( (float)-ABC_INFINITY ) );
// set l-values of constants and PIs
pObj = Abc_NtkObj( pNtk, 0 );
Seq_NodeSetLValueP( pObj, 0.0 );
Abc_NtkForEachPi( pNtk, pObj, i )
Seq_NodeSetLValueP( pObj, 0.0 );
// update all values iteratively
Counter = 0;
for ( c = 0; c < p->nMaxIters; c++ )
{
fChange = 0;
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pObj, i )
{
Counter++;
vLeaves = Vec_VecEntry( p->vMapCuts, i );
vDelays = Vec_VecEntry( p->vMapDelays, i );
if ( Vec_PtrSize(vLeaves) == 0 )
{
Seq_NodeSetLValueP( pObj, 0.0 );
continue;
}
RetValue = Seq_NtkNodeUpdateLValue( pObj, Fi, vLeaves, vDelays );
if ( RetValue == SEQ_UPDATE_YES )
fChange = 1;
}
Abc_NtkForEachPo( pNtk, pObj, i )
{
RetValue = Seq_NtkNodeUpdateLValue( pObj, Fi, NULL, NULL );
if ( RetValue == SEQ_UPDATE_FAIL )
break;
}
if ( RetValue == SEQ_UPDATE_FAIL )
break;
if ( fChange == 0 )
break;
}
if ( c == p->nMaxIters )
{
RetValue = SEQ_UPDATE_FAIL;
pReason = "(timeout)";
}
else
c++;
// report the results
if ( fVerbose )
{
if ( RetValue == SEQ_UPDATE_FAIL )
printf( "Period = %6.2f. Iterations = %3d. Updates = %10d. Infeasible %s\n", Fi, c, Counter, pReason );
else
printf( "Period = %6.2f. Iterations = %3d. Updates = %10d. Feasible\n", Fi, c, Counter );
}
return RetValue != SEQ_UPDATE_FAIL;
}
/**Function*************************************************************
Synopsis [Computes the l-value of the node.]
Description [The node can be internal or a PO.]
SideEffects []
SeeAlso []
***********************************************************************/
int Seq_NtkNodeUpdateLValue( Abc_Obj_t * pObj, float Fi, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vDelays )
{
Abc_Seq_t * p = pObj->pNtk->pManFunc;
float lValueOld, lValueNew, lValueCur, lValuePin;
unsigned SeqEdge;
Abc_Obj_t * pLeaf;
int i;
assert( !Abc_ObjIsPi(pObj) );
assert( Abc_ObjFaninNum(pObj) > 0 );
// consider the case of the PO
if ( Abc_ObjIsPo(pObj) )
{
lValueCur = Seq_NodeGetLValueP(Abc_ObjFanin0(pObj)) - Fi * Seq_ObjFaninL0(pObj);
return (lValueCur > Fi + p->fEpsilon)? SEQ_UPDATE_FAIL : SEQ_UPDATE_NO;
}
// get the new arrival time of the cut output
lValueNew = -ABC_INFINITY;
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pLeaf, i )
{
SeqEdge = (unsigned)pLeaf;
pLeaf = Abc_NtkObj( pObj->pNtk, SeqEdge >> 8 );
lValueCur = Seq_NodeGetLValueP(pLeaf) - Fi * (SeqEdge & 255);
lValuePin = Abc_Int2Float( (int)Vec_PtrEntry(vDelays, i) );
if ( lValueNew < lValuePin + lValueCur )
lValueNew = lValuePin + lValueCur;
}
// compare
lValueOld = Seq_NodeGetLValueP( pObj );
if ( lValueNew <= lValueOld + p->fEpsilon )
return SEQ_UPDATE_NO;
// update the values
if ( lValueNew > lValueOld + p->fEpsilon )
Seq_NodeSetLValueP( pObj, lValueNew );
return SEQ_UPDATE_YES;
}
/**Function*************************************************************
Synopsis [Add sequential edges.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Seq_NodeRetimeSetLag_rec( Abc_Obj_t * pNode, char Lag )
{
Abc_Obj_t * pFanin;
if ( !Abc_AigNodeIsAnd(pNode) )
return;
Seq_NodeSetLag( pNode, Lag );
// consider the first fanin
pFanin = Abc_ObjFanin0(pNode);
if ( pFanin->fMarkA == 0 ) // internal node
Seq_NodeRetimeSetLag_rec( pFanin, Lag );
// consider the second fanin
pFanin = Abc_ObjFanin1(pNode);
if ( pFanin->fMarkA == 0 ) // internal node
Seq_NodeRetimeSetLag_rec( pFanin, Lag );
}
/**Function*************************************************************
Synopsis [Add sequential edges.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Seq_NodePrintInfo( Abc_Obj_t * pNode )
{
Abc_Seq_t * p = pNode->pNtk->pManFunc;
Abc_Obj_t * pFanin, * pObj, * pLeaf;
Vec_Ptr_t * vLeaves;
unsigned SeqEdge;
int i, Number;
// print the node
printf( " Node = %6d. LValue = %7.2f. Lag = %2d.\n",
pNode->Id, Seq_NodeGetLValueP(pNode), Seq_NodeGetLag(pNode) );
// find the number
Vec_PtrForEachEntry( Abc_Obj_t *, p->vMapAnds, pObj, Number )
if ( pObj == pNode )
break;
// get the leaves
vLeaves = Vec_VecEntry( p->vMapCuts, Number );
// print the leaves
Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pLeaf, i )
{
SeqEdge = (unsigned)pLeaf;
pFanin = Abc_NtkObj( pNode->pNtk, SeqEdge >> 8 );
// print the leaf
printf( " Fanin%d(%d) = %6d. LValue = %7.2f. Lag = %2d.\n", i, SeqEdge & 255,
pFanin->Id, Seq_NodeGetLValueP(pFanin), Seq_NodeGetLag(pFanin) );
}
}
/**Function*************************************************************
Synopsis [Add sequential edges.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Seq_NodePrintInfoPlus( Abc_Obj_t * pNode )
{
Abc_Obj_t * pFanout;
int i;
printf( "CENTRAL NODE:\n" );
Seq_NodePrintInfo( pNode );
Abc_ObjForEachFanout( pNode, pFanout, i )
{
printf( "FANOUT%d:\n", i );
Seq_NodePrintInfo( pFanout );
}
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END