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

  FileName    [sclUtil.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Standard-cell library representation.]

  Synopsis    [Various utilities.]

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

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

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

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

#include "sclSize.h"
#include "map/mio/mio.h"
#include "base/main/main.h"

ABC_NAMESPACE_IMPL_START


////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

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

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

  Synopsis    [Converts pNode->pData gates into array of SC_Lit gate IDs and back.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_SclMioGates2SclGates( SC_Lib * pLib, Abc_Ntk_t * p )
{
    Abc_Obj_t * pObj;
    int i, gateId, bufferId;
    // find buffer
    if ( Mio_LibraryReadBuf((Mio_Library_t *)p->pManFunc) == NULL )
    {
        printf( "Cannot find buffer in the current library. Quitting.\n" );
        return;
    }
    bufferId = Abc_SclCellFind( pLib, Mio_GateReadName(Mio_LibraryReadBuf((Mio_Library_t *)p->pManFunc)) );
    assert( bufferId >= 0 );
    // remap cells
    assert( p->vGates == NULL );
    p->vGates = Vec_IntStartFull( Abc_NtkObjNumMax(p) );
    Abc_NtkForEachNodeNotBarBuf1( p, pObj, i )
    {
        gateId = Abc_SclCellFind( pLib, Mio_GateReadName((Mio_Gate_t *)pObj->pData) );
        assert( gateId >= 0 );
        Vec_IntWriteEntry( p->vGates, i, gateId );
    }
    p->pSCLib = pLib;
}
void Abc_SclSclGates2MioGates( SC_Lib * pLib, Abc_Ntk_t * p )
{
    Abc_Obj_t * pObj;
    SC_Cell * pCell;
    int i, Counter = 0, CounterAll = 0;
    assert( p->vGates != NULL );
    Abc_NtkForEachNodeNotBarBuf1( p, pObj, i )
    {
        pCell = Abc_SclObjCell(pObj);
        assert( pCell->n_inputs == Abc_ObjFaninNum(pObj) );
        pObj->pData = Mio_LibraryReadGateByName( (Mio_Library_t *)p->pManFunc, pCell->pName, NULL );
        Counter += (pObj->pData == NULL);
        assert( pObj->fMarkA == 0 && pObj->fMarkB == 0 );
        CounterAll++;
    }
    if ( Counter )
        printf( "Could not find %d (out of %d) gates in the current library.\n", Counter, CounterAll );
    Vec_IntFreeP( &p->vGates );
    p->pSCLib = NULL;
}

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

  Synopsis    [Transfer gate sizes from AIG without barbufs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_SclTransferGates( Abc_Ntk_t * pOld, Abc_Ntk_t * pNew )
{
    Abc_Obj_t * pObj; int i;
    assert( pOld->nBarBufs2 > 0 );
    assert( pNew->nBarBufs2 == 0 );
    Abc_NtkForEachNodeNotBarBuf( pOld, pObj, i )
    {
        if ( pObj->pCopy == NULL )
            continue;
        assert( Abc_ObjNtk(pObj->pCopy) == pNew );
        pObj->pData = pObj->pCopy->pData;
    }
}

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

  Synopsis    [Reports percentage of gates of each size.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
#define ABC_SCL_MAX_SIZE 64
void Abc_SclManPrintGateSizes( SC_Lib * pLib, Abc_Ntk_t * p, Vec_Int_t * vGates )
{
    Abc_Obj_t * pObj;
    SC_Cell * pCell;
    int i, nGates = 0, Counters[ABC_SCL_MAX_SIZE] = {0};
    double TotArea = 0, Areas[ABC_SCL_MAX_SIZE] = {0};
    Abc_NtkForEachNodeNotBarBuf1( p, pObj, i )
    {
        pCell = SC_LibCell( pLib, Vec_IntEntry(vGates, Abc_ObjId(pObj)) );
        assert( pCell->Order < ABC_SCL_MAX_SIZE );
        Counters[pCell->Order]++;
        Areas[pCell->Order] += pCell->area;
        TotArea += pCell->area;
        nGates++;
    }
    printf( "Total gates = %d.  Total area = %.1f\n", nGates, TotArea );
    for ( i = 0; i < ABC_SCL_MAX_SIZE; i++ )
    {
        if ( Counters[i] == 0 )
            continue;
        printf( "Cell size = %d.  ", i );
        printf( "Count = %6d  ",     Counters[i] );
        printf( "(%5.1f %%)   ",     100.0 * Counters[i] / nGates );
        printf( "Area = %12.1f  ",   Areas[i] );
        printf( "(%5.1f %%)  ",      100.0 * Areas[i] / TotArea );
        printf( "\n" );
    }
}
void Abc_SclPrintGateSizes( SC_Lib * pLib, Abc_Ntk_t * p )
{
    Abc_SclMioGates2SclGates( pLib, p );
    Abc_SclManPrintGateSizes( pLib, p, p->vGates );
    Abc_SclSclGates2MioGates( pLib, p );
    Vec_IntFreeP( &p->vGates );
    p->pSCLib = NULL;
}

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

  Synopsis    [Downsizes each gate to its minimium size.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
SC_Cell * Abc_SclFindMaxAreaCell( SC_Cell * pRepr )
{
    SC_Cell * pCell, * pBest = pRepr;
    float AreaBest = pRepr->area;
    int i;
    SC_RingForEachCell( pRepr, pCell, i )
        if ( AreaBest < pCell->area )
        {
            AreaBest = pCell->area;
            pBest = pCell;
        }
    return pBest;
}
Vec_Int_t * Abc_SclFindMinAreas( SC_Lib * pLib, int fUseMax )
{
    Vec_Int_t * vMinCells;
    SC_Cell * pCell, * pRepr = NULL, * pBest = NULL;
    int i, k;
    // map each gate in the library into its min/max-size prototype
    vMinCells = Vec_IntStartFull( Vec_PtrSize(&pLib->vCells) );
    SC_LibForEachCellClass( pLib, pRepr, i )
    {
        pBest = fUseMax ? Abc_SclFindMaxAreaCell(pRepr) : pRepr;
        SC_RingForEachCell( pRepr, pCell, k )
            Vec_IntWriteEntry( vMinCells, pCell->Id, pBest->Id );
    }
    return vMinCells;
}
void Abc_SclMinsizePerform( SC_Lib * pLib, Abc_Ntk_t * p, int fUseMax, int fVerbose )
{
    Vec_Int_t * vMinCells;
    Abc_Obj_t * pObj;
    int i, gateId;
    vMinCells = Abc_SclFindMinAreas( pLib, fUseMax );
    Abc_SclMioGates2SclGates( pLib, p );
    Abc_NtkForEachNodeNotBarBuf1( p, pObj, i )
    {
        gateId = Vec_IntEntry( p->vGates, i );
        assert( gateId >= 0 && gateId < Vec_PtrSize(&pLib->vCells) );
        gateId = Vec_IntEntry( vMinCells, gateId );
        assert( gateId >= 0 && gateId < Vec_PtrSize(&pLib->vCells) );
        Vec_IntWriteEntry( p->vGates, i, gateId );
    }
    Abc_SclSclGates2MioGates( pLib, p );
    Vec_IntFree( vMinCells );
}
int Abc_SclCountMinSize( SC_Lib * pLib, Abc_Ntk_t * p, int fUseMax )
{
    Vec_Int_t * vMinCells;
    Abc_Obj_t * pObj;
    int i, gateId, Counter = 0;
    vMinCells = Abc_SclFindMinAreas( pLib, fUseMax );
    Abc_NtkForEachNodeNotBarBuf1( p, pObj, i )
    {
        gateId = Vec_IntEntry( p->vGates, i );
        Counter += ( gateId == Vec_IntEntry(vMinCells, gateId) );
    }
    Vec_IntFree( vMinCells );
    return Counter;
}

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

  Synopsis    [Reads timing constraints.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_SclReadTimingConstr( Abc_Frame_t * pAbc, char * pFileName, int fVerbose )
{
    char Buffer[1000], * pToken;
    FILE * pFile = fopen( pFileName, "rb" );
    while ( fgets( Buffer, 1000, pFile ) )
    {
        pToken = strtok( Buffer, " \t\r\n" );
        if ( pToken == NULL )
            continue;
        if ( !strcmp(pToken, "set_driving_cell") )
//        if ( !strcmp(pToken, "default_input_cell") )
        {
            Abc_FrameSetDrivingCell( Abc_UtilStrsav(strtok(NULL, " \t\r\n")) );
            if ( fVerbose ) 
                printf( "Setting driving cell to be \"%s\".\n", Abc_FrameReadDrivingCell() );
        }
        else if ( !strcmp(pToken, "set_load") )
//        else if ( !strcmp(pToken, "default_output_load") )
        {
            Abc_FrameSetMaxLoad( atof(strtok(NULL, " \t\r\n")) );
            if ( fVerbose ) 
                printf( "Setting output load to be %f.\n", Abc_FrameReadMaxLoad() );
        }
        else printf( "Unrecognized token \"%s\".\n", pToken );
    }
    fclose( pFile );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Vec_Int_t * Abc_SclExtractBarBufs( Abc_Ntk_t * pNtk )
{
    Vec_Int_t * vBufs;
    Mio_Gate_t * pBuffer;
    Abc_Obj_t * pObj; int i;
    pBuffer = Mio_LibraryReadBuf( (Mio_Library_t *)pNtk->pManFunc );
    if ( pBuffer == NULL )
    {
        printf( "Cannot find buffer in the current library. Quitting.\n" );
        return NULL;
    }
    vBufs = Vec_IntAlloc( 100 );
    Abc_NtkForEachBarBuf( pNtk, pObj, i )
    {
        assert( pObj->pData == NULL );
        pObj->pData = pBuffer;
        Vec_IntPush( vBufs, i );
    }
    return vBufs;
}
void Abc_SclInsertBarBufs( Abc_Ntk_t * pNtk, Vec_Int_t * vBufs )
{
    Abc_Obj_t * pObj; int i;
    Abc_NtkForEachObjVec( vBufs, pNtk, pObj, i )
        pObj->pData = NULL;
}

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


ABC_NAMESPACE_IMPL_END