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

  FileName    [fpgaCutUtils.c]

  PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]

  Synopsis    [Generic technology mapping engine.]

  Author      [MVSIS Group]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 2.0. Started - August 18, 2004.]

  Revision    [$Id: fpgaCutUtils.h,v 1.0 2003/09/08 00:00:00 alanmi Exp $]

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

#include "fpgaInt.h"

ABC_NAMESPACE_IMPL_START


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

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

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

  Synopsis    [Allocates the cut.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fpga_Cut_t * Fpga_CutAlloc( Fpga_Man_t * p )
{
    Fpga_Cut_t * pCut;
    pCut = (Fpga_Cut_t *)Extra_MmFixedEntryFetch( p->mmCuts );
    memset( pCut, 0, sizeof(Fpga_Cut_t) );
    return pCut;
}

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

  Synopsis    [Duplicates the cut.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fpga_Cut_t * Fpga_CutDup( Fpga_Man_t * p, Fpga_Cut_t * pCutOld )
{
    Fpga_Cut_t * pCutNew;
    int i;
    pCutNew = Fpga_CutAlloc( p );
    pCutNew->pRoot   = pCutOld->pRoot;
    pCutNew->nLeaves = pCutOld->nLeaves;
    for ( i = 0; i < pCutOld->nLeaves; i++ )
        pCutNew->ppLeaves[i] = pCutOld->ppLeaves[i];
    return pCutNew;
}

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

  Synopsis    [Deallocates the cut.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fpga_CutFree( Fpga_Man_t * p, Fpga_Cut_t * pCut )
{
    if ( pCut )
    Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pCut );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fpga_CutPrint( Fpga_Man_t * p, Fpga_Node_t * pRoot, Fpga_Cut_t * pCut )
{
    int i;
    printf( "CUT:  Delay = %4.2f. Area = %4.2f. Nodes = %d -> {", 
        pCut->tArrival, pCut->aFlow, pRoot->Num );
    for ( i = 0; i < pCut->nLeaves; i++ )
        printf( " %d", pCut->ppLeaves[i]->Num );
    printf( " } \n" );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fpga_Cut_t * Fpga_CutCreateSimple( Fpga_Man_t * p, Fpga_Node_t * pNode )
{
    Fpga_Cut_t * pCut;
    pCut = Fpga_CutAlloc( p );
    pCut->pRoot       = pNode;
    pCut->nLeaves     = 1;
    pCut->ppLeaves[0] = pNode;
    pCut->uSign = FPGA_SEQ_SIGN(pCut->ppLeaves[0]);
    return pCut;
}


/**function*************************************************************

  synopsis    [Computes the exact area associated with the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutGetRootArea( Fpga_Man_t * p, Fpga_Cut_t * pCut )
{
    return p->pLutLib->pLutAreas[(int)pCut->nLeaves];
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fpga_Cut_t * Fpga_CutListAppend( Fpga_Cut_t * pSetAll, Fpga_Cut_t * pSets )
{
    Fpga_Cut_t * pPrev = NULL; // Suppress "might be used uninitialized"
    Fpga_Cut_t * pTemp;
    if ( pSetAll == NULL )
        return pSets;
    if ( pSets == NULL )
        return pSetAll;
    // find the last one
    for ( pTemp = pSets; pTemp; pTemp = pTemp->pNext )
        pPrev = pTemp;
    // append all the end of the current set
    assert( pPrev->pNext == NULL );
    pPrev->pNext = pSetAll;
    return pSets;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fpga_CutListRecycle( Fpga_Man_t * p, Fpga_Cut_t * pSetList, Fpga_Cut_t * pSave )
{
    Fpga_Cut_t * pNext, * pTemp;
    for ( pTemp = pSetList, pNext = pTemp? pTemp->pNext : NULL; 
          pTemp; 
          pTemp = pNext, pNext = pNext? pNext->pNext : NULL )
        if ( pTemp != pSave )
            Extra_MmFixedEntryRecycle( p->mmCuts, (char *)pTemp );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Fpga_CutListCount( Fpga_Cut_t * pSets )
{
    Fpga_Cut_t * pTemp;
    int i;
    for ( i = 0, pTemp = pSets; pTemp; pTemp = pTemp->pNext, i++ );
    return i;
}

#if 0

/**function*************************************************************

  synopsis    [Removes the fanouts of the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
void Fpga_CutRemoveFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut )
{
    Fpga_NodeVec_t * vFanouts;
    int i, k;
    for ( i = 0; i < pCut->nLeaves; i++ )
    {
        vFanouts = pCut->ppLeaves[i]->vFanouts;
        for ( k = 0; k < vFanouts->nSize; k++ )
            if ( vFanouts->pArray[k] == pNode )
                break;
        assert( k != vFanouts->nSize );
        for ( k++; k < vFanouts->nSize; k++ )
            vFanouts->pArray[k-1] = vFanouts->pArray[k];
        vFanouts->nSize--;
    }
}

/**function*************************************************************

  synopsis    [Removes the fanouts of the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
void Fpga_CutInsertFanouts( Fpga_Man_t * p, Fpga_Node_t * pNode, Fpga_Cut_t * pCut )
{
    int i;
    for ( i = 0; i < pCut->nLeaves; i++ )
        Fpga_NodeVecPush( pCut->ppLeaves[i]->vFanouts, pNode );
}
#endif

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

  Synopsis    [Computes the arrival time and the area flow of the cut.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fpga_CutGetParameters( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
{
    Fpga_Cut_t * pFaninCut;
    int i;
    pCut->tArrival = -FPGA_FLOAT_LARGE;
    pCut->aFlow    = pMan->pLutLib->pLutAreas[(int)pCut->nLeaves];
    for ( i = 0; i < pCut->nLeaves; i++ )
    {
        pFaninCut = pCut->ppLeaves[i]->pCutBest;
        if ( pCut->tArrival < pFaninCut->tArrival )
             pCut->tArrival = pFaninCut->tArrival;
        // if the fanout count is not set, assume it to be 1
        if ( pCut->ppLeaves[i]->nRefs == 0 )
            pCut->aFlow += pFaninCut->aFlow;
        else
//            pCut->aFlow += pFaninCut->aFlow / pCut->ppLeaves[i]->nRefs;
            pCut->aFlow += pFaninCut->aFlow / pCut->ppLeaves[i]->aEstFanouts;
    }
    // use the first pin to compute the delay of the LUT 
    // (this mapper does not support the variable pin delay model)
    pCut->tArrival += pMan->pLutLib->pLutDelays[(int)pCut->nLeaves][0];
}


/**function*************************************************************

  synopsis    [Computes the area flow of the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutGetAreaFlow( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
{
    Fpga_Cut_t * pCutFanin;
    int i;
    pCut->aFlow = pMan->pLutLib->pLutAreas[(int)pCut->nLeaves];
    for ( i = 0; i < pCut->nLeaves; i++ )
    {
        // get the cut implementing this phase of the fanin
        pCutFanin  = pCut->ppLeaves[i]->pCutBest;   
        assert( pCutFanin );
        pCut->aFlow  += pCutFanin->aFlow / pCut->ppLeaves[i]->nRefs;
    }
    return pCut->aFlow;
}

/**function*************************************************************

  synopsis    [Computes the exact area associated with the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutGetAreaRefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
{
    float aResult, aResult2;
    if ( pCut->nLeaves == 1 )
        return 0;
    aResult  = Fpga_CutDeref( pMan, NULL, pCut, 0 );
    aResult2 = Fpga_CutRef( pMan, NULL, pCut, 0 );
    assert( Fpga_FloatEqual( pMan, aResult, aResult2 ) );
    return aResult;
}

/**function*************************************************************

  synopsis    [Computes the exact area associated with the cut.]

  description []
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutGetAreaDerefed( Fpga_Man_t * pMan, Fpga_Cut_t * pCut )
{
    float aResult, aResult2;
    if ( pCut->nLeaves == 1 )
        return 0;
    aResult2 = Fpga_CutRef( pMan, NULL, pCut, 0 );
    aResult  = Fpga_CutDeref( pMan, NULL, pCut, 0 );
    assert( Fpga_FloatEqual( pMan, aResult, aResult2 ) );
    return aResult;
}

/**function*************************************************************

  synopsis    [References the cut.]

  description [This procedure is similar to the procedure NodeReclaim.]
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutRef( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
{
    Fpga_Node_t * pNodeChild;
    float aArea;
    int i;

    // deref the fanouts
//    if ( fFanouts ) 
//        Fpga_CutInsertFanouts( pMan, pNode, pCut );

    // start the area of this cut
    aArea = pMan->pLutLib->pLutAreas[(int)pCut->nLeaves];
    // go through the children
    for ( i = 0; i < pCut->nLeaves; i++ )
    {
        pNodeChild = pCut->ppLeaves[i];
        assert( pNodeChild->nRefs >= 0 );
        if ( pNodeChild->nRefs++ > 0 )  
            continue;
        if ( !Fpga_NodeIsAnd(pNodeChild) ) 
            continue;
        aArea += Fpga_CutRef( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
    }
    return aArea;
}

/**function*************************************************************

  synopsis    [Dereferences the cut.]

  description [This procedure is similar to the procedure NodeRecusiveDeref.]
               
  sideeffects []

  seealso     []

***********************************************************************/
float Fpga_CutDeref( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Cut_t * pCut, int fFanouts )
{
    Fpga_Node_t * pNodeChild;
    float aArea;
    int i;

    // deref the fanouts
//    if ( fFanouts ) 
//        Fpga_CutRemoveFanouts( pMan, pNode, pCut );

    // start the area of this cut
    aArea = pMan->pLutLib->pLutAreas[(int)pCut->nLeaves];
    // go through the children
    for ( i = 0; i < pCut->nLeaves; i++ )
    {
        pNodeChild = pCut->ppLeaves[i];
        assert( pNodeChild->nRefs > 0 );
        if ( --pNodeChild->nRefs > 0 )  
            continue;
        if ( !Fpga_NodeIsAnd(pNodeChild) ) 
            continue;
        aArea += Fpga_CutDeref( pMan, pNodeChild, pNodeChild->pCutBest, fFanouts );
    }
    return aArea;
}


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

  Synopsis    [Sets the used cuts to be the currently selected ones.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fpga_MappingSetUsedCuts( Fpga_Man_t * pMan )
{
    int i;
    for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
        if ( pMan->vNodesAll->pArray[i]->pCutOld )
        {
            pMan->vNodesAll->pArray[i]->pCutBest = pMan->vNodesAll->pArray[i]->pCutOld;
            pMan->vNodesAll->pArray[i]->pCutOld  = NULL;
        }
}

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


ABC_NAMESPACE_IMPL_END