blob: 42c04c02ba401fd9fb8eca257723d3c586f9a26d [file] [log] [blame]
/**CFile****************************************************************
FileName [casCore.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [CASCADE: Decomposition of shared BDDs into a LUT cascade.]
Synopsis [Entrance into the implementation.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - Spring 2002.]
Revision [$Id: casCore.c,v 1.0 2002/01/01 00:00:00 alanmi Exp $]
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "base/main/main.h"
#include "base/cmd/cmd.h"
#include "bdd/extrab/extraBdd.h"
#include "cas.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// static functions ///
////////////////////////////////////////////////////////////////////////
DdNode * GetSingleOutputFunction( DdManager * dd, DdNode ** pbOuts, int nOuts, DdNode ** pbVarsEnc, int nVarsEnc, int fVerbose );
DdNode * GetSingleOutputFunctionRemapped( DdManager * dd, DdNode ** pOutputs, int nOuts, DdNode ** pbVarsEnc, int nVarsEnc );
DdNode * GetSingleOutputFunctionRemappedNewDD( DdManager * dd, DdNode ** pOutputs, int nOuts, DdManager ** DdNew );
extern int CreateDecomposedNetwork( DdManager * dd, DdNode * aFunc, char ** pNames, int nNames, char * FileName, int nLutSize, int fCheck, int fVerbose );
void WriteSingleOutputFunctionBlif( DdManager * dd, DdNode * aFunc, char ** pNames, int nNames, char * FileName );
DdNode * Cudd_bddTransferPermute( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute );
////////////////////////////////////////////////////////////////////////
/// static varibles ///
////////////////////////////////////////////////////////////////////////
//static FILE * pTable = NULL;
//static long s_RemappingTime = 0;
////////////////////////////////////////////////////////////////////////
/// debugging macros ///
////////////////////////////////////////////////////////////////////////
#define PRD(p) printf( "\nDECOMPOSITION TREE:\n\n" ); PrintDecEntry( (p), 0 )
#define PRB_(f) printf( #f " = " ); Cudd_bddPrint(dd,f); printf( "\n" )
#define PRK(f,n) Cudd_PrintKMap(stdout,dd,(f),Cudd_Not(f),(n),NULL,0); printf( "K-map for function" #f "\n\n" )
#define PRK2(f,g,n) Cudd_PrintKMap(stdout,dd,(f),(g),(n),NULL,0); printf( "K-map for function <" #f ", " #g ">\n\n" )
////////////////////////////////////////////////////////////////////////
/// EXTERNAL FUNCTIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_CascadeExperiment( char * pFileGeneric, DdManager * dd, DdNode ** pOutputs, int nInputs, int nOutputs, int nLutSize, int fCheck, int fVerbose )
{
int i;
int nVars = nInputs;
int nOuts = nOutputs;
abctime clk1;
int nVarsEnc; // the number of additional variables to encode outputs
DdNode * pbVarsEnc[MAXOUTPUTS]; // the BDDs of the encoding vars
int nNames; // the total number of all inputs
char * pNames[MAXINPUTS]; // the temporary storage for the input (and output encoding) names
DdNode * aFunc; // the encoded 0-1 BDD containing all the outputs
char FileNameIni[100];
char FileNameFin[100];
char Buffer[100];
//pTable = fopen( "stats.txt", "a+" );
//fprintf( pTable, "%s ", pFileGeneric );
//fprintf( pTable, "%d ", nVars );
//fprintf( pTable, "%d ", nOuts );
// assign the file names
strcpy( FileNameIni, pFileGeneric );
strcat( FileNameIni, "_ENC.blif" );
strcpy( FileNameFin, pFileGeneric );
strcat( FileNameFin, "_LUT.blif" );
// create the variables to encode the outputs
nVarsEnc = Abc_Base2Log( nOuts );
for ( i = 0; i < nVarsEnc; i++ )
pbVarsEnc[i] = Cudd_bddNewVarAtLevel( dd, i );
// store the input names
nNames = nVars + nVarsEnc;
for ( i = 0; i < nVars; i++ )
{
// pNames[i] = Extra_UtilStrsav( pFunc->pInputNames[i] );
sprintf( Buffer, "pi%03d", i );
pNames[i] = Extra_UtilStrsav( Buffer );
}
// set the encoding variable name
for ( ; i < nNames; i++ )
{
sprintf( Buffer, "OutEnc_%02d", i-nVars );
pNames[i] = Extra_UtilStrsav( Buffer );
}
// print the variable order
// printf( "\n" );
// printf( "Variable order is: " );
// for ( i = 0; i < dd->size; i++ )
// printf( " %d", dd->invperm[i] );
// printf( "\n" );
// derive the single-output function
clk1 = Abc_Clock();
aFunc = GetSingleOutputFunction( dd, pOutputs, nOuts, pbVarsEnc, nVarsEnc, fVerbose ); Cudd_Ref( aFunc );
// aFunc = GetSingleOutputFunctionRemapped( dd, pOutputs, nOuts, pbVarsEnc, nVarsEnc ); Cudd_Ref( aFunc );
// if ( fVerbose )
// printf( "Single-output function computation time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
//fprintf( pTable, "%d ", Cudd_SharingSize( pOutputs, nOutputs ) );
//fprintf( pTable, "%d ", Extra_ProfileWidthSharingMax(dd, pOutputs, nOutputs) );
// dispose of the multiple-output function
// Extra_Dissolve( pFunc );
// reorder the single output function
// if ( fVerbose )
// printf( "Reordering variables...\n");
clk1 = Abc_Clock();
// if ( fVerbose )
// printf( "Node count before = %6d\n", Cudd_DagSize( aFunc ) );
// Cudd_ReduceHeap(dd, CUDD_REORDER_SIFT,1);
Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(dd, CUDD_REORDER_SYMM_SIFT,1);
if ( fVerbose )
printf( "MTBDD reordered = %6d nodes\n", Cudd_DagSize( aFunc ) );
if ( fVerbose )
printf( "Variable reordering time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
// printf( "\n" );
// printf( "Variable order is: " );
// for ( i = 0; i < dd->size; i++ )
// printf( " %d", dd->invperm[i] );
// printf( "\n" );
//fprintf( pTable, "%d ", Cudd_DagSize( aFunc ) );
//fprintf( pTable, "%d ", Extra_ProfileWidthMax(dd, aFunc) );
// write the single-output function into BLIF for verification
clk1 = Abc_Clock();
if ( fCheck )
WriteSingleOutputFunctionBlif( dd, aFunc, pNames, nNames, FileNameIni );
// if ( fVerbose )
// printf( "Single-output function writing time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
/*
///////////////////////////////////////////////////////////////////
// verification of single output function
clk1 = Abc_Clock();
{
BFunc g_Func;
DdNode * aRes;
g_Func.dd = dd;
g_Func.FileInput = Extra_UtilStrsav(FileNameIni);
if ( Extra_ReadFile( &g_Func ) == 0 )
{
printf( "\nSomething did not work out while reading the input file for verification\n");
Extra_Dissolve( &g_Func );
return;
}
aRes = Cudd_BddToAdd( dd, g_Func.pOutputs[0] ); Cudd_Ref( aRes );
if ( aRes != aFunc )
printf( "\nVerification FAILED!\n");
else
printf( "\nVerification okay!\n");
Cudd_RecursiveDeref( dd, aRes );
// delocate
Extra_Dissolve( &g_Func );
}
printf( "Preliminary verification time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
///////////////////////////////////////////////////////////////////
*/
if ( !CreateDecomposedNetwork( dd, aFunc, pNames, nNames, FileNameFin, nLutSize, fCheck, fVerbose ) )
return 0;
/*
///////////////////////////////////////////////////////////////////
// verification of the decomposed LUT network
clk1 = Abc_Clock();
{
BFunc g_Func;
DdNode * aRes;
g_Func.dd = dd;
g_Func.FileInput = Extra_UtilStrsav(FileNameFin);
if ( Extra_ReadFile( &g_Func ) == 0 )
{
printf( "\nSomething did not work out while reading the input file for verification\n");
Extra_Dissolve( &g_Func );
return;
}
aRes = Cudd_BddToAdd( dd, g_Func.pOutputs[0] ); Cudd_Ref( aRes );
if ( aRes != aFunc )
printf( "\nFinal verification FAILED!\n");
else
printf( "\nFinal verification okay!\n");
Cudd_RecursiveDeref( dd, aRes );
// delocate
Extra_Dissolve( &g_Func );
}
printf( "Final verification time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
///////////////////////////////////////////////////////////////////
*/
// verify the results
if ( fCheck )
{
char Command[200];
sprintf( Command, "cec %s %s", FileNameIni, FileNameFin );
Cmd_CommandExecute( Abc_FrameGetGlobalFrame(), Command );
}
Cudd_RecursiveDeref( dd, aFunc );
// release the names
for ( i = 0; i < nNames; i++ )
ABC_FREE( pNames[i] );
//fprintf( pTable, "\n" );
//fclose( pTable );
return 1;
}
#if 0
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Experiment2( BFunc * pFunc )
{
int i, x, RetValue;
int nVars = pFunc->nInputs;
int nOuts = pFunc->nOutputs;
DdManager * dd = pFunc->dd;
long clk1;
// int nVarsEnc; // the number of additional variables to encode outputs
// DdNode * pbVarsEnc[MAXOUTPUTS]; // the BDDs of the encoding vars
int nNames; // the total number of all inputs
char * pNames[MAXINPUTS]; // the temporary storage for the input (and output encoding) names
DdNode * aFunc; // the encoded 0-1 BDD containing all the outputs
char FileNameIni[100];
char FileNameFin[100];
char Buffer[100];
DdManager * DdNew;
//pTable = fopen( "stats.txt", "a+" );
//fprintf( pTable, "%s ", pFunc->FileGeneric );
//fprintf( pTable, "%d ", nVars );
//fprintf( pTable, "%d ", nOuts );
// assign the file names
strcpy( FileNameIni, pFunc->FileGeneric );
strcat( FileNameIni, "_ENC.blif" );
strcpy( FileNameFin, pFunc->FileGeneric );
strcat( FileNameFin, "_LUT.blif" );
// derive the single-output function IN THE NEW MANAGER
clk1 = Abc_Clock();
// aFunc = GetSingleOutputFunction( dd, pFunc->pOutputs, nOuts, pbVarsEnc, nVarsEnc ); Cudd_Ref( aFunc );
aFunc = GetSingleOutputFunctionRemappedNewDD( dd, pFunc->pOutputs, nOuts, &DdNew ); Cudd_Ref( aFunc );
printf( "Single-output function derivation time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
// s_RemappingTime = Abc_Clock() - clk1;
// dispose of the multiple-output function
Extra_Dissolve( pFunc );
// reorder the single output function
printf( "\nReordering variables in the new manager...\n");
clk1 = Abc_Clock();
printf( "Node count before = %d\n", Cudd_DagSize( aFunc ) );
// Cudd_ReduceHeap(DdNew, CUDD_REORDER_SIFT,1);
Cudd_ReduceHeap(DdNew, CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(DdNew, CUDD_REORDER_SYMM_SIFT,1);
printf( "Node count after = %d\n", Cudd_DagSize( aFunc ) );
printf( "Variable reordering time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
printf( "\n" );
//fprintf( pTable, "%d ", Cudd_DagSize( aFunc ) );
//fprintf( pTable, "%d ", Extra_ProfileWidthMax(DdNew, aFunc) );
// create the names to be used with the new manager
nNames = DdNew->size;
for ( x = 0; x < nNames; x++ )
{
sprintf( Buffer, "v%02d", x );
pNames[x] = Extra_UtilStrsav( Buffer );
}
// write the single-output function into BLIF for verification
clk1 = Abc_Clock();
WriteSingleOutputFunctionBlif( DdNew, aFunc, pNames, nNames, FileNameIni );
printf( "Single-output function writing time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
///////////////////////////////////////////////////////////////////
// verification of single output function
clk1 = Abc_Clock();
{
BFunc g_Func;
DdNode * aRes;
g_Func.dd = DdNew;
g_Func.FileInput = Extra_UtilStrsav(FileNameIni);
if ( Extra_ReadFile( &g_Func ) == 0 )
{
printf( "\nSomething did not work out while reading the input file for verification\n");
Extra_Dissolve( &g_Func );
return;
}
aRes = Cudd_BddToAdd( DdNew, g_Func.pOutputs[0] ); Cudd_Ref( aRes );
if ( aRes != aFunc )
printf( "\nVerification FAILED!\n");
else
printf( "\nVerification okay!\n");
Cudd_RecursiveDeref( DdNew, aRes );
// delocate
Extra_Dissolve( &g_Func );
}
printf( "Preliminary verification time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
///////////////////////////////////////////////////////////////////
CreateDecomposedNetwork( DdNew, aFunc, pNames, nNames, FileNameFin, nLutSize, 0 );
/*
///////////////////////////////////////////////////////////////////
// verification of the decomposed LUT network
clk1 = Abc_Clock();
{
BFunc g_Func;
DdNode * aRes;
g_Func.dd = DdNew;
g_Func.FileInput = Extra_UtilStrsav(FileNameFin);
if ( Extra_ReadFile( &g_Func ) == 0 )
{
printf( "\nSomething did not work out while reading the input file for verification\n");
Extra_Dissolve( &g_Func );
return;
}
aRes = Cudd_BddToAdd( DdNew, g_Func.pOutputs[0] ); Cudd_Ref( aRes );
if ( aRes != aFunc )
printf( "\nFinal verification FAILED!\n");
else
printf( "\nFinal verification okay!\n");
Cudd_RecursiveDeref( DdNew, aRes );
// delocate
Extra_Dissolve( &g_Func );
}
printf( "Final verification time = %.2f sec\n", (float)(Abc_Clock() - clk1)/(float)(CLOCKS_PER_SEC) );
///////////////////////////////////////////////////////////////////
*/
Cudd_RecursiveDeref( DdNew, aFunc );
// release the names
for ( i = 0; i < nNames; i++ )
ABC_FREE( pNames[i] );
/////////////////////////////////////////////////////////////////////
// check for remaining references in the package
RetValue = Cudd_CheckZeroRef( DdNew );
printf( "\nThe number of referenced nodes in the new manager = %d\n", RetValue );
Cudd_Quit( DdNew );
//fprintf( pTable, "\n" );
//fclose( pTable );
}
#endif
////////////////////////////////////////////////////////////////////////
/// SINGLE OUTPUT FUNCTION ///
////////////////////////////////////////////////////////////////////////
// the bit count for the first 256 integer numbers
//static unsigned char BitCount8[256] = {
// 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
// 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
// 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
// 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
// 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
// 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
// 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
// 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
//};
/////////////////////////////////////////////////////////////
static int s_SuppSize[MAXOUTPUTS];
int CompareSupports( int *ptrX, int *ptrY )
{
return ( s_SuppSize[*ptrY] - s_SuppSize[*ptrX] );
}
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
static int s_MintOnes[MAXOUTPUTS];
int CompareMinterms( int *ptrX, int *ptrY )
{
return ( s_MintOnes[*ptrY] - s_MintOnes[*ptrX] );
}
/////////////////////////////////////////////////////////////
int GrayCode ( int BinCode )
{
return BinCode ^ ( BinCode >> 1 );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * GetSingleOutputFunction( DdManager * dd, DdNode ** pbOuts, int nOuts, DdNode ** pbVarsEnc, int nVarsEnc, int fVerbose )
{
int i;
DdNode * bResult, * aResult;
DdNode * bCube, * bTemp, * bProd;
int Order[MAXOUTPUTS];
// int OrderMint[MAXOUTPUTS];
// sort the output according to their support size
for ( i = 0; i < nOuts; i++ )
{
s_SuppSize[i] = Cudd_SupportSize( dd, pbOuts[i] );
// s_MintOnes[i] = BitCount8[i];
Order[i] = i;
// OrderMint[i] = i;
}
// order the outputs
qsort( (void*)Order, nOuts, sizeof(int), (int(*)(const void*, const void*)) CompareSupports );
// order the outputs
// qsort( (void*)OrderMint, nOuts, sizeof(int), (int(*)(const void*, const void*)) CompareMinterms );
bResult = b0; Cudd_Ref( bResult );
for ( i = 0; i < nOuts; i++ )
{
// bCube = Cudd_bddBitsToCube( dd, OrderMint[i], nVarsEnc, pbVarsEnc ); Cudd_Ref( bCube );
// bProd = Cudd_bddAnd( dd, bCube, pbOuts[Order[nOuts-1-i]] ); Cudd_Ref( bProd );
bCube = Extra_bddBitsToCube( dd, i, nVarsEnc, pbVarsEnc, 1 ); Cudd_Ref( bCube );
bProd = Cudd_bddAnd( dd, bCube, pbOuts[Order[i]] ); Cudd_Ref( bProd );
Cudd_RecursiveDeref( dd, bCube );
bResult = Cudd_bddOr( dd, bProd, bTemp = bResult ); Cudd_Ref( bResult );
Cudd_RecursiveDeref( dd, bTemp );
Cudd_RecursiveDeref( dd, bProd );
}
// convert to the ADD
if ( fVerbose )
printf( "Single BDD size = %6d nodes\n", Cudd_DagSize(bResult) );
aResult = Cudd_BddToAdd( dd, bResult ); Cudd_Ref( aResult );
Cudd_RecursiveDeref( dd, bResult );
if ( fVerbose )
printf( "MTBDD = %6d nodes\n", Cudd_DagSize(aResult) );
Cudd_Deref( aResult );
return aResult;
}
/*
DdNode * GetSingleOutputFunction( DdManager * dd, DdNode ** pbOuts, int nOuts, DdNode ** pbVarsEnc, int nVarsEnc )
{
int i;
DdNode * bResult, * aResult;
DdNode * bCube, * bTemp, * bProd;
bResult = b0; Cudd_Ref( bResult );
for ( i = 0; i < nOuts; i++ )
{
// bCube = Extra_bddBitsToCube( dd, i, nVarsEnc, pbVarsEnc ); Cudd_Ref( bCube );
bCube = Extra_bddBitsToCube( dd, nOuts-1-i, nVarsEnc, pbVarsEnc ); Cudd_Ref( bCube );
bProd = Cudd_bddAnd( dd, bCube, pbOuts[i] ); Cudd_Ref( bProd );
Cudd_RecursiveDeref( dd, bCube );
bResult = Cudd_bddOr( dd, bProd, bTemp = bResult ); Cudd_Ref( bResult );
Cudd_RecursiveDeref( dd, bTemp );
Cudd_RecursiveDeref( dd, bProd );
}
// conver to the ADD
aResult = Cudd_BddToAdd( dd, bResult ); Cudd_Ref( aResult );
Cudd_RecursiveDeref( dd, bResult );
Cudd_Deref( aResult );
return aResult;
}
*/
////////////////////////////////////////////////////////////////////////
/// INPUT REMAPPING ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * GetSingleOutputFunctionRemapped( DdManager * dd, DdNode ** pOutputs, int nOuts, DdNode ** pbVarsEnc, int nVarsEnc )
// returns the ADD of the remapped function
{
static int Permute[MAXINPUTS];
static DdNode * pRemapped[MAXOUTPUTS];
DdNode * bSupp, * bTemp;
int i, Counter;
DdNode * bFunc;
DdNode * aFunc;
Cudd_AutodynDisable(dd);
// perform the remapping
for ( i = 0; i < nOuts; i++ )
{
// get support
bSupp = Cudd_Support( dd, pOutputs[i] ); Cudd_Ref( bSupp );
// create the variable map
Counter = 0;
for ( bTemp = bSupp; bTemp != dd->one; bTemp = cuddT(bTemp) )
Permute[bTemp->index] = Counter++;
// transfer the BDD and remap it
pRemapped[i] = Cudd_bddPermute( dd, pOutputs[i], Permute ); Cudd_Ref( pRemapped[i] );
// remove support
Cudd_RecursiveDeref( dd, bSupp );
}
// perform the encoding
bFunc = Extra_bddEncodingBinary( dd, pRemapped, nOuts, pbVarsEnc, nVarsEnc ); Cudd_Ref( bFunc );
// convert to ADD
aFunc = Cudd_BddToAdd( dd, bFunc ); Cudd_Ref( aFunc );
Cudd_RecursiveDeref( dd, bFunc );
// deref the intermediate results
for ( i = 0; i < nOuts; i++ )
Cudd_RecursiveDeref( dd, pRemapped[i] );
Cudd_Deref( aFunc );
return aFunc;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * GetSingleOutputFunctionRemappedNewDD( DdManager * dd, DdNode ** pOutputs, int nOuts, DdManager ** DdNew )
// returns the ADD of the remapped function
{
static int Permute[MAXINPUTS];
static DdNode * pRemapped[MAXOUTPUTS];
static DdNode * pbVarsEnc[MAXINPUTS];
int nVarsEnc;
DdManager * ddnew;
DdNode * bSupp, * bTemp;
int i, v, Counter;
DdNode * bFunc;
// these are in the new manager
DdNode * bFuncNew;
DdNode * aFuncNew;
int nVarsMax = 0;
// perform the remapping and write the DDs into the new manager
for ( i = 0; i < nOuts; i++ )
{
// get support
bSupp = Cudd_Support( dd, pOutputs[i] ); Cudd_Ref( bSupp );
// create the variable map
// to remap the DD into the upper part of the manager
Counter = 0;
for ( bTemp = bSupp; bTemp != dd->one; bTemp = cuddT(bTemp) )
Permute[bTemp->index] = dd->invperm[Counter++];
// transfer the BDD and remap it
pRemapped[i] = Cudd_bddPermute( dd, pOutputs[i], Permute ); Cudd_Ref( pRemapped[i] );
// remove support
Cudd_RecursiveDeref( dd, bSupp );
// determine the largest support size
if ( nVarsMax < Counter )
nVarsMax = Counter;
}
// select the encoding variables to follow immediately after the original variables
nVarsEnc = Abc_Base2Log(nOuts);
/*
for ( v = 0; v < nVarsEnc; v++ )
if ( nVarsMax + v < dd->size )
pbVarsEnc[v] = dd->var[ dd->invperm[nVarsMax+v] ];
else
pbVarsEnc[v] = Cudd_bddNewVar( dd );
*/
// create the new variables on top of the manager
for ( v = 0; v < nVarsEnc; v++ )
pbVarsEnc[v] = Cudd_bddNewVarAtLevel( dd, v );
//fprintf( pTable, "%d ", Cudd_SharingSize( pRemapped, nOuts ) );
//fprintf( pTable, "%d ", Extra_ProfileWidthSharingMax(dd, pRemapped, nOuts) );
// perform the encoding
bFunc = Extra_bddEncodingBinary( dd, pRemapped, nOuts, pbVarsEnc, nVarsEnc ); Cudd_Ref( bFunc );
// find the cross-manager permutation
// the variable from the level v in the old manager
// should become a variable number v in the new manager
for ( v = 0; v < nVarsMax + nVarsEnc; v++ )
Permute[dd->invperm[v]] = v;
///////////////////////////////////////////////////////////////////////////////
// start the new manager
ddnew = Cudd_Init( nVarsMax + nVarsEnc, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
// Cudd_AutodynDisable(ddnew);
Cudd_AutodynEnable(dd, CUDD_REORDER_SYMM_SIFT);
// transfer it to the new manager
bFuncNew = Cudd_bddTransferPermute( dd, ddnew, bFunc, Permute ); Cudd_Ref( bFuncNew );
///////////////////////////////////////////////////////////////////////////////
// deref the intermediate results in the old manager
Cudd_RecursiveDeref( dd, bFunc );
for ( i = 0; i < nOuts; i++ )
Cudd_RecursiveDeref( dd, pRemapped[i] );
///////////////////////////////////////////////////////////////////////////////
// convert to ADD in the new manager
aFuncNew = Cudd_BddToAdd( ddnew, bFuncNew ); Cudd_Ref( aFuncNew );
Cudd_RecursiveDeref( ddnew, bFuncNew );
// return the manager
*DdNew = ddnew;
///////////////////////////////////////////////////////////////////////////////
Cudd_Deref( aFuncNew );
return aFuncNew;
}
////////////////////////////////////////////////////////////////////////
/// BLIF WRITING FUNCTIONS ///
////////////////////////////////////////////////////////////////////////
void WriteDDintoBLIFfile( FILE * pFile, DdNode * Func, char * OutputName, char * Prefix, char ** InputNames );
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void WriteSingleOutputFunctionBlif( DdManager * dd, DdNode * aFunc, char ** pNames, int nNames, char * FileName )
{
int i;
FILE * pFile;
// start the file
pFile = fopen( FileName, "w" );
fprintf( pFile, ".model %s\n", FileName );
fprintf( pFile, ".inputs" );
for ( i = 0; i < nNames; i++ )
fprintf( pFile, " %s", pNames[i] );
fprintf( pFile, "\n" );
fprintf( pFile, ".outputs F" );
fprintf( pFile, "\n" );
// write the DD into the file
WriteDDintoBLIFfile( pFile, aFunc, "F", "", pNames );
fprintf( pFile, ".end\n" );
fclose( pFile );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void WriteDDintoBLIFfile( FILE * pFile, DdNode * Func, char * OutputName, char * Prefix, char ** InputNames )
// writes the main part of the BLIF file
// Func is a BDD or a 0-1 ADD to be written
// OutputName is the name of the output
// Prefix is attached to each intermendiate signal to make it unique
// InputNames are the names of the input signals
// (some part of the code is borrowed from Cudd_DumpDot())
{
int i;
st__table * visited;
st__generator * gen = NULL;
long refAddr, diff, mask;
DdNode * Node, * Else, * ElseR, * Then;
/* Initialize symbol table for visited nodes. */
visited = st__init_table( st__ptrcmp, st__ptrhash );
/* Collect all the nodes of this DD in the symbol table. */
cuddCollectNodes( Cudd_Regular(Func), visited );
/* Find how many most significant hex digits are identical
** in the addresses of all the nodes. Build a mask based
** on this knowledge, so that digits that carry no information
** will not be printed. This is done in two steps.
** 1. We scan the symbol table to find the bits that differ
** in at least 2 addresses.
** 2. We choose one of the possible masks. There are 8 possible
** masks for 32-bit integer, and 16 possible masks for 64-bit
** integers.
*/
/* Find the bits that are different. */
refAddr = ( long )Cudd_Regular(Func);
diff = 0;
gen = st__init_gen( visited );
while ( st__gen( gen, ( const char ** ) &Node, NULL ) )
{
diff |= refAddr ^ ( long ) Node;
}
st__free_gen( gen );
gen = NULL;
/* Choose the mask. */
for ( i = 0; ( unsigned ) i < 8 * sizeof( long ); i += 4 )
{
mask = ( 1 << i ) - 1;
if ( diff <= mask )
break;
}
// write the buffer for the output
fprintf( pFile, ".names %s%lx %s\n", Prefix, ( mask & (long)Cudd_Regular(Func) ) / sizeof(DdNode), OutputName );
fprintf( pFile, "%s 1\n", (Cudd_IsComplement(Func))? "0": "1" );
gen = st__init_gen( visited );
while ( st__gen( gen, ( const char ** ) &Node, NULL ) )
{
if ( Node->index == CUDD_MAXINDEX )
{
// write the terminal node
fprintf( pFile, ".names %s%lx\n", Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, " %s\n", (cuddV(Node) == 0.0)? "0": "1" );
continue;
}
Else = cuddE(Node);
ElseR = Cudd_Regular(Else);
Then = cuddT(Node);
assert( InputNames[Node->index] );
if ( Else == ElseR )
{ // no inverter
fprintf( pFile, ".names %s %s%lx %s%lx %s%lx\n", InputNames[Node->index],
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)Then ) / sizeof(DdNode),
Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, "01- 1\n" );
fprintf( pFile, "1-1 1\n" );
}
else
{ // inverter
int * pSlot;
fprintf( pFile, ".names %s %s%lx_i %s%lx %s%lx\n", InputNames[Node->index],
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)Then ) / sizeof(DdNode),
Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, "01- 1\n" );
fprintf( pFile, "1-1 1\n" );
// if the inverter is written, skip
if ( ! st__find( visited, (char *)ElseR, (char ***)&pSlot ) )
assert( 0 );
if ( *pSlot )
continue;
*pSlot = 1;
fprintf( pFile, ".names %s%lx %s%lx_i\n",
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode) );
fprintf( pFile, "0 1\n" );
}
}
st__free_gen( gen );
gen = NULL;
st__free_table( visited );
}
static DdManager * s_ddmin;
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void WriteDDintoBLIFfileReorder( DdManager * dd, FILE * pFile, DdNode * Func, char * OutputName, char * Prefix, char ** InputNames )
// writes the main part of the BLIF file
// Func is a BDD or a 0-1 ADD to be written
// OutputName is the name of the output
// Prefix is attached to each intermendiate signal to make it unique
// InputNames are the names of the input signals
// (some part of the code is borrowed from Cudd_DumpDot())
{
int i;
st__table * visited;
st__generator * gen = NULL;
long refAddr, diff, mask;
DdNode * Node, * Else, * ElseR, * Then;
///////////////////////////////////////////////////////////////
DdNode * bFmin;
abctime clk1;
if ( s_ddmin == NULL )
s_ddmin = Cudd_Init( dd->size, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
clk1 = Abc_Clock();
bFmin = Cudd_bddTransfer( dd, s_ddmin, Func ); Cudd_Ref( bFmin );
// reorder
printf( "Nodes before = %d. ", Cudd_DagSize(bFmin) );
Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT,1);
// Cudd_ReduceHeap(s_ddmin,CUDD_REORDER_SYMM_SIFT_CONV,1);
printf( "Nodes after = %d. \n", Cudd_DagSize(bFmin) );
///////////////////////////////////////////////////////////////
/* Initialize symbol table for visited nodes. */
visited = st__init_table( st__ptrcmp, st__ptrhash );
/* Collect all the nodes of this DD in the symbol table. */
cuddCollectNodes( Cudd_Regular(bFmin), visited );
/* Find how many most significant hex digits are identical
** in the addresses of all the nodes. Build a mask based
** on this knowledge, so that digits that carry no information
** will not be printed. This is done in two steps.
** 1. We scan the symbol table to find the bits that differ
** in at least 2 addresses.
** 2. We choose one of the possible masks. There are 8 possible
** masks for 32-bit integer, and 16 possible masks for 64-bit
** integers.
*/
/* Find the bits that are different. */
refAddr = ( long )Cudd_Regular(bFmin);
diff = 0;
gen = st__init_gen( visited );
while ( st__gen( gen, ( const char ** ) &Node, NULL ) )
{
diff |= refAddr ^ ( long ) Node;
}
st__free_gen( gen );
gen = NULL;
/* Choose the mask. */
for ( i = 0; ( unsigned ) i < 8 * sizeof( long ); i += 4 )
{
mask = ( 1 << i ) - 1;
if ( diff <= mask )
break;
}
// write the buffer for the output
fprintf( pFile, ".names %s%lx %s\n", Prefix, ( mask & (long)Cudd_Regular(bFmin) ) / sizeof(DdNode), OutputName );
fprintf( pFile, "%s 1\n", (Cudd_IsComplement(bFmin))? "0": "1" );
gen = st__init_gen( visited );
while ( st__gen( gen, ( const char ** ) &Node, NULL ) )
{
if ( Node->index == CUDD_MAXINDEX )
{
// write the terminal node
fprintf( pFile, ".names %s%lx\n", Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, " %s\n", (cuddV(Node) == 0.0)? "0": "1" );
continue;
}
Else = cuddE(Node);
ElseR = Cudd_Regular(Else);
Then = cuddT(Node);
assert( InputNames[Node->index] );
if ( Else == ElseR )
{ // no inverter
fprintf( pFile, ".names %s %s%lx %s%lx %s%lx\n", InputNames[Node->index],
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)Then ) / sizeof(DdNode),
Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, "01- 1\n" );
fprintf( pFile, "1-1 1\n" );
}
else
{ // inverter
fprintf( pFile, ".names %s %s%lx_i %s%lx %s%lx\n", InputNames[Node->index],
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)Then ) / sizeof(DdNode),
Prefix, ( mask & (long)Node ) / sizeof(DdNode) );
fprintf( pFile, "01- 1\n" );
fprintf( pFile, "1-1 1\n" );
fprintf( pFile, ".names %s%lx %s%lx_i\n",
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode),
Prefix, ( mask & (long)ElseR ) / sizeof(DdNode) );
fprintf( pFile, "0 1\n" );
}
}
st__free_gen( gen );
gen = NULL;
st__free_table( visited );
//////////////////////////////////////////////////
Cudd_RecursiveDeref( s_ddmin, bFmin );
//////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////
/// TRANSFER WITH MAPPING ///
////////////////////////////////////////////////////////////////////////
static DdNode * cuddBddTransferPermuteRecur
ARGS((DdManager * ddS, DdManager * ddD, DdNode * f, st__table * table, int * Permute ));
static DdNode * cuddBddTransferPermute
ARGS((DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute));
/**Function********************************************************************
Synopsis [Convert a BDD from a manager to another one.]
Description [Convert a BDD from a manager to another one. The orders of the
variables in the two managers may be different. Returns a
pointer to the BDD in the destination manager if successful; NULL
otherwise. The i-th entry in the array Permute tells what is the index
of the i-th variable from the old manager in the new manager.]
SideEffects [None]
SeeAlso []
******************************************************************************/
DdNode *
Cudd_bddTransferPermute( DdManager * ddSource,
DdManager * ddDestination, DdNode * f, int * Permute )
{
DdNode *res;
do
{
ddDestination->reordered = 0;
res = cuddBddTransferPermute( ddSource, ddDestination, f, Permute );
}
while ( ddDestination->reordered == 1 );
return ( res );
} /* end of Cudd_bddTransferPermute */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Convert a BDD from a manager to another one.]
Description [Convert a BDD from a manager to another one. Returns a
pointer to the BDD in the destination manager if successful; NULL
otherwise.]
SideEffects [None]
SeeAlso [Cudd_bddTransferPermute]
******************************************************************************/
DdNode *
cuddBddTransferPermute( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute )
{
DdNode *res;
st__table *table = NULL;
st__generator *gen = NULL;
DdNode *key, *value;
table = st__init_table( st__ptrcmp, st__ptrhash );
if ( table == NULL )
goto failure;
res = cuddBddTransferPermuteRecur( ddS, ddD, f, table, Permute );
if ( res != NULL )
cuddRef( res );
/* Dereference all elements in the table and dispose of the table.
** This must be done also if res is NULL to avoid leaks in case of
** reordering. */
gen = st__init_gen( table );
if ( gen == NULL )
goto failure;
while ( st__gen( gen, ( const char ** ) &key, ( char ** ) &value ) )
{
Cudd_RecursiveDeref( ddD, value );
}
st__free_gen( gen );
gen = NULL;
st__free_table( table );
table = NULL;
if ( res != NULL )
cuddDeref( res );
return ( res );
failure:
if ( table != NULL )
st__free_table( table );
if ( gen != NULL )
st__free_gen( gen );
return ( NULL );
} /* end of cuddBddTransferPermute */
/**Function********************************************************************
Synopsis [Performs the recursive step of Cudd_bddTransferPermute.]
Description [Performs the recursive step of Cudd_bddTransferPermute.
Returns a pointer to the result if successful; NULL otherwise.]
SideEffects [None]
SeeAlso [cuddBddTransferPermute]
******************************************************************************/
static DdNode *
cuddBddTransferPermuteRecur( DdManager * ddS,
DdManager * ddD, DdNode * f, st__table * table, int * Permute )
{
DdNode *ft, *fe, *t, *e, *var, *res;
DdNode *one, *zero;
int index;
int comple = 0;
statLine( ddD );
one = DD_ONE( ddD );
comple = Cudd_IsComplement( f );
/* Trivial cases. */
if ( Cudd_IsConstant( f ) )
return ( Cudd_NotCond( one, comple ) );
/* Make canonical to increase the utilization of the cache. */
f = Cudd_NotCond( f, comple );
/* Now f is a regular pointer to a non-constant node. */
/* Check the cache. */
if ( st__lookup( table, ( char * ) f, ( char ** ) &res ) )
return ( Cudd_NotCond( res, comple ) );
/* Recursive step. */
index = Permute[f->index];
ft = cuddT( f );
fe = cuddE( f );
t = cuddBddTransferPermuteRecur( ddS, ddD, ft, table, Permute );
if ( t == NULL )
{
return ( NULL );
}
cuddRef( t );
e = cuddBddTransferPermuteRecur( ddS, ddD, fe, table, Permute );
if ( e == NULL )
{
Cudd_RecursiveDeref( ddD, t );
return ( NULL );
}
cuddRef( e );
zero = Cudd_Not( one );
var = cuddUniqueInter( ddD, index, one, zero );
if ( var == NULL )
{
Cudd_RecursiveDeref( ddD, t );
Cudd_RecursiveDeref( ddD, e );
return ( NULL );
}
res = cuddBddIteRecur( ddD, var, t, e );
if ( res == NULL )
{
Cudd_RecursiveDeref( ddD, t );
Cudd_RecursiveDeref( ddD, e );
return ( NULL );
}
cuddRef( res );
Cudd_RecursiveDeref( ddD, t );
Cudd_RecursiveDeref( ddD, e );
if ( st__add_direct( table, ( char * ) f, ( char * ) res ) ==
st__OUT_OF_MEM )
{
Cudd_RecursiveDeref( ddD, res );
return ( NULL );
}
return ( Cudd_NotCond( res, comple ) );
} /* end of cuddBddTransferPermuteRecur */
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END