/**CFile****************************************************************

  FileName    [sclMan.h]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Standard-cell library representation.]

  Synopsis    [Timing/gate-sizing manager.]

  Author      [Alan Mishchenko, Niklas Een]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - August 24, 2012.]

  Revision    [$Id: sclMan.h,v 1.0 2012/08/24 00:00:00 alanmi Exp $]

***********************************************************************/

#ifndef ABC__map__scl__sclMan_h
#define ABC__map__scl__sclMan_h


////////////////////////////////////////////////////////////////////////
///                          INCLUDES                                ///
////////////////////////////////////////////////////////////////////////

#include "misc/vec/vecQue.h"

ABC_NAMESPACE_HEADER_START

////////////////////////////////////////////////////////////////////////
///                         PARAMETERS                               ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                    STRUCTURE DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

typedef struct SC_Pair_         SC_Pair;
typedef struct SC_Man_          SC_Man;

struct SC_Pair_ 
{
    float          rise;
    float          fall;
};

struct SC_Man_ 
{
    SC_Lib *       pLib;          // library
    Abc_Ntk_t *    pNtk;          // network
    int            nObjs;         // allocated size
    // get assignment
    Vec_Int_t *    vGates;        // mapping of objId into gateId
    Vec_Int_t *    vGatesBest;    // best gate sizes found so far
    Vec_Int_t *    vUpdates;      // sizing updates in this round
    // timing information
    SC_Pair *      pLoads;        // loads for each gate
    SC_Pair *      pLoads2;       // loads for each gate
    SC_Pair *      pDepts;        // departures for each gate
    SC_Pair *      pTimes;        // arrivals for each gate
    SC_Pair *      pSlews;        // slews for each gate
    SC_Pair *      pTimes2;       // arrivals for each gate
    SC_Pair *      pSlews2;       // slews for each gate
    float *        pSlack;        // slacks for each gate
    Vec_Flt_t *    vTimesOut;     // output arrival times
    Vec_Que_t *    vQue;          // outputs by their time
    SC_WireLoad *  pWLoadUsed;    // name of the used WireLoad model
    // intermediate data
    Vec_Que_t *    vNodeByGain;   // nodes by gain
    Vec_Flt_t *    vNode2Gain;    // mapping node into its gain
    Vec_Int_t *    vNode2Gate;    // mapping node into its best gate
    Vec_Int_t *    vNodeIter;     // the last iteration the node was upsized
    // optimization parameters
    float          SumArea;       // total area
    float          MaxDelay;      // max delay
    float          SumArea0;      // total area at the begining 
    float          MaxDelay0;     // max delay at the begining
    float          BestDelay;     // best delay in the middle
    // runtime statistics
    clock_t        timeTotal;     // starting/total time
    clock_t        timeCone;      // critical path selection 
    clock_t        timeSize;      // incremental sizing
    clock_t        timeTime;      // timing update
    clock_t        timeOther;     // everything else
};

////////////////////////////////////////////////////////////////////////
///                       GLOBAL VARIABLES                           ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                       MACRO DEFINITIONS                          ///
////////////////////////////////////////////////////////////////////////

static inline SC_Cell * Abc_SclObjCell( SC_Man * p, Abc_Obj_t * pObj )              { return SC_LibCell( p->pLib, Vec_IntEntry(p->vGates, Abc_ObjId(pObj)) );       }
static inline void      Abc_SclObjSetCell( SC_Man * p, Abc_Obj_t * pObj, SC_Cell * pCell ) { Vec_IntWriteEntry( p->vGates, Abc_ObjId(pObj), pCell->Id );    }

