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

  FileName    [timMan.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Hierarchy/timing manager.]

  Synopsis    [Manipulation of manager data-structure.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - April 28, 2007.]

  Revision    [$Id: timMan.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $]

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

#include "timInt.h"

ABC_NAMESPACE_IMPL_START

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

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

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

  Synopsis    [Starts the timing manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Tim_Man_t * Tim_ManStart( int nCis, int nCos )
{
    Tim_Man_t * p;
    Tim_Obj_t * pObj;
    int i;
    p = ABC_ALLOC( Tim_Man_t, 1 );
    memset( p, 0, sizeof(Tim_Man_t) );
    p->pMemObj = Mem_FlexStart();
    p->nCis = nCis;
    p->nCos = nCos;
    p->pCis = ABC_ALLOC( Tim_Obj_t, nCis );
    memset( p->pCis, 0, sizeof(Tim_Obj_t) * nCis );
    p->pCos = ABC_ALLOC( Tim_Obj_t, nCos );
    memset( p->pCos, 0, sizeof(Tim_Obj_t) * nCos );
    Tim_ManForEachCi( p, pObj, i )
    {
        pObj->Id = i;
        pObj->iObj2Box = pObj->iObj2Num = -1;
        pObj->timeReq = TIM_ETERNITY;
    }
    Tim_ManForEachCo( p, pObj, i )
    {
        pObj->Id = i;
        pObj->iObj2Box = pObj->iObj2Num = -1;
        pObj->timeReq = TIM_ETERNITY;
    }
    p->fUseTravId = 1;
    return p;
}

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

  Synopsis    [Duplicates the timing manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Tim_Man_t * Tim_ManDup( Tim_Man_t * p, int fUnitDelay )
{
    Tim_Man_t * pNew;
    Tim_Box_t * pBox;
    Tim_Obj_t * pObj;
    float * pDelayTable, * pDelayTableNew;
    int i, k, nInputs, nOutputs;
    // create new manager
    pNew = Tim_ManStart( p->nCis, p->nCos );
    // copy box connectivity information
    memcpy( pNew->pCis, p->pCis, sizeof(Tim_Obj_t) * p->nCis );
    memcpy( pNew->pCos, p->pCos, sizeof(Tim_Obj_t) * p->nCos );
    // clear traversal IDs
    Tim_ManForEachCi( p, pObj, i )
        pObj->TravId = 0;
    Tim_ManForEachCo( p, pObj, i )
        pObj->TravId = 0;
    if ( fUnitDelay )
    {
        // discretize PI arrival times
//        Tim_ManForEachPi( pNew, pObj, k )
//          pObj->timeArr = (int)pObj->timeArr;
        // discretize PO required times
//        Tim_ManForEachPo( pNew, pObj, k )
//          pObj->timeReq = 1 + (int)pObj->timeReq;
        // clear PI arrival and PO required
        Tim_ManInitPiArrivalAll( p, 0.0 );
        Tim_ManInitPoRequiredAll( p, (float)TIM_ETERNITY );
    }
    // duplicate delay tables
    if ( Tim_ManDelayTableNum(p) > 0 )
    {
        pNew->vDelayTables = Vec_PtrAlloc( Vec_PtrSize(p->vDelayTables) );
        Tim_ManForEachTable( p, pDelayTable, i )
        {
            assert( i == (int)pDelayTable[0] );
            nInputs   = (int)pDelayTable[1];
            nOutputs  = (int)pDelayTable[2];
            pDelayTableNew = ABC_ALLOC( float, 3 + nInputs * nOutputs );
            pDelayTableNew[0] = (int)pDelayTable[0];
            pDelayTableNew[1] = (int)pDelayTable[1];
            pDelayTableNew[2] = (int)pDelayTable[2];
            for ( k = 0; k < nInputs * nOutputs; k++ )
                pDelayTableNew[3+k] = fUnitDelay ? 1.0 : pDelayTable[3+k];
            assert( (int)pDelayTableNew[0] == Vec_PtrSize(pNew->vDelayTables) );
            Vec_PtrPush( pNew->vDelayTables, pDelayTableNew );
        }
    }
    // duplicate boxes
    if ( Tim_ManBoxNum(p) > 0 )
    {
        pNew->vBoxes = Vec_PtrAlloc( Tim_ManBoxNum(p) );
        Tim_ManForEachBox( p, pBox, i )
           Tim_ManCreateBox( pNew, pBox->Inouts[0], pBox->nInputs, 
                pBox->Inouts[pBox->nInputs], pBox->nOutputs, pBox->iDelayTable );
    }
    return pNew;
}

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

  Synopsis    [Stops the timing manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tim_ManStop( Tim_Man_t * p )
{
    Vec_PtrFreeFree( p->vDelayTables );
    Vec_PtrFreeP( &p->vBoxes );
    Mem_FlexStop( p->pMemObj, 0 );
    ABC_FREE( p->pCis );
    ABC_FREE( p->pCos );
    ABC_FREE( p );
}
void Tim_ManStopP( Tim_Man_t ** p )
{
    if ( *p == NULL )
        return;
    Tim_ManStop( *p );
    *p = NULL;
}

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

  Synopsis    [Prints the timing manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tim_ManPrint( Tim_Man_t * p )
{
    Tim_Box_t * pBox;
    Tim_Obj_t * pObj, * pPrev;
    float * pTable;
    int i, j, k, TableX, TableY;
    if ( p == NULL )
        return;
    printf( "TIMING MANAGER:\n" );

    // print CI info
    pPrev = p->pCis;
    Tim_ManForEachPi( p, pObj, i )
        if ( pPrev->timeArr != pObj->timeArr || pPrev->timeReq != pObj->timeReq )
            break;
    if ( i == Tim_ManCiNum(p) )
        printf( "All PIs :  arr = %5.3f  req = %5.3f\n", pPrev->timeArr, pPrev->timeReq );
    else
        Tim_ManForEachPi( p, pObj, i )
            printf( "PI%5d :  arr = %5.3f  req = %5.3f\n", i, pObj->timeArr, pObj->timeReq );

    // print CO info
    pPrev = p->pCos;
    Tim_ManForEachPo( p, pObj, i )
        if ( pPrev->timeArr != pObj->timeArr || pPrev->timeReq != pObj->timeReq )
            break;
    if ( i == Tim_ManCoNum(p) )
        printf( "All POs :  arr = %5.3f  req = %5.3f\n", pPrev->timeArr, pPrev->timeReq );
    else
        Tim_ManForEachPo( p, pObj, i )
            printf( "PO%5d :  arr = %5.3f  req = %5.3f\n", i, pObj->timeArr, pObj->timeReq );

    // print box info
    if ( Tim_ManBoxNum(p) > 0 )
    Tim_ManForEachBox( p, pBox, i )
    {
        printf( "*** Box %5d :  I =%4d. O =%4d. I1 =%6d. O1 =%6d. Table =%4d\n", 
            i, pBox->nInputs, pBox->nOutputs, 
            Tim_ManBoxInputFirst(p, i), Tim_ManBoxOutputFirst(p, i), 
            pBox->iDelayTable );

        // print box inputs
        pPrev = Tim_ManBoxInput( p, pBox, 0 );
        Tim_ManBoxForEachInput( p, pBox, pObj, k )
            if ( pPrev->timeArr != pObj->timeArr || pPrev->timeReq != pObj->timeReq )
                break;
        if ( k == Tim_ManBoxInputNum(p, pBox->iBox) )
            printf( "Box inputs  :  arr = %5.3f  req = %5.3f\n", pPrev->timeArr, pPrev->timeReq );
        else
            Tim_ManBoxForEachInput( p, pBox, pObj, k )
                printf( "box-in%4d :  arr = %5.3f  req = %5.3f\n", k, pObj->timeArr, pObj->timeReq );

        // print box outputs
        pPrev = Tim_ManBoxOutput( p, pBox, 0 );
        Tim_ManBoxForEachOutput( p, pBox, pObj, k )
            if ( pPrev->timeArr != pObj->timeArr || pPrev->timeReq != pObj->timeReq )
                break;
        if ( k == Tim_ManBoxOutputNum(p, pBox->iBox) )
            printf( "Box outputs :  arr = %5.3f  req = %5.3f\n", pPrev->timeArr, pPrev->timeReq );
        else
            Tim_ManBoxForEachOutput( p, pBox, pObj, k )
                printf( "box-out%3d :  arr = %5.3f  req = %5.3f\n", k, pObj->timeArr, pObj->timeReq );
    }

    // print delay tables
    if ( Tim_ManDelayTableNum(p) > 0 )
    Tim_ManForEachTable( p, pTable, i )
    {
        printf( "Delay table %d:\n", i );
        assert( i == (int)pTable[0] );
        TableX = (int)pTable[1];
        TableY = (int)pTable[2];
        for ( j = 0; j < TableY; j++, printf( "\n" ) )
            for ( k = 0; k < TableX; k++ )
                if ( pTable[3+j*TableX+k] == -ABC_INFINITY )
                    printf( "%5s", "-" );
                else
                    printf( "%5.0f", pTable[3+j*TableX+k] );
    }
    printf( "\n" );
}

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

  Synopsis    [Read parameters.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Tim_ManCiNum( Tim_Man_t * p )
{
    return p->nCis;
}
int Tim_ManCoNum( Tim_Man_t * p )
{
    return p->nCos;
}
int Tim_ManPiNum( Tim_Man_t * p )
{
    if ( Tim_ManBoxNum(p) == 0 )
        return Tim_ManCiNum(p);
    return Tim_ManBoxOutputFirst(p, 0);
}
int Tim_ManPoNum( Tim_Man_t * p )
{
    int iLastBoxId;
    if ( Tim_ManBoxNum(p) == 0 )
        return Tim_ManCoNum(p);
    iLastBoxId = Tim_ManBoxNum(p) - 1;
    return Tim_ManCoNum(p) - (Tim_ManBoxInputFirst(p, iLastBoxId) + Tim_ManBoxInputNum(p, iLastBoxId));
}
int Tim_ManBoxNum( Tim_Man_t * p )
{
    return p->vBoxes ? Vec_PtrSize(p->vBoxes) : 0;
}
int Tim_ManDelayTableNum( Tim_Man_t * p )
{
    return p->vDelayTables ? Vec_PtrSize(p->vDelayTables) : 0;
}

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

  Synopsis    [Sets the vector of timing tables associated with the manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tim_ManSetDelayTables( Tim_Man_t * p, Vec_Ptr_t * vDelayTables )
{
    assert( p->vDelayTables == NULL );
    p->vDelayTables = vDelayTables;
}

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

  Synopsis    [Disables the use of the traversal ID.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tim_ManTravIdDisable( Tim_Man_t * p )
{
    p->fUseTravId = 0;
}

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

  Synopsis    [Enables the use of the traversal ID.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Tim_ManTravIdEnable( Tim_Man_t * p )
{
    p->fUseTravId = 1;
}

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


ABC_NAMESPACE_IMPL_END

