mirror of https://github.com/YosysHQ/abc.git
1384 lines
37 KiB
C
1384 lines
37 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [fretMain.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Flow-based retiming package.]
|
|
|
|
Synopsis [Main file for retiming package.]
|
|
|
|
Author [Aaron Hurst]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - January 1, 2008.]
|
|
|
|
Revision [$Id: fretMain.c,v 1.00 2008/01/01 00:00:00 ahurst Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "fretime.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static void Abc_FlowRetime_AddDummyFanin( Abc_Obj_t * pObj );
|
|
|
|
static Abc_Ntk_t* Abc_FlowRetime_MainLoop( );
|
|
|
|
static void Abc_FlowRetime_MarkBlocks( Abc_Ntk_t * pNtk );
|
|
static void Abc_FlowRetime_MarkReachable_rec( Abc_Obj_t * pObj, char end );
|
|
static int Abc_FlowRetime_ImplementCut( Abc_Ntk_t * pNtk );
|
|
static void Abc_FlowRetime_RemoveLatchBubbles( Abc_Obj_t * pLatch );
|
|
|
|
static Abc_Ntk_t* Abc_FlowRetime_NtkDup( Abc_Ntk_t * pNtk );
|
|
|
|
static void Abc_FlowRetime_VerifyPathLatencies( Abc_Ntk_t * pNtk );
|
|
static int Abc_FlowRetime_VerifyPathLatencies_rec( Abc_Obj_t * pObj, int markD );
|
|
|
|
static void Abc_FlowRetime_UpdateLags_forw_rec( Abc_Obj_t *pObj );
|
|
static void Abc_FlowRetime_UpdateLags_back_rec( Abc_Obj_t *pObj );
|
|
|
|
extern void Abc_NtkMarkCone_rec( Abc_Obj_t * pObj, int fForward );
|
|
|
|
void
|
|
print_node3(Abc_Obj_t *pObj);
|
|
|
|
MinRegMan_t *pManMR;
|
|
|
|
int fPathError = 0;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs minimum-register retiming.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t *
|
|
Abc_FlowRetime_MinReg( Abc_Ntk_t * pNtk, int fVerbose,
|
|
int fComputeInitState, int fGuaranteeInitState, int fBlockConst,
|
|
int fForwardOnly, int fBackwardOnly, int nMaxIters,
|
|
int maxDelay, int fFastButConservative ) {
|
|
|
|
int i;
|
|
Abc_Obj_t *pObj, *pNext;
|
|
InitConstraint_t *pData;
|
|
|
|
// create manager
|
|
pManMR = ABC_ALLOC( MinRegMan_t, 1 );
|
|
|
|
pManMR->pNtk = pNtk;
|
|
pManMR->fVerbose = fVerbose;
|
|
pManMR->fComputeInitState = fComputeInitState;
|
|
pManMR->fGuaranteeInitState = fGuaranteeInitState;
|
|
pManMR->fBlockConst = fBlockConst;
|
|
pManMR->fForwardOnly = fForwardOnly;
|
|
pManMR->fBackwardOnly = fBackwardOnly;
|
|
pManMR->nMaxIters = nMaxIters;
|
|
pManMR->maxDelay = maxDelay;
|
|
pManMR->fComputeInitState = fComputeInitState;
|
|
pManMR->fConservTimingOnly = fFastButConservative;
|
|
pManMR->vNodes = Vec_PtrAlloc(100);
|
|
pManMR->vInitConstraints = Vec_PtrAlloc(2);
|
|
pManMR->pInitNtk = NULL;
|
|
pManMR->pInitToOrig = NULL;
|
|
pManMR->sizeInitToOrig = 0;
|
|
|
|
vprintf("Flow-based minimum-register retiming...\n");
|
|
|
|
if (!Abc_NtkHasOnlyLatchBoxes(pNtk)) {
|
|
printf("\tERROR: Can not retime with black/white boxes\n");
|
|
return pNtk;
|
|
}
|
|
|
|
if (maxDelay) {
|
|
vprintf("\tmax delay constraint = %d\n", maxDelay);
|
|
if (maxDelay < (i = Abc_NtkLevel(pNtk))) {
|
|
printf("ERROR: max delay constraint (%d) must be > current max delay (%d)\n", maxDelay, i);
|
|
return pNtk;
|
|
}
|
|
}
|
|
|
|
// print info about type of network
|
|
vprintf("\tnetlist type = ");
|
|
if (Abc_NtkIsNetlist( pNtk )) { vprintf("netlist/"); }
|
|
else if (Abc_NtkIsLogic( pNtk )) { vprintf("logic/"); }
|
|
else if (Abc_NtkIsStrash( pNtk )) { vprintf("strash/"); }
|
|
else { vprintf("***unknown***/"); }
|
|
if (Abc_NtkHasSop( pNtk )) { vprintf("sop\n"); }
|
|
else if (Abc_NtkHasBdd( pNtk )) { vprintf("bdd\n"); }
|
|
else if (Abc_NtkHasAig( pNtk )) { vprintf("aig\n"); }
|
|
else if (Abc_NtkHasMapping( pNtk )) { vprintf("mapped\n"); }
|
|
else { vprintf("***unknown***\n"); }
|
|
|
|
vprintf("\tinitial reg count = %d\n", Abc_NtkLatchNum(pNtk));
|
|
vprintf("\tinitial levels = %d\n", Abc_NtkLevel(pNtk));
|
|
|
|
// remove bubbles from latch boxes
|
|
if (pManMR->fVerbose) Abc_FlowRetime_PrintInitStateInfo(pNtk);
|
|
vprintf("\tpushing bubbles out of latch boxes\n");
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
Abc_FlowRetime_RemoveLatchBubbles(pObj);
|
|
if (pManMR->fVerbose) Abc_FlowRetime_PrintInitStateInfo(pNtk);
|
|
|
|
// check for box inputs/outputs
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
assert(Abc_ObjFaninNum(pObj) == 1);
|
|
assert(Abc_ObjFanoutNum(pObj) == 1);
|
|
assert(!Abc_ObjFaninC0(pObj));
|
|
|
|
pNext = Abc_ObjFanin0(pObj);
|
|
assert(Abc_ObjIsBi(pNext));
|
|
assert(Abc_ObjFaninNum(pNext) <= 1);
|
|
if(Abc_ObjFaninNum(pNext) == 0) // every Bi should have a fanin
|
|
Abc_FlowRetime_AddDummyFanin( pNext );
|
|
|
|
pNext = Abc_ObjFanout0(pObj);
|
|
assert(Abc_ObjIsBo(pNext));
|
|
assert(Abc_ObjFaninNum(pNext) == 1);
|
|
assert(!Abc_ObjFaninC0(pNext));
|
|
}
|
|
|
|
pManMR->nLatches = Abc_NtkLatchNum( pNtk );
|
|
pManMR->nNodes = Abc_NtkObjNumMax( pNtk )+1;
|
|
|
|
// build histogram
|
|
pManMR->vSinkDistHist = Vec_IntStart( pManMR->nNodes*2+10 );
|
|
|
|
// initialize timing
|
|
if (maxDelay)
|
|
Abc_FlowRetime_InitTiming( pNtk );
|
|
|
|
// create lag and Flow_Data structure
|
|
pManMR->vLags = Vec_IntStart(pManMR->nNodes);
|
|
memset(pManMR->vLags->pArray, 0, sizeof(int)*pManMR->nNodes);
|
|
|
|
pManMR->pDataArray = ABC_ALLOC( Flow_Data_t, pManMR->nNodes );
|
|
Abc_FlowRetime_ClearFlows( 1 );
|
|
|
|
// main loop!
|
|
pNtk = Abc_FlowRetime_MainLoop();
|
|
|
|
// cleanup node fields
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
// if not computing init state, set all latches to DC
|
|
if (!fComputeInitState && Abc_ObjIsLatch(pObj))
|
|
Abc_LatchSetInitDc(pObj);
|
|
}
|
|
|
|
// deallocate space
|
|
ABC_FREE( pManMR->pDataArray );
|
|
if (pManMR->pInitToOrig) ABC_FREE( pManMR->pInitToOrig );
|
|
if (pManMR->vNodes) Vec_PtrFree(pManMR->vNodes);
|
|
if (pManMR->vLags) Vec_IntFree(pManMR->vLags);
|
|
if (pManMR->vSinkDistHist) Vec_IntFree(pManMR->vSinkDistHist);
|
|
if (pManMR->maxDelay) Abc_FlowRetime_FreeTiming( pNtk );
|
|
while( Vec_PtrSize( pManMR->vInitConstraints )) {
|
|
pData = (InitConstraint_t*)Vec_PtrPop( pManMR->vInitConstraints );
|
|
//assert( pData->pBiasNode );
|
|
//Abc_NtkDeleteObj( pData->pBiasNode );
|
|
ABC_FREE( pData->vNodes.pArray );
|
|
ABC_FREE( pData );
|
|
}
|
|
ABC_FREE( pManMR->vInitConstraints );
|
|
|
|
// restrash if necessary
|
|
if (Abc_NtkIsStrash(pNtk)) {
|
|
Abc_NtkReassignIds( pNtk );
|
|
pNtk = Abc_FlowRetime_NtkSilentRestrash( pNtk, 1 );
|
|
}
|
|
|
|
vprintf("\tfinal reg count = %d\n", Abc_NtkLatchNum(pNtk));
|
|
vprintf("\tfinal levels = %d\n", Abc_NtkLevel(pNtk));
|
|
|
|
#if defined(DEBUG_CHECK)
|
|
Abc_NtkDoCheck( pNtk );
|
|
#endif
|
|
|
|
// free manager
|
|
ABC_FREE( pManMR );
|
|
|
|
return pNtk;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Main loop.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t *
|
|
Abc_FlowRetime_MainLoop( ) {
|
|
Abc_Ntk_t *pNtk = pManMR->pNtk, *pNtkCopy = pNtk;
|
|
Abc_Obj_t *pObj; int i;
|
|
int last, flow = 0, cut;
|
|
|
|
// (i) forward retiming loop
|
|
pManMR->fIsForward = 1;
|
|
pManMR->iteration = 0;
|
|
|
|
if (!pManMR->fBackwardOnly) do {
|
|
if (pManMR->iteration == pManMR->nMaxIters) break;
|
|
pManMR->subIteration = 0;
|
|
|
|
vprintf("\tforward iteration %d\n", pManMR->iteration);
|
|
last = Abc_NtkLatchNum( pNtk );
|
|
|
|
Abc_FlowRetime_MarkBlocks( pNtk );
|
|
|
|
if (pManMR->maxDelay) {
|
|
// timing-constrained loop
|
|
Abc_FlowRetime_ConstrainConserv( pNtk );
|
|
while(Abc_FlowRetime_RefineConstraints( )) {
|
|
pManMR->subIteration++;
|
|
Abc_FlowRetime_ClearFlows( 0 );
|
|
}
|
|
} else {
|
|
flow = Abc_FlowRetime_PushFlows( pNtk, 1 );
|
|
}
|
|
|
|
cut = Abc_FlowRetime_ImplementCut( pNtk );
|
|
|
|
#if defined (DEBUG_PRINT_LEVELS)
|
|
vprintf("\t\tlevels = %d\n", Abc_NtkLevel(pNtk));
|
|
#endif
|
|
|
|
Abc_FlowRetime_ClearFlows( 1 );
|
|
|
|
pManMR->iteration++;
|
|
} while( cut != last );
|
|
|
|
// intermediate cleanup (for strashed networks)
|
|
if (Abc_NtkIsStrash(pNtk)) {
|
|
Abc_NtkReassignIds( pNtk );
|
|
pNtk = pManMR->pNtk = Abc_FlowRetime_NtkSilentRestrash( pNtk, 1 );
|
|
}
|
|
|
|
// print info about initial states
|
|
if (pManMR->fComputeInitState && pManMR->fVerbose)
|
|
Abc_FlowRetime_PrintInitStateInfo( pNtk );
|
|
|
|
// (ii) backward retiming loop
|
|
pManMR->fIsForward = 0;
|
|
|
|
if (!pManMR->fForwardOnly) do {
|
|
// initializability loop
|
|
pManMR->iteration = 0;
|
|
|
|
// copy/restore network
|
|
if (pManMR->fGuaranteeInitState) {
|
|
if ( pNtk != pNtkCopy )
|
|
Abc_NtkDelete( pNtk );
|
|
pNtk = pManMR->pNtk = Abc_FlowRetime_NtkDup( pNtkCopy );
|
|
vprintf("\trestoring network. regs = %d\n", Abc_NtkLatchNum( pNtk ));
|
|
}
|
|
|
|
if (pManMR->fComputeInitState) {
|
|
Abc_FlowRetime_SetupBackwardInit( pNtk );
|
|
}
|
|
|
|
do {
|
|
if (pManMR->iteration == pManMR->nMaxIters) break;
|
|
pManMR->subIteration = 0;
|
|
|
|
vprintf("\tbackward iteration %d\n", pManMR->iteration);
|
|
last = Abc_NtkLatchNum( pNtk );
|
|
|
|
Abc_FlowRetime_AddInitBias( );
|
|
Abc_FlowRetime_MarkBlocks( pNtk );
|
|
|
|
if (pManMR->maxDelay) {
|
|
// timing-constrained loop
|
|
Abc_FlowRetime_ConstrainConserv( pNtk );
|
|
while(Abc_FlowRetime_RefineConstraints( )) {
|
|
pManMR->subIteration++;
|
|
Abc_FlowRetime_ClearFlows( 0 );
|
|
}
|
|
} else {
|
|
flow = Abc_FlowRetime_PushFlows( pNtk, 1 );
|
|
}
|
|
|
|
Abc_FlowRetime_RemoveInitBias( );
|
|
cut = Abc_FlowRetime_ImplementCut( pNtk );
|
|
|
|
#if defined(DEBUG_PRINT_LEVELS)
|
|
vprintf("\t\tlevels = %d\n", Abc_NtkLevelReverse(pNtk));
|
|
#endif
|
|
|
|
Abc_FlowRetime_ClearFlows( 1 );
|
|
|
|
pManMR->iteration++;
|
|
} while( cut != last );
|
|
|
|
// compute initial states
|
|
if (!pManMR->fComputeInitState) break;
|
|
|
|
if (Abc_FlowRetime_SolveBackwardInit( pNtk )) {
|
|
if (pManMR->fVerbose) Abc_FlowRetime_PrintInitStateInfo( pNtk );
|
|
break;
|
|
} else {
|
|
if (!pManMR->fGuaranteeInitState) {
|
|
printf("WARNING: no equivalent init state. setting all initial states to don't-cares\n");
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) Abc_LatchSetInitDc( pObj );
|
|
break;
|
|
}
|
|
Abc_FlowRetime_ConstrainInit( );
|
|
}
|
|
|
|
Abc_NtkDelete(pManMR->pInitNtk);
|
|
pManMR->pInitNtk = NULL;
|
|
} while(1);
|
|
|
|
// assert(!pManMR->fComputeInitState || pManMR->pInitNtk);
|
|
if (pManMR->fComputeInitState) Abc_NtkDelete(pManMR->pInitNtk);
|
|
// if (pManMR->fGuaranteeInitState) ; /* Abc_NtkDelete(pNtkCopy); note: original ntk deleted later */
|
|
|
|
return pNtk;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Pushes latch bubbles outside of box.]
|
|
|
|
Description [If network is an AIG, a fCompl0 is allowed to remain on
|
|
the BI node.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_RemoveLatchBubbles( Abc_Obj_t * pLatch ) {
|
|
int bubble = 0;
|
|
Abc_Ntk_t *pNtk = pManMR->pNtk;
|
|
Abc_Obj_t *pBi, *pBo, *pInv;
|
|
|
|
pBi = Abc_ObjFanin0(pLatch);
|
|
pBo = Abc_ObjFanout0(pLatch);
|
|
assert(!Abc_ObjIsComplement(pBi));
|
|
assert(!Abc_ObjIsComplement(pBo));
|
|
|
|
// push bubbles on BO into latch box
|
|
if (Abc_ObjFaninC0(pBo) && Abc_ObjFanoutNum(pBo) > 0) {
|
|
bubble = 1;
|
|
if (Abc_LatchIsInit0(pLatch)) Abc_LatchSetInit1(pLatch);
|
|
else if (Abc_LatchIsInit1(pLatch)) Abc_LatchSetInit0(pLatch);
|
|
}
|
|
|
|
// absorb bubbles on BI
|
|
pBi->fCompl0 ^= bubble ^ Abc_ObjFaninC0(pLatch);
|
|
|
|
// convert bubble to INV if not AIG
|
|
if (!Abc_NtkIsStrash( pNtk ) && Abc_ObjFaninC0(pBi)) {
|
|
pBi->fCompl0 = 0;
|
|
pInv = Abc_NtkCreateNodeInv( pNtk, Abc_ObjFanin0(pBi) );
|
|
Abc_ObjPatchFanin( pBi, Abc_ObjFanin0(pBi), pInv );
|
|
}
|
|
|
|
pBo->fCompl0 = 0;
|
|
pLatch->fCompl0 = 0;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Marks nodes in TFO/TFI of PI/PO.]
|
|
|
|
Description [Sets flow data flag BLOCK appropriately.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_MarkBlocks( Abc_Ntk_t * pNtk ) {
|
|
int i;
|
|
Abc_Obj_t *pObj;
|
|
|
|
if (pManMR->fIsForward){
|
|
// --- forward retiming : block TFO of inputs
|
|
|
|
// mark the frontier
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
pObj->fMarkA = 1;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
{
|
|
pObj->fMarkA = 1;
|
|
}
|
|
// mark the nodes reachable from the PIs
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
Abc_NtkMarkCone_rec( pObj, pManMR->fIsForward );
|
|
} else {
|
|
// --- backward retiming : block TFI of outputs
|
|
|
|
// mark the frontier
|
|
Abc_NtkForEachPi( pNtk, pObj, i )
|
|
pObj->fMarkA = 1;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
{
|
|
pObj->fMarkA = 1;
|
|
}
|
|
// mark the nodes reachable from the POs
|
|
Abc_NtkForEachPo( pNtk, pObj, i )
|
|
Abc_NtkMarkCone_rec( pObj, pManMR->fIsForward );
|
|
// block constant nodes (if enabled)
|
|
if (pManMR->fBlockConst) {
|
|
Abc_NtkForEachObj( pNtk, pObj, i )
|
|
if ((Abc_NtkIsStrash(pNtk) && Abc_AigNodeIsConst(pObj)) ||
|
|
(!Abc_NtkIsStrash(pNtk) && Abc_NodeIsConst(pObj))) {
|
|
FSET(pObj, BLOCK);
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy marks
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
if (pObj->fMarkA) {
|
|
pObj->fMarkA = 0;
|
|
if (!Abc_ObjIsLatch(pObj) /* && !Abc_ObjIsPi(pObj) */ )
|
|
FSET(pObj, BLOCK);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Computes maximum flow.]
|
|
|
|
Description []
|
|
|
|
SideEffects [Leaves VISITED flags on source-reachable nodes.]
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int
|
|
Abc_FlowRetime_PushFlows( Abc_Ntk_t * pNtk, int fVerbose ) {
|
|
int i, j, flow = 0, last, srcDist = 0;
|
|
Abc_Obj_t *pObj, *pObj2;
|
|
// int clk = clock();
|
|
|
|
pManMR->constraintMask |= BLOCK;
|
|
|
|
pManMR->fSinkDistTerminate = 0;
|
|
dfsfast_preorder( pNtk );
|
|
|
|
// (i) fast max-flow computation
|
|
while(!pManMR->fSinkDistTerminate && srcDist < MAX_DIST) {
|
|
srcDist = MAX_DIST;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i )
|
|
if (FDATA(pObj)->e_dist)
|
|
srcDist = MIN(srcDist, (int)FDATA(pObj)->e_dist);
|
|
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
if (srcDist == (int)FDATA(pObj)->e_dist &&
|
|
dfsfast_e( pObj, NULL )) {
|
|
#ifdef DEBUG_PRINT_FLOWS
|
|
printf("\n\n");
|
|
#endif
|
|
flow++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fVerbose) vprintf("\t\tmax-flow1 = %d \t", flow);
|
|
|
|
// (ii) complete max-flow computation
|
|
// also, marks source-reachable nodes
|
|
do {
|
|
last = flow;
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
if (dfsplain_e( pObj, NULL )) {
|
|
#ifdef DEBUG_PRINT_FLOWS
|
|
printf("\n\n");
|
|
#endif
|
|
flow++;
|
|
Abc_NtkForEachObj( pNtk, pObj2, j )
|
|
FUNSET( pObj2, VISITED );
|
|
}
|
|
}
|
|
} while (flow > last);
|
|
|
|
if (fVerbose) vprintf("max-flow2 = %d\n", flow);
|
|
|
|
// PRT( "time", clock() - clk );
|
|
return flow;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Restores latch boxes.]
|
|
|
|
Description [Latchless BI/BO nodes are removed. Latch boxes are
|
|
restored around remaining latches.]
|
|
|
|
SideEffects [Deletes nodes as appropriate.]
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_FixLatchBoxes( Abc_Ntk_t *pNtk, Vec_Ptr_t *vBoxIns ) {
|
|
int i;
|
|
Abc_Obj_t *pObj, *pBo = NULL, *pBi = NULL;
|
|
Vec_Ptr_t *vFreeBi = Vec_PtrAlloc( 100 );
|
|
Vec_Ptr_t *vFreeBo = Vec_PtrAlloc( 100 );
|
|
|
|
// 1. remove empty bi/bo pairs
|
|
while(Vec_PtrSize( vBoxIns )) {
|
|
pBi = (Abc_Obj_t *)Vec_PtrPop( vBoxIns );
|
|
assert(Abc_ObjIsBi(pBi));
|
|
assert(Abc_ObjFanoutNum(pBi) == 1);
|
|
// APH: broken by bias nodes assert(Abc_ObjFaninNum(pBi) == 1);
|
|
pBo = Abc_ObjFanout0(pBi);
|
|
assert(!Abc_ObjFaninC0(pBo));
|
|
|
|
if (Abc_ObjIsBo(pBo)) {
|
|
// an empty bi/bo pair
|
|
|
|
Abc_ObjRemoveFanins( pBo );
|
|
// transfer complement from BI, if present
|
|
assert(!Abc_ObjIsComplement(Abc_ObjFanin0(pBi)));
|
|
Abc_ObjBetterTransferFanout( pBo, Abc_ObjFanin0(pBi), Abc_ObjFaninC0(pBi) );
|
|
|
|
Abc_ObjRemoveFanins( pBi );
|
|
pBi->fCompl0 = 0;
|
|
Vec_PtrPush( vFreeBi, pBi );
|
|
Vec_PtrPush( vFreeBo, pBo );
|
|
|
|
// free names
|
|
if (Nm_ManFindNameById(pNtk->pManName, Abc_ObjId(pBi)))
|
|
Nm_ManDeleteIdName( pNtk->pManName, Abc_ObjId(pBi));
|
|
if (Nm_ManFindNameById(pNtk->pManName, Abc_ObjId(pBo)))
|
|
Nm_ManDeleteIdName( pNtk->pManName, Abc_ObjId(pBo));
|
|
|
|
// check for complete detachment
|
|
assert(Abc_ObjFaninNum(pBi) == 0);
|
|
assert(Abc_ObjFanoutNum(pBi) == 0);
|
|
assert(Abc_ObjFaninNum(pBo) == 0);
|
|
assert(Abc_ObjFanoutNum(pBo) == 0);
|
|
} else if (Abc_ObjIsLatch(pBo)) {
|
|
} else {
|
|
Abc_ObjPrint(stdout, pBi);
|
|
Abc_ObjPrint(stdout, pBo);
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
// 2. add bi/bos as necessary for latches
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
assert(Abc_ObjFaninNum(pObj) == 1);
|
|
if (Abc_ObjFanoutNum(pObj))
|
|
pBo = Abc_ObjFanout0(pObj);
|
|
else pBo = NULL;
|
|
pBi = Abc_ObjFanin0(pObj);
|
|
|
|
// add BO
|
|
if (!pBo || !Abc_ObjIsBo(pBo)) {
|
|
pBo = (Abc_Obj_t *)Vec_PtrPop( vFreeBo );
|
|
if (Abc_ObjFanoutNum(pObj)) Abc_ObjTransferFanout( pObj, pBo );
|
|
Abc_ObjAddFanin( pBo, pObj );
|
|
}
|
|
// add BI
|
|
if (!Abc_ObjIsBi(pBi)) {
|
|
pBi = (Abc_Obj_t *)Vec_PtrPop( vFreeBi );
|
|
assert(Abc_ObjFaninNum(pBi) == 0);
|
|
Abc_ObjAddFanin( pBi, Abc_ObjFanin0(pObj) );
|
|
pBi->fCompl0 = pObj->fCompl0;
|
|
Abc_ObjRemoveFanins( pObj );
|
|
Abc_ObjAddFanin( pObj, pBi );
|
|
}
|
|
}
|
|
|
|
// delete remaining BIs and BOs
|
|
while(Vec_PtrSize( vFreeBi )) {
|
|
pObj = (Abc_Obj_t *)Vec_PtrPop( vFreeBi );
|
|
Abc_NtkDeleteObj( pObj );
|
|
}
|
|
while(Vec_PtrSize( vFreeBo )) {
|
|
pObj = (Abc_Obj_t *)Vec_PtrPop( vFreeBo );
|
|
Abc_NtkDeleteObj( pObj );
|
|
}
|
|
|
|
#if defined(DEBUG_CHECK)
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
if (Abc_ObjIsBo(pObj)) {
|
|
assert(Abc_ObjFaninNum(pObj) == 1);
|
|
assert(Abc_ObjIsLatch(Abc_ObjFanin0(pObj)));
|
|
}
|
|
if (Abc_ObjIsBi(pObj)) {
|
|
assert(Abc_ObjFaninNum(pObj) == 1);
|
|
assert(Abc_ObjFanoutNum(pObj) == 1);
|
|
assert(Abc_ObjIsLatch(Abc_ObjFanout0(pObj)));
|
|
}
|
|
if (Abc_ObjIsLatch(pObj)) {
|
|
assert(Abc_ObjFanoutNum(pObj) == 1);
|
|
assert(Abc_ObjFaninNum(pObj) == 1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Vec_PtrFree( vFreeBi );
|
|
Vec_PtrFree( vFreeBo );
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Checks register count along all combinational paths.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_VerifyPathLatencies( Abc_Ntk_t * pNtk ) {
|
|
int i;
|
|
Abc_Obj_t *pObj;
|
|
fPathError = 0;
|
|
|
|
vprintf("\t\tVerifying latency along all paths...");
|
|
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
if (Abc_ObjIsBo(pObj)) {
|
|
Abc_FlowRetime_VerifyPathLatencies_rec( pObj, 0 );
|
|
} else if (!pManMR->fIsForward && Abc_ObjIsPi(pObj)) {
|
|
Abc_FlowRetime_VerifyPathLatencies_rec( pObj, 0 );
|
|
}
|
|
|
|
if (fPathError) {
|
|
if (Abc_ObjFaninNum(pObj) > 0) {
|
|
printf("fanin ");
|
|
print_node(Abc_ObjFanin0(pObj));
|
|
}
|
|
printf("\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
vprintf(" ok\n");
|
|
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
pObj->fMarkA = 0;
|
|
pObj->fMarkB = 0;
|
|
pObj->fMarkC = 0;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
Abc_FlowRetime_VerifyPathLatencies_rec( Abc_Obj_t * pObj, int markD ) {
|
|
int i, j;
|
|
Abc_Obj_t *pNext;
|
|
int fCare = 0;
|
|
int markC = pObj->fMarkC;
|
|
|
|
if (!pObj->fMarkB) {
|
|
pObj->fMarkB = 1; // visited
|
|
|
|
if (Abc_ObjIsLatch(pObj))
|
|
markC = 1; // latch in output
|
|
|
|
if (!pManMR->fIsForward && !Abc_ObjIsPo(pObj) && !Abc_ObjFanoutNum(pObj))
|
|
return -1; // dangling non-PO outputs : don't care what happens
|
|
|
|
Abc_ObjForEachFanout( pObj, pNext, i ) {
|
|
// reached end of cycle?
|
|
if ( Abc_ObjIsBo(pNext) ||
|
|
(pManMR->fIsForward && Abc_ObjIsPo(pNext)) ) {
|
|
if (!markD && !Abc_ObjIsLatch(pObj)) {
|
|
printf("\nERROR: no-latch path (end)\n");
|
|
print_node(pNext);
|
|
printf("\n");
|
|
fPathError = 1;
|
|
}
|
|
} else if (!pManMR->fIsForward && Abc_ObjIsPo(pNext)) {
|
|
if (markD || Abc_ObjIsLatch(pObj)) {
|
|
printf("\nERROR: extra-latch path to outputs\n");
|
|
print_node(pNext);
|
|
printf("\n");
|
|
fPathError = 1;
|
|
}
|
|
} else {
|
|
j = Abc_FlowRetime_VerifyPathLatencies_rec( pNext, markD || Abc_ObjIsLatch(pObj) );
|
|
if (j >= 0) {
|
|
markC |= j;
|
|
fCare = 1;
|
|
}
|
|
}
|
|
|
|
if (fPathError) {
|
|
print_node(pObj);
|
|
printf("\n");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fCare) return -1;
|
|
|
|
if (markC && markD) {
|
|
printf("\nERROR: mult-latch path\n");
|
|
print_node(pObj);
|
|
printf("\n");
|
|
fPathError = 1;
|
|
}
|
|
if (!markC && !markD) {
|
|
printf("\nERROR: no-latch path (inter)\n");
|
|
print_node(pObj);
|
|
printf("\n");
|
|
fPathError = 1;
|
|
}
|
|
|
|
return (pObj->fMarkC = markC);
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Copies initial state from latches to BO nodes.]
|
|
|
|
Description [Initial states are marked on BO nodes with INIT_0 and
|
|
INIT_1 flags in their Flow_Data structures.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_CopyInitState( Abc_Obj_t * pSrc, Abc_Obj_t * pDest ) {
|
|
Abc_Obj_t *pObj;
|
|
|
|
if (!pManMR->fComputeInitState) return;
|
|
|
|
assert(Abc_ObjIsLatch(pSrc));
|
|
assert(Abc_ObjFanin0(pDest) == pSrc);
|
|
assert(!Abc_ObjFaninC0(pDest));
|
|
|
|
FUNSET(pDest, INIT_CARE);
|
|
if (Abc_LatchIsInit0(pSrc)) {
|
|
FSET(pDest, INIT_0);
|
|
} else if (Abc_LatchIsInit1(pSrc)) {
|
|
FSET(pDest, INIT_1);
|
|
}
|
|
|
|
if (!pManMR->fIsForward) {
|
|
pObj = (Abc_Obj_t*)Abc_ObjData(pSrc);
|
|
assert(Abc_ObjIsPi(pObj));
|
|
FDATA(pDest)->pInitObj = pObj;
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Implements min-cut.]
|
|
|
|
Description [Requires source-reachable nodes to be marked VISITED.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int
|
|
Abc_FlowRetime_ImplementCut( Abc_Ntk_t * pNtk ) {
|
|
int i, j, cut = 0, unmoved = 0;
|
|
Abc_Obj_t *pObj, *pReg, *pNext, *pBo = NULL, *pBi = NULL;
|
|
Vec_Ptr_t *vFreeRegs = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
|
|
Vec_Ptr_t *vBoxIns = Vec_PtrAlloc( Abc_NtkLatchNum(pNtk) );
|
|
Vec_Ptr_t *vMove = Vec_PtrAlloc( 100 );
|
|
|
|
// remove latches from netlist
|
|
Abc_NtkForEachLatch( pNtk, pObj, i ) {
|
|
pBo = Abc_ObjFanout0(pObj);
|
|
pBi = Abc_ObjFanin0(pObj);
|
|
assert(Abc_ObjIsBo(pBo) && Abc_ObjIsBi(pBi));
|
|
Vec_PtrPush( vBoxIns, pBi );
|
|
|
|
// copy initial state values to BO
|
|
Abc_FlowRetime_CopyInitState( pObj, pBo );
|
|
|
|
// re-use latch elsewhere
|
|
Vec_PtrPush( vFreeRegs, pObj );
|
|
FSET(pBo, CROSS_BOUNDARY);
|
|
|
|
// cut out of netlist
|
|
Abc_ObjPatchFanin( pBo, pObj, pBi );
|
|
Abc_ObjRemoveFanins( pObj );
|
|
|
|
// free name
|
|
if (Nm_ManFindNameById(pNtk->pManName, Abc_ObjId(pObj)))
|
|
Nm_ManDeleteIdName( pNtk->pManName, Abc_ObjId(pObj));
|
|
}
|
|
|
|
// insert latches into netlist
|
|
Abc_NtkForEachObj( pNtk, pObj, i ) {
|
|
if (Abc_ObjIsLatch( pObj )) continue;
|
|
if (FTEST(pObj, BIAS_NODE)) continue;
|
|
|
|
// a latch is required on every node that lies across the min-cit
|
|
assert(!pManMR->fIsForward || !FTEST(pObj, VISITED_E) || FTEST(pObj, VISITED_R));
|
|
if (FTEST(pObj, VISITED_R) && !FTEST(pObj, VISITED_E)) {
|
|
assert(FTEST(pObj, FLOW));
|
|
|
|
// count size of cut
|
|
cut++;
|
|
if ((pManMR->fIsForward && Abc_ObjIsBo(pObj)) ||
|
|
(!pManMR->fIsForward && Abc_ObjIsBi(pObj)))
|
|
unmoved++;
|
|
|
|
// only insert latch between fanouts that lie across min-cut
|
|
// some fanout paths may be cut at deeper points
|
|
Abc_ObjForEachFanout( pObj, pNext, j )
|
|
if (Abc_FlowRetime_IsAcrossCut( pObj, pNext ))
|
|
Vec_PtrPush(vMove, pNext);
|
|
|
|
// check that move-set is non-zero
|
|
if (Vec_PtrSize(vMove) == 0)
|
|
print_node(pObj);
|
|
assert(Vec_PtrSize(vMove) > 0);
|
|
|
|
// insert one of re-useable registers
|
|
assert(Vec_PtrSize( vFreeRegs ));
|
|
pReg = (Abc_Obj_t *)Vec_PtrPop( vFreeRegs );
|
|
|
|
Abc_ObjAddFanin(pReg, pObj);
|
|
while(Vec_PtrSize( vMove )) {
|
|
pNext = (Abc_Obj_t *)Vec_PtrPop( vMove );
|
|
Abc_ObjPatchFanin( pNext, pObj, pReg );
|
|
if (Abc_ObjIsBi(pNext)) assert(Abc_ObjFaninNum(pNext) == 1);
|
|
|
|
}
|
|
// APH: broken by bias nodes if (Abc_ObjIsBi(pObj)) assert(Abc_ObjFaninNum(pObj) == 1);
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG_CHECK)
|
|
Abc_FlowRetime_VerifyPathLatencies( pNtk );
|
|
#endif
|
|
|
|
// delete remaining latches
|
|
while(Vec_PtrSize( vFreeRegs )) {
|
|
pReg = (Abc_Obj_t *)Vec_PtrPop( vFreeRegs );
|
|
Abc_NtkDeleteObj( pReg );
|
|
}
|
|
|
|
// update initial states
|
|
Abc_FlowRetime_UpdateLags( );
|
|
Abc_FlowRetime_InitState( pNtk );
|
|
|
|
// restore latch boxes
|
|
Abc_FlowRetime_FixLatchBoxes( pNtk, vBoxIns );
|
|
|
|
Vec_PtrFree( vFreeRegs );
|
|
Vec_PtrFree( vMove );
|
|
Vec_PtrFree( vBoxIns );
|
|
|
|
vprintf("\t\tmin-cut = %d (unmoved = %d)\n", cut, unmoved);
|
|
return cut;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Adds dummy fanin.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_AddDummyFanin( Abc_Obj_t * pObj ) {
|
|
Abc_Ntk_t *pNtk = Abc_ObjNtk( pObj );
|
|
|
|
if (Abc_NtkIsStrash(pNtk))
|
|
Abc_ObjAddFanin(pObj, Abc_AigConst1( pNtk ));
|
|
else
|
|
Abc_ObjAddFanin(pObj, Abc_NtkCreateNodeConst0( pNtk ));
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Prints information about a node.]
|
|
|
|
Description [Debuging.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
print_node(Abc_Obj_t *pObj) {
|
|
int i;
|
|
Abc_Obj_t * pNext;
|
|
char m[6];
|
|
|
|
m[0] = 0;
|
|
if (pObj->fMarkA)
|
|
strcat(m, "A");
|
|
if (pObj->fMarkB)
|
|
strcat(m, "B");
|
|
if (pObj->fMarkC)
|
|
strcat(m, "C");
|
|
|
|
printf("node %d type=%d lev=%d tedge=%d (%x%s) fanouts {", Abc_ObjId(pObj), Abc_ObjType(pObj),
|
|
pObj->Level, Vec_PtrSize(FTIMEEDGES(pObj)), FDATA(pObj)->mark, m);
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
printf("%d[%d](%d),", Abc_ObjId(pNext), Abc_ObjType(pNext), FDATA(pNext)->mark);
|
|
printf("} fanins {");
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
printf("%d[%d](%d),", Abc_ObjId(pNext), Abc_ObjType(pNext), FDATA(pNext)->mark);
|
|
printf("}\n");
|
|
}
|
|
|
|
void
|
|
print_node2(Abc_Obj_t *pObj) {
|
|
int i;
|
|
Abc_Obj_t * pNext;
|
|
char m[6];
|
|
|
|
m[0] = 0;
|
|
if (pObj->fMarkA)
|
|
strcat(m, "A");
|
|
if (pObj->fMarkB)
|
|
strcat(m, "B");
|
|
if (pObj->fMarkC)
|
|
strcat(m, "C");
|
|
|
|
printf("node %d type=%d %s fanouts {", Abc_ObjId(pObj), Abc_ObjType(pObj), m);
|
|
Abc_ObjForEachFanout( pObj, pNext, i )
|
|
printf("%d ,", Abc_ObjId(pNext));
|
|
printf("} fanins {");
|
|
Abc_ObjForEachFanin( pObj, pNext, i )
|
|
printf("%d ,", Abc_ObjId(pNext));
|
|
printf("} ");
|
|
}
|
|
|
|
void
|
|
print_node3(Abc_Obj_t *pObj) {
|
|
int i;
|
|
Abc_Obj_t * pNext;
|
|
char m[6];
|
|
|
|
m[0] = 0;
|
|
if (pObj->fMarkA)
|
|
strcat(m, "A");
|
|
if (pObj->fMarkB)
|
|
strcat(m, "B");
|
|
if (pObj->fMarkC)
|
|
strcat(m, "C");
|
|
|
|
printf("\nnode %d type=%d mark=%d %s\n", Abc_ObjId(pObj), Abc_ObjType(pObj), FDATA(pObj)->mark, m);
|
|
printf("fanouts\n");
|
|
Abc_ObjForEachFanout( pObj, pNext, i ) {
|
|
print_node(pNext);
|
|
printf("\n");
|
|
}
|
|
printf("fanins\n");
|
|
Abc_ObjForEachFanin( pObj, pNext, i ) {
|
|
print_node(pNext);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Transfers fanout.]
|
|
|
|
Description [Does not produce an error if there is no fanout.
|
|
Complements as necessary.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_ObjBetterTransferFanout( Abc_Obj_t * pFrom, Abc_Obj_t * pTo, int complement ) {
|
|
Abc_Obj_t *pNext;
|
|
|
|
while(Abc_ObjFanoutNum(pFrom) > 0) {
|
|
pNext = Abc_ObjFanout0(pFrom);
|
|
Abc_ObjPatchFanin( pNext, pFrom, Abc_ObjNotCond(pTo, complement) );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Returns true is a connection spans the min-cut.]
|
|
|
|
Description [pNext is a direct fanout of pObj.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int
|
|
Abc_FlowRetime_IsAcrossCut( Abc_Obj_t *pObj, Abc_Obj_t *pNext ) {
|
|
|
|
if (FTEST(pObj, VISITED_R) && !FTEST(pObj, VISITED_E)) {
|
|
if (pManMR->fIsForward) {
|
|
if (!FTEST(pNext, VISITED_R) ||
|
|
(FTEST(pNext, BLOCK_OR_CONS) & pManMR->constraintMask)||
|
|
FTEST(pNext, CROSS_BOUNDARY) ||
|
|
Abc_ObjIsLatch(pNext))
|
|
return 1;
|
|
} else {
|
|
if (FTEST(pNext, VISITED_E) ||
|
|
FTEST(pNext, CROSS_BOUNDARY))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Resets flow problem]
|
|
|
|
Description [If fClearAll is true, all marks will be cleared; this is
|
|
typically appropriate after the circuit structure has
|
|
been modified.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Abc_FlowRetime_ClearFlows( int fClearAll ) {
|
|
int i;
|
|
|
|
if (fClearAll)
|
|
memset(pManMR->pDataArray, 0, sizeof(Flow_Data_t)*pManMR->nNodes);
|
|
else {
|
|
// clear only data related to flow problem
|
|
for(i=0; i<pManMR->nNodes; i++) {
|
|
pManMR->pDataArray[i].mark &= ~(VISITED | FLOW );
|
|
pManMR->pDataArray[i].e_dist = 0;
|
|
pManMR->pDataArray[i].r_dist = 0;
|
|
pManMR->pDataArray[i].pred = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Duplicates network.]
|
|
|
|
Description [Duplicates any type of network. Preserves copy data.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
static Abc_Ntk_t* Abc_FlowRetime_NtkDup( Abc_Ntk_t * pNtk ) {
|
|
Abc_Ntk_t *pNtkCopy;
|
|
Abc_Obj_t *pObj, *pObjCopy, *pNext, *pNextCopy;
|
|
int i, j;
|
|
|
|
pNtkCopy = Abc_NtkAlloc( pNtk->ntkType, pNtk->ntkFunc, 1 );
|
|
pNtkCopy->pName = Extra_UtilStrsav(pNtk->pName);
|
|
pNtkCopy->pSpec = Extra_UtilStrsav(pNtk->pSpec);
|
|
|
|
// copy each object
|
|
Abc_NtkForEachObj( pNtk, pObj, i) {
|
|
|
|
if (Abc_NtkIsStrash( pNtk ) && Abc_AigNodeIsConst( pObj ))
|
|
pObjCopy = Abc_AigConst1( pNtkCopy );
|
|
else
|
|
pObjCopy = Abc_NtkDupObj( pNtkCopy, pObj, 0 );
|
|
|
|
FDATA( pObj )->pCopy = pObjCopy;
|
|
FDATA( pObj )->mark = 0;
|
|
|
|
// assert( pManMR->fIsForward || pObj->Id == pObjCopy->Id );
|
|
|
|
// copy complementation
|
|
pObjCopy->fCompl0 = pObj->fCompl0;
|
|
pObjCopy->fCompl1 = pObj->fCompl1;
|
|
pObjCopy->fPhase = pObj->fPhase;
|
|
}
|
|
|
|
// connect fanin
|
|
Abc_NtkForEachObj( pNtk, pObj, i) {
|
|
pObjCopy = FDATA(pObj)->pCopy;
|
|
assert(pObjCopy);
|
|
Abc_ObjForEachFanin( pObj, pNext, j ) {
|
|
pNextCopy = FDATA(pNext)->pCopy;
|
|
assert(pNextCopy);
|
|
assert(pNext->Type == pNextCopy->Type);
|
|
|
|
Abc_ObjAddFanin(pObjCopy, pNextCopy);
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG_CHECK) || 1
|
|
Abc_NtkForEachObj( pNtk, pObj, i) {
|
|
pObjCopy = FDATA(pObj)->pCopy;
|
|
assert( Abc_ObjFanoutNum( pObj ) == Abc_ObjFanoutNum( pObjCopy ) );
|
|
assert( Abc_ObjFaninNum( pObj ) == Abc_ObjFaninNum( pObjCopy ) );
|
|
}
|
|
#endif
|
|
|
|
assert(Abc_NtkObjNum( pNtk ) == Abc_NtkObjNum( pNtkCopy ) );
|
|
assert(Abc_NtkLatchNum( pNtk ) == Abc_NtkLatchNum( pNtkCopy ) );
|
|
assert(Abc_NtkPoNum( pNtk ) == Abc_NtkPoNum( pNtkCopy ) );
|
|
assert(Abc_NtkPiNum( pNtk ) == Abc_NtkPiNum( pNtkCopy ) );
|
|
|
|
return pNtkCopy;
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Silent restrash.]
|
|
|
|
Description [Same functionality as Abc_NtkRestrash but w/o warnings.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Abc_Ntk_t * Abc_FlowRetime_NtkSilentRestrash( Abc_Ntk_t * pNtk, int fCleanup )
|
|
{
|
|
Abc_Ntk_t * pNtkAig;
|
|
Abc_Obj_t * pObj;
|
|
int i, nNodes;//, RetValue;
|
|
assert( Abc_NtkIsStrash(pNtk) );
|
|
// start the new network (constants and CIs of the old network will point to the their counterparts in the new network)
|
|
pNtkAig = Abc_NtkStartFrom( pNtk, ABC_NTK_STRASH, ABC_FUNC_AIG );
|
|
// restrash the nodes (assuming a topological order of the old network)
|
|
Abc_NtkForEachNode( pNtk, pObj, i )
|
|
pObj->pCopy = Abc_AigAnd( (Abc_Aig_t *)pNtkAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) );
|
|
// finalize the network
|
|
Abc_NtkFinalize( pNtk, pNtkAig );
|
|
// perform cleanup if requested
|
|
if ( fCleanup )
|
|
nNodes = Abc_AigCleanup((Abc_Aig_t *)pNtkAig->pManFunc);
|
|
// duplicate EXDC
|
|
if ( pNtk->pExdc )
|
|
pNtkAig->pExdc = Abc_NtkDup( pNtk->pExdc );
|
|
// make sure everything is okay
|
|
if ( !Abc_NtkCheck( pNtkAig ) )
|
|
{
|
|
printf( "Abc_NtkStrash: The network check has failed.\n" );
|
|
Abc_NtkDelete( pNtkAig );
|
|
return NULL;
|
|
}
|
|
return pNtkAig;
|
|
}
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates lag values.]
|
|
|
|
Description [Recursive. Forward retiming.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_UpdateLags_forw_rec( Abc_Obj_t *pObj ) {
|
|
Abc_Obj_t *pNext;
|
|
int i;
|
|
|
|
assert(!Abc_ObjIsPi(pObj));
|
|
assert(!Abc_ObjIsLatch(pObj));
|
|
|
|
if (Abc_ObjIsBo(pObj)) return;
|
|
if (Abc_NodeIsTravIdCurrent(pObj)) return;
|
|
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
|
|
if (Abc_ObjIsNode(pObj)) {
|
|
Abc_FlowRetime_SetLag( pObj, -1+Abc_FlowRetime_GetLag(pObj) );
|
|
}
|
|
|
|
Abc_ObjForEachFanin( pObj, pNext, i ) {
|
|
Abc_FlowRetime_UpdateLags_forw_rec( pNext );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates lag values.]
|
|
|
|
Description [Recursive. Backward retiming.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_UpdateLags_back_rec( Abc_Obj_t *pObj ) {
|
|
Abc_Obj_t *pNext;
|
|
int i;
|
|
|
|
assert(!Abc_ObjIsPo(pObj));
|
|
assert(!Abc_ObjIsLatch(pObj));
|
|
|
|
if (Abc_ObjIsBo(pObj)) return;
|
|
if (Abc_NodeIsTravIdCurrent(pObj)) return;
|
|
|
|
Abc_NodeSetTravIdCurrent(pObj);
|
|
|
|
if (Abc_ObjIsNode(pObj)) {
|
|
Abc_FlowRetime_SetLag( pObj, 1+Abc_FlowRetime_GetLag(pObj) );
|
|
}
|
|
|
|
Abc_ObjForEachFanout( pObj, pNext, i ) {
|
|
Abc_FlowRetime_UpdateLags_back_rec( pNext );
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates lag values.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_UpdateLags( ) {
|
|
Abc_Obj_t *pObj, *pNext;
|
|
int i, j;
|
|
|
|
Abc_NtkIncrementTravId( pManMR->pNtk );
|
|
|
|
Abc_NtkForEachLatch( pManMR->pNtk, pObj, i )
|
|
if (pManMR->fIsForward) {
|
|
Abc_ObjForEachFanin( pObj, pNext, j )
|
|
Abc_FlowRetime_UpdateLags_forw_rec( pNext );
|
|
} else {
|
|
Abc_ObjForEachFanout( pObj, pNext, j )
|
|
Abc_FlowRetime_UpdateLags_back_rec( pNext );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Gets lag value of a node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int
|
|
Abc_FlowRetime_GetLag( Abc_Obj_t *pObj ) {
|
|
assert( !Abc_ObjIsLatch(pObj) );
|
|
assert( (int)Abc_ObjId(pObj) < Vec_IntSize(pManMR->vLags) );
|
|
|
|
return Vec_IntEntry(pManMR->vLags, Abc_ObjId(pObj));
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Sets lag value of a node.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void
|
|
Abc_FlowRetime_SetLag( Abc_Obj_t *pObj, int lag ) {
|
|
assert( Abc_ObjIsNode(pObj) );
|
|
assert( (int)Abc_ObjId(pObj) < Vec_IntSize(pManMR->vLags) );
|
|
|
|
Vec_IntWriteEntry(pManMR->vLags, Abc_ObjId(pObj), lag);
|
|
}
|
|
|
|
|
|
static void Abc_ObjPrintNeighborhood_rec( Abc_Obj_t *pObj, Vec_Ptr_t *vNodes, int depth ) {
|
|
Abc_Obj_t *pObj2;
|
|
int i;
|
|
|
|
if (pObj->fMarkC || depth < 0) return;
|
|
|
|
pObj->fMarkC = 1;
|
|
Vec_PtrPush( vNodes, pObj );
|
|
|
|
Abc_ObjPrint( stdout, pObj );
|
|
|
|
Abc_ObjForEachFanout(pObj, pObj2, i) {
|
|
Abc_ObjPrintNeighborhood_rec( pObj2, vNodes, depth-1 );
|
|
}
|
|
Abc_ObjForEachFanin(pObj, pObj2, i) {
|
|
Abc_ObjPrintNeighborhood_rec( pObj2, vNodes, depth-1 );
|
|
}
|
|
}
|
|
|
|
void Abc_ObjPrintNeighborhood( Abc_Obj_t *pObj, int depth ) {
|
|
Vec_Ptr_t *vNodes = Vec_PtrAlloc(100);
|
|
Abc_Obj_t *pObj2;
|
|
|
|
Abc_ObjPrintNeighborhood_rec( pObj, vNodes, depth );
|
|
|
|
while(Vec_PtrSize(vNodes)) {
|
|
pObj2 = (Abc_Obj_t*)Vec_PtrPop(vNodes);
|
|
pObj2->fMarkC = 0;
|
|
}
|
|
|
|
Vec_PtrFree(vNodes);
|
|
}
|
|
ABC_NAMESPACE_IMPL_END
|
|
|