VIS
|
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