blob: 9b9dd21210a8541d633e7fea2d7edf10dd18ab2a [file] [log] [blame]
/**CFile****************************************************************
FileName [dsdTree.c]
PackageName [DSD: Disjoint-support decomposition package.]
Synopsis [Managing the decomposition tree.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 8.0. Started - September 22, 2003.]
Revision [$Id: dsdTree.c,v 1.0 2002/22/09 00:00:00 alanmi Exp $]
***********************************************************************/
#include "dsdInt.h"
#include "misc/util/utilTruth.h"
#include "opt/dau/dau.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// FUNCTION DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode );
static void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur );
static int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode );
static int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode );
static int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars );
static void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes );
static void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fCcmp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames );
static void Dsd_NodePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fComp, char * pOutputName, int nOffset, int * pSigCounter );
////////////////////////////////////////////////////////////////////////
/// STATIC VARIABLES ///
////////////////////////////////////////////////////////////////////////
static int s_DepthMax;
static int s_GateSizeMax;
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Create the DSD node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Dsd_Node_t * Dsd_TreeNodeCreate( int Type, int nDecs, int BlockNum )
{
// allocate memory for this node
Dsd_Node_t * p = (Dsd_Node_t *) ABC_ALLOC( char, sizeof(Dsd_Node_t) );
memset( p, 0, sizeof(Dsd_Node_t) );
p->Type = (Dsd_Type_t)Type; // the type of this block
p->nDecs = nDecs; // the number of decompositions
if ( p->nDecs )
{
p->pDecs = (Dsd_Node_t **) ABC_ALLOC( char, p->nDecs * sizeof(Dsd_Node_t *) );
p->pDecs[0] = NULL;
}
return p;
}
/**Function*************************************************************
Synopsis [Frees the DSD node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeNodeDelete( DdManager * dd, Dsd_Node_t * pNode )
{
if ( pNode->G ) Cudd_RecursiveDeref( dd, pNode->G );
if ( pNode->S ) Cudd_RecursiveDeref( dd, pNode->S );
ABC_FREE( pNode->pDecs );
ABC_FREE( pNode );
}
/**Function*************************************************************
Synopsis [Unmarks the decomposition tree.]
Description [This function assumes that originally pNode->nVisits are
set to zero!]
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeUnmark( Dsd_Manager_t * pDsdMan )
{
int i;
for ( i = 0; i < pDsdMan->nRoots; i++ )
Dsd_TreeUnmark_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
}
/**Function*************************************************************
Synopsis [Recursive unmarking.]
Description [This function should be called with a non-complemented
pointer.]
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeUnmark_rec( Dsd_Node_t * pNode )
{
int i;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->nVisits > 0 );
if ( --pNode->nVisits ) // if this is not the last visit, return
return;
// upon the last visit, go through the list of successors and call recursively
if ( pNode->Type != DSD_NODE_BUF && pNode->Type != DSD_NODE_CONST1 )
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreeUnmark_rec( Dsd_Regular(pNode->pDecs[i]) );
}
/**Function*************************************************************
Synopsis [Getting information about the node.]
Description [This function computes the max depth and the max gate size
of the tree rooted at the node.]
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeNodeGetInfo( Dsd_Manager_t * pDsdMan, int * DepthMax, int * GateSizeMax )
{
int i;
s_DepthMax = 0;
s_GateSizeMax = 0;
for ( i = 0; i < pDsdMan->nRoots; i++ )
Dsd_TreeGetInfo_rec( Dsd_Regular( pDsdMan->pRoots[i] ), 0 );
if ( DepthMax )
*DepthMax = s_DepthMax;
if ( GateSizeMax )
*GateSizeMax = s_GateSizeMax;
}
/**Function*************************************************************
Synopsis [Getting information about the node.]
Description [This function computes the max depth and the max gate size
of the tree rooted at the node.]
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeNodeGetInfoOne( Dsd_Node_t * pNode, int * DepthMax, int * GateSizeMax )
{
s_DepthMax = 0;
s_GateSizeMax = 0;
Dsd_TreeGetInfo_rec( Dsd_Regular(pNode), 0 );
if ( DepthMax )
*DepthMax = s_DepthMax;
if ( GateSizeMax )
*GateSizeMax = s_GateSizeMax;
}
/**Function*************************************************************
Synopsis [Performs the recursive step of Dsd_TreeNodeGetInfo().]
Description [pNode is the node, for the tree rooted in which we are
determining info. RankCur is the current rank to assign to the node.
fSetRank is the flag saying whether the rank will be written in the
node. s_DepthMax is the maximum depths of the tree. s_GateSizeMax is
the maximum gate size.]
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeGetInfo_rec( Dsd_Node_t * pNode, int RankCur )
{
int i;
int GateSize;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->nVisits >= 0 );
// we don't want the two-input gates to count for non-decomposable blocks
if ( pNode->Type == DSD_NODE_OR ||
pNode->Type == DSD_NODE_EXOR )
GateSize = 2;
else
GateSize = pNode->nDecs;
// update the max size of the node
if ( s_GateSizeMax < GateSize )
s_GateSizeMax = GateSize;
if ( pNode->nDecs < 2 )
return;
// update the max rank
if ( s_DepthMax < RankCur+1 )
s_DepthMax = RankCur+1;
// call recursively
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreeGetInfo_rec( Dsd_Regular(pNode->pDecs[i]), RankCur+1 );
}
/**Function*************************************************************
Synopsis [Counts AIG nodes needed to implement this node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeGetAigCost_rec( Dsd_Node_t * pNode )
{
int i, Counter = 0;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->nVisits >= 0 );
if ( pNode->nDecs < 2 )
return 0;
// we don't want the two-input gates to count for non-decomposable blocks
if ( pNode->Type == DSD_NODE_OR )
Counter += pNode->nDecs - 1;
else if ( pNode->Type == DSD_NODE_EXOR )
Counter += 3*(pNode->nDecs - 1);
else if ( pNode->Type == DSD_NODE_PRIME && pNode->nDecs == 3 )
Counter += 3;
// call recursively
for ( i = 0; i < pNode->nDecs; i++ )
Counter += Dsd_TreeGetAigCost_rec( Dsd_Regular(pNode->pDecs[i]) );
return Counter;
}
/**Function*************************************************************
Synopsis [Counts AIG nodes needed to implement this node.]
Description [Assumes that the only primes of the DSD tree are MUXes.]
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeGetAigCost( Dsd_Node_t * pNode )
{
return Dsd_TreeGetAigCost_rec( Dsd_Regular(pNode) );
}
/**Function*************************************************************
Synopsis [Counts non-terminal nodes of the DSD tree.]
Description [Nonterminal nodes include all the nodes with the
support more than 1. These are OR, EXOR, and PRIME nodes. They
do not include the elementary variable nodes and the constant 1
node.]
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountNonTerminalNodes( Dsd_Manager_t * pDsdMan )
{
int Counter, i;
Counter = 0;
for ( i = 0; i < pDsdMan->nRoots; i++ )
Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
Dsd_TreeUnmark( pDsdMan );
return Counter;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountNonTerminalNodesOne( Dsd_Node_t * pRoot )
{
int Counter = 0;
// go through the list of successors and call recursively
Counter = Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pRoot) );
Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
return Counter;
}
/**Function*************************************************************
Synopsis [Counts non-terminal nodes for one root.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountNonTerminalNodes_rec( Dsd_Node_t * pNode )
{
int i;
int Counter = 0;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->nVisits >= 0 );
if ( pNode->nVisits++ ) // if this is not the first visit, return zero
return 0;
if ( pNode->nDecs <= 1 )
return 0;
// upon the first visit, go through the list of successors and call recursively
for ( i = 0; i < pNode->nDecs; i++ )
Counter += Dsd_TreeCountNonTerminalNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
return Counter + 1;
}
/**Function*************************************************************
Synopsis [Counts prime nodes of the DSD tree.]
Description [Prime nodes are nodes with the support more than 2,
that is not an OR or EXOR gate.]
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountPrimeNodes( Dsd_Manager_t * pDsdMan )
{
int Counter, i;
Counter = 0;
for ( i = 0; i < pDsdMan->nRoots; i++ )
Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular( pDsdMan->pRoots[i] ) );
Dsd_TreeUnmark( pDsdMan );
return Counter;
}
/**Function*************************************************************
Synopsis [Counts prime nodes for one root.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountPrimeNodesOne( Dsd_Node_t * pRoot )
{
int Counter = 0;
// go through the list of successors and call recursively
Counter = Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pRoot) );
Dsd_TreeUnmark_rec( Dsd_Regular(pRoot) );
return Counter;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCountPrimeNodes_rec( Dsd_Node_t * pNode )
{
int i;
int Counter = 0;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->nVisits >= 0 );
if ( pNode->nVisits++ ) // if this is not the first visit, return zero
return 0;
if ( pNode->nDecs <= 1 )
return 0;
// upon the first visit, go through the list of successors and call recursively
for ( i = 0; i < pNode->nDecs; i++ )
Counter += Dsd_TreeCountPrimeNodes_rec( Dsd_Regular(pNode->pDecs[i]) );
if ( pNode->Type == DSD_NODE_PRIME )
Counter++;
return Counter;
}
/**Function*************************************************************
Synopsis [Collects the decomposable vars on the PI side.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCollectDecomposableVars( Dsd_Manager_t * pDsdMan, int * pVars )
{
int nVars;
// set the vars collected to 0
nVars = 0;
Dsd_TreeCollectDecomposableVars_rec( pDsdMan->dd, Dsd_Regular(pDsdMan->pRoots[0]), pVars, &nVars );
// return the number of collected vars
return nVars;
}
/**Function*************************************************************
Synopsis [Implements the recursive part of Dsd_TreeCollectDecomposableVars().]
Description [Adds decomposable variables as they are found to pVars and increments
nVars. Returns 1 if a non-dec node with more than 4 inputs was encountered
in the processed subtree. Returns 0, otherwise. ]
SideEffects []
SeeAlso []
***********************************************************************/
int Dsd_TreeCollectDecomposableVars_rec( DdManager * dd, Dsd_Node_t * pNode, int * pVars, int * nVars )
{
int fSkipThisNode, i;
Dsd_Node_t * pTemp;
int fVerbose = 0;
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
if ( pNode->nDecs <= 1 )
return 0;
// go through the list of successors and call recursively
fSkipThisNode = 0;
for ( i = 0; i < pNode->nDecs; i++ )
if ( Dsd_TreeCollectDecomposableVars_rec(dd, Dsd_Regular(pNode->pDecs[i]), pVars, nVars) )
fSkipThisNode = 1;
if ( !fSkipThisNode && (pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR || pNode->nDecs <= 4) )
{
if ( fVerbose )
printf( "Node of type <%d> (OR=6,EXOR=8,RAND=1): ", pNode->Type );
for ( i = 0; i < pNode->nDecs; i++ )
{
pTemp = Dsd_Regular(pNode->pDecs[i]);
if ( pTemp->Type == DSD_NODE_BUF )
{
if ( pVars )
pVars[ (*nVars)++ ] = pTemp->S->index;
else
(*nVars)++;
if ( fVerbose )
printf( "%d ", pTemp->S->index );
}
}
if ( fVerbose )
printf( "\n" );
}
else
fSkipThisNode = 1;
return fSkipThisNode;
}
/**Function*************************************************************
Synopsis [Creates the DFS ordered array of DSD nodes in the tree.]
Description [The collected nodes do not include the terminal nodes
and the constant 1 node. The array of nodes is returned. The number
of entries in the array is returned in the variale pnNodes.]
SideEffects []
SeeAlso []
***********************************************************************/
Dsd_Node_t ** Dsd_TreeCollectNodesDfs( Dsd_Manager_t * pDsdMan, int * pnNodes )
{
Dsd_Node_t ** ppNodes;
int nNodes, nNodesAlloc;
int i;
nNodesAlloc = Dsd_TreeCountNonTerminalNodes(pDsdMan);
nNodes = 0;
ppNodes = ABC_ALLOC( Dsd_Node_t *, nNodesAlloc );
for ( i = 0; i < pDsdMan->nRoots; i++ )
Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pDsdMan->pRoots[i]), ppNodes, &nNodes );
Dsd_TreeUnmark( pDsdMan );
assert( nNodesAlloc == nNodes );
*pnNodes = nNodes;
return ppNodes;
}
/**Function*************************************************************
Synopsis [Creates the DFS ordered array of DSD nodes in the tree.]
Description [The collected nodes do not include the terminal nodes
and the constant 1 node. The array of nodes is returned. The number
of entries in the array is returned in the variale pnNodes.]
SideEffects []
SeeAlso []
***********************************************************************/
Dsd_Node_t ** Dsd_TreeCollectNodesDfsOne( Dsd_Manager_t * pDsdMan, Dsd_Node_t * pNode, int * pnNodes )
{
Dsd_Node_t ** ppNodes;
int nNodes, nNodesAlloc;
nNodesAlloc = Dsd_TreeCountNonTerminalNodesOne(pNode);
nNodes = 0;
ppNodes = ABC_ALLOC( Dsd_Node_t *, nNodesAlloc );
Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pNode), ppNodes, &nNodes );
Dsd_TreeUnmark_rec(Dsd_Regular(pNode));
assert( nNodesAlloc == nNodes );
*pnNodes = nNodes;
return ppNodes;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreeCollectNodesDfs_rec( Dsd_Node_t * pNode, Dsd_Node_t * ppNodes[], int * pnNodes )
{
int i;
assert( pNode );
assert( !Dsd_IsComplement(pNode) );
assert( pNode->nVisits >= 0 );
if ( pNode->nVisits++ ) // if this is not the first visit, return zero
return;
if ( pNode->nDecs <= 1 )
return;
// upon the first visit, go through the list of successors and call recursively
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreeCollectNodesDfs_rec( Dsd_Regular(pNode->pDecs[i]), ppNodes, pnNodes );
ppNodes[ (*pnNodes)++ ] = pNode;
}
/**Function*************************************************************
Synopsis [Prints the decompostion tree into file.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreePrint( FILE * pFile, Dsd_Manager_t * pDsdMan, char * pInputNames[], char * pOutputNames[], int fShortNames, int Output )
{
Dsd_Node_t * pNode;
int SigCounter;
int i;
SigCounter = 1;
if ( Output == -1 )
{
for ( i = 0; i < pDsdMan->nRoots; i++ )
{
pNode = Dsd_Regular( pDsdMan->pRoots[i] );
Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[i]), pInputNames, pOutputNames[i], 0, &SigCounter, fShortNames );
}
}
else
{
assert( Output >= 0 && Output < pDsdMan->nRoots );
pNode = Dsd_Regular( pDsdMan->pRoots[Output] );
Dsd_TreePrint_rec( pFile, pNode, (pNode != pDsdMan->pRoots[Output]), pInputNames, pOutputNames[Output], 0, &SigCounter, fShortNames );
}
}
/**Function*************************************************************
Synopsis [Prints the decompostion tree into file.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_TreePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fComp, char * pInputNames[], char * pOutputName, int nOffset, int * pSigCounter, int fShortNames )
{
char Buffer[100];
Dsd_Node_t * pInput;
int * pInputNums;
int fCompNew, i;
assert( pNode->Type == DSD_NODE_BUF || pNode->Type == DSD_NODE_CONST1 ||
pNode->Type == DSD_NODE_PRIME || pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR );
Extra_PrintSymbols( pFile, ' ', nOffset, 0 );
if ( !fComp )
fprintf( pFile, "%s = ", pOutputName );
else
fprintf( pFile, "NOT(%s) = ", pOutputName );
pInputNums = ABC_ALLOC( int, pNode->nDecs );
if ( pNode->Type == DSD_NODE_CONST1 )
{
fprintf( pFile, " Constant 1.\n" );
}
else if ( pNode->Type == DSD_NODE_BUF )
{
if ( fShortNames )
fprintf( pFile, "%d", 'a' + pNode->S->index );
else
fprintf( pFile, "%s", pInputNames[pNode->S->index] );
fprintf( pFile, "\n" );
}
else if ( pNode->Type == DSD_NODE_PRIME )
{
// print the line
fprintf( pFile, "PRIME(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
if ( i )
fprintf( pFile, "," );
if ( fCompNew )
fprintf( pFile, " NOT(" );
else
fprintf( pFile, " " );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
if ( fShortNames )
fprintf( pFile, "%d", pInput->S->index );
else
fprintf( pFile, "%s", pInputNames[pInput->S->index] );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, "<%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, ")" );
}
fprintf( pFile, " )\n" );
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
}
}
else if ( pNode->Type == DSD_NODE_OR )
{
// print the line
fprintf( pFile, "OR(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
if ( i )
fprintf( pFile, "," );
if ( fCompNew )
fprintf( pFile, " NOT(" );
else
fprintf( pFile, " " );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
if ( fShortNames )
fprintf( pFile, "%c", 'a' + pInput->S->index );
else
fprintf( pFile, "%s", pInputNames[pInput->S->index] );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, "<%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, ")" );
}
fprintf( pFile, " )\n" );
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
}
}
else if ( pNode->Type == DSD_NODE_EXOR )
{
// print the line
fprintf( pFile, "EXOR(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
if ( i )
fprintf( pFile, "," );
if ( fCompNew )
fprintf( pFile, " NOT(" );
else
fprintf( pFile, " " );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
if ( fShortNames )
fprintf( pFile, "%c", 'a' + pInput->S->index );
else
fprintf( pFile, "%s", pInputNames[pInput->S->index] );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, "<%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, ")" );
}
fprintf( pFile, " )\n" );
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_TreePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, pInputNames, Buffer, nOffset + 6, pSigCounter, fShortNames );
}
}
ABC_FREE( pInputNums );
}
/**Function*************************************************************
Synopsis [Prints the decompostion tree into file.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
word Dsd_TreeFunc2Truth_rec( DdManager * dd, DdNode * bFunc )
{
word Cof0, Cof1;
int Level;
if ( bFunc == b0 )
return 0;
if ( bFunc == b1 )
return ~(word)0;
if ( Cudd_IsComplement(bFunc) )
return ~Dsd_TreeFunc2Truth_rec( dd, Cudd_Not(bFunc) );
Level = dd->perm[bFunc->index];
assert( Level >= 0 && Level < 6 );
Cof0 = Dsd_TreeFunc2Truth_rec( dd, cuddE(bFunc) );
Cof1 = Dsd_TreeFunc2Truth_rec( dd, cuddT(bFunc) );
return (s_Truths6[Level] & Cof1) | (~s_Truths6[Level] & Cof0);
}
void Dsd_TreePrint2_rec( FILE * pFile, DdManager * dd, Dsd_Node_t * pNode, int fComp, char * pInputNames[] )
{
int i;
if ( pNode->Type == DSD_NODE_CONST1 )
{
fprintf( pFile, "Const%d", !fComp );
return;
}
assert( pNode->Type == DSD_NODE_BUF || pNode->Type == DSD_NODE_PRIME || pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR );
// fprintf( pFile, "%s", (fComp ^ (pNode->Type == DSD_NODE_OR))? "!" : "" );
if ( pNode->Type == DSD_NODE_BUF )
{
fprintf( pFile, "%s", fComp? "!" : "" );
fprintf( pFile, "%s", pInputNames[pNode->S->index] );
}
else if ( pNode->Type == DSD_NODE_PRIME )
{
fprintf( pFile, " " );
if ( pNode->nDecs <= 6 )
{
char pCanonPerm[6]; int uCanonPhase;
// compute truth table
DdNode * bFunc = Dsd_TreeGetPrimeFunction( dd, pNode );
word uTruth = Dsd_TreeFunc2Truth_rec( dd, bFunc );
Cudd_Ref( bFunc );
Cudd_RecursiveDeref( dd, bFunc );
// canonicize truth table
uCanonPhase = Abc_TtCanonicize( &uTruth, pNode->nDecs, pCanonPerm );
fprintf( pFile, "%s", (fComp ^ ((uCanonPhase >> pNode->nDecs) & 1)) ? "!" : "" );
Abc_TtPrintHexRev( pFile, &uTruth, pNode->nDecs );
fprintf( pFile, "{" );
for ( i = 0; i < pNode->nDecs; i++ )
{
Dsd_Node_t * pInput = pNode->pDecs[(int)pCanonPerm[i]];
Dsd_TreePrint2_rec( pFile, dd, Dsd_Regular(pInput), Dsd_IsComplement(pInput) ^ ((uCanonPhase>>i)&1), pInputNames );
}
fprintf( pFile, "} " );
}
else
{
fprintf( pFile, "|%d|", pNode->nDecs );
fprintf( pFile, "{" );
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreePrint2_rec( pFile, dd, Dsd_Regular(pNode->pDecs[i]), Dsd_IsComplement(pNode->pDecs[i]), pInputNames );
fprintf( pFile, "} " );
}
}
else if ( pNode->Type == DSD_NODE_OR )
{
fprintf( pFile, "%s", !fComp? "!" : "" );
fprintf( pFile, "(" );
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreePrint2_rec( pFile, dd, Dsd_Regular(pNode->pDecs[i]), !Dsd_IsComplement(pNode->pDecs[i]), pInputNames );
fprintf( pFile, ")" );
}
else if ( pNode->Type == DSD_NODE_EXOR )
{
fprintf( pFile, "%s", fComp? "!" : "" );
fprintf( pFile, "[" );
for ( i = 0; i < pNode->nDecs; i++ )
Dsd_TreePrint2_rec( pFile, dd, Dsd_Regular(pNode->pDecs[i]), Dsd_IsComplement(pNode->pDecs[i]), pInputNames );
fprintf( pFile, "]" );
}
}
void Dsd_TreePrint2( FILE * pFile, Dsd_Manager_t * pDsdMan, char * pInputNames[], char * pOutputNames[], int Output )
{
if ( Output == -1 )
{
int i;
for ( i = 0; i < pDsdMan->nRoots; i++ )
{
fprintf( pFile, "%8s = ", pOutputNames[i] );
Dsd_TreePrint2_rec( pFile, pDsdMan->dd, Dsd_Regular(pDsdMan->pRoots[i]), Dsd_IsComplement(pDsdMan->pRoots[i]), pInputNames );
fprintf( pFile, "\n" );
}
}
else
{
assert( Output >= 0 && Output < pDsdMan->nRoots );
fprintf( pFile, "%8s = ", pOutputNames[Output] );
Dsd_TreePrint2_rec( pFile, pDsdMan->dd, Dsd_Regular(pDsdMan->pRoots[Output]), Dsd_IsComplement(pDsdMan->pRoots[Output]), pInputNames );
fprintf( pFile, "\n" );
}
}
/**Function*************************************************************
Synopsis [Prints the decompostion tree into file.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_NodePrint( FILE * pFile, Dsd_Node_t * pNode )
{
Dsd_Node_t * pNodeR;
int SigCounter = 1;
pNodeR = Dsd_Regular(pNode);
Dsd_NodePrint_rec( pFile, pNodeR, pNodeR != pNode, "F", 0, &SigCounter );
}
/**Function*************************************************************
Synopsis [Prints one node of the decomposition tree.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Dsd_NodePrint_rec( FILE * pFile, Dsd_Node_t * pNode, int fComp, char * pOutputName, int nOffset, int * pSigCounter )
{
char Buffer[100];
Dsd_Node_t * pInput;
int * pInputNums;
int fCompNew, i;
assert( pNode->Type == DSD_NODE_BUF || pNode->Type == DSD_NODE_CONST1 ||
pNode->Type == DSD_NODE_PRIME || pNode->Type == DSD_NODE_OR || pNode->Type == DSD_NODE_EXOR );
Extra_PrintSymbols( pFile, ' ', nOffset, 0 );
if ( !fComp )
fprintf( pFile, "%s = ", pOutputName );
else
fprintf( pFile, "NOT(%s) = ", pOutputName );
pInputNums = ABC_ALLOC( int, pNode->nDecs );
if ( pNode->Type == DSD_NODE_CONST1 )
{
fprintf( pFile, " Constant 1.\n" );
}
else if ( pNode->Type == DSD_NODE_BUF )
{
fprintf( pFile, " " );
fprintf( pFile, "%c", 'a' + pNode->S->index );
fprintf( pFile, "\n" );
}
else if ( pNode->Type == DSD_NODE_PRIME )
{
// print the line
fprintf( pFile, "PRIME(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
assert( fCompNew == 0 );
if ( i )
fprintf( pFile, "," );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
fprintf( pFile, " %c", 'a' + pInput->S->index );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, " <%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, "\'" );
}
fprintf( pFile, " )\n" );
/*
fprintf( pFile, " ) " );
{
DdNode * bLocal;
bLocal = Dsd_TreeGetPrimeFunction( dd, pNodeDsd ); Cudd_Ref( bLocal );
Extra_bddPrint( dd, bLocal );
Cudd_RecursiveDeref( dd, bLocal );
}
*/
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_NodePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, Buffer, nOffset + 6, pSigCounter );
}
}
else if ( pNode->Type == DSD_NODE_OR )
{
// print the line
fprintf( pFile, "OR(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
if ( i )
fprintf( pFile, "," );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
fprintf( pFile, " %c", 'a' + pInput->S->index );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, " <%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, "\'" );
}
fprintf( pFile, " )\n" );
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_NodePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, Buffer, nOffset + 6, pSigCounter );
}
}
else if ( pNode->Type == DSD_NODE_EXOR )
{
// print the line
fprintf( pFile, "EXOR(" );
for ( i = 0; i < pNode->nDecs; i++ )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
fCompNew = (int)( pInput != pNode->pDecs[i] );
assert( fCompNew == 0 );
if ( i )
fprintf( pFile, "," );
if ( pInput->Type == DSD_NODE_BUF )
{
pInputNums[i] = 0;
fprintf( pFile, " %c", 'a' + pInput->S->index );
}
else
{
pInputNums[i] = (*pSigCounter)++;
fprintf( pFile, " <%d>", pInputNums[i] );
}
if ( fCompNew )
fprintf( pFile, "\'" );
}
fprintf( pFile, " )\n" );
// call recursively for the following blocks
for ( i = 0; i < pNode->nDecs; i++ )
if ( pInputNums[i] )
{
pInput = Dsd_Regular( pNode->pDecs[i] );
sprintf( Buffer, "<%d>", pInputNums[i] );
Dsd_NodePrint_rec( pFile, Dsd_Regular( pNode->pDecs[i] ), 0, Buffer, nOffset + 6, pSigCounter );
}
}
ABC_FREE( pInputNums );
}
/**Function*************************************************************
Synopsis [Retuns the function of one node of the decomposition tree.]
Description [This is the old procedure. It is now superceded by the
procedure Dsd_TreeGetPrimeFunction() found in "dsdLocal.c".]
SideEffects []
SeeAlso []
***********************************************************************/
DdNode * Dsd_TreeGetPrimeFunctionOld( DdManager * dd, Dsd_Node_t * pNode, int fRemap )
{
DdNode * bCof0, * bCof1, * bCube0, * bCube1, * bNewFunc, * bTemp;
int i;
static int Permute[MAXINPUTS];
assert( pNode );
assert( !Dsd_IsComplement( pNode ) );
assert( pNode->Type == DSD_NODE_PRIME );
// transform the function of this block to depend on inputs
// corresponding to the formal inputs
// first, substitute those inputs that have some blocks associated with them
// second, remap the inputs to the top of the manager (then, it is easy to output them)
// start the function
bNewFunc = pNode->G; Cudd_Ref( bNewFunc );
// go over all primary inputs
for ( i = 0; i < pNode->nDecs; i++ )
if ( pNode->pDecs[i]->Type != DSD_NODE_BUF ) // remap only if it is not the buffer
{
bCube0 = Extra_bddFindOneCube( dd, Cudd_Not(pNode->pDecs[i]->G) ); Cudd_Ref( bCube0 );
bCof0 = Cudd_Cofactor( dd, bNewFunc, bCube0 ); Cudd_Ref( bCof0 );
Cudd_RecursiveDeref( dd, bCube0 );
bCube1 = Extra_bddFindOneCube( dd, pNode->pDecs[i]->G ); Cudd_Ref( bCube1 );
bCof1 = Cudd_Cofactor( dd, bNewFunc, bCube1 ); Cudd_Ref( bCof1 );
Cudd_RecursiveDeref( dd, bCube1 );
Cudd_RecursiveDeref( dd, bNewFunc );
// use the variable in the i-th level of the manager
// bNewFunc = Cudd_bddIte( dd, dd->vars[dd->invperm[i]],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
// use the first variale in the support of the component
bNewFunc = Cudd_bddIte( dd, dd->vars[pNode->pDecs[i]->S->index],bCof1,bCof0 ); Cudd_Ref( bNewFunc );
Cudd_RecursiveDeref( dd, bCof0 );
Cudd_RecursiveDeref( dd, bCof1 );
}
if ( fRemap )
{
// remap the function to the top of the manager
// remap the function to the first variables of the manager
for ( i = 0; i < pNode->nDecs; i++ )
// Permute[ pNode->pDecs[i]->S->index ] = dd->invperm[i];
Permute[ pNode->pDecs[i]->S->index ] = i;
bNewFunc = Cudd_bddPermute( dd, bTemp = bNewFunc, Permute ); Cudd_Ref( bNewFunc );
Cudd_RecursiveDeref( dd, bTemp );
}
Cudd_Deref( bNewFunc );
return bNewFunc;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END