VIS

src/ntk/ntkGraph.c

Go to the documentation of this file.
00001 
00032 #include "ntkInt.h"
00033 
00034 static char rcsid[] UNUSED = "$Id: ntkGraph.c,v 1.11 2005/04/16 04:24:15 fabio Exp $";
00035 
00036 /*---------------------------------------------------------------------------*/
00037 /* Structure declarations                                                     */
00038 /*---------------------------------------------------------------------------*/
00039 
00046 typedef enum {
00047   dfsWhite_c,   /* unvisited node */
00048   dfsGrey_c,    /* node on "stack" */
00049   dfsBlack_c    /* node completely visited */
00050 } DfsColor;
00051 
00052 
00055 /*---------------------------------------------------------------------------*/
00056 /* Static function prototypes                                                */
00057 /*---------------------------------------------------------------------------*/
00058 
00059 static void RegionFindNodesRecursively(Ntk_Node_t *node, st_table *leaves, st_table *result);
00060 static boolean NodeTestCannotReachCycle(Ntk_Node_t * node);
00061 static boolean NodeTestCoveredByLeaves(Ntk_Node_t *node, st_table *leaves, st_table *visited);
00062 static DfsColor NodeReadColor(Ntk_Node_t * node);
00063 static void NodeSetColor(Ntk_Node_t * node, DfsColor color);
00064 static void NodeSetTfoLatchList(Ntk_Node_t * node, lsList tfoLatchList);
00065 static lsList NodeReadTfoLatchList(Ntk_Node_t * node);
00066 static void NodeFreeTfoLatchList(Ntk_Node_t * node);
00067 static void ListAppendList(lsList list1, lsList list2);
00068 static lsList NodeComputeTfoLatchList(Ntk_Node_t * node);
00069 static void NodeRecursivelyComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches);
00070 static void NodeComputeTopologicalOrderRecursively(Ntk_Node_t *node, st_table *leafNodesTable, lsList topologicalNodeList);
00071 static void NodeComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches);
00072 
00076 /*---------------------------------------------------------------------------*/
00077 /* Definition of exported functions                                          */
00078 /*---------------------------------------------------------------------------*/
00079 
00093 array_t *
00094 Ntk_NodeComputeTransitiveFanoutNodes(
00095   array_t * nodeArray,
00096   int  depth)
00097 {
00098   fail("not yet implemented");
00099   return(NIL(array_t));
00100 }
00101 
00115 array_t *
00116 Ntk_NodeComputeTransitiveFanInputNodes(
00117   array_t * nodeArray,
00118   int  depth)
00119 {
00120   fail("not yet implemented");
00121   return(NIL(array_t));
00122 }
00123 
00139 array_t *
00140 Ntk_NodeComputeTransitiveFaninNodes(
00141   Ntk_Network_t *network,
00142   array_t * nodeArray,
00143   boolean stopAtLatches,
00144   boolean combInputsOnly)
00145 {
00146   int i;
00147   Ntk_Node_t *node;
00148   st_generator *stGen;
00149   st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash );
00150   array_t *resultArray = array_alloc( Ntk_Node_t *, 0 );
00151 
00152   arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) {
00153     NodeComputeTransitiveFaninNodes(node, resultTable, stopAtLatches );
00154   }
00155   
00156   st_foreach_item( resultTable, stGen, &node, NULL ){
00157     if ( !combInputsOnly || Ntk_NodeTestIsCombInput(node) ) 
00158       array_insert_last( Ntk_Node_t *, resultArray, node );
00159   }
00160   st_free_table( resultTable );
00161   
00162   return resultArray;
00163 }
00164 
00181 array_t *
00182 Ntk_NodeComputeCombinationalSupport(
00183   Ntk_Network_t *network,
00184   array_t * nodeArray,
00185   boolean stopAtLatches )
00186 {
00187   lsGen gen;
00188   int i;
00189   Ntk_Node_t *node;
00190   st_generator *stGen;
00191   st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash );
00192   array_t *resultArray = array_alloc( Ntk_Node_t *, 0 );
00193 
00194   Ntk_NetworkForEachNode( network, gen, node ) {
00195         NodeSetColor( node, dfsWhite_c );
00196   }
00197 
00198   arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) {
00199         NodeRecursivelyComputeTransitiveFaninNodes( node, resultTable, stopAtLatches );
00200   }
00201 
00202   st_foreach_item( resultTable, stGen, &node, NULL ){
00203         array_insert_last( Ntk_Node_t *, resultArray, node );
00204   }
00205   st_free_table( resultTable );
00206 
00207   return resultArray;
00208 }
00209 
00210 
00221 st_table *
00222 Ntk_RegionFindNodes(
00223   array_t *roots, 
00224   st_table *leaves)
00225 {
00226   int i;
00227   st_table *result = st_init_table(st_ptrcmp, st_ptrhash);
00228   for (i = 0; i < array_n(roots); i++) {
00229     Ntk_Node_t *root = array_fetch(Ntk_Node_t *, roots, i);
00230     RegionFindNodesRecursively(root, leaves, result);
00231   }
00232   return result;
00233 }
00234 
00253 st_table *
00254 Ntk_NetworkComputeLatchDependencies(
00255   Ntk_Network_t * network)
00256 {
00257   lsGen       gen;
00258   Ntk_Node_t *node;
00259   Ntk_Node_t *latch;
00260   st_table   *latchDependencies = st_init_table(st_ptrcmp, st_ptrhash);
00261 
00262   /*
00263    * Initialize the TFO latch list of each node to NULL.
00264    */
00265   Ntk_NetworkForEachNode(network, gen, node) {
00266     NodeSetTfoLatchList(node, (lsList) NULL);
00267   }
00268 
00269   /*
00270    * For each latch, compute the set of latches in its TFO (including possibly
00271    * itself).  Accumulate this set of latches into a list, and when the list
00272    * is complete, store the latch and list as the key and value in the hash
00273    * table.
00274    */
00275   Ntk_NetworkForEachLatch(network, gen, latch) {
00276     int         i;
00277     Ntk_Node_t *fanout;
00278     lsList      tfoLatchList = lsCreate();  /* allocate a fresh list */
00279 
00280     /*
00281      * Get the latches in the TFO of each fanout of latch, and accumulate into
00282      * a list. Note that we can't call NodeComputeTfoLatchList on latch
00283      * itself, because latches serve as the terminal case of the recursion.
00284      */
00285     Ntk_NodeForEachFanout(latch, i, fanout) {
00286       lsList fanoutTfoLatchList = NodeComputeTfoLatchList(fanout);
00287 
00288       ListAppendList(tfoLatchList, fanoutTfoLatchList);
00289     }
00290 
00291     st_insert(latchDependencies, (char *) latch, (char *) tfoLatchList);
00292     
00293   }
00294 
00295   /*
00296    * Free the tfoLatchList stored at the nodes.  Only nodes in the transitive
00297    * fanout of latches will have a non-NULL list, but we just call free
00298    * tfoLatchList function on each node.  Note that the lists being returned
00299    * in the hash table are distinct from those stored at nodes.
00300    */
00301   Ntk_NetworkForEachNode(network, gen, node) {
00302     NodeFreeTfoLatchList(node);
00303   }
00304 
00305   return (latchDependencies);
00306 }
00307 
00308 
00332 boolean
00333 Ntk_NetworkTestIsAcyclic(
00334   Ntk_Network_t * network)
00335 {
00336   lsGen       gen;
00337   Ntk_Node_t *node;
00338   boolean     status = 1; /* In case network has no vertices. */
00339 
00340   /* The meaning of the colors is:
00341    *   white: node has not been visited yet
00342    *   grey:  node is on the "stack"
00343    *   black: node, and all its descendents, have been visited
00344    */
00345 
00346   /*
00347    * Initialize the color of each node to white.
00348    */
00349   Ntk_NetworkForEachNode(network, gen, node) {
00350     NodeSetColor(node, dfsWhite_c);
00351   }
00352   
00353   /*
00354    * Recursively visit each unvisited node.  The order in which we visit the
00355    * nodes is immaterial.  
00356    */  
00357   Ntk_NetworkForEachNode(network, gen, node) {
00358     if (NodeReadColor(node) == dfsWhite_c) {
00359       status = NodeTestCannotReachCycle(node);
00360       if (status == 0) {
00361         /* A cycle has been found. */
00362         break;
00363       }
00364     }
00365   }
00366 
00367   /*
00368    * Colors will be left in the undef field of the nodes, but we don't care.
00369    */
00370   return (status);
00371 }
00372 
00373 
00401 boolean
00402 Ntk_NetworkTestLeavesCoverSupportOfRoots(
00403   Ntk_Network_t *network,
00404   array_t       *roots,
00405   st_table      *leaves)
00406 {
00407   int         i;
00408   Ntk_Node_t *root;
00409   st_table   *visited = st_init_table(st_ptrcmp, st_ptrhash);
00410   
00411   /* Perform DFS from the roots.  Return FALSE upon the first failure. */
00412   arrayForEachItem(Ntk_Node_t *, roots, i, root) {
00413     boolean status = NodeTestCoveredByLeaves(root, leaves, visited);
00414     
00415     if(!status) {
00416       error_append(Ntk_NodeReadName(root));
00417       error_append(".\n");
00418       st_free_table(visited);
00419       return FALSE; 
00420     }
00421   }
00422   st_free_table(visited);
00423   return TRUE;
00424 }
00425 
00426 
00427 /*---------------------------------------------------------------------------*/
00428 /* Definition of internal functions                                          */
00429 /*---------------------------------------------------------------------------*/
00446 lsList
00447 Ntk_NetworkComputeTopologicalOrder(Ntk_Network_t *network, array_t
00448                                   *rootNodesArray, st_table
00449                                   *leafNodesTable) 
00450 {
00451   int i;
00452   lsList topologicalNodeList = lsCreate();
00453   Ntk_Node_t *node;
00454   lsGen gen;
00455   
00456   Ntk_NetworkForEachNode(network, gen, node) {
00457     NodeSetColor(node, dfsWhite_c);
00458   }
00459 
00460   for (i=0; i<array_n(rootNodesArray); i++){
00461     node = array_fetch(Ntk_Node_t *, rootNodesArray, i);
00462     NodeComputeTopologicalOrderRecursively(node, leafNodesTable,
00463                                            topologicalNodeList);
00464   }
00465   return topologicalNodeList;
00466 }
00467 
00468 
00469 /*---------------------------------------------------------------------------*/
00470 /* Definition of static functions                                            */
00471 /*---------------------------------------------------------------------------*/
00472 
00481 static void
00482 RegionFindNodesRecursively(
00483   Ntk_Node_t *node, 
00484   st_table *leaves,
00485   st_table *result)
00486 {
00487   int i;
00488   Ntk_Node_t *fanin;
00489 
00490   if (st_is_member(result, (char *) node)) {
00491     /* already visited this node */
00492     return;
00493   }
00494   else {
00495     /*
00496      * Add to table before recursing, to avoid infinite loops in presence of
00497      * combinational cycles.
00498      */
00499     st_insert(result, (char *) node, NIL(char));
00500   }
00501   
00502   
00503   if (!st_is_member(leaves, (char *) node) && !Ntk_NodeTestIsConstant(node)) {
00504     /* not a leaf; recurse */
00505     Ntk_NodeForEachFanin(node, i, fanin) {
00506       RegionFindNodesRecursively(fanin, leaves, result);
00507     }
00508   }
00509 
00510   return;
00511 }
00512 
00525 static boolean
00526 NodeTestCannotReachCycle(
00527   Ntk_Node_t * node)
00528 {
00529   Ntk_Node_t *fanout;
00530   int i;
00531 
00532   /*
00533    * Set the color of node to grey to indicate that it is on the "stack".
00534    */
00535   NodeSetColor(node, dfsGrey_c);
00536 
00537   Ntk_NodeForEachFanout(node, i, fanout) {
00538     /*
00539      * Traverse fanout if it is *not* a latch; latches break combinational cycles.
00540      */
00541     if (Ntk_NodeTestIsLatch(fanout) == 0) {
00542       DfsColor fanoutColor = NodeReadColor(fanout);
00543 
00544       /* 
00545        * If fanout is white, it has not been visited yet, so visit it, and 
00546        * break the search if it can reach a cycle.  Else if fanout is grey, it 
00547        * means that fanout is also on the stack, so a cycle has been found; 
00548        * thus break.  Else, the fanout is black, and there is nothing to do.
00549        */
00550       if (fanoutColor == dfsWhite_c) {
00551         if (NodeTestCannotReachCycle(fanout) == 0) {
00552           return (0);
00553         }
00554       }
00555       else if (fanoutColor == dfsGrey_c) {
00556         error_append("(");
00557         error_append(Ntk_NodeReadName(node));
00558         error_append(", ");
00559         error_append(Ntk_NodeReadName(fanout));
00560         error_append(")");
00561         return (0);
00562       } 
00563     }
00564   }
00565 
00566   /*
00567    * Set the color of node to black to indicate that it has been visited.
00568    */
00569   NodeSetColor(node, dfsBlack_c);
00570   
00571   /*
00572    * No cycles found from node.
00573    */
00574   return (1);
00575 }
00576 
00577 
00593 static boolean
00594 NodeTestCoveredByLeaves(
00595   Ntk_Node_t *node,
00596   st_table   *leaves,
00597   st_table   *visited)
00598 {
00599   int         i;
00600   Ntk_Node_t *fanin;
00601 
00602   /*
00603    * If node has already been visited, just return.  Else, mark it as
00604    * visited. Note that it is important to mark it as visited BEFORE recursing,
00605    * in case combinational cycles are present.
00606    */
00607   if (st_is_member(visited, (char *) node)) {
00608     return TRUE;
00609   }
00610   else {
00611     st_insert(visited, (char *) node, NIL(char));
00612   }
00613 
00614   if (st_is_member(leaves, (char *) node)) {
00615     /*
00616      * Positive termination of recursion: if node is a leaf, then everything
00617      * is fine.
00618      */ 
00619     return TRUE;
00620   }
00621   else {
00622     /* Node is not a leaf. */
00623     if (Ntk_NodeTestIsCombInput(node)) {
00624       /*
00625        * Negative termination of recursion: a combinational input was reached
00626        * without seeing a leaf.
00627        */ 
00628       error_append("Node ");
00629       error_append(Ntk_NodeReadName(node));
00630       error_append(" found in the support of node ");
00631       return FALSE;
00632     }
00633     else {
00634       /*
00635        * Node is not a leaf nor a combinational input.  Recurse over fanins.
00636        * Return FALSE if any fanins fail the test.
00637        */
00638       Ntk_NodeForEachFanin(node, i, fanin) {
00639         boolean status = NodeTestCoveredByLeaves(fanin, leaves, visited);
00640         if (!status) {
00641           return FALSE;
00642         }
00643       }
00644       /*
00645        * If the loop terminates without the function returning, then each
00646        * fanin has already been visited and no dfsWhite_c-labelled comb input
00647        * can be reached from the fanins. Therefore, return TRUE.
00648        */
00649       return TRUE;
00650     }
00651   }
00652   
00653 }
00654 
00655 
00665 static DfsColor
00666 NodeReadColor(
00667   Ntk_Node_t * node)
00668 {
00669   return ((DfsColor) (long) Ntk_NodeReadUndef(node));
00670 }
00671 
00672 
00682 static void
00683 NodeSetColor(
00684   Ntk_Node_t * node,
00685   DfsColor  color)
00686 {
00687   Ntk_NodeSetUndef(node, (void *) (long) color);
00688 }
00689 
00690 
00700 static void
00701 NodeSetTfoLatchList(
00702   Ntk_Node_t * node,
00703   lsList  tfoLatchList)
00704 {
00705   Ntk_NodeSetUndef(node, (void *) tfoLatchList);
00706 }
00707 
00708 
00718 static lsList
00719 NodeReadTfoLatchList(
00720   Ntk_Node_t * node)
00721 {
00722   return ((lsList) Ntk_NodeReadUndef(node));
00723 }
00724 
00725 
00738 static void
00739 NodeFreeTfoLatchList(
00740   Ntk_Node_t * node)
00741 {
00742   lsList tfoLatchList = NodeReadTfoLatchList(node);
00743 
00744   if (tfoLatchList != (lsList) NULL) {
00745     (void) lsDestroy(tfoLatchList, (void (*) (lsGeneric)) NULL);
00746     Ntk_NodeSetUndef(node, (void *) NULL);
00747   }
00748 }
00749 
00764 static void
00765 ListAppendList(
00766   lsList  list1,
00767   lsList  list2)
00768 {
00769   lsGen      gen;
00770   lsGeneric  data;
00771   st_table  *table1 = st_init_table(st_ptrcmp, st_ptrhash);
00772   
00773   /*
00774    * Load a hash table mapping each item in list1 to NULL.
00775    */
00776   gen = lsStart(list1);
00777   while (lsNext(gen, &data, LS_NH) == LS_OK) {
00778     st_insert(table1, (char *) data, (char *) NULL);
00779   }
00780   (void) lsFinish(gen);
00781 
00782   /*
00783    * For each item in list2, if it's not already present in list1, then add it
00784    * to the end of list1.
00785    */
00786   lsForEachItem(list2, gen, data) {
00787     if (st_is_member(table1, (char *) data) == 0) {
00788       lsNewEnd(list1, data, LS_NH);
00789     }
00790   }
00791   st_free_table(table1);
00792 }
00793 
00794 
00808 static lsList
00809 NodeComputeTfoLatchList(
00810   Ntk_Node_t * node)
00811 {
00812   lsList tfoLatchList = NodeReadTfoLatchList(node);
00813 
00814   /*
00815    * If node already has a non-NULL tfoLatchList, then just return it (this
00816    * can happen if the node was already visited via one of its other
00817    * fanins). Otherwise, create an empty list and fill it appropriately.
00818    */
00819   if (tfoLatchList != (lsList) NULL) {
00820     return (tfoLatchList);
00821   }
00822   else {
00823     tfoLatchList = lsCreate();
00824 
00825     if (Ntk_NodeTestIsLatch(node)) {
00826       /*
00827        * Special case; terminal condition.
00828        */
00829       lsNewEnd(tfoLatchList, (lsGeneric) node, LS_NH);
00830     }
00831     else {
00832       int         i;
00833       Ntk_Node_t *fanout;
00834       
00835       /*
00836        * Get the latches in the TFO of each fanout of node, and accumulate into
00837        * a list.
00838        */
00839       Ntk_NodeForEachFanout(node, i, fanout) {
00840         lsList fanoutTfoLatchList = NodeComputeTfoLatchList(fanout);
00841 
00842         ListAppendList(tfoLatchList, fanoutTfoLatchList);
00843       }
00844     }
00845 
00846     /*
00847      * Store the list with the node, then return the list.
00848      */
00849     NodeSetTfoLatchList(node, tfoLatchList);
00850     return (tfoLatchList);    
00851   }
00852 }
00853 
00854 
00855 
00868 static void
00869 NodeRecursivelyComputeTransitiveFaninNodes( 
00870   Ntk_Node_t *node, 
00871   st_table *resultTable,
00872   boolean stopAtLatches) 
00873 {
00874   int i;
00875   Ntk_Node_t * fanin;
00876 
00877   /* test if we have already started processing this node */
00878   if ( NodeReadColor( node ) == dfsBlack_c ) {
00879         return;
00880   }
00881   NodeSetColor( node, dfsBlack_c );
00882 
00883   if ( Ntk_NodeTestIsCombInput( node ) ) {
00884         st_insert( resultTable, (char *) node, (char *) 0 );
00885   }
00886 
00887   if ( Ntk_NodeTestIsInput(node) || ((stopAtLatches == TRUE)&&(Ntk_NodeTestIsLatch(node))) ) {
00888         return;
00889   }
00890 
00891   Ntk_NodeForEachFanin( node, i, fanin ) {
00892         NodeRecursivelyComputeTransitiveFaninNodes( fanin, resultTable, stopAtLatches );
00893   }
00894 }
00895 
00896 
00897 
00911 static void
00912 NodeComputeTopologicalOrderRecursively(Ntk_Node_t *node, st_table
00913                                        *leafNodesTable, lsList
00914                                        topologicalNodeList) 
00915 {
00916   int i;
00917   Ntk_Node_t *fanin;
00918   
00919   if (NodeReadColor(node) == dfsBlack_c){
00920     /* Has already been put in the list. */
00921     return;
00922   }
00923   if (NodeReadColor(node) == dfsGrey_c){
00924     /* Indicates that this node is currently being processed (possibly a
00925        combinational loop). */
00926     return;
00927   }
00928   if (st_is_member(leafNodesTable, (char *)node)== 0){
00929     NodeSetColor(node, dfsGrey_c);
00930     Ntk_NodeForEachFanin(node, i, fanin){
00931       NodeComputeTopologicalOrderRecursively(fanin, leafNodesTable,
00932                                              topologicalNodeList);
00933     }
00934   }
00935   NodeSetColor(node, dfsBlack_c);
00936   lsNewEnd(topologicalNodeList, (lsGeneric)node, LS_NH);
00937   return;
00938 }
00939 
00952 static void
00953 NodeComputeTransitiveFaninNodes( 
00954   Ntk_Node_t *node, 
00955   st_table *resultTable,
00956   boolean stopAtLatches) 
00957 {
00958   int i;
00959   Ntk_Node_t * fanin;
00960   
00961   /* test if we have already started processing this node */
00962   if (st_is_member(resultTable, node))
00963     return;
00964 
00965   st_insert(resultTable, node, (char *)(long)2);
00966 
00967   if (Ntk_NodeTestIsInput(node) || (stopAtLatches && Ntk_NodeTestIsLatch(node)))
00968     return;
00969 
00970   Ntk_NodeForEachFanin(node, i, fanin) {
00971     NodeComputeTransitiveFaninNodes(fanin, resultTable, stopAtLatches);
00972   }
00973 }
00974