Skip to content

Commit

Permalink
Experiments with adder-based circuits.
Browse files Browse the repository at this point in the history
  • Loading branch information
alanminko committed Aug 17, 2024
1 parent 732abf5 commit 03b786a
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 2 deletions.
258 changes: 258 additions & 0 deletions src/aig/gia/giaGen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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<<n)-1)) );
}
// Vec_StrPrint( vRes, 0 );
Vec_StrFree( vRes );
}
Vec_Int_t * Gia_ManSumGenDec( int n )
{
Vec_Int_t * vDec = Vec_IntAlloc( n + 1 );
Vec_IntPush( vDec, 0 );
Vec_IntPush( vDec, 0 );
Vec_IntPush( vDec, 4 );
Vec_IntPush( vDec, 12 );
for ( int i = 4; i <= n; i++ ) {
int Ent0 = Vec_IntEntry( vDec, i / 2 );
int Ent1 = Vec_IntEntry( vDec, i - i / 2 );
assert( Vec_IntSize(vDec) == i );
Vec_IntPush( vDec, Ent0 + Ent1 + (1 << i / 2) * (1 << (i - i / 2)) );
}
return vDec;
}
void Gia_ManSumEnumTest()
{
Vec_Int_t * vDec = Gia_ManSumGenDec( 16 );
printf( " " );
for ( int b = 1; b <= 256; b <<= 1 )
printf( " %8d", b );
printf( "\n" );
for ( int i = 1; i <= 15; i++ ) {
printf( "%2d :", i );
Gia_ManSumEnum( i, vDec );
printf( "\n" );
}
Vec_IntFree( vDec );
}


/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Gia_ManGenNeuronDumpVerilog( Vec_Wrd_t * vData, int nIBits, int nOBits )
{
FILE * pFile = fopen( "temp.v", "wb" );
if ( pFile == NULL ) {
printf( "Cannot open output file.\n" );
return;
}
fprintf( pFile, "module neuron_%d_%d_%d ( input [%d:0] i, output [%d:0] o );\n",
Vec_WrdSize(vData)-1, nIBits, nOBits, (Vec_WrdSize(vData)-1)*nIBits-1, nOBits-1 );
fprintf( pFile, "assign o = %d'h%lX", nOBits, Vec_WrdEntryLast(vData) );
word Data; int i;
Vec_WrdForEachEntryStop( vData, Data, i, Vec_WrdSize(vData)-1 )
fprintf( pFile, "\n + %d'h%lX * i[%d:%d]", nOBits, Data, nIBits*(i+1)-1, nIBits*i );
fprintf( pFile, ";\nendmodule\n\n" );
fclose( pFile );
printf( "Dumped the neuron specification into file \"temp.v\".\n" );
}
void Gia_ManGenNeuronAdder( Gia_Man_t * p, int nLits, int * pLitsA, int * pLitsB, int Carry, Vec_Int_t * vRes )
{
extern void Wlc_BlastFullAdder( Gia_Man_t * pNew, int a, int b, int c, int * pc, int * ps );
int i, Res = -1;
Vec_IntClear( vRes );
for ( i = 0; i < nLits; i++ ) {
Wlc_BlastFullAdder( p, pLitsA[i], pLitsB[i], Carry, &Carry, &Res );
Vec_IntPush( vRes, Res );
}
}
void Gia_ManGenCompact( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1, Vec_Int_t * vIn2, Vec_Int_t * vOut0, Vec_Int_t * vOut1 )
{
extern void Wlc_BlastFullAdder( Gia_Man_t * pNew, int a, int b, int c, int * pc, int * ps );
assert( Vec_IntSize(vIn0) == Vec_IntSize(vIn1) );
assert( Vec_IntSize(vIn0) == Vec_IntSize(vIn2) );
Vec_IntPush( vOut1, 0 );
int i, Lit0, Lit1, Lit2, Out0, Out1;
Vec_IntForEachEntryThree( vIn0, vIn1, vIn2, Lit0, Lit1, Lit2, i ) {
Wlc_BlastFullAdder( p, Lit0, Lit1, Lit2, &Out1, &Out0 );
Vec_IntPush( vOut0, Out0 );
Vec_IntPush( vOut1, Out1 );
}
Vec_IntPop( vOut1 );
assert( Vec_IntSize(vIn0) == Vec_IntSize(vOut0) );
assert( Vec_IntSize(vIn0) == Vec_IntSize(vOut1) );
}
Vec_Wec_t * Gia_ManGenNeuronCreateArgs( Vec_Wrd_t * vData, int nIBits, int nOBits )
{
word Data = Vec_WrdEntryLast(vData); int i, b, n, nLits = 2;
Vec_Wec_t * vArgs = Vec_WecAlloc( Vec_WrdSize(vData) * nIBits );
Vec_Int_t * vLev = Vec_WecPushLevel( vArgs );
Vec_IntFill( vLev, nOBits, 0 );
for ( b = 0; b < nOBits; b++ )
if ( (Data >> 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<<nIBits)-1;
word Data, DataMax = Vec_WrdEntryLast(vData);
Vec_WrdForEachEntryStop( vData, Data, i, Vec_WrdSize(vData)-1 )
DataMax += InMask * Data;
return Abc_Base2LogW(DataMax);
}
Gia_Man_t * Gia_ManGenNeuron( char * pFileName, int nIBits, int nLutSize, int fDump, int fVerbose )
{
int nWords = -1;
Vec_Wrd_t * vData = Vec_WrdReadHex( pFileName, &nWords, 0 );
if ( vData == NULL )
return NULL;

assert( nWords == 1 );
assert( 0 < nIBits && nIBits < 32 );
int i, Lit, nOBits = Gia_ManGenNeuronBitWidth( vData, nIBits );
if ( fDump ) Gia_ManGenNeuronDumpVerilog( vData, nIBits, nOBits );

Gia_Man_t * pTemp, * pNew = Gia_ManStart( 10000 );
pNew->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 ///
////////////////////////////////////////////////////////////////////////
Expand Down
90 changes: 88 additions & 2 deletions src/base/abci/abc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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:
Expand All @@ -53970,6 +53973,89 @@ int Abc_CommandAbc9GenComp( Abc_Frame_t * pAbc, int argc, char ** argv )
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 <num>] [-dvh] <file>\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<file> : the weights one per line followed by the bias (in hex notation)\n");
return 1;
}

/**Function*************************************************************

Synopsis []
Expand Down
3 changes: 3 additions & 0 deletions src/misc/util/abc_global.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
Loading

0 comments on commit 03b786a

Please sign in to comment.