/**CFile**************************************************************** FileName [abcSpeedup.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Network and node package.] Synopsis [Delay trace and speedup.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: abcSpeedup.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "base/abc/abc.h" #include "base/main/main.h" #include "map/if/if.h" #include "aig/aig/aig.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// static inline float Abc_ObjArrival( Abc_Obj_t * pNode ) { return pNode->pNtk->pLutTimes[3*pNode->Id+0]; } static inline float Abc_ObjRequired( Abc_Obj_t * pNode ) { return pNode->pNtk->pLutTimes[3*pNode->Id+1]; } static inline float Abc_ObjSlack( Abc_Obj_t * pNode ) { return pNode->pNtk->pLutTimes[3*pNode->Id+2]; } static inline void Abc_ObjSetArrival( Abc_Obj_t * pNode, float Time ) { pNode->pNtk->pLutTimes[3*pNode->Id+0] = Time; } static inline void Abc_ObjSetRequired( Abc_Obj_t * pNode, float Time ) { pNode->pNtk->pLutTimes[3*pNode->Id+1] = Time; } static inline void Abc_ObjSetSlack( Abc_Obj_t * pNode, float Time ) { pNode->pNtk->pLutTimes[3*pNode->Id+2] = Time; } //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Sorts the pins in the decreasing order of delays.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDelayTraceSortPins( Abc_Obj_t * pNode, int * pPinPerm, float * pPinDelays ) { Abc_Obj_t * pFanin; int i, j, best_i, temp; // start the trivial permutation and collect pin delays Abc_ObjForEachFanin( pNode, pFanin, i ) { pPinPerm[i] = i; pPinDelays[i] = Abc_ObjArrival(pFanin); } // selection sort the pins in the decreasible order of delays // this order will match the increasing order of LUT input pins for ( i = 0; i < Abc_ObjFaninNum(pNode)-1; i++ ) { best_i = i; for ( j = i+1; j < Abc_ObjFaninNum(pNode); j++ ) if ( pPinDelays[pPinPerm[j]] > pPinDelays[pPinPerm[best_i]] ) best_i = j; if ( best_i == i ) continue; temp = pPinPerm[i]; pPinPerm[i] = pPinPerm[best_i]; pPinPerm[best_i] = temp; } // verify assert( Abc_ObjFaninNum(pNode) == 0 || pPinPerm[0] < Abc_ObjFaninNum(pNode) ); for ( i = 1; i < Abc_ObjFaninNum(pNode); i++ ) { assert( pPinPerm[i] < Abc_ObjFaninNum(pNode) ); assert( pPinDelays[pPinPerm[i-1]] >= pPinDelays[pPinPerm[i]] ); } } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ float Abc_NtkDelayTraceLut( Abc_Ntk_t * pNtk, int fUseLutLib ) { int fUseSorting = 1; int pPinPerm[32]; float pPinDelays[32]; If_LibLut_t * pLutLib; Abc_Obj_t * pNode, * pFanin; Vec_Ptr_t * vNodes; float tArrival, tRequired, tSlack, * pDelays; int i, k; assert( Abc_NtkIsLogic(pNtk) ); // get the library pLutLib = fUseLutLib? (If_LibLut_t *)Abc_FrameReadLibLut() : NULL; if ( pLutLib && pLutLib->LutMax < Abc_NtkGetFaninMax(pNtk) ) { printf( "The max LUT size (%d) is less than the max fanin count (%d).\n", pLutLib->LutMax, Abc_NtkGetFaninMax(pNtk) ); return -ABC_INFINITY; } // initialize the arrival times ABC_FREE( pNtk->pLutTimes ); pNtk->pLutTimes = ABC_ALLOC( float, 3 * Abc_NtkObjNumMax(pNtk) ); for ( i = 0; i < Abc_NtkObjNumMax(pNtk); i++ ) { pNtk->pLutTimes[3*i+0] = pNtk->pLutTimes[3*i+2] = 0; pNtk->pLutTimes[3*i+1] = ABC_INFINITY; } // propagate arrival times vNodes = Abc_NtkDfs( pNtk, 1 ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) { tArrival = -ABC_INFINITY; if ( pLutLib == NULL ) { Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tArrival < Abc_ObjArrival(pFanin) + 1.0 ) tArrival = Abc_ObjArrival(pFanin) + 1.0; } else if ( !pLutLib->fVarPinDelays ) { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tArrival < Abc_ObjArrival(pFanin) + pDelays[0] ) tArrival = Abc_ObjArrival(pFanin) + pDelays[0]; } else { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; if ( fUseSorting ) { Abc_NtkDelayTraceSortPins( pNode, pPinPerm, pPinDelays ); Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tArrival < Abc_ObjArrival(Abc_ObjFanin(pNode,pPinPerm[k])) + pDelays[k] ) tArrival = Abc_ObjArrival(Abc_ObjFanin(pNode,pPinPerm[k])) + pDelays[k]; } else { Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tArrival < Abc_ObjArrival(pFanin) + pDelays[k] ) tArrival = Abc_ObjArrival(pFanin) + pDelays[k]; } } if ( Abc_ObjFaninNum(pNode) == 0 ) tArrival = 0.0; Abc_ObjSetArrival( pNode, tArrival ); } Vec_PtrFree( vNodes ); // get the latest arrival times tArrival = -ABC_INFINITY; Abc_NtkForEachCo( pNtk, pNode, i ) if ( tArrival < Abc_ObjArrival(Abc_ObjFanin0(pNode)) ) tArrival = Abc_ObjArrival(Abc_ObjFanin0(pNode)); // initialize the required times Abc_NtkForEachCo( pNtk, pNode, i ) if ( Abc_ObjRequired(Abc_ObjFanin0(pNode)) > tArrival ) Abc_ObjSetRequired( Abc_ObjFanin0(pNode), tArrival ); // propagate the required times vNodes = Abc_NtkDfsReverse( pNtk ); Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) { if ( pLutLib == NULL ) { tRequired = Abc_ObjRequired(pNode) - (float)1.0; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( Abc_ObjRequired(pFanin) > tRequired ) Abc_ObjSetRequired( pFanin, tRequired ); } else if ( !pLutLib->fVarPinDelays ) { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; tRequired = Abc_ObjRequired(pNode) - pDelays[0]; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( Abc_ObjRequired(pFanin) > tRequired ) Abc_ObjSetRequired( pFanin, tRequired ); } else { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; if ( fUseSorting ) { Abc_NtkDelayTraceSortPins( pNode, pPinPerm, pPinDelays ); Abc_ObjForEachFanin( pNode, pFanin, k ) { tRequired = Abc_ObjRequired(pNode) - pDelays[k]; if ( Abc_ObjRequired(Abc_ObjFanin(pNode,pPinPerm[k])) > tRequired ) Abc_ObjSetRequired( Abc_ObjFanin(pNode,pPinPerm[k]), tRequired ); } } else { Abc_ObjForEachFanin( pNode, pFanin, k ) { tRequired = Abc_ObjRequired(pNode) - pDelays[k]; if ( Abc_ObjRequired(pFanin) > tRequired ) Abc_ObjSetRequired( pFanin, tRequired ); } } } // set slack for this object tSlack = Abc_ObjRequired(pNode) - Abc_ObjArrival(pNode); assert( tSlack + 0.001 > 0.0 ); Abc_ObjSetSlack( pNode, tSlack < 0.0 ? 0.0 : tSlack ); } Vec_PtrFree( vNodes ); return tArrival; } /**Function************************************************************* Synopsis [Delay tracing of the LUT mapped network.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkDelayTracePrint( Abc_Ntk_t * pNtk, int fUseLutLib, int fVerbose ) { Abc_Obj_t * pNode; If_LibLut_t * pLutLib; int i, Nodes, * pCounters; float tArrival, tDelta, nSteps, Num; // get the library pLutLib = fUseLutLib? (If_LibLut_t *)Abc_FrameReadLibLut() : NULL; if ( pLutLib && pLutLib->LutMax < Abc_NtkGetFaninMax(pNtk) ) { printf( "The max LUT size (%d) is less than the max fanin count (%d).\n", pLutLib->LutMax, Abc_NtkGetFaninMax(pNtk) ); return; } // decide how many steps nSteps = fUseLutLib ? 20 : Abc_NtkLevel(pNtk); pCounters = ABC_ALLOC( int, nSteps + 1 ); memset( pCounters, 0, sizeof(int)*(nSteps + 1) ); // perform delay trace tArrival = Abc_NtkDelayTraceLut( pNtk, fUseLutLib ); tDelta = tArrival / nSteps; // count how many nodes have slack in the corresponding intervals Abc_NtkForEachNode( pNtk, pNode, i ) { if ( Abc_ObjFaninNum(pNode) == 0 ) continue; Num = Abc_ObjSlack(pNode) / tDelta; assert( Num >=0 && Num <= nSteps ); pCounters[(int)Num]++; } // print the results printf( "Max delay = %6.2f. Delay trace using %s model:\n", tArrival, fUseLutLib? "LUT library" : "unit-delay" ); Nodes = 0; for ( i = 0; i < nSteps; i++ ) { Nodes += pCounters[i]; printf( "%3d %s : %5d (%6.2f %%)\n", fUseLutLib? 5*(i+1) : i+1, fUseLutLib? "%":"lev", Nodes, 100.0*Nodes/Abc_NtkNodeNum(pNtk) ); } ABC_FREE( pCounters ); } /**Function************************************************************* Synopsis [Returns 1 if pOld is in the TFI of pNew.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_AigCheckTfi_rec( Abc_Obj_t * pNode, Abc_Obj_t * pOld ) { // check the trivial cases if ( pNode == NULL ) return 0; if ( Abc_ObjIsCi(pNode) ) return 0; if ( pNode == pOld ) return 1; // skip the visited node if ( Abc_NodeIsTravIdCurrent( pNode ) ) return 0; Abc_NodeSetTravIdCurrent( pNode ); // check the children if ( Abc_AigCheckTfi_rec( Abc_ObjFanin0(pNode), pOld ) ) return 1; if ( Abc_AigCheckTfi_rec( Abc_ObjFanin1(pNode), pOld ) ) return 1; // check equivalent nodes return Abc_AigCheckTfi_rec( (Abc_Obj_t *)pNode->pData, pOld ); } /**Function************************************************************* Synopsis [Returns 1 if pOld is in the TFI of pNew.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_AigCheckTfi( Abc_Obj_t * pNew, Abc_Obj_t * pOld ) { assert( !Abc_ObjIsComplement(pNew) ); assert( !Abc_ObjIsComplement(pOld) ); Abc_NtkIncrementTravId( pNew->pNtk ); return Abc_AigCheckTfi_rec( pNew, pOld ); } /**Function************************************************************* Synopsis [Adds strashed nodes for one node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Abc_NtkSpeedupNode_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vNodes ) { if ( Abc_NodeIsTravIdCurrent(pNode) ) return 1; if ( Abc_ObjIsCi(pNode) ) return 0; assert( Abc_ObjIsNode(pNode) ); Abc_NodeSetTravIdCurrent( pNode ); if ( !Abc_NtkSpeedupNode_rec( Abc_ObjFanin0(pNode), vNodes ) ) return 0; if ( !Abc_NtkSpeedupNode_rec( Abc_ObjFanin1(pNode), vNodes ) ) return 0; Vec_PtrPush( vNodes, pNode ); return 1; } /**Function************************************************************* Synopsis [Adds strashed nodes for one node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkSpeedupNode( Abc_Ntk_t * pNtk, Abc_Ntk_t * pAig, Abc_Obj_t * pNode, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vTimes ) { Vec_Ptr_t * vNodes; Abc_Obj_t * pObj, * pObj2, * pAnd; Abc_Obj_t * ppCofs[32]; int nCofs, i, k, nSkip; // quit of regulars are the same Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pObj, i ) Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pObj2, k ) if ( i != k && Abc_ObjRegular(pObj->pCopy) == Abc_ObjRegular(pObj2->pCopy) ) { // printf( "Identical after structural hashing!!!\n" ); return; } // collect the AIG nodes vNodes = Vec_PtrAlloc( 100 ); Abc_NtkIncrementTravId( pAig ); Abc_NodeSetTravIdCurrent( Abc_AigConst1(pAig) ); Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pObj, i ) { pAnd = pObj->pCopy; Abc_NodeSetTravIdCurrent( Abc_ObjRegular(pAnd) ); } // traverse from the root node pAnd = pNode->pCopy; if ( !Abc_NtkSpeedupNode_rec( Abc_ObjRegular(pAnd), vNodes ) ) { // printf( "Bad node!!!\n" ); Vec_PtrFree( vNodes ); return; } // derive cofactors nCofs = (1 << Vec_PtrSize(vTimes)); for ( i = 0; i < nCofs; i++ ) { Vec_PtrForEachEntry( Abc_Obj_t *, vLeaves, pObj, k ) { pAnd = pObj->pCopy; Abc_ObjRegular(pAnd)->pCopy = Abc_ObjRegular(pAnd); } Vec_PtrForEachEntry( Abc_Obj_t *, vTimes, pObj, k ) { pAnd = pObj->pCopy; Abc_ObjRegular(pAnd)->pCopy = Abc_ObjNotCond( Abc_AigConst1(pAig), ((i & (1<pCopy = Abc_AigAnd( (Abc_Aig_t *)pAig->pManFunc, Abc_ObjChild0Copy(pObj), Abc_ObjChild1Copy(pObj) ); // save the result pAnd = pNode->pCopy; ppCofs[i] = Abc_ObjNotCond( Abc_ObjRegular(pAnd)->pCopy, Abc_ObjIsComplement(pAnd) ); } Vec_PtrFree( vNodes ); //Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), ppCofs[0] ); //Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), ppCofs[1] ); // collect the resulting tree Vec_PtrForEachEntry( Abc_Obj_t *, vTimes, pObj, k ) for ( nSkip = (1<pCopy; ppCofs[i] = Abc_AigMux( (Abc_Aig_t *)pAig->pManFunc, Abc_ObjRegular(pAnd), ppCofs[i+nSkip], ppCofs[i] ); } //Abc_ObjAddFanin( Abc_NtkCreatePo(pAig), ppCofs[0] ); // create choice node pAnd = Abc_ObjRegular(pNode->pCopy); // repr pObj = Abc_ObjRegular(ppCofs[0]); // new if ( pAnd->pData == NULL && pObj->pData == NULL && !Abc_AigNodeIsConst(pObj) && !Abc_AigCheckTfi(pObj, pAnd) ) { pObj->pData = pAnd->pData; pAnd->pData = pObj; } } /**Function************************************************************* Synopsis [Determines timing-critical edges of the node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ unsigned Abc_NtkDelayTraceTCEdges( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, float tDelta, int fUseLutLib ) { int pPinPerm[32]; float pPinDelays[32]; If_LibLut_t * pLutLib; Abc_Obj_t * pFanin; unsigned uResult = 0; float tRequired, * pDelays; int k; pLutLib = fUseLutLib? (If_LibLut_t *)Abc_FrameReadLibLut() : NULL; tRequired = Abc_ObjRequired(pNode); if ( pLutLib == NULL ) { Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tRequired < Abc_ObjArrival(pFanin) + 1.0 + tDelta ) uResult |= (1 << k); } else if ( !pLutLib->fVarPinDelays ) { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tRequired < Abc_ObjArrival(pFanin) + pDelays[0] + tDelta ) uResult |= (1 << k); } else { pDelays = pLutLib->pLutDelays[Abc_ObjFaninNum(pNode)]; Abc_NtkDelayTraceSortPins( pNode, pPinPerm, pPinDelays ); Abc_ObjForEachFanin( pNode, pFanin, k ) if ( tRequired < Abc_ObjArrival(Abc_ObjFanin(pNode,pPinPerm[k])) + pDelays[k] + tDelta ) uResult |= (1 << pPinPerm[k]); } return uResult; } /**Function************************************************************* Synopsis [Adds choices to speed up the network by the given percentage.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Ntk_t * Abc_NtkSpeedup( Abc_Ntk_t * pNtk, int fUseLutLib, int Percentage, int Degree, int fVerbose, int fVeryVerbose ) { Abc_Ntk_t * pNtkNew; Vec_Ptr_t * vTimeCries, * vTimeFanins; Abc_Obj_t * pNode, * pFanin, * pFanin2; float tDelta, tArrival; int i, k, k2, Counter, CounterRes, nTimeCris; unsigned * puTCEdges; // perform delay trace tArrival = Abc_NtkDelayTraceLut( pNtk, fUseLutLib ); tDelta = fUseLutLib ? tArrival*Percentage/100.0 : 1.0; if ( fVerbose ) { printf( "Max delay = %.2f. Delta = %.2f. ", tArrival, tDelta ); printf( "Using %s model. ", fUseLutLib? "LUT library" : "unit-delay" ); if ( fUseLutLib ) printf( "Percentage = %d. ", Percentage ); printf( "\n" ); } // mark the timing critical nodes and edges puTCEdges = ABC_ALLOC( unsigned, Abc_NtkObjNumMax(pNtk) ); memset( puTCEdges, 0, sizeof(unsigned) * Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachNode( pNtk, pNode, i ) { if ( Abc_ObjSlack(pNode) >= tDelta ) continue; puTCEdges[pNode->Id] = Abc_NtkDelayTraceTCEdges( pNtk, pNode, tDelta, fUseLutLib ); } if ( fVerbose ) { Counter = CounterRes = 0; Abc_NtkForEachNode( pNtk, pNode, i ) { Abc_ObjForEachFanin( pNode, pFanin, k ) if ( !Abc_ObjIsCi(pFanin) && Abc_ObjSlack(pFanin) < tDelta ) Counter++; CounterRes += Extra_WordCountOnes( puTCEdges[pNode->Id] ); } printf( "Edges: Total = %7d. 0-slack = %7d. Critical = %7d. Ratio = %4.2f\n", Abc_NtkGetTotalFanins(pNtk), Counter, CounterRes, 1.0*CounterRes/Counter ); } // start the resulting network pNtkNew = Abc_NtkStrash( pNtk, 0, 1, 0 ); // collect nodes to be used for resynthesis Counter = CounterRes = 0; vTimeCries = Vec_PtrAlloc( 16 ); vTimeFanins = Vec_PtrAlloc( 16 ); Abc_NtkForEachNode( pNtk, pNode, i ) { if ( Abc_ObjSlack(pNode) >= tDelta ) continue; // count the number of non-PI timing-critical nodes nTimeCris = 0; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( !Abc_ObjIsCi(pFanin) && (puTCEdges[pNode->Id] & (1<Id] & (1<Id] & (1< Degree) ) if ( (Vec_PtrSize(vTimeCries) == 0 || Vec_PtrSize(vTimeCries) > Degree) ) continue; CounterRes++; // collect second generation nodes Vec_PtrClear( vTimeFanins ); Abc_ObjForEachFanin( pNode, pFanin, k ) { if ( Abc_ObjIsCi(pFanin) ) Vec_PtrPushUnique( vTimeFanins, pFanin ); else Abc_ObjForEachFanin( pFanin, pFanin2, k2 ) Vec_PtrPushUnique( vTimeFanins, pFanin2 ); } // print the results if ( fVeryVerbose ) { printf( "%5d Node %5d : %d %2d %2d ", Counter, pNode->Id, nTimeCris, Vec_PtrSize(vTimeCries), Vec_PtrSize(vTimeFanins) ); Abc_ObjForEachFanin( pNode, pFanin, k ) printf( "%d(%.2f)%s ", pFanin->Id, Abc_ObjSlack(pFanin), (puTCEdges[pNode->Id] & (1< Degree ) continue; // order the fanins in the increasing order of criticalily if ( Vec_PtrSize(vTimeCries) > 1 ) { pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 0 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) { Vec_PtrWriteEntry( vTimeCries, 0, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 1, pFanin ); } } if ( Vec_PtrSize(vTimeCries) > 2 ) { pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 2 ); if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) { Vec_PtrWriteEntry( vTimeCries, 1, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 2, pFanin ); } pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 0 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) { Vec_PtrWriteEntry( vTimeCries, 0, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 1, pFanin ); } } // add choice Abc_NtkSpeedupNode( pNtk, pNtkNew, pNode, vTimeFanins, vTimeCries ); } Vec_PtrFree( vTimeCries ); Vec_PtrFree( vTimeFanins ); ABC_FREE( puTCEdges ); if ( fVerbose ) printf( "Nodes: Total = %7d. 0-slack = %7d. Workable = %7d. Ratio = %4.2f\n", Abc_NtkNodeNum(pNtk), Counter, CounterRes, 1.0*CounterRes/Counter ); // remove invalid choice nodes Abc_AigForEachAnd( pNtkNew, pNode, i ) if ( pNode->pData ) { if ( Abc_ObjFanoutNum((Abc_Obj_t *)pNode->pData) > 0 ) pNode->pData = NULL; } // return the result return pNtkNew; } /**Function************************************************************* Synopsis [Marks nodes for power-optimization.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Abc_NtkPowerEstimate( Abc_Ntk_t * pNtk, int fProbOne ) { extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); extern Vec_Int_t * Saig_ManComputeSwitchProbs( Aig_Man_t * p, int nFrames, int nPref, int fProbOne ); Vec_Int_t * vProbs; Vec_Int_t * vSwitching; float * pProbability; float * pSwitching; Abc_Ntk_t * pNtkStr; Aig_Man_t * pAig; Aig_Obj_t * pObjAig; Abc_Obj_t * pObjAbc, * pObjAbc2; int i; // start the resulting array vProbs = Vec_IntStart( Abc_NtkObjNumMax(pNtk) ); pProbability = (float *)vProbs->pArray; // strash the network pNtkStr = Abc_NtkStrash( pNtk, 0, 1, 0 ); Abc_NtkForEachObj( pNtk, pObjAbc, i ) if ( Abc_ObjRegular((Abc_Obj_t *)pObjAbc->pTemp)->Type == ABC_FUNC_NONE ) pObjAbc->pTemp = NULL; // map network into an AIG pAig = Abc_NtkToDar( pNtkStr, 0, (int)(Abc_NtkLatchNum(pNtk) > 0) ); vSwitching = Saig_ManComputeSwitchProbs( pAig, 48, 16, fProbOne ); pSwitching = (float *)vSwitching->pArray; Abc_NtkForEachObj( pNtk, pObjAbc, i ) { if ( (pObjAbc2 = Abc_ObjRegular((Abc_Obj_t *)pObjAbc->pTemp)) && (pObjAig = Aig_Regular((Aig_Obj_t *)pObjAbc2->pTemp)) ) pProbability[pObjAbc->Id] = pSwitching[pObjAig->Id]; } Vec_IntFree( vSwitching ); Aig_ManStop( pAig ); Abc_NtkDelete( pNtkStr ); return vProbs; } /**Function************************************************************* Synopsis [Marks nodes for power-optimization.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Abc_NtkPowerPrint( Abc_Ntk_t * pNtk, Vec_Int_t * vProbs ) { Abc_Obj_t * pObj; float * pProb, TotalProb = 0.0, ProbThis, Probs[6] = {0.0}; int i, nNodes = 0, nEdges = 0, Counter[6] = {0}; pProb = (float *)vProbs->pArray; assert( Vec_IntSize(vProbs) >= Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachObj( pNtk, pObj, i ) { if ( !Abc_ObjIsNode(pObj) && !Abc_ObjIsPi(pObj) ) continue; nNodes++; nEdges += Abc_ObjFanoutNum(pObj); ProbThis = pProb[i] * Abc_ObjFanoutNum(pObj); TotalProb += ProbThis; assert( pProb[i] >= 0.0 && pProb[i] <= 1.0 ); if ( pProb[i] >= 0.5 ) { Counter[5]++; Probs[5] += ProbThis; } else if ( pProb[i] >= 0.4 ) { Counter[4]++; Probs[4] += ProbThis; } else if ( pProb[i] >= 0.3 ) { Counter[3]++; Probs[3] += ProbThis; } else if ( pProb[i] >= 0.2 ) { Counter[2]++; Probs[2] += ProbThis; } else if ( pProb[i] >= 0.1 ) { Counter[1]++; Probs[1] += ProbThis; } else { Counter[0]++; Probs[0] += ProbThis; } } printf( "Node distribution: " ); for ( i = 0; i < 6; i++ ) printf( "n%d%d = %6.2f%% ", i, i+1, 100.0 * Counter[i]/nNodes ); printf( "\n" ); printf( "Power distribution: " ); for ( i = 0; i < 6; i++ ) printf( "p%d%d = %6.2f%% ", i, i+1, 100.0 * Probs[i]/TotalProb ); printf( "\n" ); printf( "Total probs = %7.2f. ", TotalProb ); printf( "Total edges = %d. ", nEdges ); printf( "Average = %7.2f. ", TotalProb / nEdges ); printf( "\n" ); } /**Function************************************************************* Synopsis [Determines timing-critical edges of the node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ unsigned Abc_NtkPowerCriticalEdges( Abc_Ntk_t * pNtk, Abc_Obj_t * pNode, float Limit, Vec_Int_t * vProbs ) { Abc_Obj_t * pFanin; float * pProb = (float *)vProbs->pArray; unsigned uResult = 0; int k; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( pProb[pFanin->Id] >= Limit ) uResult |= (1 << k); return uResult; } /**Function************************************************************* Synopsis [Adds choices to speed up the network by the given percentage.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Ntk_t * Abc_NtkPowerdown( Abc_Ntk_t * pNtk, int fUseLutLib, int Percentage, int Degree, int fVerbose, int fVeryVerbose ) { Abc_Ntk_t * pNtkNew; Vec_Int_t * vProbs; Vec_Ptr_t * vTimeCries, * vTimeFanins; Abc_Obj_t * pNode, * pFanin, * pFanin2; float * pProb, Limit; int i, k, k2, Counter, CounterRes, nTimeCris; unsigned * puPCEdges; // compute the limit Limit = 0.5 - (1.0 * Percentage / 100); // perform computation of switching probability vProbs = Abc_NtkPowerEstimate( pNtk, 0 ); pProb = (float *)vProbs->pArray; // compute percentage of wires of each type if ( fVerbose ) Abc_NtkPowerPrint( pNtk, vProbs ); // mark the power critical nodes and edges puPCEdges = ABC_ALLOC( unsigned, Abc_NtkObjNumMax(pNtk) ); memset( puPCEdges, 0, sizeof(unsigned) * Abc_NtkObjNumMax(pNtk) ); Abc_NtkForEachNode( pNtk, pNode, i ) { if ( pProb[pNode->Id] < Limit ) continue; puPCEdges[pNode->Id] = Abc_NtkPowerCriticalEdges( pNtk, pNode, Limit, vProbs ); } /* if ( fVerbose ) { Counter = CounterRes = 0; Abc_NtkForEachNode( pNtk, pNode, i ) { Counter += Abc_ObjFaninNum(pNode); CounterRes += Extra_WordCountOnes( puPCEdges[pNode->Id] ); } printf( "Edges: Total = %7d. Critical = %7d. Ratio = %4.2f\n", Counter, CounterRes, 1.0*CounterRes/Counter ); } */ // start the resulting network pNtkNew = Abc_NtkStrash( pNtk, 0, 1, 0 ); // collect nodes to be used for resynthesis Counter = CounterRes = 0; vTimeCries = Vec_PtrAlloc( 16 ); vTimeFanins = Vec_PtrAlloc( 16 ); Abc_NtkForEachNode( pNtk, pNode, i ) { // if ( pProb[pNode->Id] < Limit ) // continue; // count the number of non-PI power-critical nodes nTimeCris = 0; Abc_ObjForEachFanin( pNode, pFanin, k ) if ( !Abc_ObjIsCi(pFanin) && (puPCEdges[pNode->Id] & (1<Id] & (1<Id] & (1< Degree) ) if ( (Vec_PtrSize(vTimeCries) == 0 || Vec_PtrSize(vTimeCries) > Degree) ) continue; CounterRes++; // collect second generation nodes Vec_PtrClear( vTimeFanins ); Abc_ObjForEachFanin( pNode, pFanin, k ) { if ( Abc_ObjIsCi(pFanin) ) Vec_PtrPushUnique( vTimeFanins, pFanin ); else Abc_ObjForEachFanin( pFanin, pFanin2, k2 ) Vec_PtrPushUnique( vTimeFanins, pFanin2 ); } // print the results if ( fVeryVerbose ) { printf( "%5d Node %5d : %d %2d %2d ", Counter, pNode->Id, nTimeCris, Vec_PtrSize(vTimeCries), Vec_PtrSize(vTimeFanins) ); Abc_ObjForEachFanin( pNode, pFanin, k ) printf( "%d(%.2f)%s ", pFanin->Id, pProb[pFanin->Id], (puPCEdges[pNode->Id] & (1< Degree ) continue; // order the fanins in the increasing order of criticalily if ( Vec_PtrSize(vTimeCries) > 1 ) { pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 0 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); // if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) if ( pProb[pFanin->Id] > pProb[pFanin2->Id] ) { Vec_PtrWriteEntry( vTimeCries, 0, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 1, pFanin ); } } if ( Vec_PtrSize(vTimeCries) > 2 ) { pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 2 ); // if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) if ( pProb[pFanin->Id] > pProb[pFanin2->Id] ) { Vec_PtrWriteEntry( vTimeCries, 1, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 2, pFanin ); } pFanin = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 0 ); pFanin2 = (Abc_Obj_t *)Vec_PtrEntry( vTimeCries, 1 ); // if ( Abc_ObjSlack(pFanin) < Abc_ObjSlack(pFanin2) ) if ( pProb[pFanin->Id] > pProb[pFanin2->Id] ) { Vec_PtrWriteEntry( vTimeCries, 0, pFanin2 ); Vec_PtrWriteEntry( vTimeCries, 1, pFanin ); } } // add choice Abc_NtkSpeedupNode( pNtk, pNtkNew, pNode, vTimeFanins, vTimeCries ); } Vec_PtrFree( vTimeCries ); Vec_PtrFree( vTimeFanins ); ABC_FREE( puPCEdges ); if ( fVerbose ) printf( "Nodes: Total = %7d. Power-critical = %7d. Workable = %7d. Ratio = %4.2f\n", Abc_NtkNodeNum(pNtk), Counter, CounterRes, 1.0*CounterRes/Counter ); // remove invalid choice nodes Abc_AigForEachAnd( pNtkNew, pNode, i ) if ( pNode->pData ) { if ( Abc_ObjFanoutNum((Abc_Obj_t *)pNode->pData) > 0 ) pNode->pData = NULL; } // return the result Vec_IntFree( vProbs ); return pNtkNew; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END