Experiments with adder-tree mapping.

This commit is contained in:
Alan Mishchenko 2025-03-29 15:37:22 -07:00
parent 2442720528
commit bb11cc4c46
2 changed files with 237 additions and 1 deletions

View File

@ -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 ///
////////////////////////////////////////////////////////////////////////

View File

@ -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<ones> : 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] <GPC(0)> <GPC(1)> ... <GPC(N-1)>\n" );
Abc_Print( -2, "\t maps rectangular adder tree using GPCs\n" );
Abc_Print( -2, "\t-X <num> : the number of different ranks [default = %d]\n", nXVars );
Abc_Print( -2, "\t-Y <num> : 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 []