diff --git a/abclib.dsp b/abclib.dsp index ca5d132f96..559d59d2a3 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -1195,6 +1195,10 @@ SOURCE=.\src\bdd\extrab\extraBdd.h # End Source File # Begin Source File +SOURCE=.\src\bdd\extrab\extraLutCas.h +# End Source File +# Begin Source File + SOURCE=.\src\bdd\extrab\extraBddAuto.c # End Source File # Begin Source File diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index dafc9ab44a..a78706032e 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -153,6 +153,7 @@ static int Abc_CommandResubCore ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandResubCheck ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRr ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandCascade ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandLutCas ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandExtract ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandVarMin ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandFaultClasses ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -947,6 +948,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Synthesis", "resub_check", Abc_CommandResubCheck, 0 ); // Cmd_CommandAdd( pAbc, "Synthesis", "rr", Abc_CommandRr, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "cascade", Abc_CommandCascade, 1 ); + Cmd_CommandAdd( pAbc, "Synthesis", "lutcas", Abc_CommandLutCas, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "extract", Abc_CommandExtract, 1 ); Cmd_CommandAdd( pAbc, "Synthesis", "varmin", Abc_CommandVarMin, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "faultclasses", Abc_CommandFaultClasses, 0 ); @@ -8820,6 +8822,81 @@ int Abc_CommandCascade( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Abc_Ntk_t * Abc_NtkLutCascade( Abc_Ntk_t * pNtk, int nLutSize, int fVerbose ); + Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pNtkRes; + int c, nLutSize = 6, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "Kvh" ) ) != EOF ) + { + switch ( c ) + { + case 'K': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-K\" should be followed by an integer.\n" ); + goto usage; + } + nLutSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nLutSize < 0 ) + goto usage; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + + if ( pNtk == NULL ) + { + Abc_Print( -1, "Empty network.\n" ); + return 1; + } + if ( Abc_NtkCoNum(pNtk) != 1 ) + { + Abc_Print( -1, "This command is currently applicable only to single-output networks.\n" ); + return 1; + } + if ( !Abc_NtkIsStrash(pNtk) ) + { + Abc_Print( -1, "Run command \"strash\" to convert the network into an AIG.\n" ); + return 1; + } + pNtkRes = Abc_NtkLutCascade( pNtk, nLutSize, fVerbose ); + if ( pNtkRes == NULL ) + { + Abc_Print( -1, "LUT cascade mapping failed.\n" ); + return 1; + } + Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); + return 0; + +usage: + Abc_Print( -2, "usage: lutcas [-K ] [-vh]\n" ); + Abc_Print( -2, "\t derives single-rail LUT cascade for the primary output function\n" ); + Abc_Print( -2, "\t-K : the number of LUT inputs [default = %d]\n", nLutSize ); + Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 6615bff0ac..b81d813d64 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -19,9 +19,12 @@ ***********************************************************************/ #include "base/abc/abc.h" +#include "bool/kit/kit.h" +#include "aig/miniaig/miniaig.h" #ifdef ABC_USE_CUDD #include "bdd/extrab/extraBdd.h" +#include "bdd/extrab/extraLutCas.h" #endif ABC_NAMESPACE_IMPL_START @@ -116,9 +119,153 @@ Abc_Ntk_t * Abc_NtkCascade( Abc_Ntk_t * pNtk, int nLutSize, int fCheck, int fVer #else Abc_Ntk_t * Abc_NtkCascade( Abc_Ntk_t * pNtk, int nLutSize, int fCheck, int fVerbose ) { return NULL; } +word * Abc_LutCascade( Mini_Aig_t * p, int nLutSize, int fVerbose ) { return NULL; } #endif + +/* + The decomposed structure of the LUT cascade is represented as an array of 64-bit integers (words). + The first word in the record is the number of LUT info blocks in the record, which follow one by one. + Each LUT info block contains the following: + - the number of words in this block + - the number of fanins + - the list of fanins + - the variable ID of the output (can be one of the fanin variables) + - truth tables (one word for 6 vars or less; more words as needed for more than 6 vars) + For a 6-input node, the LUT info block takes 10 words (block size, fanin count, 6 fanins, output ID, truth table). + For a 4-input node, the LUT info block takes 8 words (block size, fanin count, 4 fanins, output ID, truth table). + If the LUT cascade contains a 6-LUT followed by a 4-LUT, the record contains 1+10+8=19 words. +*/ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +word * Abc_LutCascadeGenTest() +{ + word * pLuts = ABC_CALLOC( word, 20 ); int i; + // node count + pLuts[0] = 2; + // first node + pLuts[1+0] = 10; + pLuts[1+1] = 6; + for ( i = 0; i < 6; i++ ) + pLuts[1+2+i] = i; + pLuts[1+8] = 0; + pLuts[1+9] = ABC_CONST(0x8000000000000000); + // second node + pLuts[11+0] = 8; + pLuts[11+1] = 4; + for ( i = 0; i < 4; i++ ) + pLuts[11+2+i] = i ? i + 5 : 0; + pLuts[11+6] = 1; + pLuts[11+7] = ABC_CONST(0xFFFEFFFEFFFEFFFE); + return pLuts; +} +void Abc_LutCascadePrint( word * pLuts ) +{ + int n, i, k; + printf( "Single-rail LUT cascade has %d nodes:\n", (int)pLuts[0] ); + for ( n = 0, i = 1; n < pLuts[0]; n++, i += pLuts[i] ) + { + word nIns = pLuts[i+1]; + word * pIns = pLuts+i+2; + word * pT = pLuts+i+2+nIns+1; + printf( "LUT%d : ", n ); + printf( "%02d = F( ", (int)pIns[nIns] ); + for ( k = 0; k < nIns; k++ ) + printf( "%02d ", (int)pIns[k] ); + for ( ; k < 8; k++ ) + printf( " " ); + printf( ") " ); + Extra_PrintHex2( stdout, (unsigned *)pT, nIns ); + printf( "\n" ); + } +} +word * Abc_LutCascadeTest( Mini_Aig_t * p, int nLutSize, int fVerbose ) +{ + word * pLuts = Abc_LutCascadeGenTest(); + Abc_LutCascadePrint( pLuts ); + return pLuts; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Obj_t * Abc_NtkLutCascadeDeriveSop( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNodeNew, word * pT, int nIns, Vec_Int_t * vCover ) +{ + int RetValue = Kit_TruthIsop( (unsigned *)pT, nIns, vCover, 1 ); + assert( RetValue == 0 || RetValue == 1 ); + if ( Vec_IntSize(vCover) == 0 || (Vec_IntSize(vCover) == 1 && Vec_IntEntry(vCover,0) == 0) ) { + assert( RetValue == 0 ); + pNodeNew->pData = Abc_SopCreateAnd( (Mem_Flex_t *)pNtkNew->pManFunc, nIns, NULL ); + return (Vec_IntSize(vCover) == 0) ? Abc_NtkCreateNodeConst0(pNtkNew) : Abc_NtkCreateNodeConst1(pNtkNew); + } + else { + char * pSop = Abc_SopCreateFromIsop( (Mem_Flex_t *)pNtkNew->pManFunc, nIns, vCover ); + if ( RetValue ) Abc_SopComplement( (char *)pSop ); + pNodeNew->pData = pSop; + return pNodeNew; + } +} +Abc_Ntk_t * Abc_NtkLutCascadeFromLuts( word * pLuts, Abc_Ntk_t * pNtk, int nLutSize, int fVerbose ) +{ + Abc_Ntk_t * pNtkNew = Abc_NtkStartFrom( pNtk, ABC_NTK_LOGIC, ABC_FUNC_SOP ); + Vec_Int_t * vCover = Vec_IntAlloc( 1000 ); word n, i, k, iLastLut = -1; + assert( Abc_NtkCoNum(pNtk) == 1 ); + for ( n = 0, i = 1; n < pLuts[0]; n++, i += pLuts[i] ) + { + word nIns = pLuts[i+1]; + word * pIns = pLuts+i+2; + word * pT = pLuts+i+2+nIns+1; + Abc_Obj_t * pNodeNew = Abc_NtkCreateNode( pNtkNew ); + for ( k = 0; k < nIns; k++ ) + Abc_ObjAddFanin( pNodeNew, Abc_NtkCi(pNtk, pIns[k])->pCopy ); + Abc_NtkCi(pNtk, pIns[nIns])->pCopy = Abc_NtkLutCascadeDeriveSop( pNtkNew, pNodeNew, pT, nIns, vCover ); + iLastLut = pIns[nIns]; + } + Vec_IntFree( vCover ); + Abc_ObjAddFanin( Abc_NtkCo(pNtk, 0)->pCopy, Abc_NtkCi(pNtk, iLastLut)->pCopy ); + if ( !Abc_NtkCheck( pNtkNew ) ) + { + printf( "Abc_NtkLutCascadeFromLuts: The network check has failed.\n" ); + Abc_NtkDelete( pNtkNew ); + return NULL; + } + return pNtkNew; +} +Abc_Ntk_t * Abc_NtkLutCascade( Abc_Ntk_t * pNtk, int nLutSize, int fVerbose ) +{ + extern Gia_Man_t * Abc_NtkStrashToGia( Abc_Ntk_t * pNtk ); + extern Mini_Aig_t * Gia_ManToMiniAig( Gia_Man_t * pGia ); + extern word * Abc_LutCascade( Mini_Aig_t * p, int nLutSize, int fVerbose ); + Gia_Man_t * pGia = Abc_NtkStrashToGia( pNtk ); + Mini_Aig_t * pM = Gia_ManToMiniAig( pGia ); + word * pLuts = Abc_LutCascade( pM, nLutSize, fVerbose ); + Abc_Ntk_t * pNew = pLuts ? Abc_NtkLutCascadeFromLuts( pLuts, pNtk, nLutSize, fVerbose ) : NULL; + ABC_FREE( pLuts ); + Mini_AigStop( pM ); + Gia_ManStop( pGia ); + return pNew; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/bdd/extrab/extraLutCas.h b/src/bdd/extrab/extraLutCas.h new file mode 100644 index 0000000000..df7a14010f --- /dev/null +++ b/src/bdd/extrab/extraLutCas.h @@ -0,0 +1,72 @@ +/**CFile**************************************************************** + + FileName [extraLutCas.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [extra] + + Synopsis [LUT cascade decomposition.] + + Description [LUT cascade decomposition.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - August 6, 2024.] + + Revision [$Id: extraLutCas.h,v 1.00 2024/08/06 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#ifndef ABC__misc__extra__extra_lutcas_h +#define ABC__misc__extra__extra_lutcas_h + +#ifdef _WIN32 +#define inline __inline // compatible with MS VS 6.0 +#endif + +#include +#include +#include +#include + +#include "bdd/cudd/cuddInt.h" + +ABC_NAMESPACE_HEADER_START + +/* + The decomposed structure of the LUT cascade is represented as an array of 64-bit integers (words). + The first word in the record is the number of LUT info blocks in the record, which follow one by one. + Each LUT info block contains the following: + - the number of words in this block + - the number of fanins + - the list of fanins + - the variable ID of the output (can be one of the fanin variables) + - truth tables (one word for 6 vars or less; more words as needed for more than 6 vars) + For a 6-input node, the LUT info block takes 10 words (block size, fanin count, 6 fanins, output ID, truth table). + For a 4-input node, the LUT info block takes 8 words (block size, fanin count, 4 fanins, output ID, truth table). + If the LUT cascade contains a 6-LUT followed by a 4-LUT, the record contains 1+10+8=19 words. +*/ + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline word * Abc_LutCascade( Mini_Aig_t * p, int nLutSize, int fVerbose ) +{ + word * pLuts = NULL; + return pLuts; +} + +ABC_NAMESPACE_HEADER_END + +#endif /* __EXTRA_H__ */