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

  FileName    [sscSim.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [SAT sweeping under constraints.]

  Synopsis    [Simulation procedures.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - June 29, 2008.]

  Revision    [$Id: sscSim.c,v 1.00 2008/07/29 00:00:00 alanmi Exp $]

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

#include "sscInt.h"

ABC_NAMESPACE_IMPL_START


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

static inline word Ssc_Random()            { return ((word)Gia_ManRandom(0) << 32) | ((word)Gia_ManRandom(0) << 0);              }
static inline word Ssc_Random1( int Bit )  { return ((word)Gia_ManRandom(0) << 32) | ((word)Gia_ManRandom(0) << 1) | (word)Bit;  }
static inline word Ssc_Random2()           { return ((word)Gia_ManRandom(0) << 32) | ((word)Gia_ManRandom(0) << 2) | (word)2;    }

static inline void Ssc_SimAnd( word * pSim, word * pSim0, word * pSim1, int nWords, int fComp0, int fComp1 )
{
    int w;
    if ( fComp0 && fComp1 ) for ( w = 0; w < nWords; w++ )  pSim[w] = ~(pSim0[w] | pSim1[w]);
    else if ( fComp0 )      for ( w = 0; w < nWords; w++ )  pSim[w] =  ~pSim0[w] & pSim1[w];
    else if ( fComp1 )      for ( w = 0; w < nWords; w++ )  pSim[w] =   pSim0[w] &~pSim1[w];
    else                    for ( w = 0; w < nWords; w++ )  pSim[w] =   pSim0[w] & pSim1[w];
}

static inline void Ssc_SimDup( word * pSim, word * pSim0, int nWords, int fComp0 )
{
    int w;
    if ( fComp0 ) for ( w = 0; w < nWords; w++ )  pSim[w] = ~pSim0[w];
    else          for ( w = 0; w < nWords; w++ )  pSim[w] =  pSim0[w];
}

static inline void Ssc_SimConst( word * pSim, int nWords, int fComp0 )
{
    int w;
    if ( fComp0 ) for ( w = 0; w < nWords; w++ )  pSim[w] = ~(word)0;
    else          for ( w = 0; w < nWords; w++ )  pSim[w] = 0;
}

static inline void Ssc_SimOr( word * pSim, word * pSim0, int nWords, int fComp0 )
{
    int w;
    if ( fComp0 ) for ( w = 0; w < nWords; w++ )  pSim[w] |= ~pSim0[w];
    else          for ( w = 0; w < nWords; w++ )  pSim[w] |=  pSim0[w];
}

static inline int Ssc_SimFindBitWord( word t )
{
    int n = 0;
    if ( t == 0 ) return -1;
    if ( (t & 0x00000000FFFFFFFF) == 0 ) { n += 32; t >>= 32; }
    if ( (t & 0x000000000000FFFF) == 0 ) { n += 16; t >>= 16; }
    if ( (t & 0x00000000000000FF) == 0 ) { n +=  8; t >>=  8; }
    if ( (t & 0x000000000000000F) == 0 ) { n +=  4; t >>=  4; }
    if ( (t & 0x0000000000000003) == 0 ) { n +=  2; t >>=  2; }
    if ( (t & 0x0000000000000001) == 0 ) { n++; }
    return n;
}
static inline int Ssc_SimFindBit( word * pSim, int nWords )
{
    int w;
    for ( w = 0; w < nWords; w++ )
        if ( pSim[w] )
            return 64*w + Ssc_SimFindBitWord(pSim[w]);
    return -1;
}

static inline int Ssc_SimCountBitsWord( word x )
{
    x = x - ((x >> 1) & ABC_CONST(0x5555555555555555));   
    x = (x & ABC_CONST(0x3333333333333333)) + ((x >> 2) & ABC_CONST(0x3333333333333333));    
    x = (x + (x >> 4)) & ABC_CONST(0x0F0F0F0F0F0F0F0F);    
    x = x + (x >> 8);
    x = x + (x >> 16);
    x = x + (x >> 32); 
    return (int)(x & 0xFF);
}
static inline int Ssc_SimCountBits( word * pSim, int nWords )
{
    int w, Counter = 0;
    for ( w = 0; w < nWords; w++ )
        Counter += Ssc_SimCountBitsWord(pSim[w]);
    return Counter;
}


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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Vec_WrdDoubleSimInfo( Vec_Wrd_t * p, int nObjs )
{
    word * pArray = ABC_CALLOC( word, 2 * Vec_WrdSize(p) );
    int i, nWords = Vec_WrdSize(p) / nObjs;
    assert( Vec_WrdSize(p) % nObjs == 0 );
    for ( i = 0; i < nObjs; i++ )
        memcpy( pArray + 2*i*nWords, p->pArray + i*nWords, sizeof(word) * nWords );
    ABC_FREE( p->pArray ); p->pArray = pArray;
    p->nSize = p->nCap = 2*nWords*nObjs;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ssc_GiaResetPiPattern( Gia_Man_t * p, int nWords )
{
    p->iPatsPi = 0;
    if ( p->vSimsPi == NULL )
        p->vSimsPi = Vec_WrdStart(0);
    Vec_WrdFill( p->vSimsPi, nWords * Gia_ManCiNum(p), 0 );
    assert( nWords == Gia_ObjSimWords( p ) );
}
void Ssc_GiaSavePiPattern( Gia_Man_t * p, Vec_Int_t * vPat )
{
    word * pSimPi;
    int i;
    assert( Vec_IntSize(vPat) == Gia_ManCiNum(p) );
    if ( p->iPatsPi == 64 * Gia_ObjSimWords(p) )
        Vec_WrdDoubleSimInfo( p->vSimsPi, Gia_ManCiNum(p) );
    assert( p->iPatsPi < 64 * Gia_ObjSimWords(p) );
    pSimPi = Gia_ObjSimPi( p, 0 );
    for ( i = 0; i < Gia_ManCiNum(p); i++, pSimPi += Gia_ObjSimWords(p) )
        if ( Vec_IntEntry(vPat, i) )
            Abc_InfoSetBit( (unsigned *)pSimPi, p->iPatsPi );
    p->iPatsPi++;
}
void Ssc_GiaRandomPiPattern( Gia_Man_t * p, int nWords, Vec_Int_t * vPivot )
{
    word * pSimPi;
    int i, w;
    Ssc_GiaResetPiPattern( p, nWords );
    pSimPi = Gia_ObjSimPi( p, 0 );
    for ( i = 0; i < Gia_ManPiNum(p); i++, pSimPi += nWords )
    {
        pSimPi[0] = vPivot ? Ssc_Random1(Vec_IntEntry(vPivot, i)) : Ssc_Random2();
        for ( w = 1; w < nWords; w++ )
            pSimPi[w] = Ssc_Random();
//        if ( i < 10 )
//            Extra_PrintBinary( stdout, (unsigned *)pSimPi, 64 ), printf( "\n" );
    }
}
void Ssc_GiaPrintPiPatterns( Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    word * pSimAig;
    int i;//, nWords = Gia_ObjSimWords( p );
    Gia_ManForEachCi( p, pObj, i )
    {
        pSimAig = Gia_ObjSimObj( p, pObj );
//        Extra_PrintBinary( stdout, pSimAig, 64 * nWords );
    }
}

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

  Synopsis    [Transfer the simulation pattern from pCare to pAig.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ssc_GiaTransferPiPattern( Gia_Man_t * pAig, Gia_Man_t * pCare, Vec_Int_t * vPivot )
{
    extern word * Ssc_GiaGetCareMask( Gia_Man_t * p );
    Gia_Obj_t * pObj;
    int i, w, nWords = Gia_ObjSimWords( pCare );
    word * pCareMask = Ssc_GiaGetCareMask( pCare );
    int Count = Ssc_SimCountBits( pCareMask, nWords );
    word * pSimPiCare, * pSimPiAig;
    if ( Count == 0 )
    {
        ABC_FREE( pCareMask );
        return 0;
    }
    Ssc_GiaResetPiPattern( pAig, nWords );
    Gia_ManForEachCi( pCare, pObj, i )
    {
        pSimPiAig  = Gia_ObjSimPi( pAig, i );
        pSimPiCare = Gia_ObjSimObj( pCare, pObj );
        for ( w = 0; w < nWords; w++ )
            if ( Vec_IntEntry(vPivot, i) )
                pSimPiAig[w] = pSimPiCare[w] | ~pCareMask[w];
            else
                pSimPiAig[w] = pSimPiCare[w] & pCareMask[w];
    }
    ABC_FREE( pCareMask );
    return Count;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Ssc_GiaResetSimInfo( Gia_Man_t * p )
{
    assert( Vec_WrdSize(p->vSimsPi) % Gia_ManCiNum(p) == 0 );
    if ( p->vSims == NULL )
        p->vSims = Vec_WrdAlloc(0);
    Vec_WrdFill( p->vSims, Gia_ObjSimWords(p) * Gia_ManObjNum(p), 0 );
}
void Ssc_GiaSimRound( Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    word * pSim, * pSim0, * pSim1;
    int i, nWords = Gia_ObjSimWords(p);
    Ssc_GiaResetSimInfo( p );
    assert( nWords == Vec_WrdSize(p->vSims) / Gia_ManObjNum(p) );
    // constant node
    Ssc_SimConst( Gia_ObjSim(p, 0), nWords, 0 );
    // primary inputs
    pSim = Gia_ObjSim( p, 1 );
    pSim0 = Gia_ObjSimPi( p, 0 );
    Gia_ManForEachCi( p, pObj, i )
    {
        assert( pSim == Gia_ObjSimObj( p, pObj ) );
        Ssc_SimDup( pSim, pSim0, nWords, 0 );
        pSim += nWords;
        pSim0 += nWords;
    }
    // intermediate nodes
    pSim = Gia_ObjSim( p, 1+Gia_ManCiNum(p) );
    Gia_ManForEachAnd( p, pObj, i )
    {
        assert( pSim == Gia_ObjSim( p, i ) );
        pSim0 = pSim - pObj->iDiff0 * nWords;
        pSim1 = pSim - pObj->iDiff1 * nWords;
        Ssc_SimAnd( pSim, pSim0, pSim1, nWords, Gia_ObjFaninC0(pObj), Gia_ObjFaninC1(pObj) );
        pSim += nWords;
    }
    // primary outputs
    pSim = Gia_ObjSim( p, Gia_ManObjNum(p) - Gia_ManPoNum(p) );
    Gia_ManForEachPo( p, pObj, i )
    {
        assert( pSim == Gia_ObjSimObj( p, pObj ) );
        pSim0 = pSim - pObj->iDiff0 * nWords;
        Ssc_SimDup( pSim, pSim0, nWords, Gia_ObjFaninC0(pObj) );
//        Extra_PrintBinary( stdout, pSim, 64 ), printf( "\n" );
        pSim += nWords;
    }
}

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

  Synopsis    [Returns one SAT assignment of the PIs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
word * Ssc_GiaGetCareMask( Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    int i, nWords = Gia_ObjSimWords( p );
    word * pRes = ABC_FALLOC( word, nWords );
    Gia_ManForEachPo( p, pObj, i )
        Ssc_SimAnd( pRes, pRes, Gia_ObjSimObj(p, pObj), nWords, 0, 0 );
    return pRes;
}
Vec_Int_t * Ssc_GiaGetOneSim( Gia_Man_t * p )
{
    Vec_Int_t * vInit;
    Gia_Obj_t * pObj;
    int i, iBit, nWords = Gia_ObjSimWords( p );
    word * pRes = Ssc_GiaGetCareMask( p );
    iBit = Ssc_SimFindBit( pRes, nWords );
    ABC_FREE( pRes );
    if ( iBit == -1 )
        return NULL;
    vInit = Vec_IntAlloc( 100 );
    Gia_ManForEachCi( p, pObj, i )
        Vec_IntPush( vInit, Abc_InfoHasBit((unsigned *)Gia_ObjSimObj(p, pObj), iBit) );
    return vInit;
}
Vec_Int_t * Ssc_GiaFindPivotSim( Gia_Man_t * p )
{
    Vec_Int_t * vInit;
    Ssc_GiaRandomPiPattern( p, 1, NULL );
    Ssc_GiaSimRound( p );
    vInit = Ssc_GiaGetOneSim( p );
    return vInit;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Ssc_GiaCountCaresSim( Gia_Man_t * p )
{
    word * pRes = Ssc_GiaGetCareMask( p );
    int nWords = Gia_ObjSimWords( p );
    int Count = Ssc_SimCountBits( pRes, nWords );
    ABC_FREE( pRes );
    return Count;
}
int Ssc_GiaEstimateCare( Gia_Man_t * p, int nWords )
{
    Ssc_GiaRandomPiPattern( p, nWords, NULL );
    Ssc_GiaSimRound( p );
    return Ssc_GiaCountCaresSim( p );
}

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


ABC_NAMESPACE_IMPL_END