From bb11cc4c46e8bea5096f0de1dfcb6f7d59e6c7b0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 29 Mar 2025 15:37:22 -0700 Subject: [PATCH] Experiments with adder-tree mapping. --- src/base/abc/abcUtil.c | 160 +++++++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 78 +++++++++++++++++++- 2 files changed, 237 insertions(+), 1 deletion(-) diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index 88a16e7b6..812256a1d 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -24,6 +24,7 @@ #include "bool/dec/dec.h" #include "opt/fxu/fxu.h" #include "aig/miniaig/ndr.h" +#include "misc/util/utilTruth.h" #ifdef ABC_USE_CUDD #include "bdd/extrab/extraBdd.h" @@ -3352,6 +3353,165 @@ Abc_Ntk_t * Abc_NtkFromArray() return pNtkNew; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_PrintAT( Vec_Int_t * vRanks ) +{ + int i, Entry; + Vec_IntForEachEntryReverse( vRanks, Entry, i ) + if ( Entry == 0 ) + printf( " " ); + else + printf( "%4d", Entry ); + //printf( "\n" ); +} +int Abc_NtkMatchGpcPattern( Vec_Int_t * vRanks, int i, char * pGPC ) +{ + int k, Cur, Min = ABC_INFINITY; + for ( k = 0; pGPC[k] != ':' && i+k < Vec_IntSize(vRanks); k++ ) { + Cur = Vec_IntEntry(vRanks, i+k) / Abc_TtReadHexDigit(pGPC[k]); + if ( Min > Cur ) + Min = Cur; + } + return Min; +} +void Abc_NtkUpdateGpcPattern( Vec_Int_t * vRank, int i, char * pGPC, int nGpcs, Vec_Int_t * vRank2, Vec_Int_t * vLevel ) +{ + int k; char * pOut = strstr(pGPC, ":"); + assert( pOut && pOut[0] == ':' ); + pOut++; + Vec_IntAddToEntry( vLevel, i, nGpcs ); + for ( k = 0; pGPC[k] != ':'; k++ ) + Vec_IntAddToEntry( vRank, i+k, -nGpcs * Abc_TtReadHexDigit(pGPC[k]) ); + for ( k = 0; pOut[k] != ':'; k++ ) + Vec_IntAddToEntry( vRank2, i+k, nGpcs * Abc_TtReadHexDigit(pOut[k]) ); +} +int Abc_NtkGetGpcLutCount( char * pGPC ) +{ + char * pOut = strstr(pGPC, ":"); + char * pLut = strstr(pOut+1, ":"); + return atoi(pLut+1); +} +static inline int Vec_WecSum( Vec_Wec_t * p ) +{ + Vec_Int_t * vVec; + int i, Counter = 0; + Vec_WecForEachLevel( p, vVec, i ) + Counter += Vec_IntSum(vVec); + return Counter; +} +char ** Abc_NtkTransformGPCs( char ** pGPCs, int nGPCs ) +{ + char * pOut, * pLut, ** pRes = ABC_ALLOC( char *, nGPCs ); + int i, k, nLength; + for ( i = 0; i < nGPCs; i++ ) { + pRes[i] = Abc_UtilStrsav(pGPCs[i]); + pOut = strstr(pRes[i], ":"); + nLength = (int)(pOut-pRes[i]); + for ( k = 0; k < nLength/2; k++ ) + ABC_SWAP( char, pRes[i][k], pRes[i][nLength-1-k] ) + pLut = strstr(pOut+1, ":"); + nLength = (int)(pLut-pOut-1); + for ( k = 0; k < nLength/2; k++ ) + ABC_SWAP( char, pOut[1+k], pOut[1+nLength-1-k] ) + } + return pRes; +} +void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fVerbose ) +{ + abctime clkStart = Abc_Clock(); + char ** pGPCs = Abc_NtkTransformGPCs(pGPCs0, nGPCs); + int i, nGPCluts[100] = {0}; + for ( i = 0; i < nGPCs; i++ ) + nGPCluts[i] = Abc_NtkGetGpcLutCount(pGPCs[i]); + int x, n, Entry, iLevel = 0, Sum = 0, nGpcs = 0, nBits, fFinished, nLuts = 0; + for ( x = 0; x < nXVars; x++ ) + Sum += (1 << x) * nYVars; + nBits = Abc_Base2Log( Sum ); + printf( "Rectangular adder tree (X=%d Y=%d Sum=%d Out=%d) mapped with", nXVars, nYVars, Sum, nBits ); + for ( i = 0; i < nGPCs; i++ ) + printf( " GPC%d=%s", i, pGPCs0[i] ); + printf( "\n" ); + Vec_Int_t * vLevel; + Vec_Int_t * vRank[2] = { Vec_IntAlloc(100), Vec_IntAlloc(100) }; + Vec_Wec_t ** vGPCs = ABC_ALLOC( Vec_Wec_t *, nGPCs ); + for ( i = 0; i < nGPCs; i++ ) + vGPCs[i] = Vec_WecAlloc(100); + Vec_IntFill( vRank[0], nBits, 0 ); + for ( x = 0; x < nXVars; x++ ) + Vec_IntAddToEntry( vRank[0], x, nYVars ); + printf( "Ranks: " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " : " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " LUT6\n" ); + for ( n = 0; n < nGPCs; n++ ) + for ( i = 0, fFinished = 0; !fFinished; i++ ) + { + printf( "Lev%02d: ", iLevel++ ); + Abc_PrintAT( vRank[0] ); + vLevel = Vec_WecPushLevel( vGPCs[n] ); + Vec_IntFill( vLevel, nBits, 0 ); + Vec_IntFill( vRank[1], nBits, 0 ); + fFinished = 1; + for ( x = 0; x < nBits; x++ ) + if ( (nGpcs = Abc_NtkMatchGpcPattern(vRank[0], x, pGPCs[n])) ) + Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0; + printf( " GPC%d: ", n ); + Abc_PrintAT( vLevel ); + printf( " %4d", Vec_IntSum(vLevel) * nGPCluts[n] ); + printf( "\n" ); + nLuts += Vec_IntSum(vLevel) * nGPCluts[n]; + Vec_IntForEachEntry( vRank[1], Entry, x ) + Vec_IntAddToEntry( vRank[0], x, Entry ); + } + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[0], x) > 2 ) + break; + if ( x < nBits ) + printf( "Synthesis of the adder tree is incomplete. Try using the full adder \"3:11:1\" as the last GPC.\n" ); + else { + printf( "Lev%02d: ", iLevel++ ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", 1 ); + printf( " RCA : " ); + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[0], x) > 1 ) + break; + for ( i = nBits-1; i >= x; i-- ) + printf( "%4d", 1 ); + for ( ; i >= 0; i-- ) + printf( " " ); + printf( " %4d", nBits-x ); + printf( "\n" ); + } + printf( "Statistics: " ); + for ( n = 0; n < nGPCs; n++ ) + printf( "GPC%d = %d. ", n, Vec_WecSum(vGPCs[n]) ); + printf( "RCA = %d. ", nBits-x ); + printf( "Total LUT count = %d. ", nLuts+nBits-x ); + Vec_IntFree( vRank[0] ); + Vec_IntFree( vRank[1] ); + for ( i = 0; i < nGPCs; i++ ) + Vec_WecFree( vGPCs[i] ); + ABC_FREE( vGPCs ); + for ( i = 0; i < nGPCs; i++ ) + ABC_FREE( pGPCs[i] ); + ABC_FREE( pGPCs ); + Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e52c1f4ee..166ede24b 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -341,6 +341,7 @@ static int Abc_CommandClockGate ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandExtWin ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandInsWin ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandSymFun ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandATMap ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandPermute ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandUnpermute ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandCubeEnum ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1149,6 +1150,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Sequential", "extwin", Abc_CommandExtWin, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "inswin", Abc_CommandInsWin, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "symfun", Abc_CommandSymFun, 0 ); + Cmd_CommandAdd( pAbc, "Sequential", "atmap", Abc_CommandATMap, 0 ); Cmd_CommandAdd( pAbc, "Sequential", "permute", Abc_CommandPermute, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "unpermute", Abc_CommandUnpermute, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "cubeenum", Abc_CommandCubeEnum, 0 ); @@ -26067,9 +26069,83 @@ usage: Abc_Print( -2, "\t : the string of N+1 zeros and ones, where N is the number of variables\n" ); Abc_Print( -2, "\t For example, to get 3-input NAND-gate, use \"symfun 1000\".\n" ); Abc_Print( -2, "\t To get 5-input majority gate, use \"symfun 000111\".\n" ); - return 1; } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPC, int nGPCs, int fVerbose ); + int c, nXVars = -1, nYVars = -1, fVerbose = 0; + char * pGPCs0[1] = { (char*)"3:11:1" }; + char ** pGPCs = NULL; int nGPCs = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "XYvh" ) ) != EOF ) + { + switch ( c ) + { + case 'X': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-X\" should be followed by a file name.\n" ); + goto usage; + } + nXVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'Y': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-Y\" should be followed by a file name.\n" ); + goto usage; + } + nYVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + Abc_Print( -2, "Unknown switch.\n"); + goto usage; + } + } + pGPCs = argv + globalUtilOptind; + nGPCs = argc - globalUtilOptind; + if ( nGPCs == 0 ) + { + printf( "GPCs are not listed on the command line. The simplest GPC (full adder) will be used.\n" ); + pGPCs = pGPCs0; + nGPCs = 1; + } + Abc_NtkATMap( nXVars, nYVars, pGPCs, nGPCs, fVerbose ); + return 0; + +usage: + Abc_Print( -2, "usage: atmap [-XY num] [-G str] [-v] ... \n" ); + Abc_Print( -2, "\t maps rectangular adder tree using GPCs\n" ); + Abc_Print( -2, "\t-X : the number of different ranks [default = %d]\n", nXVars ); + Abc_Print( -2, "\t-Y : the number of bits of each rank [default = %d]\n", nYVars ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n\n"); + Abc_Print( -2, "\t For example, to map an adder tree with dimensions 4 x 648 using GPC(6,6,6,6:1,2,2,2,2,1)\n" ); + Abc_Print( -2, "\t having LUT efficiency E = 1.75, use the command line \"atmap -X 4 -Y 648 6666:122221:8 3:11:1\"\n" ); + Abc_Print( -2, "\t where 8 is the number of 6-LUTs needed to implement the GPC and E = (24-10)/8 = 1.75.\n" ); + return 1; +} + /**Function************************************************************* Synopsis []