static inline SC_Pair * Abc_SclObjLoad( SC_Man * p, Abc_Obj_t * pObj )              { return p->pLoads + Abc_ObjId(pObj);  }
static inline SC_Pair * Abc_SclObjLoad2( SC_Man * p, Abc_Obj_t * pObj )             { return p->pLoads2 + Abc_ObjId(pObj); }
static inline SC_Pair * Abc_SclObjDept( SC_Man * p, Abc_Obj_t * pObj )              { return p->pDepts + Abc_ObjId(pObj);  }
static inline SC_Pair * Abc_SclObjTime( SC_Man * p, Abc_Obj_t * pObj )              { return p->pTimes + Abc_ObjId(pObj);  }
static inline SC_Pair * Abc_SclObjSlew( SC_Man * p, Abc_Obj_t * pObj )              { return p->pSlews + Abc_ObjId(pObj);  }
static inline SC_Pair * Abc_SclObjTime2( SC_Man * p, Abc_Obj_t * pObj )             { return p->pTimes2 + Abc_ObjId(pObj); }
static inline SC_Pair * Abc_SclObjSlew2( SC_Man * p, Abc_Obj_t * pObj )             { return p->pSlews2 + Abc_ObjId(pObj); }

static inline float     Abc_SclObjTimeMax( SC_Man * p, Abc_Obj_t * pObj )           { return Abc_MaxFloat(Abc_SclObjTime(p, pObj)->rise, Abc_SclObjTime(p, pObj)->fall);  }
static inline float     Abc_SclObjDepthMax( SC_Man * p, Abc_Obj_t * pObj )          { return Abc_MaxFloat(Abc_SclObjDept(p, pObj)->rise, Abc_SclObjDept(p, pObj)->fall);  }
static inline float     Abc_SclObjGetSlack( SC_Man * p, Abc_Obj_t * pObj, float D ) { return D - Abc_MaxFloat(Abc_SclObjTime(p, pObj)->rise + Abc_SclObjDept(p, pObj)->rise, Abc_SclObjTime(p, pObj)->fall + Abc_SclObjDept(p, pObj)->fall);  }
static inline float     Abc_SclObjSlack( SC_Man * p, Abc_Obj_t * pObj )             { return p->pSlack[Abc_ObjId(pObj)];   }

static inline void      Abc_SclObjDupFanin( SC_Man * p, Abc_Obj_t * pObj )          { assert( Abc_ObjIsCo(pObj) ); *Abc_SclObjTime(p, pObj) = *Abc_SclObjTime(p, Abc_ObjFanin0(pObj));  }
static inline float     Abc_SclObjGain( SC_Man * p, Abc_Obj_t * pObj )              { return (Abc_SclObjTime2(p, pObj)->rise - Abc_SclObjTime(p, pObj)->rise) + (Abc_SclObjTime2(p, pObj)->fall - Abc_SclObjTime(p, pObj)->fall); }

