summaryrefslogtreecommitdiffstats
path: root/src/map/fpga/fpgaUtils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/fpga/fpgaUtils.c')
-rw-r--r--src/map/fpga/fpgaUtils.c986
1 files changed, 986 insertions, 0 deletions
diff --git a/src/map/fpga/fpgaUtils.c b/src/map/fpga/fpgaUtils.c
new file mode 100644
index 00000000..b951fd8f
--- /dev/null
+++ b/src/map/fpga/fpgaUtils.c
@@ -0,0 +1,986 @@
+/**CFile****************************************************************
+
+ FileName [fpgaUtils.c]
+
+ PackageName [MVSIS 1.3: Multi-valued logic synthesis system.]
+
+ Synopsis [Technology mapping for variable-size-LUT FPGAs.]
+
+ Author [MVSIS Group]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 2.0. Started - August 18, 2004.]
+
+ Revision [$Id: fpgaUtils.c,v 1.3 2004/07/06 04:55:58 alanmi Exp $]
+
+***********************************************************************/
+
+#include "fpgaInt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define FPGA_CO_LIST_SIZE 5
+
+static void Fpga_MappingDfs_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes, int fCollectEquiv );
+static void Fpga_MappingDfsCuts_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes );
+static int Fpga_MappingCompareOutputDelay( Fpga_Node_t ** ppNode1, Fpga_Node_t ** ppNode2 );
+static void Fpga_MappingFindLatest( Fpga_Man_t * p, int * pNodes, int nNodesMax );
+static void Fpga_DfsLim_rec( Fpga_Node_t * pNode, int Level, Fpga_NodeVec_t * vNodes );
+static int Fpga_CollectNodeTfo_rec( Fpga_Node_t * pNode, Fpga_Node_t * pPivot, Fpga_NodeVec_t * vVisited, Fpga_NodeVec_t * vTfo );
+static Fpga_NodeVec_t * Fpga_MappingOrderCosByLevel( Fpga_Man_t * pMan );
+static Fpga_Man_t * s_pMan = NULL;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfs( Fpga_Man_t * pMan, int fCollectEquiv )
+{
+ Fpga_NodeVec_t * vNodes;//, * vNodesCo;
+ Fpga_Node_t * pNode;
+ int i;
+ // collect the CO nodes by level
+// vNodesCo = Fpga_MappingOrderCosByLevel( pMan );
+ // start the array
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ // collect the PIs
+ for ( i = 0; i < pMan->nInputs; i++ )
+ {
+ pNode = pMan->pInputs[i];
+ Fpga_NodeVecPush( vNodes, pNode );
+ pNode->fMark0 = 1;
+ }
+ // perform the traversal
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingDfs_rec( Fpga_Regular(pMan->pOutputs[i]), vNodes, fCollectEquiv );
+// for ( i = vNodesCo->nSize - 1; i >= 0 ; i-- )
+// for ( pNode = vNodesCo->pArray[i]; pNode; pNode = (Fpga_Node_t *)pNode->pData0 )
+// Fpga_MappingDfs_rec( pNode, vNodes, fCollectEquiv );
+ // clean the node marks
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+// for ( i = 0; i < pMan->nOutputs; i++ )
+// Fpga_MappingUnmark_rec( Fpga_Regular(pMan->pOutputs[i]) );
+// Fpga_NodeVecFree( vNodesCo );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingDfs_rec( Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes, int fCollectEquiv )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ // visit the transitive fanin
+ if ( Fpga_NodeIsAnd(pNode) )
+ {
+ Fpga_MappingDfs_rec( Fpga_Regular(pNode->p1), vNodes, fCollectEquiv );
+ Fpga_MappingDfs_rec( Fpga_Regular(pNode->p2), vNodes, fCollectEquiv );
+ }
+ // visit the equivalent nodes
+ if ( fCollectEquiv && pNode->pNextE )
+ Fpga_MappingDfs_rec( pNode->pNextE, vNodes, fCollectEquiv );
+ // make sure the node is not visited through the equivalent nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingDfsNodes( Fpga_Man_t * pMan, Fpga_Node_t ** ppNodes, int nNodes, int fEquiv )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 200 );
+ for ( i = 0; i < nNodes; i++ )
+ Fpga_MappingDfs_rec( ppNodes[i], vNodes, fEquiv );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingGetAreaFlow( Fpga_Man_t * p )
+{
+ float aFlowFlowTotal = 0;
+ int i;
+ for ( i = 0; i < p->nOutputs; i++ )
+ {
+ if ( Fpga_NodeIsConst(p->pOutputs[i]) )
+ continue;
+ aFlowFlowTotal += Fpga_Regular(p->pOutputs[i])->pCutBest->aFlow;
+ }
+ return aFlowFlowTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the area of the current mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingArea( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode;
+ float aTotal;
+ int i;
+ // perform the traversal
+ aTotal = 0;
+ for ( i = 0; i < pMan->vMapping->nSize; i++ )
+ {
+ pNode = pMan->vMapping->pArray[i];
+ aTotal += pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ }
+ return aTotal;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_NodeVec_t * vNodes )
+{
+ float aArea;
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return 0;
+ if ( pNode->fMark0 )
+ return 0;
+ assert( pNode->pCutBest != NULL );
+ // visit the transitive fanin of the selected cut
+ aArea = 0;
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ aArea += Fpga_MappingArea_rec( pMan, pNode->pCutBest->ppLeaves[i], vNodes );
+ // make sure the node is not visited through the fanin nodes
+ assert( pNode->fMark0 == 0 );
+ // mark the node as visited
+ pNode->fMark0 = 1;
+ // add the node to the list
+ aArea += pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+ return aArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the area of the current mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingAreaTrav( Fpga_Man_t * pMan )
+{
+ Fpga_NodeVec_t * vNodes;
+ float aTotal;
+ int i;
+ // perform the traversal
+ aTotal = 0;
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ aTotal += Fpga_MappingArea_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ Fpga_NodeVecFree( vNodes );
+ return aTotal;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingSetRefsAndArea_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, Fpga_Node_t ** ppStore )
+{
+ float aArea;
+ int i;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->nRefs++ )
+ return 0;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return 0;
+ assert( pNode->pCutBest != NULL );
+ // store the node in the structure by level
+ pNode->pData0 = (char *)ppStore[pNode->Level];
+ ppStore[pNode->Level] = pNode;
+ // visit the transitive fanin of the selected cut
+ aArea = pMan->pLutLib->pLutAreas[pNode->pCutBest->nLeaves];
+ for ( i = 0; i < pNode->pCutBest->nLeaves; i++ )
+ aArea += Fpga_MappingSetRefsAndArea_rec( pMan, pNode->pCutBest->ppLeaves[i], ppStore );
+ return aArea;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the correct reference counts for the mapping.]
+
+ Description [Collects the nodes in reverse topological order
+ and places in them in array pMan->vMapping.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+float Fpga_MappingSetRefsAndArea( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode, ** ppStore;
+ float aArea;
+ int i, LevelMax;
+
+ // clean all references
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ pMan->vNodesAll->pArray[i]->nRefs = 0;
+
+ // allocate place to store the nodes
+ LevelMax = Fpga_MappingMaxLevel( pMan );
+ ppStore = ALLOC( Fpga_Node_t *, LevelMax + 1 );
+ memset( ppStore, 0, sizeof(Fpga_Node_t *) * (LevelMax + 1) );
+
+ // collect nodes reachable from POs in the DFS order through the best cuts
+ aArea = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ pNode = Fpga_Regular(pMan->pOutputs[i]);
+ if ( pNode == pMan->pConst1 )
+ continue;
+ aArea += Fpga_MappingSetRefsAndArea_rec( pMan, pNode, ppStore );
+ pNode->nRefs++;
+ }
+
+ // reconnect the nodes in reverse topological order
+ pMan->vMapping->nSize = 0;
+ for ( i = LevelMax; i >= 0; i-- )
+ for ( pNode = ppStore[i]; pNode; pNode = (Fpga_Node_t *)pNode->pData0 )
+ Fpga_NodeVecPush( pMan->vMapping, pNode );
+ free( ppStore );
+ return aArea;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Compares the outputs by their arrival times.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingCompareOutputDelay( Fpga_Node_t ** ppNode1, Fpga_Node_t ** ppNode2 )
+{
+ Fpga_Node_t * pNode1 = Fpga_Regular(*ppNode1);
+ Fpga_Node_t * pNode2 = Fpga_Regular(*ppNode2);
+ float Arrival1 = pNode1->pCutBest? pNode1->pCutBest->tArrival : 0;
+ float Arrival2 = pNode2->pCutBest? pNode2->pCutBest->tArrival : 0;
+ if ( Arrival1 < Arrival2 )
+ return -1;
+ if ( Arrival1 > Arrival2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds given number of latest arriving COs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingFindLatest( Fpga_Man_t * p, int * pNodes, int nNodesMax )
+{
+ int nNodes, i, k, v;
+ assert( p->nOutputs >= nNodesMax );
+ pNodes[0] = 0;
+ nNodes = 1;
+ for ( i = 1; i < p->nOutputs; i++ )
+ {
+ for ( k = nNodes - 1; k >= 0; k-- )
+ if ( Fpga_MappingCompareOutputDelay( &p->pOutputs[pNodes[k]], &p->pOutputs[i] ) >= 0 )
+ break;
+ if ( k == nNodesMax - 1 )
+ continue;
+ if ( nNodes < nNodesMax )
+ nNodes++;
+ for ( v = nNodes - 1; v > k+1; v-- )
+ pNodes[v] = pNodes[v-1];
+ pNodes[k+1] = i;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints a bunch of latest arriving outputs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingPrintOutputArrivals( Fpga_Man_t * p )
+{
+ Fpga_Node_t * pNode;
+ int pSorted[FPGA_CO_LIST_SIZE];
+ int fCompl, Limit, MaxNameSize, i;
+
+ // determine the number of nodes to print
+ Limit = (p->nOutputs > FPGA_CO_LIST_SIZE)? FPGA_CO_LIST_SIZE : p->nOutputs;
+
+ // determine the order
+ Fpga_MappingFindLatest( p, pSorted, Limit );
+
+ // determine max size of the node's name
+ MaxNameSize = 0;
+ for ( i = 0; i < Limit; i++ )
+ if ( MaxNameSize < (int)strlen(p->ppOutputNames[pSorted[i]]) )
+ MaxNameSize = strlen(p->ppOutputNames[pSorted[i]]);
+
+ // print the latest outputs
+ for ( i = 0; i < Limit; i++ )
+ {
+ // get the i-th latest output
+ pNode = Fpga_Regular(p->pOutputs[pSorted[i]]);
+ fCompl = Fpga_IsComplement(p->pOutputs[pSorted[i]]);
+ // print out the best arrival time
+ printf( "Output %-*s : ", MaxNameSize + 3, p->ppOutputNames[pSorted[i]] );
+ printf( "Delay = %8.2f ", (double)pNode->pCutBest->tArrival );
+ if ( fCompl )
+ printf( "NEG" );
+ else
+ printf( "POS" );
+ printf( "\n" );
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the truth tables.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetupTruthTables( unsigned uTruths[][2] )
+{
+ int m, v;
+ // set up the truth tables
+ for ( m = 0; m < 32; m++ )
+ for ( v = 0; v < 5; v++ )
+ if ( m & (1 << v) )
+ uTruths[v][0] |= (1 << m);
+ // make adjustments for the case of 6 variables
+ for ( v = 0; v < 5; v++ )
+ uTruths[v][1] = uTruths[v][0];
+ uTruths[5][0] = 0;
+ uTruths[5][1] = FPGA_FULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetupMask( unsigned uMask[], int nVarsMax )
+{
+ if ( nVarsMax == 6 )
+ uMask[0] = uMask[1] = FPGA_FULL;
+ else
+ {
+ uMask[0] = FPGA_MASK(1 << nVarsMax);
+ uMask[1] = 0;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verify one useful property.]
+
+ Description [This procedure verifies one useful property. After
+ the FRAIG construction with choice nodes is over, each primary node
+ should have fanins that are primary nodes. The primary nodes is the
+ one that does not have pNode->pRepr set to point to another node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_ManCheckConsistency( Fpga_Man_t * p )
+{
+ Fpga_Node_t * pNode;
+ Fpga_NodeVec_t * pVec;
+ int i;
+ pVec = Fpga_MappingDfs( p, 0 );
+ for ( i = 0; i < pVec->nSize; i++ )
+ {
+ pNode = pVec->pArray[i];
+ if ( Fpga_NodeIsVar(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Primary input %d is a secondary node.\n", pNode->Num );
+ }
+ else if ( Fpga_NodeIsConst(pNode) )
+ {
+ if ( pNode->pRepr )
+ printf( "Constant 1 %d is a secondary node.\n", pNode->Num );
+ }
+ else
+ {
+ if ( pNode->pRepr )
+ printf( "Internal node %d is a secondary node.\n", pNode->Num );
+ if ( Fpga_Regular(pNode->p1)->pRepr )
+ printf( "Internal node %d has first fanin that is a secondary node.\n", pNode->Num );
+ if ( Fpga_Regular(pNode->p2)->pRepr )
+ printf( "Internal node %d has second fanin that is a secondary node.\n", pNode->Num );
+ }
+ }
+ Fpga_NodeVecFree( pVec );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CompareNodesByLevelDecreasing( Fpga_Node_t ** ppS1, Fpga_Node_t ** ppS2 )
+{
+ if ( Fpga_Regular(*ppS1)->Level > Fpga_Regular(*ppS2)->Level )
+ return -1;
+ if ( Fpga_Regular(*ppS1)->Level < Fpga_Regular(*ppS2)->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the supergates by their level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CompareNodesByLevelIncreasing( Fpga_Node_t ** ppS1, Fpga_Node_t ** ppS2 )
+{
+ if ( Fpga_Regular(*ppS1)->Level < Fpga_Regular(*ppS2)->Level )
+ return -1;
+ if ( Fpga_Regular(*ppS1)->Level > Fpga_Regular(*ppS2)->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Orders the nodes in the decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSortByLevel( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes, int fIncreasing )
+{
+ if ( fIncreasing )
+ qsort( (void *)vNodes->pArray, vNodes->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_CompareNodesByLevelIncreasing );
+ else
+ qsort( (void *)vNodes->pArray, vNodes->nSize, sizeof(Fpga_Node_t *),
+ (int (*)(const void *, const void *)) Fpga_CompareNodesByLevelDecreasing );
+// assert( Fpga_CompareNodesByLevel( vNodes->pArray, vNodes->pArray + vNodes->nSize - 1 ) <= 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the limited DFS ordering for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_DfsLim( Fpga_Man_t * pMan, Fpga_Node_t * pNode, int nLevels )
+{
+ Fpga_NodeVec_t * vNodes;
+ int i;
+ // perform the traversal
+ vNodes = Fpga_NodeVecAlloc( 100 );
+ Fpga_DfsLim_rec( pNode, nLevels, vNodes );
+ for ( i = 0; i < vNodes->nSize; i++ )
+ vNodes->pArray[i]->fMark0 = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively computes the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_DfsLim_rec( Fpga_Node_t * pNode, int Level, Fpga_NodeVec_t * vNodes )
+{
+ assert( !Fpga_IsComplement(pNode) );
+ if ( pNode->fMark0 )
+ return;
+ pNode->fMark0 = 1;
+ // visit the transitive fanin
+ Level--;
+ if ( Level > 0 && Fpga_NodeIsAnd(pNode) )
+ {
+ Fpga_DfsLim_rec( Fpga_Regular(pNode->p1), Level, vNodes );
+ Fpga_DfsLim_rec( Fpga_Regular(pNode->p2), Level, vNodes );
+ }
+ // add the node to the list
+ Fpga_NodeVecPush( vNodes, pNode );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the limited DFS ordering for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManCleanData0( Fpga_Man_t * pMan )
+{
+ int i;
+ for ( i = 0; i < pMan->vNodesAll->nSize; i++ )
+ pMan->vNodesAll->pArray[i]->pData0 = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the TFO of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_CollectNodeTfo( Fpga_Man_t * pMan, Fpga_Node_t * pNode )
+{
+ Fpga_NodeVec_t * vVisited, * vTfo;
+ int i;
+ // perform the traversal
+ vVisited = Fpga_NodeVecAlloc( 100 );
+ vTfo = Fpga_NodeVecAlloc( 100 );
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_CollectNodeTfo_rec( Fpga_Regular(pMan->pOutputs[i]), pNode, vVisited, vTfo );
+ for ( i = 0; i < vVisited->nSize; i++ )
+ vVisited->pArray[i]->fMark0 = vVisited->pArray[i]->fMark1 = 0;
+ Fpga_NodeVecFree( vVisited );
+ return vTfo;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the TFO of the node.]
+
+ Description [Returns 1 if the node should be collected.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_CollectNodeTfo_rec( Fpga_Node_t * pNode, Fpga_Node_t * pPivot, Fpga_NodeVec_t * vVisited, Fpga_NodeVec_t * vTfo )
+{
+ int Ret1, Ret2;
+ assert( !Fpga_IsComplement(pNode) );
+ // skip visited nodes
+ if ( pNode->fMark0 )
+ return pNode->fMark1;
+ pNode->fMark0 = 1;
+ Fpga_NodeVecPush( vVisited, pNode );
+
+ // return the pivot node
+ if ( pNode == pPivot )
+ {
+ pNode->fMark1 = 1;
+ return 1;
+ }
+ if ( pNode->Level < pPivot->Level )
+ {
+ pNode->fMark1 = 0;
+ return 0;
+ }
+ // visit the transitive fanin
+ assert( Fpga_NodeIsAnd(pNode) );
+ Ret1 = Fpga_CollectNodeTfo_rec( Fpga_Regular(pNode->p1), pPivot, vVisited, vTfo );
+ Ret2 = Fpga_CollectNodeTfo_rec( Fpga_Regular(pNode->p2), pPivot, vVisited, vTfo );
+ if ( Ret1 || Ret2 )
+ {
+ pNode->fMark1 = 1;
+ Fpga_NodeVecPush( vTfo, pNode );
+ }
+ else
+ pNode->fMark1 = 0;
+ return pNode->fMark1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Levelizes the nodes accessible from the POs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingLevelize( Fpga_Man_t * pMan, Fpga_NodeVec_t * vNodes )
+{
+ Fpga_NodeVec_t * vLevels;
+ Fpga_Node_t ** ppNodes;
+ Fpga_Node_t * pNode;
+ int nNodes, nLevelsMax, i;
+
+ // reassign the levels (this may be necessary for networks which choices)
+ ppNodes = vNodes->pArray;
+ nNodes = vNodes->nSize;
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = ppNodes[i];
+ if ( !Fpga_NodeIsAnd(pNode) )
+ {
+ pNode->Level = 0;
+ continue;
+ }
+ pNode->Level = 1 + FPGA_MAX( Fpga_Regular(pNode->p1)->Level, Fpga_Regular(pNode->p2)->Level );
+ }
+
+ // get the max levels
+ nLevelsMax = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ nLevelsMax = FPGA_MAX( nLevelsMax, (int)Fpga_Regular(pMan->pOutputs[i])->Level );
+ nLevelsMax++;
+
+ // allocate storage for levels
+ vLevels = Fpga_NodeVecAlloc( nLevelsMax );
+ for ( i = 0; i < nLevelsMax; i++ )
+ Fpga_NodeVecPush( vLevels, NULL );
+
+ // go through the nodes and add them to the levels
+ for ( i = 0; i < nNodes; i++ )
+ {
+ pNode = ppNodes[i];
+ pNode->pLevel = NULL;
+ if ( !Fpga_NodeIsAnd(pNode) )
+ continue;
+ // attach the node to this level
+ pNode->pLevel = Fpga_NodeVecReadEntry( vLevels, pNode->Level );
+ Fpga_NodeVecWriteEntry( vLevels, pNode->Level, pNode );
+ }
+ return vLevels;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets up the mask.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingMaxLevel( Fpga_Man_t * pMan )
+{
+ int nLevelMax, i;
+ nLevelMax = 0;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ nLevelMax = nLevelMax > (int)Fpga_Regular(pMan->pOutputs[i])->Level?
+ nLevelMax : (int)Fpga_Regular(pMan->pOutputs[i])->Level;
+ return nLevelMax;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Analyses choice nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Fpga_MappingUpdateLevel_rec( Fpga_Man_t * pMan, Fpga_Node_t * pNode, int fMaximum )
+{
+ Fpga_Node_t * pTemp;
+ int Level1, Level2, LevelE;
+ assert( !Fpga_IsComplement(pNode) );
+ if ( !Fpga_NodeIsAnd(pNode) )
+ return pNode->Level;
+ // skip the visited node
+ if ( pNode->TravId == pMan->nTravIds )
+ return pNode->Level;
+ pNode->TravId = pMan->nTravIds;
+ // compute levels of the children nodes
+ Level1 = Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pNode->p1), fMaximum );
+ Level2 = Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pNode->p2), fMaximum );
+ pNode->Level = 1 + FPGA_MAX( Level1, Level2 );
+ if ( pNode->pNextE )
+ {
+ LevelE = Fpga_MappingUpdateLevel_rec( pMan, pNode->pNextE, fMaximum );
+ if ( fMaximum )
+ {
+ if ( pNode->Level < (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ else
+ {
+ if ( pNode->Level > (unsigned)LevelE )
+ pNode->Level = LevelE;
+ }
+ // set the level of all equivalent nodes to be the same minimum
+ if ( pNode->pRepr == NULL ) // the primary node
+ for ( pTemp = pNode->pNextE; pTemp; pTemp = pTemp->pNextE )
+ pTemp->Level = pNode->Level;
+ }
+ return pNode->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resets the levels of the nodes in the choice graph.]
+
+ Description [Makes the level of the choice nodes to be equal to the
+ maximum of the level of the nodes in the equivalence class. This way
+ sorting by level leads to the reverse topological order, which is
+ needed for the required time computation.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_MappingSetChoiceLevels( Fpga_Man_t * pMan )
+{
+ int i;
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports statistics on choice nodes.]
+
+ Description [The number of choice nodes is the number of primary nodes,
+ which has pNextE set to a pointer. The number of choices is the number
+ of entries in the equivalent-node lists of the primary nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Fpga_ManReportChoices( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode, * pTemp;
+ int nChoiceNodes, nChoices;
+ int i, LevelMax1, LevelMax2;
+
+ // report the number of levels
+ LevelMax1 = Fpga_MappingMaxLevel( pMan );
+ pMan->nTravIds++;
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_MappingUpdateLevel_rec( pMan, Fpga_Regular(pMan->pOutputs[i]), 0 );
+ LevelMax2 = Fpga_MappingMaxLevel( pMan );
+
+ // report statistics about choices
+ nChoiceNodes = nChoices = 0;
+ for ( i = 0; i < pMan->vAnds->nSize; i++ )
+ {
+ pNode = pMan->vAnds->pArray[i];
+ if ( pNode->pRepr == NULL && pNode->pNextE != NULL )
+ { // this is a choice node = the primary node that has equivalent nodes
+ nChoiceNodes++;
+ for ( pTemp = pNode; pTemp; pTemp = pTemp->pNextE )
+ nChoices++;
+ }
+ }
+ if ( pMan->fVerbose )
+ {
+ printf( "Maximum level: Original = %d. Reduced due to choices = %d.\n", LevelMax1, LevelMax2 );
+ printf( "Choice stats: Choice nodes = %d. Total choices = %d.\n", nChoiceNodes, nChoices );
+ }
+/*
+ {
+ FILE * pTable;
+ pTable = fopen( "stats_choice.txt", "a+" );
+ fprintf( pTable, "%s ", pMan->pFileName );
+ fprintf( pTable, "%4d ", LevelMax1 );
+ fprintf( pTable, "%4d ", pMan->vAnds->nSize - pMan->nInputs );
+ fprintf( pTable, "%4d ", LevelMax2 );
+ fprintf( pTable, "%7d ", nChoiceNodes );
+ fprintf( pTable, "%7d ", nChoices + nChoiceNodes );
+ fprintf( pTable, "\n" );
+ fclose( pTable );
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the array of CO nodes sorted by level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Fpga_NodeVec_t * Fpga_MappingOrderCosByLevel( Fpga_Man_t * pMan )
+{
+ Fpga_Node_t * pNode;
+ Fpga_NodeVec_t * vNodes;
+ int i, nLevels;
+ // get the largest level of a CO
+ nLevels = Fpga_MappingMaxLevel( pMan );
+ // allocate the array of nodes
+ vNodes = Fpga_NodeVecAlloc( nLevels + 1 );
+ for ( i = 0; i <= nLevels; i++ )
+ Fpga_NodeVecPush( vNodes, NULL );
+ // clean the marks
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_Regular(pMan->pOutputs[i])->fMark0 = 0;
+ // put the nodes into the structure
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ {
+ pNode = Fpga_Regular(pMan->pOutputs[i]);
+ if ( pNode->fMark0 )
+ continue;
+ pNode->fMark0 = 1;
+ pNode->pData0 = (char *)Fpga_NodeVecReadEntry( vNodes, pNode->Level );
+ Fpga_NodeVecWriteEntry( vNodes, pNode->Level, pNode );
+ }
+ for ( i = 0; i < pMan->nOutputs; i++ )
+ Fpga_Regular(pMan->pOutputs[i])->fMark0 = 0;
+ return vNodes;
+
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+