From 52e5b91cbbfe587bae80984bb3672e4c1a70203c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 4 Dec 2006 08:01:00 -0800 Subject: [PATCH] Version abc61204 --- Makefile | 4 +- abc.dsp | 12 + src/aig/aig-alan.tar.gz | Bin 27265 -> 0 bytes src/aig/ivy/ivyFactor.c | 833 +++++++++++++++++++++++++++++++++++++++ src/aig/rwt/module.make | 6 +- src/base/abci/abc.c | 30 +- src/base/abci/abcIf.c | 7 +- src/base/abci/abcPrint.c | 9 +- src/map/fpga/fpga.c | 4 +- src/map/if/if.h | 44 ++- src/map/if/ifCore.c | 41 +- src/map/if/ifMan.c | 9 +- src/map/if/ifMap.c | 261 +++++++++--- src/map/if/ifReduce.c | 576 +++++++++++++++++++++++++++ src/map/if/ifSelect.c | 175 ++++++++ src/map/if/ifSeq.c | 170 ++++++++ src/map/if/module.make | 4 + src/sat/fraig/fraigMan.c | 3 +- 18 files changed, 2079 insertions(+), 109 deletions(-) delete mode 100644 src/aig/aig-alan.tar.gz create mode 100644 src/aig/ivy/ivyFactor.c create mode 100644 src/map/if/ifReduce.c create mode 100644 src/map/if/ifSelect.c create mode 100644 src/map/if/ifSeq.c diff --git a/Makefile b/Makefile index 3b37b2e63..d09511974 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ CP := cp PROG := abc MODULES := src/base/abc src/base/abci src/base/cmd src/base/io src/base/main src/base/ver \ - src/aig/ivy src/aig/hop src/aig/rwt src/aig/deco src/mem/deco src/aig/ec \ + src/aig/ivy src/aig/hop src/aig/rwt src/aig/deco src/aig/mem src/aig/ec \ src/bdd/cudd src/bdd/dsd src/bdd/epd src/bdd/mtr src/bdd/parse src/bdd/reo \ - src/map/fpga src/map/pga src/map/mapper src/map/mio src/map/super src/map/if \ + src/map/fpga src/map/mapper src/map/mio src/map/super src/map/if \ src/misc/extra src/misc/mvc src/misc/st src/misc/util src/misc/espresso src/misc/nm src/misc/vec src/misc/hash \ src/opt/cut src/opt/dec src/opt/fxu src/opt/rwr src/opt/sim src/opt/ret \ src/sat/asat src/sat/bsat src/sat/csat src/sat/msat src/sat/fraig diff --git a/abc.dsp b/abc.dsp index c94c0e6df..12161a339 100644 --- a/abc.dsp +++ b/abc.dsp @@ -1826,6 +1826,18 @@ SOURCE=.\src\map\if\ifMap.c # End Source File # Begin Source File +SOURCE=.\src\map\if\ifReduce.c +# End Source File +# Begin Source File + +SOURCE=.\src\map\if\ifSelect.c +# End Source File +# Begin Source File + +SOURCE=.\src\map\if\ifSeq.c +# End Source File +# Begin Source File + SOURCE=.\src\map\if\ifUtil.c # End Source File # End Group diff --git a/src/aig/aig-alan.tar.gz b/src/aig/aig-alan.tar.gz deleted file mode 100644 index b61827adab2a74f1593da4cb0793b2b2d1959ff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27265 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 diff --git a/src/aig/ivy/ivyFactor.c b/src/aig/ivy/ivyFactor.c new file mode 100644 index 000000000..d83239313 --- /dev/null +++ b/src/aig/ivy/ivyFactor.c @@ -0,0 +1,833 @@ +/**CFile**************************************************************** + + FileName [ivyFactor.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [And-Inverter Graph package.] + + Synopsis [Factoring the cover up to 16 inputs.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - May 11, 2006.] + + Revision [$Id: ivyFactor.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "ivy.h" +#include "dec.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +extern Dec_Edge_t Dec_Factor32_rec( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars ); +extern Dec_Edge_t Dec_Factor32LF_rec( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars, Vec_Int_t * vSimple ); +extern Dec_Edge_t Dec_Factor32Trivial( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars ); +extern Dec_Edge_t Dec_Factor32TrivialCube( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars, Mvc_Cube_t * pCube, Vec_Int_t * vEdgeLits ); +extern Dec_Edge_t Dec_Factor32TrivialTree_rec( Dec_Graph_t * pFForm, Dec_Edge_t * peNodes, int nNodes, int fNodeOr ); +extern Vec_Int_t * Dec_Factor32Divisor( Vec_Int_t * vCover, int nVars ); +extern void Dec_Factor32DivisorZeroKernel( Vec_Int_t * vCover, int nVars ); +extern int Dec_Factor32WorstLiteral( Vec_Int_t * vCover, int nVars ); + +extern Vec_Int_t * Mvc_CoverCommonCubeCover( Vec_Int_t * vCover ); + + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Factors the cover.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Graph_t * Dec_Factor32( Vec_Int_t * vCover, int nVars ) +{ + Dec_Graph_t * pFForm; + Dec_Edge_t eRoot; + + // check for trivial functions + if ( Vec_IntSize(vCover) == 0 ) + return Dec_GraphCreateConst0(); + if ( Vec_IntSize(vCover) == 1 && /* tautology */ ) + return Dec_GraphCreateConst1(); + + // perform CST + Mvc_CoverInverse( vCover ); // CST + // start the factored form + pFForm = Dec_GraphCreate( Abc_SopGetVarNum(pSop) ); + // factor the cover + eRoot = Dec_Factor32_rec( pFForm, vCover, nVars ); + // finalize the factored form + Dec_GraphSetRoot( pFForm, eRoot ); + // verify the factored form +// if ( !Dec_Factor32Verify( pSop, pFForm ) ) +// printf( "Verification has failed.\n" ); +// Mvc_CoverInverse( vCover ); // undo CST + return pFForm; +} + +/**Function************************************************************* + + Synopsis [Internal recursive factoring procedure.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor32_rec( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars ) +{ + Vec_Int_t * vDiv, * vQuo, * vRem, * vCom; + Dec_Edge_t eNodeDiv, eNodeQuo, eNodeRem; + Dec_Edge_t eNodeAnd, eNode; + + // make sure the cover contains some cubes + assert( Vec_IntSize(vCover) ); + + // get the divisor + vDiv = Dec_Factor32Divisor( vCover, nVars ); + if ( vDiv == NULL ) + return Dec_Factor32Trivial( pFForm, vCover, nVars ); + + // divide the cover by the divisor + Mvc_CoverDivideInternal( vCover, nVars, vDiv, &vQuo, &vRem ); + assert( Vec_IntSize(vQuo) ); + + Vec_IntFree( vDiv ); + Vec_IntFree( vRem ); + + // check the trivial case + if ( Vec_IntSize(vQuo) == 1 ) + { + eNode = Dec_Factor32LF_rec( pFForm, vCover, nVars, vQuo ); + Vec_IntFree( vQuo ); + return eNode; + } + + // make the quotient cube free + Mvc_CoverMakeCubeFree( vQuo ); + + // divide the cover by the quotient + Mvc_CoverDivideInternal( vCover, nVars, vQuo, &vDiv, &vRem ); + + // check the trivial case + if ( Mvc_CoverIsCubeFree( vDiv ) ) + { + eNodeDiv = Dec_Factor32_rec( pFForm, vDiv ); + eNodeQuo = Dec_Factor32_rec( pFForm, vQuo ); + Vec_IntFree( vDiv ); + Vec_IntFree( vQuo ); + eNodeAnd = Dec_GraphAddNodeAnd( pFForm, eNodeDiv, eNodeQuo ); + if ( Vec_IntSize(vRem) == 0 ) + { + Vec_IntFree( vRem ); + return eNodeAnd; + } + else + { + eNodeRem = Dec_Factor32_rec( pFForm, vRem ); + Vec_IntFree( vRem ); + return Dec_GraphAddNodeOr( pFForm, eNodeAnd, eNodeRem ); + } + } + + // get the common cube + vCom = Mvc_CoverCommonCubeCover( vDiv ); + Vec_IntFree( vDiv ); + Vec_IntFree( vQuo ); + Vec_IntFree( vRem ); + + // solve the simple problem + eNode = Dec_Factor32LF_rec( pFForm, vCover, nVars, vCom ); + Vec_IntFree( vCom ); + return eNode; +} + + +/**Function************************************************************* + + Synopsis [Internal recursive factoring procedure for the leaf case.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor32LF_rec( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars, Vec_Int_t * vSimple ) +{ + Dec_Man_t * pManDec = Abc_FrameReadManDec(); + Vec_Int_t * vEdgeLits = pManDec->vLits; + Vec_Int_t * vDiv, * vQuo, * vRem; + Dec_Edge_t eNodeDiv, eNodeQuo, eNodeRem; + Dec_Edge_t eNodeAnd; + + // get the most often occurring literal + vDiv = Mvc_CoverBestLiteralCover( vCover, nVars, vSimple ); + // divide the cover by the literal + Mvc_CoverDivideByLiteral( vCover, nVars, vDiv, &vQuo, &vRem ); + // get the node pointer for the literal + eNodeDiv = Dec_Factor32TrivialCube( pFForm, vDiv, Mvc_CoverReadCubeHead(vDiv), vEdgeLits ); + Vec_IntFree( vDiv ); + // factor the quotient and remainder + eNodeQuo = Dec_Factor32_rec( pFForm, vQuo ); + Vec_IntFree( vQuo ); + eNodeAnd = Dec_GraphAddNodeAnd( pFForm, eNodeDiv, eNodeQuo ); + if ( Vec_IntSize(vRem) == 0 ) + { + Vec_IntFree( vRem ); + return eNodeAnd; + } + else + { + eNodeRem = Dec_Factor32_rec( pFForm, vRem ); + Vec_IntFree( vRem ); + return Dec_GraphAddNodeOr( pFForm, eNodeAnd, eNodeRem ); + } +} + + + +/**Function************************************************************* + + Synopsis [Factoring the cover, which has no algebraic divisors.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor32Trivial( Dec_Graph_t * pFForm, Vec_Int_t * vCover, int nVars ) +{ + Dec_Man_t * pManDec = Abc_FrameReadManDec(); + Vec_Int_t * vEdgeCubes = pManDec->vCubes; + Vec_Int_t * vEdgeLits = pManDec->vLits; + Mvc_Manager_t * pMem = pManDec->pMvcMem; + Dec_Edge_t eNode; + Mvc_Cube_t * pCube; + int i; + // create the factored form for each cube + Vec_IntClear( vEdgeCubes ); + Mvc_CoverForEachCube( vCover, pCube ) + { + eNode = Dec_Factor32TrivialCube( pFForm, vCover, nVars, pCube, vEdgeLits ); + Vec_IntPush( vEdgeCubes, Dec_EdgeToInt_(eNode) ); + } + // balance the factored forms + return Dec_Factor32TrivialTree_rec( pFForm, (Dec_Edge_t *)vEdgeCubes->pArray, vEdgeCubes->nSize, 1 ); +} + +/**Function************************************************************* + + Synopsis [Factoring the cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor32TrivialCube( Dec_Graph_t * pFForm, Vec_Int_t * vCover, Mvc_Cube_t * pCube, int nVars, Vec_Int_t * vEdgeLits ) +{ + Dec_Edge_t eNode; + int iBit, Value; + // create the factored form for each literal + Vec_IntClear( vEdgeLits ); + Mvc_CubeForEachBit( vCover, pCube, iBit, Value ) + if ( Value ) + { + eNode = Dec_EdgeCreate( iBit/2, iBit%2 ); // CST + Vec_IntPush( vEdgeLits, Dec_EdgeToInt_(eNode) ); + } + // balance the factored forms + return Dec_Factor32TrivialTree_rec( pFForm, (Dec_Edge_t *)vEdgeLits->pArray, vEdgeLits->nSize, 0 ); +} + +/**Function************************************************************* + + Synopsis [Create the well-balanced tree of nodes.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Dec_Edge_t Dec_Factor32TrivialTree_rec( Dec_Graph_t * pFForm, Dec_Edge_t * peNodes, int nNodes, int fNodeOr ) +{ + Dec_Edge_t eNode1, eNode2; + int nNodes1, nNodes2; + + if ( nNodes == 1 ) + return peNodes[0]; + + // split the nodes into two parts + nNodes1 = nNodes/2; + nNodes2 = nNodes - nNodes1; +// nNodes2 = nNodes/2; +// nNodes1 = nNodes - nNodes2; + + // recursively construct the tree for the parts + eNode1 = Dec_Factor32TrivialTree_rec( pFForm, peNodes, nNodes1, fNodeOr ); + eNode2 = Dec_Factor32TrivialTree_rec( pFForm, peNodes + nNodes1, nNodes2, fNodeOr ); + + if ( fNodeOr ) + return Dec_GraphAddNodeOr( pFForm, eNode1, eNode2 ); + else + return Dec_GraphAddNodeAnd( pFForm, eNode1, eNode2 ); +} + +/**Function************************************************************* + + Synopsis [Returns the quick divisor of the cover.] + + Description [Returns NULL, if there is not divisor other than + trivial.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Dec_Factor32Divisor( Vec_Int_t * vCover, int nVars ) +{ + Vec_Int_t * pKernel; + if ( Vec_IntSize(vCover) <= 1 ) + return NULL; + // allocate the literal array and count literals + if ( Mvc_CoverAnyLiteral( vCover, NULL ) == -1 ) + return NULL; + // duplicate the cover + pKernel = Mvc_CoverDup(vCover); + // perform the kerneling + Dec_Factor32DivisorZeroKernel( pKernel ); + assert( Vec_IntSize(pKernel) ); + return pKernel; +} + +/**Function************************************************************* + + Synopsis [Computes a level-zero kernel.] + + Description [Modifies the cover to contain one level-zero kernel.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dec_Factor32DivisorZeroKernel( Vec_Int_t * vCover, int nVars ) +{ + int iLit; + // find any literal that occurs at least two times +// iLit = Mvc_CoverAnyLiteral( vCover, NULL ); + iLit = Dec_Factor32WorstLiteral( vCover, NULL ); +// iLit = Mvc_CoverBestLiteral( vCover, NULL ); + if ( iLit == -1 ) + return; + // derive the cube-free quotient + Mvc_CoverDivideByLiteralQuo( vCover, iLit ); // the same cover + Mvc_CoverMakeCubeFree( vCover ); // the same cover + // call recursively + Dec_Factor32DivisorZeroKernel( vCover ); // the same cover +} + +/**Function************************************************************* + + Synopsis [Find the most often occurring literal.] + + Description [Find the most often occurring literal among those + that occur more than once.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Dec_Factor32WorstLiteral( Vec_Int_t * vCover, int nVars ) +{ + Mvc_Cube_t * pCube; + int nWord, nBit; + int i, iMin, nLitsMin, nLitsCur; + int fUseFirst = 1; + + // go through each literal + iMin = -1; + nLitsMin = 1000000; + for ( i = 0; i < vCover->nBits; i++ ) + { + // get the word and bit of this literal + nWord = Mvc_CubeWhichWord(i); + nBit = Mvc_CubeWhichBit(i); + // go through all the cubes + nLitsCur = 0; + Mvc_CoverForEachCube( vCover, pCube ) + if ( pCube->pData[nWord] & (1< nLitsCur ) + { + nLitsMin = nLitsCur; + iMin = i; + } + } + else + { + if ( nLitsMin >= nLitsCur ) + { + nLitsMin = nLitsCur; + iMin = i; + } + } + } + + if ( nLitsMin < 1000000 ) + return iMin; + return -1; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Int_t * Mvc_CoverCommonCubeCover( Vec_Int_t * vCover ) +{ + Vec_Int_t * vRes; + unsigned uTemp, uCube; + int i; + uCube = ~(unsigned)0; + Vec_IntForEachEntry( vCover, uTemp, i ) + uCube &= uTemp; + vRes = Vec_IntAlloc( 1 ); + Vec_IntPush( vRes, uCube ); + return vRes; +} + +/**Function************************************************************* + + Synopsis [Returns 1 if the support of cover2 is contained in the support of cover1.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Mvc_CoverCheckSuppContainment( Vec_Int_t * vCover1, Vec_Int_t * vCover2 ) +{ + unsigned uTemp, uSupp1, uSupp2; + int i; + // set the supports + uSupp1 = 0; + Vec_IntForEachEntry( vCover1, uTemp, i ) + uSupp1 |= uTemp; + uSupp2 = 0; + Vec_IntForEachEntry( vCover2, uTemp, i ) + uSupp2 |= uTemp; + // return containment + return uSupp1 & !uSupp2; +// Mvc_CubeBitNotImpl( Result, vCover2->pMask, vCover1->pMask ); +// return !Result; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivide( Vec_Int_t * vCover, Vec_Int_t * vDiv, Vec_Int_t ** pvQuo, Vec_Int_t ** pvRem ) +{ + // check the number of cubes + if ( Vec_IntSize( vCover ) < Vec_IntSize( vDiv ) ) + { + *pvQuo = NULL; + *pvRem = NULL; + return; + } + + // make sure that support of vCover contains that of vDiv + if ( !Mvc_CoverCheckSuppContainment( vCover, vDiv ) ) + { + *pvQuo = NULL; + *pvRem = NULL; + return; + } + + // perform the general division + Mvc_CoverDivideInternal( vCover, vDiv, pvQuo, pvRem ); +} + + +/**Function************************************************************* + + Synopsis [Merge the cubes inside the groups.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideInternal( Vec_Int_t * vCover, Vec_Int_t * vDiv, Vec_Int_t ** pvQuo, Vec_Int_t ** pvRem ) +{ + Vec_Int_t * vQuo, * vRem; + Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy; + Mvc_Cube_t * pCube1, * pCube2; + int * pGroups, nGroups; // the cube groups + int nCubesC, nCubesD, nMerges, iCubeC, iCubeD, iMerge; + int fSkipG, GroupSize, g, c, RetValue; + int nCubes; + + // get cover sizes + nCubesD = Vec_IntSize( vDiv ); + nCubesC = Vec_IntSize( vCover ); + + // check trivial cases + if ( nCubesD == 1 ) + { + if ( Mvc_CoverIsOneLiteral( vDiv ) ) + Mvc_CoverDivideByLiteral( vCover, vDiv, pvQuo, pvRem ); + else + Mvc_CoverDivideByCube( vCover, vDiv, pvQuo, pvRem ); + return; + } + + // create the divisor and the remainder + vQuo = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + vRem = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + + // get the support of the divisor + Mvc_CoverAllocateMask( vDiv ); + Mvc_CoverSupport( vDiv, vDiv->pMask ); + + // sort the cubes of the divisor + Mvc_CoverSort( vDiv, NULL, Mvc_CubeCompareInt ); + // sort the cubes of the cover + Mvc_CoverSort( vCover, vDiv->pMask, Mvc_CubeCompareIntOutsideAndUnderMask ); + + // allocate storage for cube groups + pGroups = MEM_ALLOC( vCover->pMem, int, nCubesC + 1 ); + + // mask contains variables in the support of Div + // split the cubes into groups using the mask + Mvc_CoverList2Array( vCover ); + Mvc_CoverList2Array( vDiv ); + pGroups[0] = 0; + nGroups = 1; + for ( c = 1; c < nCubesC; c++ ) + { + // get the cubes + pCube1 = vCover->pCubes[c-1]; + pCube2 = vCover->pCubes[c ]; + // compare the cubes + Mvc_CubeBitEqualOutsideMask( RetValue, pCube1, pCube2, vDiv->pMask ); + if ( !RetValue ) + pGroups[nGroups++] = c; + } + // finish off the last group + pGroups[nGroups] = nCubesC; + + // consider each group separately and decide + // whether it can produce a quotient cube + nCubes = 0; + for ( g = 0; g < nGroups; g++ ) + { + // if the group has less than nCubesD cubes, + // there is no way it can produce the quotient cube + // copy the cubes to the remainder + GroupSize = pGroups[g+1] - pGroups[g]; + if ( GroupSize < nCubesD ) + { + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeCopy = Mvc_CubeDup( vRem, vCover->pCubes[c] ); + Mvc_CoverAddCubeTail( vRem, pCubeCopy ); + nCubes++; + } + continue; + } + + // mark the cubes as those that should be added to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + Mvc_CubeSetSize( vCover->pCubes[c], 1 ); + + // go through the cubes in the group and at the same time + // go through the cubes in the divisor + iCubeD = 0; + iCubeC = 0; + pCubeD = vDiv->pCubes[iCubeD++]; + pCubeC = vCover->pCubes[pGroups[g]+iCubeC++]; + fSkipG = 0; + nMerges = 0; + + while ( 1 ) + { + // compare the topmost cubes in F and in D + RetValue = Mvc_CubeCompareIntUnderMask( pCubeC, pCubeD, vDiv->pMask ); + // cube are ordered in increasing order of their int value + if ( RetValue == -1 ) // pCubeC is above pCubeD + { // cube in C should be added to the remainder + // check that there is enough cubes in the group + if ( GroupSize - iCubeC < nCubesD - nMerges ) + { + fSkipG = 1; + break; + } + // get the next cube in the cover + pCubeC = vCover->pCubes[pGroups[g]+iCubeC++]; + continue; + } + if ( RetValue == 1 ) // pCubeD is above pCubeC + { // given cube in D does not have a corresponding cube in the cover + fSkipG = 1; + break; + } + // mark the cube as the one that should NOT be added to the remainder + Mvc_CubeSetSize( pCubeC, 0 ); + // remember this merged cube + iMerge = iCubeC-1; + nMerges++; + + // stop if we considered the last cube of the group + if ( iCubeD == nCubesD ) + break; + + // advance the cube of the divisor + assert( iCubeD < nCubesD ); + pCubeD = vDiv->pCubes[iCubeD++]; + + // advance the cube of the group + assert( pGroups[g]+iCubeC < nCubesC ); + pCubeC = vCover->pCubes[pGroups[g]+iCubeC++]; + } + + if ( fSkipG ) + { + // the group has failed, add all the cubes to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeCopy = Mvc_CubeDup( vRem, vCover->pCubes[c] ); + Mvc_CoverAddCubeTail( vRem, pCubeCopy ); + nCubes++; + } + continue; + } + + // the group has worked, add left-over cubes to the remainder + for ( c = pGroups[g]; c < pGroups[g+1]; c++ ) + { + pCubeC = vCover->pCubes[c]; + if ( Mvc_CubeReadSize(pCubeC) ) + { + pCubeCopy = Mvc_CubeDup( vRem, pCubeC ); + Mvc_CoverAddCubeTail( vRem, pCubeCopy ); + nCubes++; + } + } + + // create the quotient cube + pCube1 = Mvc_CubeAlloc( vQuo ); + Mvc_CubeBitSharp( pCube1, vCover->pCubes[pGroups[g]+iMerge], vDiv->pMask ); + // add the cube to the quotient + Mvc_CoverAddCubeTail( vQuo, pCube1 ); + nCubes += nCubesD; + } + assert( nCubes == nCubesC ); + + // deallocate the memory + MEM_FREE( vCover->pMem, int, nCubesC + 1, pGroups ); + + // return the results + *pvRem = vRem; + *pvQuo = vQuo; +// Mvc_CoverVerifyDivision( vCover, vDiv, vQuo, vRem ); +} + + +/**Function************************************************************* + + Synopsis [Divides the cover by a cube.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByCube( Vec_Int_t * vCover, Vec_Int_t * vDiv, Vec_Int_t ** pvQuo, Vec_Int_t ** pvRem ) +{ + Vec_Int_t * vQuo, * vRem; + Mvc_Cube_t * pCubeC, * pCubeD, * pCubeCopy; + int ComvResult; + + // get the only cube of D + assert( Vec_IntSize(vDiv) == 1 ); + + // start the quotient and the remainder + vQuo = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + vRem = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + + // get the first and only cube of the divisor + pCubeD = Mvc_CoverReadCubeHead( vDiv ); + + // iterate through the cubes in the cover + Mvc_CoverForEachCube( vCover, pCubeC ) + { + // check the containment of literals from pCubeD in pCube + Mvc_Cube2BitNotImpl( ComvResult, pCubeD, pCubeC ); + if ( !ComvResult ) + { // this cube belongs to the quotient + // alloc the cube + pCubeCopy = Mvc_CubeAlloc( vQuo ); + // clean the support of D + Mvc_CubeBitSharp( pCubeCopy, pCubeC, pCubeD ); + // add the cube to the quotient + Mvc_CoverAddCubeTail( vQuo, pCubeCopy ); + } + else + { + // copy the cube + pCubeCopy = Mvc_CubeDup( vRem, pCubeC ); + // add the cube to the remainder + Mvc_CoverAddCubeTail( vRem, pCubeCopy ); + } + } + // return the results + *pvRem = vRem; + *pvQuo = vQuo; +} + +/**Function************************************************************* + + Synopsis [Divides the cover by a literal.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByLiteral( Vec_Int_t * vCover, Vec_Int_t * vDiv, Vec_Int_t ** pvQuo, Vec_Int_t ** pvRem ) +{ + Vec_Int_t * vQuo, * vRem; + Mvc_Cube_t * pCubeC, * pCubeCopy; + int iLit; + + // get the only cube of D + assert( Vec_IntSize(vDiv) == 1 ); + + // start the quotient and the remainder + vQuo = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + vRem = Mvc_CoverAlloc( vCover->pMem, vCover->nBits ); + + // get the first and only literal in the divisor cube + iLit = Mvc_CoverFirstCubeFirstLit( vDiv ); + + // iterate through the cubes in the cover + Mvc_CoverForEachCube( vCover, pCubeC ) + { + // copy the cube + pCubeCopy = Mvc_CubeDup( vCover, pCubeC ); + // add the cube to the quotient or to the remainder depending on the literal + if ( Mvc_CubeBitValue( pCubeCopy, iLit ) ) + { // remove the literal + Mvc_CubeBitRemove( pCubeCopy, iLit ); + // add the cube ot the quotient + Mvc_CoverAddCubeTail( vQuo, pCubeCopy ); + } + else + { // add the cube ot the remainder + Mvc_CoverAddCubeTail( vRem, pCubeCopy ); + } + } + // return the results + *pvRem = vRem; + *pvQuo = vQuo; +} + + +/**Function************************************************************* + + Synopsis [Derives the quotient of division by literal.] + + Description [Reduces the cover to be the equal to the result of + division of the given cover by the literal.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Mvc_CoverDivideByLiteralQuo( Vec_Int_t * vCover, int iLit ) +{ + Mvc_Cube_t * pCube, * pCube2, * pPrev; + // delete those cubes that do not have this literal + // remove this literal from other cubes + pPrev = NULL; + Mvc_CoverForEachCubeSafe( vCover, pCube, pCube2 ) + { + if ( Mvc_CubeBitValue( pCube, iLit ) == 0 ) + { // delete the cube from the cover + Mvc_CoverDeleteCube( vCover, pPrev, pCube ); + Mvc_CubeFree( vCover, pCube ); + // don't update the previous cube + } + else + { // delete this literal from the cube + Mvc_CubeBitRemove( pCube, iLit ); + // update the previous cube + pPrev = pCube; + } + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/aig/rwt/module.make b/src/aig/rwt/module.make index 2852f2bab..439d576fb 100644 --- a/src/aig/rwt/module.make +++ b/src/aig/rwt/module.make @@ -1,3 +1,3 @@ -SRC += src/hop/rwt/rwtDec.c \ - src/hop/rwt/rwtMan.c \ - src/hop/rwt/rwtUtil.c +SRC += src/aig/rwt/rwtDec.c \ + src/aig/rwt/rwtMan.c \ + src/aig/rwt/rwtUtil.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 4164f67aa..dbbe9d7ed 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -7090,7 +7090,7 @@ int Abc_CommandFpga( Abc_Frame_t * pAbc, int argc, char ** argv ) fRecovery = 1; fSwitching = 0; fLatchPaths = 0; - fVerbose = 1; + fVerbose = 0; DelayTarget =-1; nLutSize =-1; Extra_UtilGetoptReset(); @@ -7392,18 +7392,20 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) // set defaults memset( pPars, 0, sizeof(If_Par_t) ); pPars->Mode = 0; - pPars->nLutSize = 5; + pPars->nLutSize = 4; // pPars->pLutLib = Abc_FrameReadLibLut(); - pPars->nCutsMax = 10; + pPars->nCutsMax = 20; + pPars->fPreprocess = 1; pPars->fArea = 0; pPars->fFancy = 0; pPars->fLatchPaths = 0; + pPars->fExpRed = 1; pPars->fSeq = 0; pPars->nLatches = 0; pPars->DelayTarget = -1; - pPars->fVerbose = 1; + pPars->fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "MKCDaflsvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "MKCDpaflrsvh" ) ) != EOF ) { switch ( c ) { @@ -7451,6 +7453,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pPars->DelayTarget <= 0.0 ) goto usage; break; + case 'p': + pPars->fPreprocess ^= 1; + break; case 'a': pPars->fArea ^= 1; break; @@ -7460,6 +7465,9 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'l': pPars->fLatchPaths ^= 1; break; + case 'r': + pPars->fExpRed ^= 1; + break; case 's': pPars->fSeq ^= 1; break; @@ -7478,6 +7486,12 @@ int Abc_CommandIf( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } + if ( pPars->fSeq ) + { + fprintf( pErr, "Sequential mapping is currently being implemented.\n" ); + goto usage; + } + if ( pPars->Mode < 0 || pPars->Mode > 4 ) { fprintf( pErr, "Incorrect mapping mode.\n" ); @@ -7547,7 +7561,7 @@ usage: sprintf( LutSize, "library" ); else sprintf( LutSize, "%d", pPars->nLutSize ); - fprintf( pErr, "usage: if [-M num] [-K num] [-C num] [-D float] [-aflsvh]\n" ); + fprintf( pErr, "usage: if [-M num] [-K num] [-C num] [-D float] [-pafrsvh]\n" ); fprintf( pErr, "\t performs FPGA mapping of the network as follows:\n" ); fprintf( pErr, "\t 1 - delay only\n" ); fprintf( pErr, "\t 2 - area only\n" ); @@ -7557,9 +7571,11 @@ usage: fprintf( pErr, "\t-K num : the number of LUT inputs (2 < num < 32) [default = %s]\n", LutSize ); fprintf( pErr, "\t-C num : the max number of cuts to use (1 < num < 2^12) [default = %d]\n", pPars->nCutsMax ); fprintf( pErr, "\t-D float : sets the delay constraint for the mapping [default = %s]\n", Buffer ); + fprintf( pErr, "\t-p : toggles preprocessing using several starting points [default = %s]\n", pPars->fPreprocess? "yes": "no" ); fprintf( pErr, "\t-a : toggles area-oriented mapping [default = %s]\n", pPars->fArea? "yes": "no" ); fprintf( pErr, "\t-f : toggles one fancy feature [default = %s]\n", pPars->fFancy? "yes": "no" ); - fprintf( pErr, "\t-l : optimizes latch paths for delay, other paths for area [default = %s]\n", pPars->fLatchPaths? "yes": "no" ); +// fprintf( pErr, "\t-l : optimizes latch paths for delay, other paths for area [default = %s]\n", pPars->fLatchPaths? "yes": "no" ); + fprintf( pErr, "\t-r : enables expansion/reduction of the best cuts [default = %s]\n", pPars->fExpRed? "yes": "no" ); fprintf( pErr, "\t-s : toggles sequential mapping [default = %s]\n", pPars->fSeq? "yes": "no" ); fprintf( pErr, "\t-v : toggles verbose output [default = %s]\n", pPars->fVerbose? "yes": "no" ); fprintf( pErr, "\t-h : prints the command usage\n"); diff --git a/src/base/abci/abcIf.c b/src/base/abci/abcIf.c index 70971952e..704c8ebbe 100644 --- a/src/base/abci/abcIf.c +++ b/src/base/abci/abcIf.c @@ -55,7 +55,11 @@ Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars ) // print a warning about choice nodes if ( Abc_NtkGetChoiceNum( pNtk ) ) - printf( "Performing FPGA mapping with choices.\n" ); + { +// printf( "Performing FPGA mapping with choices.\n" ); + printf( "Currently mapping with choices is not enabled.\n" ); + return NULL; + } // get timing information pPars->pTimesArr = Abc_NtkGetCiArrivalFloats(pNtk); @@ -223,7 +227,6 @@ Abc_Obj_t * Abc_NodeFromIf_rec( Abc_Ntk_t * pNtkNew, If_Man_t * pIfMan, If_Obj_t return pNodeNew; } - /**Function************************************************************* Synopsis [Recursively derives the truth table for the cut.] diff --git a/src/base/abci/abcPrint.c b/src/base/abci/abcPrint.c index 40bf30a6a..002a885c4 100644 --- a/src/base/abci/abcPrint.c +++ b/src/base/abci/abcPrint.c @@ -148,18 +148,18 @@ void Abc_NtkPrintStats( FILE * pFile, Abc_Ntk_t * pNtk, int fFactored ) // print the statistic into a file { FILE * pTable; - pTable = fopen( "fpga/fpga_stats.txt", "a+" ); + pTable = fopen( "a/fpga_stats.txt", "a+" ); fprintf( pTable, "%s ", pNtk->pName ); fprintf( pTable, "%d ", Abc_NtkLevel(pNtk) ); fprintf( pTable, "%d ", Abc_NtkNodeNum(pNtk) ); - fprintf( pTable, "%.2f ", (float)(s_MappingMem)/(float)(1<<20) ); - fprintf( pTable, "%.2f", (float)(s_MappingTime)/(float)(CLOCKS_PER_SEC) ); +// fprintf( pTable, "%.2f ", (float)(s_MappingMem)/(float)(1<<20) ); +// fprintf( pTable, "%.2f", (float)(s_MappingTime)/(float)(CLOCKS_PER_SEC) ); fprintf( pTable, "\n" ); fclose( pTable ); } */ - +/* // print the statistic into a file { static int Counter = 0; @@ -176,6 +176,7 @@ void Abc_NtkPrintStats( FILE * pFile, Abc_Ntk_t * pNtk, int fFactored ) fprintf( pTable, "\n" ); fclose( pTable ); } +*/ /* // print the statistic into a file diff --git a/src/map/fpga/fpga.c b/src/map/fpga/fpga.c index d7a128b08..d04c9910d 100644 --- a/src/map/fpga/fpga.c +++ b/src/map/fpga/fpga.c @@ -57,8 +57,8 @@ void Fpga_Init( Abc_Frame_t * pAbc ) { // set the default library //Fpga_LutLib_t s_LutLib = { "lutlib", 6, {0,1,2,4,8,16,32}, {0,1,2,3,4,5,6} }; - Fpga_LutLib_t s_LutLib = { "lutlib", 5, {0,1,1,1,1,1}, {0,1,1,1,1,1} }; -// Fpga_LutLib_t s_LutLib = { "lutlib", 4, {0,1,1,1,1}, {0,1,1,1,1} }; +// Fpga_LutLib_t s_LutLib = { "lutlib", 5, {0,1,1,1,1,1}, {0,1,1,1,1,1} }; + Fpga_LutLib_t s_LutLib = { "lutlib", 4, {0,1,1,1,1}, {0,1,1,1,1} }; //Fpga_LutLib_t s_LutLib = { "lutlib", 3, {0,1,1,1}, {0,1,1,1} }; Abc_FrameSetLibLut( Fpga_LutLibDup(&s_LutLib) ); diff --git a/src/map/if/if.h b/src/map/if/if.h index a1d2d41b5..31c075286 100644 --- a/src/map/if/if.h +++ b/src/map/if/if.h @@ -55,7 +55,7 @@ typedef enum { IF_BO, // 6: box output IF_BOX, // 7: box IF_VOID // 8: unused object -} Hop_Type_t; +} If_Type_t; //////////////////////////////////////////////////////////////////////// /// BASIC TYPES /// @@ -75,8 +75,10 @@ struct If_Par_t_ If_Lib_t * pLutLib; // the LUT library int nCutsMax; // the max number of cuts int fVerbose; // the verbosity flag + int fPreprocess; // preprossing int fArea; // area-oriented mapping int fFancy; // a fancy feature + int fExpRed; // expand/reduce of the best cuts int fLatchPaths; // reset timing on latch paths int fSeq; // sequential mapping int nLatches; // the number of latches @@ -115,6 +117,7 @@ struct If_Man_t_ int nCutsUsed; // the number of cuts currently used int nCutsMerged; // the total number of cuts merged int nCutsMax; // the maximum number of cuts at a node + float Fi; // the current value of the clock period (for seq mapping) // memory management Mem_Fixed_t * pMem; // memory manager int nEntrySize; // the size of the entry @@ -127,15 +130,16 @@ struct If_Man_t_ // priority cut struct If_Cut_t_ { - float Delay; // the delay of the cut - float Area; // the area of the cut - If_Cut_t * pOne; // the parent cut - If_Cut_t * pTwo; // the parent cut - char fCompl0; // the complemented attribute - char fCompl1; // the complemented attribute - char Phase; // the complemented attribute - char nLeaves; // the number of leaves - int * pLeaves; // the array of fanins + float Delay; // delay of the cut + float Area; // area (or area-flow) of the cut + If_Cut_t * pOne; // parent cut + If_Cut_t * pTwo; // parent cut + unsigned uSign; // cut signature + char fCompl0; // complemented attribute + char fCompl1; // complemented attribute + char Phase; // complemented attribute + char nLeaves; // number of leaves + int * pLeaves; // array of fanins }; // node extension @@ -149,8 +153,7 @@ struct If_Obj_t_ unsigned Level : 24; // logic level of the node int Id; // integer ID int nRefs; // the number of references - short nCuts; // the number of cuts - short iCut; // the number of the best cut + int nCuts; // the number of cuts If_Obj_t * pFanin0; // the first fanin If_Obj_t * pFanin1; // the second fanin If_Obj_t * pEquiv; // the choice node @@ -188,7 +191,8 @@ static inline void If_ObjSetChoice( If_Obj_t * pObj, If_Obj_t * pEqu ) { p static inline If_Cut_t * If_ObjCut( If_Obj_t * pObj, int iCut ) { return pObj->Cuts + iCut; } static inline If_Cut_t * If_ObjCutTriv( If_Obj_t * pObj ) { return pObj->Cuts; } -static inline If_Cut_t * If_ObjCutBest( If_Obj_t * pObj ) { return pObj->Cuts + pObj->iCut; } +static inline If_Cut_t * If_ObjCutBest( If_Obj_t * pObj ) { return pObj->Cuts + 1; } +static inline unsigned If_ObjCutSign( unsigned ObjId ) { return (1 << (ObjId % 31)); } static inline void * If_CutData( If_Cut_t * pCut ) { return *(void **)pCut; } static inline void If_CutSetData( If_Cut_t * pCut, void * pData ) { *(void **)pCut = pData; } @@ -239,6 +243,7 @@ static inline float If_CutLutArea( If_Man_t * p, If_Cut_t * pCut ) { r /*=== ifCore.c ==========================================================*/ extern int If_ManPerformMapping( If_Man_t * p ); +extern int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode, int fRequired ); /*=== ifMan.c ==========================================================*/ extern If_Man_t * If_ManStart( If_Par_t * pPars ); extern void If_ManStop( If_Man_t * p ); @@ -247,6 +252,19 @@ extern If_Obj_t * If_ManCreatePo( If_Man_t * p, If_Obj_t * pDriver, int fCo extern If_Obj_t * If_ManCreateAnd( If_Man_t * p, If_Obj_t * pFan0, int fCompl0, If_Obj_t * pFan1, int fCompl1 ); /*=== ifMap.c ==========================================================*/ extern void If_ObjPerformMapping( If_Man_t * p, If_Obj_t * pObj, int Mode ); +extern float If_CutAreaDerefed( If_Man_t * p, If_Cut_t * pCut, int nLevels ); +extern float If_CutAreaRefed( If_Man_t * p, If_Cut_t * pCut, int nLevels ); +extern float If_CutDeref( If_Man_t * p, If_Cut_t * pCut, int nLevels ); +extern float If_CutRef( If_Man_t * p, If_Cut_t * pCut, int nLevels ); +extern void If_CutPrint( If_Man_t * p, If_Cut_t * pCut ); +extern float If_CutDelay( If_Man_t * p, If_Cut_t * pCut ); +extern float If_CutFlow( If_Man_t * p, If_Cut_t * pCut ); +extern int If_CutMerge( If_Cut_t * pCut0, If_Cut_t * pCut1, If_Cut_t * pCut, int nLimit ); +extern void If_CutCopy( If_Cut_t * pCutDest, If_Cut_t * pCutSrc ); +/*=== ifReduce.c ==========================================================*/ +extern void If_ManImproveMapping( If_Man_t * p ); +/*=== ifSelect.c ==========================================================*/ +extern void If_ManPerformMappingPreprocess( If_Man_t * p ); /*=== ifUtil.c ==========================================================*/ extern float If_ManDelayMax( If_Man_t * p ); extern void If_ManCleanNodeCopy( If_Man_t * p ); diff --git a/src/map/if/ifCore.c b/src/map/if/ifCore.c index 37a22d8b4..e139e14ba 100644 --- a/src/map/if/ifCore.c +++ b/src/map/if/ifCore.c @@ -24,8 +24,6 @@ /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// -static int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode ); - //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -44,7 +42,7 @@ static int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode ); int If_ManPerformMapping( If_Man_t * p ) { If_Obj_t * pObj; - int nItersFlow = 2; + int nItersFlow = 1; int nItersArea = 1; int clkTotal = clock(); int i; @@ -56,13 +54,27 @@ int If_ManPerformMapping( If_Man_t * p ) If_ManForEachPi( p, pObj, i ) pObj->EstRefs = (float)1.0; // delay oriented mapping - If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0 ); + if ( p->pPars->fPreprocess && !p->pPars->fArea && p->pPars->nCutsMax >= 4 ) + If_ManPerformMappingPreprocess( p ); + else + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 1 ); + // try to improve area by expanding and reducing the cuts + if ( p->pPars->fExpRed ) + If_ManImproveMapping( p ); // area flow oriented mapping for ( i = 0; i < nItersFlow; i++ ) - If_ManPerformMappingRound( p, p->pPars->nCutsMax, 1 ); + { + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 1, 1 ); + if ( p->pPars->fExpRed ) + If_ManImproveMapping( p ); + } // area oriented mapping for ( i = 0; i < nItersArea; i++ ) - If_ManPerformMappingRound( p, p->pPars->nCutsMax, 2 ); + { + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 2, 1 ); + if ( p->pPars->fExpRed ) + If_ManImproveMapping( p ); + } if ( p->pPars->fVerbose ) { PRT( "Total time", clock() - clkTotal ); @@ -81,7 +93,7 @@ int If_ManPerformMapping( If_Man_t * p ) SeeAlso [] ***********************************************************************/ -int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode ) +int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode, int fRequired ) { If_Obj_t * pObj; int i, clk = clock(); @@ -94,15 +106,18 @@ int If_ManPerformMappingRound( If_Man_t * p, int nCutsUsed, int Mode ) If_ManForEachNode( p, pObj, i ) If_ObjPerformMapping( p, pObj, Mode ); // compute required times and stats - If_ManComputeRequired( p, Mode==0 ); - if ( p->pPars->fVerbose ) + if ( fRequired ) { - char Symb = (Mode == 0)? 'D' : ((Mode == 1)? 'F' : 'A'); - printf( "%c: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", - Symb, p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); - PRT( "T", clock() - clk ); + If_ManComputeRequired( p, Mode==0 ); + if ( p->pPars->fVerbose ) + { + char Symb = (Mode == 0)? 'D' : ((Mode == 1)? 'F' : 'A'); + printf( "%c: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", + Symb, p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + PRT( "T", clock() - clk ); // printf( "Max number of cuts = %d. Average number of cuts = %5.2f.\n", // p->nCutsMax, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + } } return 1; } diff --git a/src/map/if/ifMan.c b/src/map/if/ifMan.c index bc13c6f02..b0c12fea6 100644 --- a/src/map/if/ifMan.c +++ b/src/map/if/ifMan.c @@ -191,6 +191,7 @@ If_Obj_t * If_ManCreateAnd( If_Man_t * p, If_Obj_t * pFan0, int fCompl0, If_Obj_ ***********************************************************************/ If_Obj_t * If_ManSetupObj( If_Man_t * p ) { + If_Cut_t * pCut; If_Obj_t * pObj; int i, * pArrays; // get memory for the object @@ -204,10 +205,12 @@ If_Obj_t * If_ManSetupObj( If_Man_t * p ) pObj->Id = Vec_PtrSize(p->vObjs); Vec_PtrPush( p->vObjs, pObj ); // assign elementary cut + pCut = pObj->Cuts; + pCut->nLeaves = 1; + pCut->pLeaves[0] = p->pPars->fSeq? (pObj->Id << 8) : pObj->Id; + pCut->uSign = If_ObjCutSign( pCut->pLeaves[0] ); + // set the number of cuts pObj->nCuts = 1; - pObj->Cuts[0].nLeaves = 1; - pObj->Cuts[0].pLeaves[0] = pObj->Id; - pObj->iCut = 0; // set the required times pObj->Required = IF_FLOAT_LARGE; return pObj; diff --git a/src/map/if/ifMap.c b/src/map/if/ifMap.c index 0b5050620..9134dc9a4 100644 --- a/src/map/if/ifMap.c +++ b/src/map/if/ifMap.c @@ -37,6 +37,26 @@ /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// +/**Function************************************************************* + + Synopsis [Counts the number of 1s in the signature.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int If_WordCountOnes( unsigned uWord ) +{ + uWord = (uWord & 0x55555555) + ((uWord>>1) & 0x55555555); + uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333); + uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F); + uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF); + return (uWord & 0x0000FFFF) + (uWord>>16); +} + /**Function************************************************************* Synopsis [Returns 1 if pDom is contained in pCut.] @@ -95,7 +115,7 @@ static inline int If_CutCheckEquality( If_Cut_t * pDom, If_Cut_t * pCut ) SeeAlso [] ***********************************************************************/ -int If_CutFilter( If_Man_t * p, If_Cut_t * pCut ) +int If_CutFilter( If_Man_t * p, If_Cut_t * pCut, int Mode ) { If_Cut_t * pTemp; int i; @@ -103,21 +123,37 @@ int If_CutFilter( If_Man_t * p, If_Cut_t * pCut ) { pTemp = p->ppCuts[i]; if ( pTemp->nLeaves > pCut->nLeaves ) - continue; - // skip the non-contained cuts -// if ( (pTemp->uSign & pCut->uSign) != pTemp->uSign ) + { // continue; - // check containment seriously - if ( If_CutCheckDominance( pTemp, pCut ) ) -// if ( If_CutCheckEquality( pTemp, pCut ) ) - return 1; + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pCut->uSign ) + continue; + // check containment seriously + if ( If_CutCheckDominance( pCut, pTemp ) ) + { + // removed contained cut + p->ppCuts[i] = p->ppCuts[p->nCuts-1]; + p->ppCuts[p->nCuts-1] = pTemp; + p->nCuts--; + i--; + } + } + else + { + // skip the non-contained cuts + if ( (pTemp->uSign & pCut->uSign) != pTemp->uSign ) + continue; + // check containment seriously + if ( If_CutCheckDominance( pTemp, pCut ) ) + return 1; + } } return 0; } /**Function************************************************************* - Synopsis [Prepares the object for FPGA mapping.] + Synopsis [Merges two cuts.] Description [] @@ -126,7 +162,7 @@ int If_CutFilter( If_Man_t * p, If_Cut_t * pCut ) SeeAlso [] ***********************************************************************/ -int If_CutMergeOrdered( If_Cut_t * pC0, If_Cut_t * pC1, If_Cut_t * pC, int nLimit ) +static inline int If_CutMergeOrdered( If_Cut_t * pC0, If_Cut_t * pC1, If_Cut_t * pC, int nLimit ) { int i, k, c; assert( pC0->nLeaves >= pC1->nLeaves ); @@ -201,6 +237,58 @@ int If_CutMergeOrdered( If_Cut_t * pC0, If_Cut_t * pC1, If_Cut_t * pC, int nLimi return 1; } +/**Function************************************************************* + + Synopsis [Merges two cuts.] + + Description [Special case when the cut is known to exist.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int If_CutMergeOrdered2( If_Cut_t * pC0, If_Cut_t * pC1, If_Cut_t * pC, int nLimit ) +{ + int i, k, c; + assert( pC0->nLeaves >= pC1->nLeaves ); + // copy the first cut + for ( i = 0; i < pC0->nLeaves; i++ ) + pC->pLeaves[i] = pC0->pLeaves[i]; + pC->nLeaves = pC0->nLeaves; + // the case when one of the cuts is the largest + if ( pC0->nLeaves == nLimit ) + return 1; + // add nodes of the second cut + k = 0; + for ( i = 0; i < pC1->nLeaves; i++ ) + { + // find k-th node before which i-th node should be added + for ( ; k < pC->nLeaves; k++ ) + if ( pC->pLeaves[k] >= pC1->pLeaves[i] ) + break; + // check the case when this should be the last node + if ( k == pC->nLeaves ) + { + pC->pLeaves[k++] = pC1->pLeaves[i]; + pC->nLeaves++; + continue; + } + // check the case when equal node is found + if ( pC1->pLeaves[i] == pC->pLeaves[k] ) + continue; + // add the node + for ( c = pC->nLeaves; c > k; c-- ) + pC->pLeaves[c] = pC->pLeaves[c-1]; + pC->pLeaves[k++] = pC1->pLeaves[i]; + pC->nLeaves++; + } + assert( pC->nLeaves <= nLimit ); + for ( i = 1; i < pC->nLeaves; i++ ) + assert( pC->pLeaves[i-1] < pC->pLeaves[i] ); + return 1; +} + /**Function************************************************************* Synopsis [Prepares the object for FPGA mapping.] @@ -212,7 +300,7 @@ int If_CutMergeOrdered( If_Cut_t * pC0, If_Cut_t * pC1, If_Cut_t * pC, int nLimi SeeAlso [] ***********************************************************************/ -static inline int If_CutMerge( If_Cut_t * pCut0, If_Cut_t * pCut1, If_Cut_t * pCut, int nLimit ) +int If_CutMerge( If_Cut_t * pCut0, If_Cut_t * pCut1, If_Cut_t * pCut, int nLimit ) { // merge the nodes if ( pCut0->nLeaves < pCut1->nLeaves ) @@ -243,17 +331,17 @@ int If_CutCompareDelay( If_Cut_t ** ppC0, If_Cut_t ** ppC1 ) { If_Cut_t * pC0 = *ppC0; If_Cut_t * pC1 = *ppC1; - if ( pC0->Delay < pC1->Delay ) + if ( pC0->Delay < pC1->Delay - 0.0001 ) return -1; - if ( pC0->Delay > pC1->Delay ) + if ( pC0->Delay > pC1->Delay + 0.0001 ) return 1; if ( pC0->nLeaves < pC1->nLeaves ) return -1; if ( pC0->nLeaves > pC1->nLeaves ) return 1; - if ( pC0->Area < pC1->Area ) + if ( pC0->Area < pC1->Area - 0.0001 ) return -1; - if ( pC0->Area > pC1->Area ) + if ( pC0->Area > pC1->Area + 0.0001 ) return 1; return 0; } @@ -273,13 +361,13 @@ int If_CutCompareDelayOld( If_Cut_t ** ppC0, If_Cut_t ** ppC1 ) { If_Cut_t * pC0 = *ppC0; If_Cut_t * pC1 = *ppC1; - if ( pC0->Delay < pC1->Delay ) + if ( pC0->Delay < pC1->Delay - 0.0001 ) return -1; - if ( pC0->Delay > pC1->Delay ) + if ( pC0->Delay > pC1->Delay + 0.0001 ) return 1; - if ( pC0->Area < pC1->Area ) + if ( pC0->Area < pC1->Area - 0.0001 ) return -1; - if ( pC0->Area > pC1->Area ) + if ( pC0->Area > pC1->Area + 0.0001 ) return 1; if ( pC0->nLeaves < pC1->nLeaves ) return -1; @@ -303,17 +391,17 @@ int If_CutCompareArea( If_Cut_t ** ppC0, If_Cut_t ** ppC1 ) { If_Cut_t * pC0 = *ppC0; If_Cut_t * pC1 = *ppC1; - if ( pC0->Area < pC1->Area ) + if ( pC0->Area < pC1->Area - 0.0001 ) return -1; - if ( pC0->Area > pC1->Area ) + if ( pC0->Area > pC1->Area + 0.0001 ) return 1; if ( pC0->nLeaves < pC1->nLeaves ) return -1; if ( pC0->nLeaves > pC1->nLeaves ) return 1; - if ( pC0->Delay < pC1->Delay ) + if ( pC0->Delay < pC1->Delay - 0.0001 ) return -1; - if ( pC0->Delay > pC1->Delay ) + if ( pC0->Delay > pC1->Delay + 0.0001 ) return 1; return 0; } @@ -394,33 +482,6 @@ float If_CutFlow( If_Man_t * p, If_Cut_t * pCut ) return Flow; } -/**Function************************************************************* - - Synopsis [Computes area of the first level.] - - Description [The cut need to be derefed.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -float If_CutRef( If_Man_t * p, If_Cut_t * pCut, int nLevels ) -{ - If_Obj_t * pLeaf; - float Area; - int i; - Area = If_CutLutArea(p, pCut); - If_CutForEachLeaf( p, pCut, pLeaf, i ) - { - assert( pLeaf->nRefs >= 0 ); - if ( pLeaf->nRefs++ > 0 || !If_ObjIsAnd(pLeaf) || nLevels == 1 ) - continue; - Area += If_CutRef( p, If_ObjCutBest(pLeaf), nLevels - 1 ); - } - return Area; -} - /**Function************************************************************* Synopsis [Computes area of the first level.] @@ -459,7 +520,54 @@ float If_CutDeref( If_Man_t * p, If_Cut_t * pCut, int nLevels ) SeeAlso [] ***********************************************************************/ -float If_CutArea( If_Man_t * p, If_Cut_t * pCut, int nLevels ) +float If_CutRef( If_Man_t * p, If_Cut_t * pCut, int nLevels ) +{ + If_Obj_t * pLeaf; + float Area; + int i; + Area = If_CutLutArea(p, pCut); + If_CutForEachLeaf( p, pCut, pLeaf, i ) + { + assert( pLeaf->nRefs >= 0 ); + if ( pLeaf->nRefs++ > 0 || !If_ObjIsAnd(pLeaf) || nLevels == 1 ) + continue; + Area += If_CutRef( p, If_ObjCutBest(pLeaf), nLevels - 1 ); + } + return Area; +} + +/**Function************************************************************* + + Synopsis [Prints one cut.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_CutPrint( If_Man_t * p, If_Cut_t * pCut ) +{ + int i; + printf( "{" ); + for ( i = 0; i < pCut->nLeaves; i++ ) + printf( " %d", pCut->pLeaves[i] ); + printf( " }\n" ); +} + +/**Function************************************************************* + + Synopsis [Computes area of the first level.] + + Description [The cut need to be derefed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float If_CutAreaDerefed( If_Man_t * p, If_Cut_t * pCut, int nLevels ) { float aResult, aResult2; assert( pCut->nLeaves > 1 ); @@ -469,6 +577,27 @@ float If_CutArea( If_Man_t * p, If_Cut_t * pCut, int nLevels ) return aResult; } +/**Function************************************************************* + + Synopsis [Computes area of the first level.] + + Description [The cut need to be derefed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +float If_CutAreaRefed( If_Man_t * p, If_Cut_t * pCut, int nLevels ) +{ + float aResult, aResult2; + assert( pCut->nLeaves > 1 ); + aResult2 = If_CutDeref( p, pCut, nLevels ); + aResult = If_CutRef( p, pCut, nLevels ); + assert( aResult == aResult2 ); + return aResult; +} + /**Function************************************************************* Synopsis [Computes area of the first level.] @@ -503,7 +632,7 @@ void If_CutCopy( If_Cut_t * pCutDest, If_Cut_t * pCutSrc ) void If_ObjPerformMapping( If_Man_t * p, If_Obj_t * pObj, int Mode ) { If_Cut_t * pCut0, * pCut1, * pCut; - int i, k; + int i, k, iCut; // prepare if ( Mode == 0 ) @@ -521,17 +650,22 @@ void If_ObjPerformMapping( If_Man_t * p, If_Obj_t * pObj, int Mode ) pCut = If_ObjCutBest(pObj); pCut->Delay = If_CutDelay( p, pCut ); assert( pCut->Delay <= pObj->Required + p->fEpsilon ); - pCut->Area = (Mode == 2)? If_CutArea( p, pCut, 100 ) : If_CutFlow( p, pCut ); + pCut->Area = (Mode == 2)? If_CutAreaDerefed( p, pCut, 100 ) : If_CutFlow( p, pCut ); // save the best cut from the previous iteration If_CutCopy( p->ppCuts[p->nCuts++], pCut ); p->nCutsMerged++; } + // prepare room for the next cut + iCut = p->nCuts; + pCut = p->ppCuts[iCut]; // generate cuts - pCut = p->ppCuts[p->nCuts]; If_ObjForEachCut( pObj->pFanin0, pCut0, i ) If_ObjForEachCut( pObj->pFanin1, pCut1, k ) { + // make sure K-feasible cut exists + if ( If_WordCountOnes(pCut0->uSign | pCut1->uSign) > p->pPars->nLutSize ) + continue; // prefilter using arrival times if ( Mode && (pCut0->Delay > pObj->Required + p->fEpsilon || pCut1->Delay > pObj->Required + p->fEpsilon) ) continue; @@ -539,7 +673,8 @@ void If_ObjPerformMapping( If_Man_t * p, If_Obj_t * pObj, int Mode ) if ( !If_CutMerge( pCut0, pCut1, pCut, p->pPars->nLutSize ) ) continue; // check if this cut is contained in any of the available cuts - if ( If_CutFilter( p, pCut ) ) + pCut->uSign = pCut0->uSign | pCut1->uSign; + if ( If_CutFilter( p, pCut, Mode ) ) continue; // check if the cut satisfies the required times pCut->Delay = If_CutDelay( p, pCut ); @@ -549,18 +684,26 @@ void If_ObjPerformMapping( If_Man_t * p, If_Obj_t * pObj, int Mode ) pCut->pOne = pCut0; pCut->fCompl0 = pObj->fCompl0; pCut->pTwo = pCut1; pCut->fCompl1 = pObj->fCompl1; // pCut->Phase = ... - pCut->Area = (Mode == 2)? If_CutArea( p, pCut, 100 ) : If_CutFlow( p, pCut ); +// pCut->Phase = (char)(int)If_CutAreaDerefed( p, pCut, 1 ); + pCut->Area = (Mode == 2)? If_CutAreaDerefed( p, pCut, 100 ) : If_CutFlow( p, pCut ); p->nCutsMerged++; + // make sure the cut is the last one (after filtering it may not be so) + assert( pCut == p->ppCuts[iCut] ); + p->ppCuts[iCut] = p->ppCuts[p->nCuts]; + p->ppCuts[p->nCuts] = pCut; // prepare room for the next cut - pCut = p->ppCuts[++p->nCuts]; + iCut = ++p->nCuts; + pCut = p->ppCuts[iCut]; } +//printf( "%d ", p->nCuts ); assert( p->nCuts > 0 ); + // sort if we have more cuts If_ManSortCuts( p, Mode ); - // take the first + // decide how many cuts to use pObj->nCuts = IF_MIN( p->nCuts + 1, p->nCutsUsed ); + // take the first If_ObjForEachCutStart( pObj, pCut, i, 1 ) If_CutCopy( pCut, p->ppCuts[i-1] ); - pObj->iCut = 1; assert( If_ObjCutBest(pObj)->nLeaves > 1 ); // assign delay of the trivial cut If_ObjCutTriv(pObj)->Delay = If_ObjCutBest(pObj)->Delay; diff --git a/src/map/if/ifReduce.c b/src/map/if/ifReduce.c new file mode 100644 index 000000000..5c8da0d04 --- /dev/null +++ b/src/map/if/ifReduce.c @@ -0,0 +1,576 @@ +/**CFile**************************************************************** + + FileName [ifExpand.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [FPGA mapping based on priority cuts.] + + Synopsis [Incremental improvement of current mapping.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - November 21, 2006.] + + Revision [$Id: ifExpand.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "if.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void If_ManImproveReduce( If_Man_t * p, int nLimit ); +static void If_ManImproveExpand( If_Man_t * p, int nLimit ); +static void If_ManImproveNodeExpand( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld, Vec_Ptr_t * vVisited ); +static void If_ManImproveNodePrepare( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld, Vec_Ptr_t * vVisited ); +static void If_ManImproveNodeUpdate( If_Man_t * p, If_Obj_t * pObj, Vec_Ptr_t * vFront ); +static void If_ManImproveNodeFaninCompact( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Improves current mapping using expand/Expand of one cut.] + + Description [Assumes current mapping assigned and required times computed.] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveMapping( If_Man_t * p ) +{ + int clk; + + clk = clock(); + If_ManImproveExpand( p, p->pPars->nLutSize ); + If_ManComputeRequired( p, 0 ); + if ( p->pPars->fVerbose ) + { + printf( "E: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", + p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + PRT( "T", clock() - clk ); + } +/* + clk = clock(); + If_ManImproveReduce( p, p->pPars->nLutSize ); + If_ManComputeRequired( p, 0 ); + if ( p->pPars->fVerbose ) + { + printf( "R: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", + p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + PRT( "T", clock() - clk ); + } + + clk = clock(); + If_ManImproveExpand( p, p->pPars->nLutSize ); + If_ManComputeRequired( p, 0 ); + if ( p->pPars->fVerbose ) + { + printf( "E: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", + p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + PRT( "T", clock() - clk ); + } +*/ +} + +/**Function************************************************************* + + Synopsis [Performs area recovery for each node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveExpand( If_Man_t * p, int nLimit ) +{ + Vec_Ptr_t * vFront, * vFrontOld, * vVisited; + If_Obj_t * pObj; + int i; + vFront = Vec_PtrAlloc( nLimit ); + vFrontOld = Vec_PtrAlloc( nLimit ); + vVisited = Vec_PtrAlloc( 100 ); + // iterate through all nodes in the topological order + If_ManForEachNode( p, pObj, i ) + If_ManImproveNodeExpand( p, pObj, nLimit, vFront, vFrontOld, vVisited ); + Vec_PtrFree( vFront ); + Vec_PtrFree( vFrontOld ); + Vec_PtrFree( vVisited ); +} + +/**Function************************************************************* + + Synopsis [Counts the number of nodes with no external fanout.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveCutCost( If_Man_t * p, Vec_Ptr_t * vFront ) +{ + If_Obj_t * pFanin; + int i, Counter = 0; + Vec_PtrForEachEntry( vFront, pFanin, i ) + if ( pFanin->nRefs == 0 ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Performs area recovery for each node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodeExpand( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld, Vec_Ptr_t * vVisited ) +{ + If_Obj_t * pFanin; + If_Cut_t * pCut; + int CostBef, CostAft, i; + float DelayOld, AreaBef, AreaAft; + pCut = If_ObjCutBest(pObj); + assert( pCut->Delay <= pObj->Required + p->fEpsilon ); + if ( pObj->nRefs == 0 ) + return; + // get the delay + DelayOld = pCut->Delay; + // get the area + AreaBef = If_CutAreaRefed( p, pCut, 100000 ); +// if ( AreaBef == 1 ) +// return; + // the cut is non-trivial + If_ManImproveNodePrepare( p, pObj, nLimit, vFront, vFrontOld, vVisited ); + // iteratively modify the cut + If_CutDeref( p, pCut, 100000 ); + CostBef = If_ManImproveCutCost( p, vFront ); + If_ManImproveNodeFaninCompact( p, pObj, nLimit, vFront, vVisited ); + CostAft = If_ManImproveCutCost( p, vFront ); + If_CutRef( p, pCut, 100000 ); + assert( CostBef >= CostAft ); + // clean up + Vec_PtrForEachEntry( vVisited, pFanin, i ) + pFanin->fMark = 0; + // update the node + If_ManImproveNodeUpdate( p, pObj, vFront ); + pCut->Delay = If_CutDelay( p, pCut ); + // get the new area + AreaAft = If_CutAreaRefed( p, pCut, 100000 ); + if ( AreaAft > AreaBef || pCut->Delay > pObj->Required + p->fEpsilon ) + { + If_ManImproveNodeUpdate( p, pObj, vFrontOld ); + AreaAft = If_CutAreaRefed( p, pCut, 100000 ); + assert( AreaAft == AreaBef ); + pCut->Delay = DelayOld; + } +} + +/**Function************************************************************* + + Synopsis [Performs area recovery for each node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveMark_rec( If_Man_t * p, If_Obj_t * pObj, Vec_Ptr_t * vVisited ) +{ + if ( pObj->fMark ) + return; + assert( If_ObjIsAnd(pObj) ); + If_ManImproveMark_rec( p, If_ObjFanin0(pObj), vVisited ); + If_ManImproveMark_rec( p, If_ObjFanin1(pObj), vVisited ); + Vec_PtrPush( vVisited, pObj ); + pObj->fMark = 1; +} + +/**Function************************************************************* + + Synopsis [Prepares node mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodePrepare( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld, Vec_Ptr_t * vVisited ) +{ + If_Cut_t * pCut; + If_Obj_t * pLeaf; + int i; + Vec_PtrClear( vFront ); + Vec_PtrClear( vFrontOld ); + Vec_PtrClear( vVisited ); + // expand the cut downwards from the given place + pCut = If_ObjCutBest(pObj); + If_CutForEachLeaf( p, pCut, pLeaf, i ) + { + Vec_PtrPush( vFront, pLeaf ); + Vec_PtrPush( vFrontOld, pLeaf ); + Vec_PtrPush( vVisited, pLeaf ); + pLeaf->fMark = 1; + } + // mark the nodes in the cone + If_ManImproveMark_rec( p, pObj, vVisited ); +} + +/**Function************************************************************* + + Synopsis [Updates the frontier.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodeUpdate( If_Man_t * p, If_Obj_t * pObj, Vec_Ptr_t * vFront ) +{ + If_Cut_t * pCut; + If_Obj_t * pFanin; + int i; + pCut = If_ObjCutBest(pObj); + // deref node's cut + If_CutDeref( p, pCut, 10000 ); + // update the node's cut + pCut->nLeaves = Vec_PtrSize(vFront); + Vec_PtrForEachEntry( vFront, pFanin, i ) + pCut->pLeaves[i] = pFanin->Id; + // ref the new cut + If_CutRef( p, pCut, 10000 ); +} + + +/**Function************************************************************* + + Synopsis [Returns 1 if the number of fanins will grow.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeWillGrow( If_Man_t * p, If_Obj_t * pObj ) +{ + If_Obj_t * pFanin0, * pFanin1; + assert( If_ObjIsAnd(pObj) ); + pFanin0 = If_ObjFanin0(pObj); + pFanin1 = If_ObjFanin1(pObj); + return !pFanin0->fMark && !pFanin1->fMark; +} + +/**Function************************************************************* + + Synopsis [Returns the increase in the number of fanins with no external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeFaninCost( If_Man_t * p, If_Obj_t * pObj ) +{ + int Counter = 0; + assert( If_ObjIsAnd(pObj) ); + // check if the node has external refs + if ( pObj->nRefs == 0 ) + Counter--; + // increment the number of fanins without external refs + if ( !If_ObjFanin0(pObj)->fMark && If_ObjFanin0(pObj)->nRefs == 0 ) + Counter++; + // increment the number of fanins without external refs + if ( !If_ObjFanin1(pObj)->fMark && If_ObjFanin1(pObj)->nRefs == 0 ) + Counter++; + return Counter; +} + +/**Function************************************************************* + + Synopsis [Updates the frontier.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodeFaninUpdate( If_Man_t * p, If_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + If_Obj_t * pFanin; + assert( If_ObjIsAnd(pObj) ); + Vec_PtrRemove( vFront, pObj ); + pFanin = If_ObjFanin0(pObj); + if ( !pFanin->fMark ) + { + Vec_PtrPush( vFront, pFanin ); + Vec_PtrPush( vVisited, pFanin ); + pFanin->fMark = 1; + } + pFanin = If_ObjFanin1(pObj); + if ( !pFanin->fMark ) + { + Vec_PtrPush( vFront, pFanin ); + Vec_PtrPush( vVisited, pFanin ); + pFanin->fMark = 1; + } +} + +/**Function************************************************************* + + Synopsis [Compacts the number of external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeFaninCompact0( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + If_Obj_t * pFanin; + int i; + Vec_PtrForEachEntry( vFront, pFanin, i ) + { + if ( If_ObjIsPi(pFanin) ) + continue; + if ( If_ManImproveNodeWillGrow(p, pFanin) ) + continue; + if ( If_ManImproveNodeFaninCost(p, pFanin) <= 0 ) + { + If_ManImproveNodeFaninUpdate( p, pFanin, vFront, vVisited ); + return 1; + } + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Compacts the number of external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeFaninCompact1( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + If_Obj_t * pFanin; + int i; + Vec_PtrForEachEntry( vFront, pFanin, i ) + { + if ( If_ObjIsPi(pFanin) ) + continue; + if ( If_ManImproveNodeFaninCost(p, pFanin) < 0 ) + { + If_ManImproveNodeFaninUpdate( p, pFanin, vFront, vVisited ); + return 1; + } + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Compacts the number of external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeFaninCompact2( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + If_Obj_t * pFanin; + int i; + Vec_PtrForEachEntry( vFront, pFanin, i ) + { + if ( If_ObjIsPi(pFanin) ) + continue; + if ( If_ManImproveNodeFaninCost(p, pFanin) <= 0 ) + { + If_ManImproveNodeFaninUpdate( p, pFanin, vFront, vVisited ); + return 1; + } + } + return 0; +} + +/**Function************************************************************* + + Synopsis [Compacts the number of external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManImproveNodeFaninCompact_int( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + if ( If_ManImproveNodeFaninCompact0(p, pObj, nLimit, vFront, vVisited) ) + return 1; + if ( Vec_PtrSize(vFront) < nLimit && If_ManImproveNodeFaninCompact1(p, pObj, nLimit, vFront, vVisited) ) + return 1; + if ( Vec_PtrSize(vFront) < nLimit && If_ManImproveNodeFaninCompact2(p, pObj, nLimit, vFront, vVisited) ) + return 1; + assert( Vec_PtrSize(vFront) <= nLimit ); + return 0; +} + +/**Function************************************************************* + + Synopsis [Compacts the number of external refs.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodeFaninCompact( If_Man_t * p, If_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vVisited ) +{ + while ( If_ManImproveNodeFaninCompact_int( p, pObj, nLimit, vFront, vVisited ) ); +} + + + + + +/**Function************************************************************* + + Synopsis [Performs fast mapping for one node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveNodeReduce( If_Man_t * p, If_Obj_t * pObj, int nLimit ) +{ + If_Cut_t * pCut, * pCut0, * pCut1, * pCutR; + If_Obj_t * pFanin0, * pFanin1; + float AreaBef, AreaAft; + int RetValue; + + assert( nLimit <= 32 ); + assert( If_ObjIsAnd(pObj) ); + // get the fanins + pFanin0 = If_ObjFanin0(pObj); + pFanin1 = If_ObjFanin1(pObj); + // get the cuts + pCut = If_ObjCutBest(pObj); + pCut0 = If_ObjIsPi(pFanin0) ? If_ObjCutTriv(pFanin0) : If_ObjCutBest(pFanin0); + pCut1 = If_ObjIsPi(pFanin1) ? If_ObjCutTriv(pFanin1) : If_ObjCutBest(pFanin1); + assert( pCut->Delay <= pObj->Required + p->fEpsilon ); + + // deref the cut if the node is refed + if ( pObj->nRefs > 0 ) + If_CutDeref( p, pCut, 100000 ); + // get the area + AreaBef = If_CutAreaDerefed( p, pCut, 100000 ); + // get the fanin support + if ( pFanin0->nRefs > 2 && pCut0->Delay < pObj->Required + p->fEpsilon ) +// if ( pSupp0->nRefs > 0 && pSupp0->Delay < pSupp->DelayR ) // this leads to 2% worse results + { + pCut0 = If_ObjCutTriv(pFanin0); + } + // get the fanin support + if ( pFanin1->nRefs > 2 && pCut1->Delay < pObj->Required + p->fEpsilon ) +// if ( pSupp1->nRefs > 0 && pSupp1->Delay < pSupp->DelayR ) + { + pCut1 = If_ObjCutTriv(pFanin1); + } + + // merge the cuts + pCutR = p->ppCuts[0]; + RetValue = If_CutMerge( pCut0, pCut1, pCutR, nLimit ); + // try very simple cut + if ( !RetValue ) + { + RetValue = If_CutMerge( If_ObjCutTriv(pFanin0), If_ObjCutTriv(pFanin1), pCutR, nLimit ); + assert( RetValue == 1 ); + } + if ( RetValue ) + { + pCutR->Delay = If_CutDelay( p, pCutR ); + AreaAft = If_CutAreaDerefed( p, pCutR, 100000 ); + // update the best cut + if ( AreaAft < AreaBef - p->fEpsilon && pCutR->Delay < pObj->Required + p->fEpsilon ) + If_CutCopy( pCut, pCutR ); + } + // recompute the delay of the best cut + pCut->Delay = If_CutDelay( p, pCut ); + // ref the cut if the node is refed + if ( pObj->nRefs > 0 ) + If_CutRef( p, pCut, 100000 ); +} + +/**Function************************************************************* + + Synopsis [Performs area recovery for each node.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManImproveReduce( If_Man_t * p, int nLimit ) +{ + If_Obj_t * pObj; + int i; + If_ManForEachNode( p, pObj, i ) + { + if ( 278 == i ) + { + int s = 0; + } + If_ManImproveNodeReduce( p, pObj, nLimit ); + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/map/if/ifSelect.c b/src/map/if/ifSelect.c new file mode 100644 index 000000000..d54abb290 --- /dev/null +++ b/src/map/if/ifSelect.c @@ -0,0 +1,175 @@ +/**CFile**************************************************************** + + FileName [ifSelect.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [FPGA mapping based on priority cuts.] + + Synopsis [Selects what mapping to use.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - November 21, 2006.] + + Revision [$Id: ifSelect.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "if.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void If_ManPerformMappingMoveBestCut( If_Man_t * p, int iPosNew, int iPosOld ); +static void If_ManPerformMappingAdjust( If_Man_t * p, int nCuts ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Merges the results of delay, relaxed delay and area-based mapping.] + + Description [Delay target may be different from minimum delay!!!] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManPerformMappingPreprocess( If_Man_t * p ) +{ + float delayArea, delayDelay, delayPure; + int clk = clock(); + assert( p->pPars->nCutsMax >= 4 ); + + // perform min-area mapping and move the cut to the end + p->pPars->fArea = 1; + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 0 ); + p->pPars->fArea = 0; + delayArea = If_ManDelayMax( p ); + if ( p->pPars->DelayTarget != -1 && delayArea < p->pPars->DelayTarget - p->fEpsilon ) + delayArea = p->pPars->DelayTarget; + If_ManPerformMappingMoveBestCut( p, p->pPars->nCutsMax - 1, 1 ); + + // perfrom min-delay mapping and move the cut to the end + p->pPars->fFancy = 1; + If_ManPerformMappingRound( p, p->pPars->nCutsMax - 1, 0, 0 ); + p->pPars->fFancy = 0; + delayDelay = If_ManDelayMax( p ); + if ( p->pPars->DelayTarget != -1 && delayDelay < p->pPars->DelayTarget - p->fEpsilon ) + delayDelay = p->pPars->DelayTarget; + If_ManPerformMappingMoveBestCut( p, p->pPars->nCutsMax - 2, 1 ); + + // perform min-area mapping + If_ManPerformMappingRound( p, p->pPars->nCutsMax - 2, 0, 0 ); + delayPure = If_ManDelayMax( p ); + if ( p->pPars->DelayTarget != -1 && delayPure < p->pPars->DelayTarget - p->fEpsilon ) + delayPure = p->pPars->DelayTarget; + + // decide what to do + if ( delayPure < delayDelay - p->fEpsilon && delayPure < delayArea - p->fEpsilon ) + { + // copy the remaining two cuts + if ( p->pPars->nCutsMax > 4 ) + { + If_ManPerformMappingMoveBestCut( p, 2, p->pPars->nCutsMax - 2 ); + If_ManPerformMappingMoveBestCut( p, 3, p->pPars->nCutsMax - 1 ); + } + If_ManComputeRequired( p, 1 ); + If_ManPerformMappingAdjust( p, 4 ); + } + else if ( delayDelay < delayArea - p->fEpsilon ) + { + If_ManPerformMappingMoveBestCut( p, 1, p->pPars->nCutsMax - 2 ); + If_ManPerformMappingMoveBestCut( p, 2, p->pPars->nCutsMax - 1 ); + If_ManComputeRequired( p, 1 ); + If_ManPerformMappingAdjust( p, 3 ); + } + else + { + If_ManPerformMappingMoveBestCut( p, 1, p->pPars->nCutsMax - 1 ); + If_ManComputeRequired( p, 1 ); + If_ManPerformMappingAdjust( p, 2 ); + } + If_ManComputeRequired( p, 1 ); + if ( p->pPars->fVerbose ) + { + printf( "S: Del = %6.2f. Area = %8.2f. Cuts = %6d. Lim = %2d. Ave = %5.2f. ", + p->RequiredGlo, p->AreaGlo, p->nCutsMerged, p->nCutsUsed, 1.0 * p->nCutsMerged / If_ManAndNum(p) ); + PRT( "T", clock() - clk ); + } +} + +/**Function************************************************************* + + Synopsis [Moves the best cut to the given position.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManPerformMappingMoveBestCut( If_Man_t * p, int iPosNew, int iPosOld ) +{ + If_Obj_t * pObj; + int i; + assert( iPosOld != iPosNew ); + assert( iPosOld > 0 && iPosOld < p->pPars->nCutsMax ); + assert( iPosNew > 0 && iPosNew < p->pPars->nCutsMax ); + If_ManForEachNode( p, pObj, i ) + If_CutCopy( pObj->Cuts + iPosNew, pObj->Cuts + iPosOld ); +} + +/**Function************************************************************* + + Synopsis [Adjusts mapping for the given cuts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ManPerformMappingAdjust( If_Man_t * p, int nCuts ) +{ + If_Cut_t * pCut, * pCutBest; + If_Obj_t * pObj; + int i, c; + assert( nCuts >= 2 && nCuts <= 4 ); + If_ManForEachNode( p, pObj, i ) + { + pCutBest = NULL; + for ( c = 1; c < nCuts; c++ ) + { + pCut = pObj->Cuts + c; + pCut->Delay = If_CutDelay( p, pCut ); + pCut->Area = If_CutFlow( p, pCut ); + assert( pCutBest || pCut->Delay < pObj->Required + p->fEpsilon ); + if ( pCutBest == NULL || + (pCut->Delay < pObj->Required + p->fEpsilon && + pCut->Area < pCutBest->Area - p->fEpsilon) ) + pCutBest = pCut; + } + assert( pCutBest != NULL ); + // check if we need to move + if ( pCutBest != pObj->Cuts + 1 ) + If_CutCopy( pObj->Cuts + 1, pCutBest ); + // set the number of cuts + pObj->nCuts = 2; + } +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/map/if/ifSeq.c b/src/map/if/ifSeq.c new file mode 100644 index 000000000..ce353f498 --- /dev/null +++ b/src/map/if/ifSeq.c @@ -0,0 +1,170 @@ +/**CFile**************************************************************** + + FileName [ifSeq.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [FPGA mapping based on priority cuts.] + + Synopsis [Sequential mapping.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - November 21, 2006.] + + Revision [$Id: ifSeq.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "if.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void If_ObjPerformMappingLI( If_Man_t * p, If_Obj_t * pLatch ); +static void If_ObjPerformMappingLO( If_Man_t * p, If_Obj_t * pLatch, If_Obj_t * pObj ); +static int If_ManMappingSeqConverged( If_Man_t * p ); + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Performs sequential mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManPerformMappingSeq( If_Man_t * p ) +{ + If_Obj_t * pObj, * pLatch; + int i, clkTotal = clock(); + // set the number of cuts used + p->nCutsUsed = p->pPars->nCutsMax; + // set arrival times and trivial cuts at const 1 and PIs + If_ManConst1(p)->Cuts[0].Delay = 0.0; + If_ManForEachPi( p, pObj, i ) + pObj->Cuts[0].Delay = p->pPars->pTimesArr[i]; + // set the fanout estimates of the PIs + If_ManForEachPi( p, pObj, i ) + pObj->EstRefs = (float)1.0; + // delay oriented mapping + p->pPars->fFancy = 1; + If_ManPerformMappingRound( p, p->pPars->nCutsMax, 0, 0 ); + p->pPars->fFancy = 0; + + // perform iterations over the circuit + while ( !If_ManMappingSeqConverged( p ) ) + { + // assign cuts to latches + If_ManForEachLatch( p, pLatch, i ) + If_ObjPerformMappingLI( p, pLatch ); + // assign cuts to primary inputs + If_ManForEachLatch( p, pLatch, i ) + If_ObjPerformMappingLO( p, pLatch, If_ManPi(p, If_ManPiNum(p) - If_ManPoNum(p) + i) ); + // map the nodes + If_ManForEachNode( p, pObj, i ) + If_ObjPerformMapping( p, pObj, 0 ); + } + + if ( p->pPars->fVerbose ) + { + PRT( "Total time", clock() - clkTotal ); + } + return 1; +} + +/**Function************************************************************* + + Synopsis [Performs sequential mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_CutLift( If_Cut_t * pCut ) +{ + int i; + for ( i = 0; i < pCut->nLeaves; i++ ) + pCut->pLeaves[i] = ((pCut->pLeaves[i] >> 8) << 8) | ((pCut->pLeaves[i] & 255) + 1); +} + +/**Function************************************************************* + + Synopsis [Performs sequential mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ObjPerformMappingLI( If_Man_t * p, If_Obj_t * pLatch ) +{ + If_Obj_t * pFanin; + int c; + assert( If_ObjIsPo(pLatch) ); + pFanin = If_ObjFanin0(pLatch); + for ( c = 0; c < pFanin->nCuts; c++ ) + If_CutCopy( pLatch->Cuts + c, pFanin->Cuts + c ); +} + +/**Function************************************************************* + + Synopsis [Performs sequential mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void If_ObjPerformMappingLO( If_Man_t * p, If_Obj_t * pLatch, If_Obj_t * pObj ) +{ + If_Cut_t * pCut; + int c, Limit = IF_MIN( p->nCuts + 1, p->nCutsUsed ); + assert( If_ObjIsPo(pLatch) ); + for ( c = 1; c < Limit; c++ ) + { + pCut = pObj->Cuts + c; + If_CutCopy( pCut, pLatch->Cuts + c - 1 ); + If_CutLift( pCut ); + pCut->Delay -= p->Fi; + } +} + +/**Function************************************************************* + + Synopsis [Performs sequential mapping.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int If_ManMappingSeqConverged( If_Man_t * p ) +{ + return 0; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/map/if/module.make b/src/map/if/module.make index be044da25..362318da6 100644 --- a/src/map/if/module.make +++ b/src/map/if/module.make @@ -1,4 +1,8 @@ SRC += src/map/if/ifCore.c \ + src/map/if/ifCut.c \ src/map/if/ifMan.c \ src/map/if/ifMap.c \ + src/map/if/ifReduce.c \ + src/map/if/ifSelect.c \ + src/map/if/ifSeq.c \ src/map/if/ifUtil.c diff --git a/src/sat/fraig/fraigMan.c b/src/sat/fraig/fraigMan.c index 4e188cf0f..4e12dfe44 100644 --- a/src/sat/fraig/fraigMan.c +++ b/src/sat/fraig/fraigMan.c @@ -64,7 +64,8 @@ void Prove_ParamsSetDefault( Prove_Params_t * pParams ) pParams->nBddSizeLimit = 1000000; // the number of BDD nodes when construction is aborted pParams->fBddReorder = 1; // enables dynamic BDD variable reordering // last-gasp mitering - pParams->nMiteringLimitLast = 1000000; // final mitering limit +// pParams->nMiteringLimitLast = 1000000; // final mitering limit + pParams->nMiteringLimitLast = 0; // final mitering limit // global SAT solver limits pParams->nTotalBacktrackLimit = 0; // global limit on the number of backtracks pParams->nTotalInspectLimit = 0; // global limit on the number of clause inspects