/**CFile*********************************************************************** FileName [ntkGraph.c] PackageName [ntk] Synopsis [Routines related to the abstract graph of a network.] Author [Adnan Aziz, Tom Shiple] Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] ******************************************************************************/ #include "ntkInt.h" static char rcsid[] UNUSED = "$Id: ntkGraph.c,v 1.11 2005/04/16 04:24:15 fabio Exp $"; /*---------------------------------------------------------------------------*/ /* Structure declarations */ /*---------------------------------------------------------------------------*/ /**Enum************************************************************************ Synopsis [Used to keep track of the state of a node during depth first search.required] ******************************************************************************/ typedef enum { dfsWhite_c, /* unvisited node */ dfsGrey_c, /* node on "stack" */ dfsBlack_c /* node completely visited */ } DfsColor; /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ static void RegionFindNodesRecursively(Ntk_Node_t *node, st_table *leaves, st_table *result); static boolean NodeTestCannotReachCycle(Ntk_Node_t * node); static boolean NodeTestCoveredByLeaves(Ntk_Node_t *node, st_table *leaves, st_table *visited); static DfsColor NodeReadColor(Ntk_Node_t * node); static void NodeSetColor(Ntk_Node_t * node, DfsColor color); static void NodeSetTfoLatchList(Ntk_Node_t * node, lsList tfoLatchList); static lsList NodeReadTfoLatchList(Ntk_Node_t * node); static void NodeFreeTfoLatchList(Ntk_Node_t * node); static void ListAppendList(lsList list1, lsList list2); static lsList NodeComputeTfoLatchList(Ntk_Node_t * node); static void NodeRecursivelyComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches); static void NodeComputeTopologicalOrderRecursively(Ntk_Node_t *node, st_table *leafNodesTable, lsList topologicalNodeList); static void NodeComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches); /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Returns array of nodes in transitive fanout of node.] Description [Returns array of nodes in transitive fanout of node. If depth is non-zero, then only includes nodes within depth of node. If depth is zero, then includes all nodes up to and including combinational outputs.] SideEffects [required] SeeAlso [optional] ******************************************************************************/ array_t * Ntk_NodeComputeTransitiveFanoutNodes( array_t * nodeArray, int depth) { fail("not yet implemented"); return(NIL(array_t)); } /**Function******************************************************************** Synopsis [Returns array of nodes in transitive fanin of node.] Description [Returns array of nodes in transitive fanin of node. If depth is non-zero, then only includes nodes within depth of node. If depth is zero, then includes all nodes up to and including combinational inputs.] SideEffects [required] SeeAlso [optional] ******************************************************************************/ array_t * Ntk_NodeComputeTransitiveFanInputNodes( array_t * nodeArray, int depth) { fail("not yet implemented"); return(NIL(array_t)); } /**Function******************************************************************** Synopsis [Returns array of nodes in transitive fanin of nodeArray.] Description [Returns array of nodes in transitive fanin of nodes in nodeArray. If stopAtLatches is TRUE, the search terminates at combinational inputs which are latches; otherwise it continues, and the search terminates only at primary inputs and pseudo inputs. It is an error if this function is called with an empty array.] SideEffects [required] SeeAlso [optional] ******************************************************************************/ array_t * Ntk_NodeComputeTransitiveFaninNodes( Ntk_Network_t *network, array_t * nodeArray, boolean stopAtLatches, boolean combInputsOnly) { int i; Ntk_Node_t *node; st_generator *stGen; st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash ); array_t *resultArray = array_alloc( Ntk_Node_t *, 0 ); arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) { NodeComputeTransitiveFaninNodes(node, resultTable, stopAtLatches ); } st_foreach_item( resultTable, stGen, &node, NULL ){ if ( !combInputsOnly || Ntk_NodeTestIsCombInput(node) ) array_insert_last( Ntk_Node_t *, resultArray, node ); } st_free_table( resultTable ); return resultArray; } /**Function******************************************************************** Synopsis [Returns array of combinational inputs in transitive fanin of nodeArray.] Description [Returns array of nodes in transitive fanin of nodes in nodeArray. If stopAtLatches is TRUE, the search terminates at combinational inputs which are latches; otherwise it continues, and the search terminates only at primary inputs and pseudo inputs. It is an error if this function is called with an empty array.] SideEffects [required] SeeAlso [optional] ******************************************************************************/ array_t * Ntk_NodeComputeCombinationalSupport( Ntk_Network_t *network, array_t * nodeArray, boolean stopAtLatches ) { lsGen gen; int i; Ntk_Node_t *node; st_generator *stGen; st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash ); array_t *resultArray = array_alloc( Ntk_Node_t *, 0 ); Ntk_NetworkForEachNode( network, gen, node ) { NodeSetColor( node, dfsWhite_c ); } arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) { NodeRecursivelyComputeTransitiveFaninNodes( node, resultTable, stopAtLatches ); } st_foreach_item( resultTable, stGen, &node, NULL ){ array_insert_last( Ntk_Node_t *, resultArray, node ); } st_free_table( resultTable ); return resultArray; } /**Function******************************************************************** Synopsis [Return table of all nodes lying in fanin of roots, stopping whenever a leaf node is reached. The search also stops on nodes that pass the test Ntk_NodeTestIsConstant. Note that the leaves are also present in the returned table.] SideEffects [] ******************************************************************************/ st_table * Ntk_RegionFindNodes( array_t *roots, st_table *leaves) { int i; st_table *result = st_init_table(st_ptrcmp, st_ptrhash); for (i = 0; i < array_n(roots); i++) { Ntk_Node_t *root = array_fetch(Ntk_Node_t *, roots, i); RegionFindNodesRecursively(root, leaves, result); } return result; } /**Function******************************************************************** Synopsis [Computes the set of latches that each latch transitively fanouts to.] Description [For each latch, builds a list containing those latches which can be transitively reached from the fanout of the latch. If a latch doesn't have any latches in its TFO, then an empty list will be built. The dependencies are returned as a hash table mapping each latch (Ntk_Node_t *) to a list (lsList). It is the user's responsibility to free the returned hash table and the lists stored as values in the table. NOTE: this function name is a misnomer because it does not compute the latches on which a given latch depends, but instead computes the latches to which a given latch fanouts.] SideEffects [] ******************************************************************************/ st_table * Ntk_NetworkComputeLatchDependencies( Ntk_Network_t * network) { lsGen gen; Ntk_Node_t *node; Ntk_Node_t *latch; st_table *latchDependencies = st_init_table(st_ptrcmp, st_ptrhash); /* * Initialize the TFO latch list of each node to NULL. */ Ntk_NetworkForEachNode(network, gen, node) { NodeSetTfoLatchList(node, (lsList) NULL); } /* * For each latch, compute the set of latches in its TFO (including possibly * itself). Accumulate this set of latches into a list, and when the list * is complete, store the latch and list as the key and value in the hash * table. */ Ntk_NetworkForEachLatch(network, gen, latch) { int i; Ntk_Node_t *fanout; lsList tfoLatchList = lsCreate(); /* allocate a fresh list */ /* * Get the latches in the TFO of each fanout of latch, and accumulate into * a list. Note that we can't call NodeComputeTfoLatchList on latch * itself, because latches serve as the terminal case of the recursion. */ Ntk_NodeForEachFanout(latch, i, fanout) { lsList fanoutTfoLatchList = NodeComputeTfoLatchList(fanout); ListAppendList(tfoLatchList, fanoutTfoLatchList); } st_insert(latchDependencies, (char *) latch, (char *) tfoLatchList); } /* * Free the tfoLatchList stored at the nodes. Only nodes in the transitive * fanout of latches will have a non-NULL list, but we just call free * tfoLatchList function on each node. Note that the lists being returned * in the hash table are distinct from those stored at nodes. */ Ntk_NetworkForEachNode(network, gen, node) { NodeFreeTfoLatchList(node); } return (latchDependencies); } /**Function******************************************************************** Synopsis [Returns 0 if a combinational cycle exists, else returns 1.] Description [Returns 0 if a cycle exists in the network, else returns 1. Latches are considered to break cycles. If a cycle is found, then a message is written to error_string (see the error package) giving two nodes in the cycle. Use a code fragment like the following to retrieve the error message:
    error_init();
    status = Ntk_NetworkTestIsAcyclic(network);
    if (status == 0) {
      (void) fprintf(fp, "%s", error_string());
    }
  
] SideEffects [] Comment [This function implements the DFS routine outlined in Cormen, Leiserson, Rivest, "Introduction to Algorithms", p. 478. It has been specialized to just detect cycles.] ******************************************************************************/ boolean Ntk_NetworkTestIsAcyclic( Ntk_Network_t * network) { lsGen gen; Ntk_Node_t *node; boolean status = 1; /* In case network has no vertices. */ /* The meaning of the colors is: * white: node has not been visited yet * grey: node is on the "stack" * black: node, and all its descendents, have been visited */ /* * Initialize the color of each node to white. */ Ntk_NetworkForEachNode(network, gen, node) { NodeSetColor(node, dfsWhite_c); } /* * Recursively visit each unvisited node. The order in which we visit the * nodes is immaterial. */ Ntk_NetworkForEachNode(network, gen, node) { if (NodeReadColor(node) == dfsWhite_c) { status = NodeTestCannotReachCycle(node); if (status == 0) { /* A cycle has been found. */ break; } } } /* * Colors will be left in the undef field of the nodes, but we don't care. */ return (status); } /**Function******************************************************************** Synopsis [Returns TRUE if leaves cover the support of roots, otherwise returns FALSE.] Description [The function takes as input a network, a hash table of nodes called leaves, and an array of nodes called roots. It returns TRUE if the nodes in leaves cover the support of the nodes in roots, otherwise it returns FALSE. In other words, if there exists a combinational input in the transitive fanin of a root, which can be reached from the root without passing through a leaf, then FALSE is returned. If FALSE is returned, then the message "Node b found in the support of node c" is written to error_string, where b is a combinational input not in leaves and c is a root. It is allowed that some roots are themselves leaves, and that some leaves are in the transitive fanin of other leaves. Combinational cycles within the region defined by roots and leaves have no effect on the result. If TRUE is returned, then the runtime of this procedure is proportional to the number of nodes in the region defined by roots and leaves; if FALSE is returned, then the worst case is proportional to the number of nodes in the network.] Comment [The undef field is modified of some of the nodes in the network to which node belongs.] SideEffects [] ******************************************************************************/ boolean Ntk_NetworkTestLeavesCoverSupportOfRoots( Ntk_Network_t *network, array_t *roots, st_table *leaves) { int i; Ntk_Node_t *root; st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); /* Perform DFS from the roots. Return FALSE upon the first failure. */ arrayForEachItem(Ntk_Node_t *, roots, i, root) { boolean status = NodeTestCoveredByLeaves(root, leaves, visited); if(!status) { error_append(Ntk_NodeReadName(root)); error_append(".\n"); st_free_table(visited); return FALSE; } } st_free_table(visited); return TRUE; } /*---------------------------------------------------------------------------*/ /* Definition of internal functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Computes the topological order of nodes in the network for a given array of root nodes and the leaf nodes.] Description [Depth first traversal is used from each node in the root node array. The search is terminated when a node in the leaf table is reached. It is necessary that all the root nodes eventually depend on the leaf nodes. The returned list contains the nodes in the topological order.] SideEffects [] SeeAlso [] ******************************************************************************/ lsList Ntk_NetworkComputeTopologicalOrder(Ntk_Network_t *network, array_t *rootNodesArray, st_table *leafNodesTable) { int i; lsList topologicalNodeList = lsCreate(); Ntk_Node_t *node; lsGen gen; Ntk_NetworkForEachNode(network, gen, node) { NodeSetColor(node, dfsWhite_c); } for (i=0; i