static inline double    Abc_SclObjLoadFf( SC_Man * p, Abc_Obj_t * pObj, int fRise ) { return SC_LibCapFf( p->pLib, fRise ? Abc_SclObjLoad(p, pObj)->rise : Abc_SclObjLoad(p, pObj)->fall); }
static inline double    Abc_SclObjTimePs( SC_Man * p, Abc_Obj_t * pObj, int fRise ) { return SC_LibTimePs(p->pLib, fRise ? Abc_SclObjTime(p, pObj)->rise : Abc_SclObjTime(p, pObj)->fall); }
static inline double    Abc_SclObjSlewPs( SC_Man * p, Abc_Obj_t * pObj, int fRise ) { return SC_LibTimePs(p->pLib, fRise ? Abc_SclObjSlew(p, pObj)->rise : Abc_SclObjSlew(p, pObj)->fall); }

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    [Constructor/destructor of STA manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline SC_Man * Abc_SclManAlloc( SC_Lib * pLib, Abc_Ntk_t * pNtk )
{
    SC_Man * p;
    int i;
    assert( Abc_NtkHasMapping(pNtk) );
    p = ABC_CALLOC( SC_Man, 1 );
    p->pLib      = pLib;
    p->pNtk      = pNtk;
    p->nObjs     = Abc_NtkObjNumMax(pNtk);
    p->pLoads    = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pLoads2   = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pDepts    = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pTimes    = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pSlews    = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pTimes2   = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pSlews2   = ABC_CALLOC( SC_Pair, p->nObjs );
    p->pSlack    = ABC_FALLOC( float, p->nObjs );
    p->vTimesOut = Vec_FltStart( Abc_NtkCoNum(pNtk) );
    p->vQue      = Vec_QueAlloc( Abc_NtkCoNum(pNtk) );
    Vec_QueSetCosts( p->vQue, Vec_FltArray(p->vTimesOut) );
    for ( i = 0; i < Abc_NtkCoNum(pNtk); i++ )
        Vec_QuePush( p->vQue, i );
    p->vUpdates  = Vec_IntAlloc( 1000 );
    // intermediate data
    p->vNode2Gain  = Vec_FltStart( p->nObjs );
    p->vNode2Gate  = Vec_IntStart( p->nObjs );
    p->vNodeByGain = Vec_QueAlloc( p->nObjs );
    Vec_QueSetCosts( p->vNodeByGain, Vec_FltArray(p->vNode2Gain) );
    p->vNodeIter   = Vec_IntStartFull( p->nObjs );
    return p;
}
static inline void Abc_SclManFree( SC_Man * p )
{
    Vec_IntFreeP( &p->vNodeIter );
    Vec_QueFreeP( &p->vNodeByGain );
    Vec_FltFreeP( &p->vNode2Gain );
    Vec_IntFreeP( &p->vNode2Gate );
    // intermediate data
    Vec_IntFreeP( &p->vUpdates );
    Vec_IntFreeP( &p->vGatesBest );
//    Vec_QuePrint( p->vQue );
    Vec_QueCheck( p->vQue );
    Vec_QueFreeP( &p->vQue );
    Vec_FltFreeP( &p->vTimesOut );
    Vec_IntFreeP( &p->vGates );
    ABC_FREE( p->pLoads );
    ABC_FREE( p->pLoads2 );
    ABC_FREE( p->pDepts );
    ABC_FREE( p->pTimes );
    ABC_FREE( p->pSlews );
    ABC_FREE( p->pTimes2 );
    ABC_FREE( p->pSlews2 );
    ABC_FREE( p->pSlack );
    ABC_FREE( p );
}
static inline void Abc_SclManCleanTime( SC_Man * p )
{
    memset( p->pDepts, 0, sizeof(SC_Pair) * p->nObjs );
    memset( p->pTimes, 0, sizeof(SC_Pair) * p->nObjs );
    memset( p->pSlews, 0, sizeof(SC_Pair) * p->nObjs );
}


/**Function*************************************************************

  Synopsis    [Stores/retrivies timing information for the logic cone.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Abc_SclConeStore( SC_Man * p, Vec_Int_t * vCone )
{
    Abc_Obj_t * pObj;
    int i;
    Abc_NtkForEachObjVec( vCone, p->pNtk, pObj, i )
    {
        *Abc_SclObjTime2(p, pObj) = *Abc_SclObjTime(p, pObj);
        *Abc_SclObjSlew2(p, pObj) = *Abc_SclObjSlew(p, pObj);
    }
}
static inline void Abc_SclConeRestore( SC_Man * p, Vec_Int_t * vCone )
{
    Abc_Obj_t * pObj;
    int i;
    Abc_NtkForEachObjVec( vCone, p->pNtk, pObj, i )
    {
        *Abc_SclObjTime(p, pObj) = *Abc_SclObjTime2(p, pObj);
        *Abc_SclObjSlew(p, pObj) = *Abc_SclObjSlew2(p, pObj);
    }
}
static inline void Abc_SclConeClear( SC_Man * p, Vec_Int_t * vCone )
{
    SC_Pair Zero = { 0.0, 0.0 };
    Abc_Obj_t * pObj;
    int i;
    Abc_NtkForEachObjVec( vCone, p->pNtk, pObj, i )
    {
        *Abc_SclObjTime(p, pObj) = Zero;
        *Abc_SclObjSlew(p, pObj) = Zero;
    }
}

/**Function*************************************************************

  Synopsis    [Stores/retrivies load information.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Abc_SclLoadStore( SC_Man * p, Abc_Obj_t * pObj )
{
    Abc_Obj_t * pFanin;
    int i;
    Abc_ObjForEachFanin( pObj, pFanin, i )
        *Abc_SclObjLoad2(p, pFanin) = *Abc_SclObjLoad(p, pFanin);
}
static inline void Abc_SclLoadRestore( SC_Man * p, Abc_Obj_t * pObj )
{
    Abc_Obj_t * pFanin;
    int i;
    Abc_ObjForEachFanin( pObj, pFanin, i )
        *Abc_SclObjLoad(p, pFanin) = *Abc_SclObjLoad2(p, pFanin);
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline float Abc_SclGetTotalArea( SC_Man * p )
{
    double Area = 0;
    Abc_Obj_t * pObj;
    int i;
    Abc_NtkForEachNode1( p->pNtk, pObj, i )
        Area += Abc_SclObjCell( p, pObj )->area;
    return Area;
}
static inline float Abc_SclGetMaxDelay( SC_Man * p )
{
    float fMaxArr = 0;
    Abc_Obj_t * pObj;
    int i;
    Abc_NtkForEachCo( p->pNtk, pObj, i )
        fMaxArr = Abc_MaxFloat( fMaxArr, Abc_SclObjTimeMax(p, pObj) );
    return fMaxArr;
}
static inline float Abc_SclGetMaxDelayNodeFanins( SC_Man * p, Abc_Obj_t * pNode )
{
    float fMaxArr = 0;
    Abc_Obj_t * pObj;
    int i;
    assert( Abc_ObjIsNode(pNode) );
    Abc_ObjForEachFanin( pNode, pObj, i )
        fMaxArr = Abc_MaxFloat( fMaxArr, Abc_SclObjTimeMax(p, pObj) );
    return fMaxArr;
}
static inline float Abc_SclReadMaxDelay( SC_Man * p )
{
    return Abc_SclObjTimeMax( p, Abc_NtkPo(p->pNtk, Vec_QueTop(p->vQue)) );
}

/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline SC_Cell * Abc_SclObjResiable( SC_Man * p, Abc_Obj_t * pObj, int fUpsize )
{
    SC_Cell * pOld = Abc_SclObjCell( p, pObj );
    if ( fUpsize )
        return pOld->pNext->Order > pOld->Order ? pOld->pNext : NULL;
    else
        return pOld->pPrev->Order < pOld->Order ? pOld->pPrev : NULL;
}

/**Function*************************************************************

  Synopsis    [Dumps timing results into a file.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline void Abc_SclDumpStats( SC_Man * p, char * pFileName, clock_t Time )
{
    FILE * pTable;
    pTable = fopen( pFileName, "a+" );
    fprintf( pTable, "%s ", p->pNtk->pName );
    fprintf( pTable, "%d ", Abc_NtkPiNum(p->pNtk) );
    fprintf( pTable, "%d ", Abc_NtkPoNum(p->pNtk) );
    fprintf( pTable, "%d ", Abc_NtkNodeNum(p->pNtk) );
    fprintf( pTable, "%d ", (int)p->SumArea );
    fprintf( pTable, "%d ", (int)SC_LibTimePs(p->pLib, p->MaxDelay) );
    fprintf( pTable, "%.2f ", 1.0*Time/CLOCKS_PER_SEC );
    fprintf( pTable, "\n" );
    fclose( pTable );
}


/*=== sclTime.c =============================================================*/
extern Abc_Obj_t * Abc_SclFindCriticalCo( SC_Man * p, int * pfRise );
extern Abc_Obj_t * Abc_SclFindMostCriticalFanin( SC_Man * p, int * pfRise, Abc_Obj_t * pNode );
extern void        Abc_SclTimeNtkPrint( SC_Man * p, int fShowAll, int fShort );
extern SC_Man *    Abc_SclManStart( SC_Lib * pLib, Abc_Ntk_t * pNtk, int fUseWireLoads, int fDept );
extern void        Abc_SclTimeCone( SC_Man * p, Vec_Int_t * vCone );
extern void        Abc_SclTimeNtkRecompute( SC_Man * p, float * pArea, float * pDelay, int fReverse );
/*=== sclTime.c =============================================================*/
extern void        Abc_SclComputeLoad( SC_Man * p );
extern void        Abc_SclUpdateLoad( SC_Man * p, Abc_Obj_t * pObj, SC_Cell * pOld, SC_Cell * pNew );


ABC_NAMESPACE_HEADER_END

#endif

////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////
