From 03b786af99b1ef9aa5b4f200a96131afa7327423 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 17 Aug 2024 16:26:20 -0700 Subject: [PATCH] Experiments with adder-based circuits. --- src/aig/gia/giaGen.c | 258 +++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 90 ++++++++++++- src/misc/util/abc_global.h | 3 + src/misc/util/utilTruth.h | 27 ++++ src/misc/vec/vecInt.h | 2 + 5 files changed, 378 insertions(+), 2 deletions(-) diff --git a/src/aig/gia/giaGen.c b/src/aig/gia/giaGen.c index cb56ef64d..2d89c12be 100644 --- a/src/aig/gia/giaGen.c +++ b/src/aig/gia/giaGen.c @@ -924,6 +924,264 @@ void Gia_ManTestWordFile( Gia_Man_t * p, char * pFileName, char * pDumpFile, int Abc_PrintTime( 1, "Total checking time", Abc_Clock() - clk ); } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Gia_ManSumCount( char * p, Vec_Int_t * vDec, int b ) +{ + int i, Ent, Count = 0, Sum = 0; + for ( i = 0; p[i]; i++ ) { + Ent = (p[i] >= '0' && p[i] <= '9') ? p[i]-'0' : p[i]-'A'+10; + Count += Vec_IntEntry(vDec, Ent) + b * (1 << (Sum += Ent)); + } + return Count + b * ((1 << Sum) - 1); +} +Vec_Str_t * Gia_ManSumEnum_rec( int Num ) +{ + if ( Num == 1 ) { + Vec_Str_t * vRes = Vec_StrAlloc(2); + Vec_StrPush( vRes, '1' ); + Vec_StrPush( vRes, '\0' ); + return vRes; + } + Vec_Str_t * vRes = Vec_StrAlloc( 16 ); + for ( int i = 1; i < Num; i++ ) { + Vec_Str_t * vRes0 = Gia_ManSumEnum_rec(i); + Vec_Str_t * vRes1 = Gia_ManSumEnum_rec(Num-i); + for ( int c0 = 0; c0 < Vec_StrSize(vRes0); c0 += strlen(Vec_StrEntryP(vRes0,c0))+1 ) + for ( int c1 = 0; c1 < Vec_StrSize(vRes1); c1 += strlen(Vec_StrEntryP(vRes1,c1))+1 ) + Vec_StrPrintF( vRes, "%s%s%c", Vec_StrEntryP(vRes0,c0), Vec_StrEntryP(vRes1,c1), '\0' ); + Vec_StrPrintF( vRes, "%c%c", Num < 10 ? '0'+Num : 'A'+Num-10, '\0' ); + Vec_StrFree( vRes0 ); + Vec_StrFree( vRes1 ); + } + return vRes; +} +void Gia_ManSumEnum( int n, Vec_Int_t * vDec ) +{ + Vec_Str_t * vRes = Gia_ManSumEnum_rec( n ); + for ( int b = 1; b <= 256; b <<= 1 ) { + int iBest = -1, CountCur, CountBest = ABC_INFINITY; + for ( int c0 = 0; c0 < Vec_StrSize(vRes); c0 += strlen(Vec_StrEntryP(vRes,c0))+1 ) { + CountCur = Gia_ManSumCount( Vec_StrEntryP(vRes,c0), vDec, b ); + if ( CountBest > CountCur ) + CountBest = CountCur, iBest = c0; + } + printf( " %8d", CountBest ); + //printf( " %8s", Vec_StrEntryP(vRes,iBest) ); + //printf( " %.3f", (float)CountBest/(3*b*((1<> b) & 1 ) + Vec_IntWriteEntry( vLev, b, 1 ); + Vec_WrdForEachEntryStop( vData, Data, i, Vec_WrdSize(vData)-1 ) { + for ( n = 0; n < nIBits; n++, nLits += 2 ) { + Vec_Int_t * vLev = Vec_WecPushLevel( vArgs ); + Vec_IntFill( vLev, nOBits, 0 ); + for ( b = 0; b < nOBits; b++ ) + if ( ((Data >> b) & 1) && b+n < nOBits ) + Vec_IntWriteEntry( vLev, b+n, nLits ); + } + } + return vArgs; +} +Vec_Wec_t * Gia_ManGenNeuronTransformArgs( Gia_Man_t * pNew, Vec_Wec_t * vArgs, int nLutSize, int nOBits ) +{ + int i, nParts = (Vec_WecSize(vArgs) + 2) / 4; + while ( Vec_WecSize(vArgs) < 4*nParts+1 ) + Vec_IntFill( Vec_WecPushLevel(vArgs), nOBits, 0 ); + assert( Vec_WecSize(vArgs) == 4*nParts+1 ); + Vec_Wec_t * vNew = Vec_WecAlloc( nParts ); + Vec_Int_t * vRes = Vec_WecPushLevel( vNew ), * vArg; + Vec_IntAppend( vRes, Vec_WecEntry(vArgs, 0) ); + Vec_WecForEachLevelStart( vArgs, vArg, i, 1 ) { + Gia_ManGenNeuronAdder( pNew, nOBits, Vec_IntArray(vArg), Vec_IntArray(vRes), 0, vRes ); + if ( (i-1) % 4 == 3 && i < Vec_WecSize(vArgs)-1 ) { + vRes = Vec_WecPushLevel( vNew ); + Vec_IntFill( vRes, nOBits, 0 ); + } + } + assert( Vec_WecSize(vNew) == nParts ); + return vNew; +} +Vec_Wec_t * Gia_ManGenNeuronCompactArgs( Gia_Man_t * pNew, Vec_Wec_t * vArgs, int nLutSize, int nOBits ) +{ + int i, nParts = Vec_WecSize(vArgs) / 3; + Vec_Wec_t * vNew = Vec_WecAlloc( 2 * nParts + Vec_WecSize(vArgs) % 3 ); + for ( i = 0; i < nParts; i++ ) { + Vec_Int_t * vIn0 = Vec_WecEntry(vArgs, 3*i+0); + Vec_Int_t * vIn1 = Vec_WecEntry(vArgs, 3*i+1); + Vec_Int_t * vIn2 = Vec_WecEntry(vArgs, 3*i+2); + Vec_Int_t * vOut0 = Vec_WecPushLevel(vNew); + Vec_Int_t * vOut1 = Vec_WecPushLevel(vNew); + Gia_ManGenCompact( pNew, vIn0, vIn1, vIn2, vOut0, vOut1 ); + } + for ( i = 3*nParts; i < Vec_WecSize(vArgs); i++ ) + Vec_IntAppend( Vec_WecPushLevel(vNew), Vec_WecEntry(vArgs, i) ); + assert( Vec_WecSize(vNew) == 2 * nParts + Vec_WecSize(vArgs) % 3 ); + return vNew; +} +Vec_Int_t * Gia_ManGenNeuronFinal( Gia_Man_t * pNew, Vec_Wec_t * vArgs, int nOBits ) +{ + Vec_Int_t * vRes = Vec_IntAlloc( nOBits ), * vArg; int i; + Vec_IntAppend( vRes, Vec_WecEntry(vArgs, 0) ); + Vec_WecForEachLevelStart( vArgs, vArg, i, 1 ) + Gia_ManGenNeuronAdder( pNew, nOBits, Vec_IntArray(vArg), Vec_IntArray(vRes), 0, vRes ); + return vRes; +} +int Gia_ManGenNeuronBitWidth( Vec_Wrd_t * vData, int nIBits ) +{ + int i, InMask = (1<pName = Abc_UtilStrsav( "neuron" ); + for ( i = 0; i < nIBits * (Vec_WrdSize(vData)-1); i++ ) + Gia_ManAppendCi( pNew ); + Gia_ManHashAlloc( pNew ); + + Vec_Wec_t * vTemp, * vArgs = Gia_ManGenNeuronCreateArgs( vData, nIBits, nOBits ); + Vec_WrdFree( vData ); + + if ( nLutSize ) { + vArgs = Gia_ManGenNeuronTransformArgs( pNew, vTemp = vArgs, nLutSize, nOBits ); + Vec_WecFree( vTemp ); + while ( Vec_WecSize(vArgs) > 2 ) { + vArgs = Gia_ManGenNeuronCompactArgs( pNew, vTemp = vArgs, nLutSize, nOBits ); + Vec_WecFree( vTemp ); + } + } + + Vec_Int_t * vRes = Gia_ManGenNeuronFinal( pNew, vArgs, nOBits ); + Vec_IntForEachEntry( vRes, Lit, i ) + Gia_ManAppendCo( pNew, Lit ); + Vec_IntFree( vRes ); + Vec_WecFree( vArgs ); + + pNew = Gia_ManCleanup( pTemp = pNew ); + Gia_ManStop( pTemp ); + return pNew; +} + + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index c06c7da25..cdf8531e3 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -615,6 +615,7 @@ static int Abc_CommandAbc9Odc ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9GenRel ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9GenMux ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9GenComp ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9GenNeuron ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Window ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9FunAbs ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9DsdInfo ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1417,6 +1418,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&genrel", Abc_CommandAbc9GenRel, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&genmux", Abc_CommandAbc9GenMux, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&gencomp", Abc_CommandAbc9GenComp, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&genneuron", Abc_CommandAbc9GenNeuron, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&window", Abc_CommandAbc9Window, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&funabs", Abc_CommandAbc9FunAbs, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&dsdinfo", Abc_CommandAbc9DsdInfo, 0 ); @@ -53955,8 +53957,9 @@ int Abc_CommandAbc9GenComp( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; } pTemp = Gia_ManDupGenComp( nBits, fInter ); - Abc_FrameUpdateGia( pAbc, pTemp ); - Abc_Print( 1, "Generated %d-bit comparator\n", nBits ); + Abc_FrameUpdateGia( pAbc, pTemp ); + if ( fVerbose ) + Abc_Print( 1, "Generated %d-bit comparator.\n", nBits ); return 0; usage: @@ -53970,6 +53973,89 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9GenNeuron( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManGenNeuron( char * pFileName, int nIBits, int nLutSize, int fDump, int fVerbose ); + Gia_Man_t * pTemp = NULL; + int c, nBits = 0, nLutSize = 0, fDump = 0, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "IKdvh" ) ) != EOF ) + { + switch ( c ) + { + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by an integer.\n" ); + goto usage; + } + nBits = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nBits < 0 ) + goto usage; + break; + 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 'd': + fDump ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( nBits < 1 || nBits > 31 ) + { + Abc_Print( -1, "Abc_CommandAbc9GenNeuron(): The number of inputs (0 < K < 32) should be defined on the command line \"-K num\".\n" ); + return 0; + } + if ( argc != globalUtilOptind + 1 ) + { + Abc_Print( 1, "Input file is not given.\n" ); + return 0; + } + pTemp = Gia_ManGenNeuron( argv[globalUtilOptind], nBits, nLutSize, fDump, fVerbose ); + if ( fVerbose ) + printf( "Generated %d-argument neuron with %d-bit inputs and %d-bit output.\n", Gia_ManCiNum(pTemp)/nBits, nBits, Gia_ManCoNum(pTemp) ); + Abc_FrameUpdateGia( pAbc, pTemp ); + return 0; + +usage: + Abc_Print( -2, "usage: &genneuron [-IK ] [-dvh] \n" ); + Abc_Print( -2, "\t generates the implementation of one neuron\n" ); + Abc_Print( -2, "\t-I num : the bit-width of each input [default = undefined]\n" ); + Abc_Print( -2, "\t-K num : the LUT size for logic structuring [default = undefined]\n" ); + Abc_Print( -2, "\t-d : toggles dumping RTL Verilog [default = %s]\n", fDump ? "yes": "no" ); + Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose ? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : the weights one per line followed by the bias (in hex notation)\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/misc/util/abc_global.h b/src/misc/util/abc_global.h index 96944d7cc..4bc3c1c15 100644 --- a/src/misc/util/abc_global.h +++ b/src/misc/util/abc_global.h @@ -287,6 +287,9 @@ static inline double Abc_Word2Dbl( word Num ) { union { word x; static inline int Abc_Base2Log( unsigned n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n >>= 1, r++ ) {}; return r; } static inline int Abc_Base10Log( unsigned n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 10, r++ ) {}; return r; } static inline int Abc_Base16Log( unsigned n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 16, r++ ) {}; return r; } +static inline int Abc_Base2LogW( word n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n >>= 1, r++ ) {}; return r; } +static inline int Abc_Base10LogW( word n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 10, r++ ) {}; return r; } +static inline int Abc_Base16LogW( word n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 16, r++ ) {}; return r; } static inline char * Abc_UtilStrsav( char * s ) { return s ? strcpy(ABC_ALLOC(char, strlen(s)+1), s) : NULL; } static inline char * Abc_UtilStrsavTwo( char * s, char * a ){ char * r; if (!a) return Abc_UtilStrsav(s); r = ABC_ALLOC(char, strlen(s)+strlen(a)+1); sprintf(r, "%s%s", s, a ); return r; } static inline char * Abc_UtilStrsavNum( char * s, int n ) { char * r; if (!s) return NULL; r = ABC_ALLOC(char, strlen(s)+12+1); sprintf(r, "%s%d", s, n ); return r; } diff --git a/src/misc/util/utilTruth.h b/src/misc/util/utilTruth.h index 35f0f83e4..323c96467 100644 --- a/src/misc/util/utilTruth.h +++ b/src/misc/util/utilTruth.h @@ -225,6 +225,33 @@ static inline void Abc_TtMask( word * pTruth, int nWords, int nBits ) pTruth[w] = 0; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline word Abc_TtWordReverseBits( word w ) +{ + int Rev[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; + word r = 0; int i; + for ( i = 0; i < 16; i++ ) + r |= (word)Rev[(w >> (i<<2))&15] << ((15-i)<<2); + return r; +} +static inline word Abc_TtWordReverseHexDigits( word w ) +{ + word r = 0; int i; + for ( i = 0; i < 16; i++ ) + r |= ((w >> (i<<2))&15) << ((15-i)<<2); + return r; +} + /**Function************************************************************* Synopsis [] diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h index e4ea6cfe3..0b1ae6d30 100644 --- a/src/misc/vec/vecInt.h +++ b/src/misc/vec/vecInt.h @@ -65,6 +65,8 @@ struct Vec_Int_t_ for ( i = Start; (i >= 0) && (((pEntry) = Vec_IntEntry(vVec, i)), 1); i-- ) #define Vec_IntForEachEntryTwo( vVec1, vVec2, Entry1, Entry2, i ) \ for ( i = 0; (i < Vec_IntSize(vVec1)) && (((Entry1) = Vec_IntEntry(vVec1, i)), 1) && (((Entry2) = Vec_IntEntry(vVec2, i)), 1); i++ ) +#define Vec_IntForEachEntryThree( vVec1, vVec2, vVec3, Entry1, Entry2, Entry3, i ) \ + for ( i = 0; (i < Vec_IntSize(vVec1)) && (((Entry1) = Vec_IntEntry(vVec1, i)), 1) && (((Entry2) = Vec_IntEntry(vVec2, i)), 1) && (((Entry3) = Vec_IntEntry(vVec3, i)), 1); i++ ) #define Vec_IntForEachEntryTwoStart( vVec1, vVec2, Entry1, Entry2, i, Start ) \ for ( i = Start; (i < Vec_IntSize(vVec1)) && (((Entry1) = Vec_IntEntry(vVec1, i)), 1) && (((Entry2) = Vec_IntEntry(vVec2, i)), 1); i++ ) #define Vec_IntForEachEntryDouble( vVec, Entry1, Entry2, i ) \