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

  FileName    [resSim.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Resynthesis package.]

  Synopsis    [Simulation engine.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - January 15, 2007.]

  Revision    [$Id: resSim.c,v 1.00 2007/01/15 00:00:00 alanmi Exp $]

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

#include "abc.h"
#include "resInt.h"

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

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

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

  Synopsis    [Allocate simulation engine.]

  Description []
               
  SideEffects []

  SeeAlso     []
 
***********************************************************************/
Res_Sim_t * Res_SimAlloc( int nWords )
{
    Res_Sim_t * p;
    p = ALLOC( Res_Sim_t, 1 );
    memset( p, 0, sizeof(Res_Sim_t) );
    // simulation parameters
    p->nWords    = nWords;
    p->nPats     = 8 * sizeof(unsigned) * p->nWords;
    p->nWordsOut = p->nPats * p->nWords;
    p->nPatsOut  = p->nPats * p->nPats;
    // simulation info
    p->vPats     = Vec_PtrAllocSimInfo( 1024, p->nWords );
    p->vPats0    = Vec_PtrAllocSimInfo( 128,  p->nWords );
    p->vPats1    = Vec_PtrAllocSimInfo( 128,  p->nWords );
    p->vOuts     = Vec_PtrAllocSimInfo( 128,  p->nWordsOut );
    // resub candidates
    p->vCands    = Vec_VecStart( 16 );
    return p;
}

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

  Synopsis    [Allocate simulation engine.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimAdjust( Res_Sim_t * p, Abc_Ntk_t * pAig )
{
    srand( 0xABC );

    assert( Abc_NtkIsStrash(pAig) );
    p->pAig = pAig;
    if ( Vec_PtrSize(p->vPats) < Abc_NtkObjNumMax(pAig)+1 )
    {
        Vec_PtrFree( p->vPats );
        p->vPats = Vec_PtrAllocSimInfo( Abc_NtkObjNumMax(pAig)+1, p->nWords );
    }
    if ( Vec_PtrSize(p->vPats0) < Abc_NtkPiNum(pAig) )
    {
        Vec_PtrFree( p->vPats0 );
        p->vPats0 = Vec_PtrAllocSimInfo( Abc_NtkPiNum(pAig), p->nWords );
    }
    if ( Vec_PtrSize(p->vPats1) < Abc_NtkPiNum(pAig) )
    {
        Vec_PtrFree( p->vPats1 );
        p->vPats1 = Vec_PtrAllocSimInfo( Abc_NtkPiNum(pAig), p->nWords );
    }
    if ( Vec_PtrSize(p->vOuts) < Abc_NtkPoNum(pAig) )
    {
        Vec_PtrFree( p->vOuts );
        p->vOuts = Vec_PtrAllocSimInfo( Abc_NtkPoNum(pAig), p->nWordsOut );
    }
    // clean storage info for patterns
    Abc_InfoClear( Vec_PtrEntry(p->vPats0,0), p->nWords * Abc_NtkPiNum(pAig) );
    Abc_InfoClear( Vec_PtrEntry(p->vPats1,0), p->nWords * Abc_NtkPiNum(pAig) );
    p->nPats0 = 0;
    p->nPats1 = 0;
}

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

  Synopsis    [Free simulation engine.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimFree( Res_Sim_t * p )
{
    Vec_PtrFree( p->vPats );
    Vec_PtrFree( p->vPats0 );
    Vec_PtrFree( p->vPats1 );
    Vec_PtrFree( p->vOuts );
    Vec_VecFree( p->vCands );
    free( p );
}


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

  Synopsis    [Sets random PI simulation info.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimSetRandom( Res_Sim_t * p )
{
    Abc_Obj_t * pObj;
    unsigned * pInfo;
    int i;
    Abc_NtkForEachPi( p->pAig, pObj, i )
    {
        pInfo = Vec_PtrEntry( p->vPats, pObj->Id );
        Abc_InfoRandom( pInfo, p->nWords );
    }
}

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

  Synopsis    [Sets given PI simulation info.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimSetGiven( Res_Sim_t * p, Vec_Ptr_t * vInfo )
{
    Abc_Obj_t * pObj;
    unsigned * pInfo, * pInfo2;
    int i, w;
    Abc_NtkForEachPi( p->pAig, pObj, i )
    {
        pInfo = Vec_PtrEntry( p->vPats, pObj->Id );
        pInfo2 = Vec_PtrEntry( vInfo, i );
        for ( w = 0; w < p->nWords; w++ )
            pInfo[w] = pInfo2[w];
    }
}

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

  Synopsis    [Simulates one node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimPerformOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords )
{
    unsigned * pInfo, * pInfo1, * pInfo2;
    int k, fComp1, fComp2;
    // simulate the internal nodes
    assert( Abc_ObjIsNode(pNode) );
    pInfo  = Vec_PtrEntry(vSimInfo, pNode->Id);
    pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode));
    pInfo2 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId1(pNode));
    fComp1 = Abc_ObjFaninC0(pNode);
    fComp2 = Abc_ObjFaninC1(pNode);
    if ( fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] = ~pInfo1[k] & ~pInfo2[k];
    else if ( fComp1 && !fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] = ~pInfo1[k] &  pInfo2[k];
    else if ( !fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] =  pInfo1[k] & ~pInfo2[k];
    else // if ( fComp1 && fComp2 )
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] =  pInfo1[k] &  pInfo2[k];
}

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

  Synopsis    [Simulates one CO node.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimTransferOne( Abc_Obj_t * pNode, Vec_Ptr_t * vSimInfo, int nSimWords )
{
    unsigned * pInfo, * pInfo1;
    int k, fComp1;
    // simulate the internal nodes
    assert( Abc_ObjIsCo(pNode) );
    pInfo  = Vec_PtrEntry(vSimInfo, pNode->Id);
    pInfo1 = Vec_PtrEntry(vSimInfo, Abc_ObjFaninId0(pNode));
    fComp1 = Abc_ObjFaninC0(pNode);
    if ( fComp1 )
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] = ~pInfo1[k];
    else 
        for ( k = 0; k < nSimWords; k++ )
            pInfo[k] =  pInfo1[k];
}

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

  Synopsis    [Performs one round of simulation.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimPerformRound( Res_Sim_t * p )
{
    Abc_Obj_t * pObj;
    int i;
    Abc_InfoFill( Vec_PtrEntry(p->vPats,0), p->nWords );
    Abc_AigForEachAnd( p->pAig, pObj, i )
        Res_SimPerformOne( pObj, p->vPats, p->nWords );
    Abc_NtkForEachPo( p->pAig, pObj, i )
        Res_SimTransferOne( pObj, p->vPats, p->nWords );
}

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

  Synopsis    [Processes simulation patterns.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimProcessPats( Res_Sim_t * p )
{
    Abc_Obj_t * pObj;
    unsigned * pInfoCare, * pInfoNode;
    int i, j, nDcs = 0;
    pInfoCare = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id );
    pInfoNode = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id );
    for ( i = 0; i < p->nPats; i++ )
    {
        // skip don't-care patterns
        if ( !Abc_InfoHasBit(pInfoCare, i) )
        {
            nDcs++;
            continue;
        }
        // separate offset and onset patterns
        if ( !Abc_InfoHasBit(pInfoNode, i) )
        {
            if ( p->nPats0 >= p->nPats )
                continue;
            Abc_NtkForEachPi( p->pAig, pObj, j )
                if ( Abc_InfoHasBit( Vec_PtrEntry(p->vPats, pObj->Id), i ) )
                    Abc_InfoSetBit( Vec_PtrEntry(p->vPats0, j), p->nPats0 );
            p->nPats0++;
        }
        else
        {
            if ( p->nPats1 >= p->nPats )
                continue;
            Abc_NtkForEachPi( p->pAig, pObj, j )
                if ( Abc_InfoHasBit( Vec_PtrEntry(p->vPats, pObj->Id), i ) )
                    Abc_InfoSetBit( Vec_PtrEntry(p->vPats1, j), p->nPats1 );
            p->nPats1++;
        }
    }
}

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

  Synopsis    [Pads the extra space with duplicated simulation info.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimPadSimInfo( Vec_Ptr_t * vPats, int nPats, int nWords )
{
    unsigned * pInfo;
    int i, w, iWords;
    assert( nPats > 0 && nPats < nWords * 8 * (int) sizeof(unsigned) );
    // pad the first word
    if ( nPats < 8 * sizeof(unsigned) )
    {
        Vec_PtrForEachEntry( vPats, pInfo, i )
            if ( pInfo[0] & 1 )
                pInfo[0] |= ((~0) << nPats);
        nPats = 8 * sizeof(unsigned);
    }
    // pad the empty words
    iWords = nPats / (8 * sizeof(unsigned));
    Vec_PtrForEachEntry( vPats, pInfo, i )
    {
        for ( w = iWords; w < nWords; w++ )
            pInfo[w] = pInfo[0];
    }
}

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

  Synopsis    [Duplicates the simulation info to fill the space.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimDeriveInfoReplicate( Res_Sim_t * p )
{
    unsigned * pInfo, * pInfo2;
    Abc_Obj_t * pObj;
    int i, j, w;
    Abc_NtkForEachPo( p->pAig, pObj, i )
    {
        pInfo = Vec_PtrEntry( p->vPats, pObj->Id );
        pInfo2 = Vec_PtrEntry( p->vOuts, i );
        for ( j = 0; j < p->nPats; j++ )
            for ( w = 0; w < p->nWords; w++ )
                *pInfo2++ = pInfo[w];
    }
}

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

  Synopsis    [Complement the simulation info if necessary.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimDeriveInfoComplement( Res_Sim_t * p )
{
    unsigned * pInfo, * pInfo2;
    Abc_Obj_t * pObj;
    int i, j, w;
    Abc_NtkForEachPo( p->pAig, pObj, i )
    {
        pInfo = Vec_PtrEntry( p->vPats, pObj->Id );
        pInfo2 = Vec_PtrEntry( p->vOuts, i );
        for ( j = 0; j < p->nPats; j++, pInfo2 += p->nWords )
            if ( Abc_InfoHasBit( pInfo, j ) )
                for ( w = 0; w < p->nWords; w++ )
                    pInfo2[w] = ~pInfo2[w];
    }
}

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

  Synopsis    [Free simulation engine.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimReportOne( Res_Sim_t * p )
{
    unsigned * pInfoCare, * pInfoNode;
    int i, nDcs, nOnes, nZeros;
    pInfoCare = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 0)->Id );
    pInfoNode = Vec_PtrEntry( p->vPats, Abc_NtkPo(p->pAig, 1)->Id );
    nDcs = nOnes = nZeros = 0;
    for ( i = 0; i < p->nPats; i++ )
    {
        // skip don't-care patterns
        if ( !Abc_InfoHasBit(pInfoCare, i) )
        {
            nDcs++;
            continue;
        }
        // separate offset and onset patterns
        if ( !Abc_InfoHasBit(pInfoNode, i) )
            nZeros++;
        else
            nOnes++;
    }
    fprintf(outStream,  "On = %3d (%7.2f %%)  ",  nOnes,  100.0*nOnes/p->nPats );
    fprintf(outStream,  "Off = %3d (%7.2f %%)  ", nZeros, 100.0*nZeros/p->nPats );
    fprintf(outStream,  "Dc = %3d (%7.2f %%)  ",  nDcs,   100.0*nDcs/p->nPats );
    fprintf(outStream,  "P0 = %3d ", p->nPats0 );
    fprintf(outStream,  "P1 = %3d ", p->nPats1 );
    if ( p->nPats0 < 4 || p->nPats1 < 4 )
        fprintf(outStream,  "*" );
    fprintf(outStream,  "\n" );
}

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

  Synopsis    [Prints output patterns.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Res_SimPrintOutPatterns( Res_Sim_t * p, Abc_Ntk_t * pAig )
{
    Abc_Obj_t * pObj;
    unsigned * pInfo2;
    int i;
    Abc_NtkForEachPo( pAig, pObj, i )
    {
        pInfo2 = Vec_PtrEntry( p->vOuts, i );
        Extra_PrintBinary( outStream, pInfo2, p->nPatsOut );
        fprintf(outStream,  "\n" );
    }
}

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

  Synopsis    [Prepares simulation info for candidate filtering.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Res_SimPrepare( Res_Sim_t * p, Abc_Ntk_t * pAig, int nTruePis, int fVerbose )
{
    int Limit;
    // prepare the manager
    Res_SimAdjust( p, pAig );
    // collect 0/1 simulation info
    for ( Limit = 0; Limit < 10; Limit++ )
    {
        Res_SimSetRandom( p );
        Res_SimPerformRound( p );
        Res_SimProcessPats( p );
        if ( !(p->nPats0 < p->nPats || p->nPats1 < p->nPats) )
            break;
    }
//    fprintf(outStream,  "%d   ", Limit );
    // report the last set of patterns
//    Res_SimReportOne( p );
//    fprintf(outStream,  "\n" );
    // quit if there is not enough
//    if ( p->nPats0 < 4 || p->nPats1 < 4 )
    if ( p->nPats0 < 4 || p->nPats1 < 4 )
    {
//        Res_SimReportOne( p );
        return 0;
    }
    // create bit-matrix info
    if ( p->nPats0 < p->nPats )
        Res_SimPadSimInfo( p->vPats0, p->nPats0, p->nWords );
    if ( p->nPats1 < p->nPats )
        Res_SimPadSimInfo( p->vPats1, p->nPats1, p->nWords );
    // resimulate 0-patterns
    Res_SimSetGiven( p, p->vPats0 );
    Res_SimPerformRound( p );
    Res_SimDeriveInfoReplicate( p );
    // resimulate 1-patterns
    Res_SimSetGiven( p, p->vPats1 );
    Res_SimPerformRound( p );
    Res_SimDeriveInfoComplement( p );
    // print output patterns
//    Res_SimPrintOutPatterns( p, pAig );
    return 1;
}

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


