1 | /**CFile*********************************************************************** |
---|
2 | |
---|
3 | FileName [ntkGraph.c] |
---|
4 | |
---|
5 | PackageName [ntk] |
---|
6 | |
---|
7 | Synopsis [Routines related to the abstract graph of a network.] |
---|
8 | |
---|
9 | Author [Adnan Aziz, Tom Shiple] |
---|
10 | |
---|
11 | Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. |
---|
12 | All rights reserved. |
---|
13 | |
---|
14 | Permission is hereby granted, without written agreement and without license |
---|
15 | or royalty fees, to use, copy, modify, and distribute this software and its |
---|
16 | documentation for any purpose, provided that the above copyright notice and |
---|
17 | the following two paragraphs appear in all copies of this software. |
---|
18 | |
---|
19 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR |
---|
20 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
---|
21 | OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF |
---|
22 | CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
23 | |
---|
24 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
---|
25 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
---|
26 | FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN |
---|
27 | "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE |
---|
28 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] |
---|
29 | |
---|
30 | ******************************************************************************/ |
---|
31 | |
---|
32 | #include "ntkInt.h" |
---|
33 | |
---|
34 | static char rcsid[] UNUSED = "$Id: ntkGraph.c,v 1.11 2005/04/16 04:24:15 fabio Exp $"; |
---|
35 | |
---|
36 | /*---------------------------------------------------------------------------*/ |
---|
37 | /* Structure declarations */ |
---|
38 | /*---------------------------------------------------------------------------*/ |
---|
39 | |
---|
40 | /**Enum************************************************************************ |
---|
41 | |
---|
42 | Synopsis [Used to keep track of the state of a node during depth first |
---|
43 | search.required] |
---|
44 | |
---|
45 | ******************************************************************************/ |
---|
46 | typedef enum { |
---|
47 | dfsWhite_c, /* unvisited node */ |
---|
48 | dfsGrey_c, /* node on "stack" */ |
---|
49 | dfsBlack_c /* node completely visited */ |
---|
50 | } DfsColor; |
---|
51 | |
---|
52 | |
---|
53 | /**AutomaticStart*************************************************************/ |
---|
54 | |
---|
55 | /*---------------------------------------------------------------------------*/ |
---|
56 | /* Static function prototypes */ |
---|
57 | /*---------------------------------------------------------------------------*/ |
---|
58 | |
---|
59 | static void RegionFindNodesRecursively(Ntk_Node_t *node, st_table *leaves, st_table *result); |
---|
60 | static boolean NodeTestCannotReachCycle(Ntk_Node_t * node); |
---|
61 | static boolean NodeTestCoveredByLeaves(Ntk_Node_t *node, st_table *leaves, st_table *visited); |
---|
62 | static DfsColor NodeReadColor(Ntk_Node_t * node); |
---|
63 | static void NodeSetColor(Ntk_Node_t * node, DfsColor color); |
---|
64 | static void NodeSetTfoLatchList(Ntk_Node_t * node, lsList tfoLatchList); |
---|
65 | static lsList NodeReadTfoLatchList(Ntk_Node_t * node); |
---|
66 | static void NodeFreeTfoLatchList(Ntk_Node_t * node); |
---|
67 | static void ListAppendList(lsList list1, lsList list2); |
---|
68 | static lsList NodeComputeTfoLatchList(Ntk_Node_t * node); |
---|
69 | static void NodeRecursivelyComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches); |
---|
70 | static void NodeComputeTopologicalOrderRecursively(Ntk_Node_t *node, st_table *leafNodesTable, lsList topologicalNodeList); |
---|
71 | static void NodeComputeTransitiveFaninNodes(Ntk_Node_t *node, st_table *resultTable, boolean stopAtLatches); |
---|
72 | |
---|
73 | /**AutomaticEnd***************************************************************/ |
---|
74 | |
---|
75 | |
---|
76 | /*---------------------------------------------------------------------------*/ |
---|
77 | /* Definition of exported functions */ |
---|
78 | /*---------------------------------------------------------------------------*/ |
---|
79 | |
---|
80 | /**Function******************************************************************** |
---|
81 | |
---|
82 | Synopsis [Returns array of nodes in transitive fanout of node.] |
---|
83 | |
---|
84 | Description [Returns array of nodes in transitive fanout of node. If depth is |
---|
85 | non-zero, then only includes nodes within depth of node. If depth is zero, |
---|
86 | then includes all nodes up to and including combinational outputs.] |
---|
87 | |
---|
88 | SideEffects [required] |
---|
89 | |
---|
90 | SeeAlso [optional] |
---|
91 | |
---|
92 | ******************************************************************************/ |
---|
93 | array_t * |
---|
94 | Ntk_NodeComputeTransitiveFanoutNodes( |
---|
95 | array_t * nodeArray, |
---|
96 | int depth) |
---|
97 | { |
---|
98 | fail("not yet implemented"); |
---|
99 | return(NIL(array_t)); |
---|
100 | } |
---|
101 | |
---|
102 | /**Function******************************************************************** |
---|
103 | |
---|
104 | Synopsis [Returns array of nodes in transitive fanin of node.] |
---|
105 | |
---|
106 | Description [Returns array of nodes in transitive fanin of node. If depth is |
---|
107 | non-zero, then only includes nodes within depth of node. If depth is zero, |
---|
108 | then includes all nodes up to and including combinational inputs.] |
---|
109 | |
---|
110 | SideEffects [required] |
---|
111 | |
---|
112 | SeeAlso [optional] |
---|
113 | |
---|
114 | ******************************************************************************/ |
---|
115 | array_t * |
---|
116 | Ntk_NodeComputeTransitiveFanInputNodes( |
---|
117 | array_t * nodeArray, |
---|
118 | int depth) |
---|
119 | { |
---|
120 | fail("not yet implemented"); |
---|
121 | return(NIL(array_t)); |
---|
122 | } |
---|
123 | |
---|
124 | /**Function******************************************************************** |
---|
125 | |
---|
126 | Synopsis [Returns array of nodes in transitive fanin of nodeArray.] |
---|
127 | |
---|
128 | Description [Returns array of nodes in transitive fanin of nodes in |
---|
129 | nodeArray. If stopAtLatches is TRUE, the search terminates at |
---|
130 | combinational inputs which are latches; otherwise it continues, and |
---|
131 | the search terminates only at primary inputs and pseudo inputs. It |
---|
132 | is an error if this function is called with an empty array.] |
---|
133 | |
---|
134 | SideEffects [required] |
---|
135 | |
---|
136 | SeeAlso [optional] |
---|
137 | |
---|
138 | ******************************************************************************/ |
---|
139 | array_t * |
---|
140 | Ntk_NodeComputeTransitiveFaninNodes( |
---|
141 | Ntk_Network_t *network, |
---|
142 | array_t * nodeArray, |
---|
143 | boolean stopAtLatches, |
---|
144 | boolean combInputsOnly) |
---|
145 | { |
---|
146 | int i; |
---|
147 | Ntk_Node_t *node; |
---|
148 | st_generator *stGen; |
---|
149 | st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash ); |
---|
150 | array_t *resultArray = array_alloc( Ntk_Node_t *, 0 ); |
---|
151 | |
---|
152 | arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) { |
---|
153 | NodeComputeTransitiveFaninNodes(node, resultTable, stopAtLatches ); |
---|
154 | } |
---|
155 | |
---|
156 | st_foreach_item( resultTable, stGen, &node, NULL ){ |
---|
157 | if ( !combInputsOnly || Ntk_NodeTestIsCombInput(node) ) |
---|
158 | array_insert_last( Ntk_Node_t *, resultArray, node ); |
---|
159 | } |
---|
160 | st_free_table( resultTable ); |
---|
161 | |
---|
162 | return resultArray; |
---|
163 | } |
---|
164 | |
---|
165 | /**Function******************************************************************** |
---|
166 | |
---|
167 | Synopsis [Returns array of combinational inputs in transitive fanin |
---|
168 | of nodeArray.] |
---|
169 | |
---|
170 | Description [Returns array of nodes in transitive fanin of nodes in |
---|
171 | nodeArray. If stopAtLatches is TRUE, the search terminates at |
---|
172 | combinational inputs which are latches; otherwise it continues, and |
---|
173 | the search terminates only at primary inputs and pseudo inputs. It |
---|
174 | is an error if this function is called with an empty array.] |
---|
175 | |
---|
176 | SideEffects [required] |
---|
177 | |
---|
178 | SeeAlso [optional] |
---|
179 | |
---|
180 | ******************************************************************************/ |
---|
181 | array_t * |
---|
182 | Ntk_NodeComputeCombinationalSupport( |
---|
183 | Ntk_Network_t *network, |
---|
184 | array_t * nodeArray, |
---|
185 | boolean stopAtLatches ) |
---|
186 | { |
---|
187 | lsGen gen; |
---|
188 | int i; |
---|
189 | Ntk_Node_t *node; |
---|
190 | st_generator *stGen; |
---|
191 | st_table *resultTable = st_init_table( st_ptrcmp, st_ptrhash ); |
---|
192 | array_t *resultArray = array_alloc( Ntk_Node_t *, 0 ); |
---|
193 | |
---|
194 | Ntk_NetworkForEachNode( network, gen, node ) { |
---|
195 | NodeSetColor( node, dfsWhite_c ); |
---|
196 | } |
---|
197 | |
---|
198 | arrayForEachItem( Ntk_Node_t *, nodeArray, i, node ) { |
---|
199 | NodeRecursivelyComputeTransitiveFaninNodes( node, resultTable, stopAtLatches ); |
---|
200 | } |
---|
201 | |
---|
202 | st_foreach_item( resultTable, stGen, &node, NULL ){ |
---|
203 | array_insert_last( Ntk_Node_t *, resultArray, node ); |
---|
204 | } |
---|
205 | st_free_table( resultTable ); |
---|
206 | |
---|
207 | return resultArray; |
---|
208 | } |
---|
209 | |
---|
210 | |
---|
211 | /**Function******************************************************************** |
---|
212 | |
---|
213 | Synopsis [Return table of all nodes lying in fanin of roots, stopping |
---|
214 | whenever a leaf node is reached. The search also stops on nodes that pass |
---|
215 | the test Ntk_NodeTestIsConstant. Note that the leaves are also present in |
---|
216 | the returned table.] |
---|
217 | |
---|
218 | SideEffects [] |
---|
219 | |
---|
220 | ******************************************************************************/ |
---|
221 | st_table * |
---|
222 | Ntk_RegionFindNodes( |
---|
223 | array_t *roots, |
---|
224 | st_table *leaves) |
---|
225 | { |
---|
226 | int i; |
---|
227 | st_table *result = st_init_table(st_ptrcmp, st_ptrhash); |
---|
228 | for (i = 0; i < array_n(roots); i++) { |
---|
229 | Ntk_Node_t *root = array_fetch(Ntk_Node_t *, roots, i); |
---|
230 | RegionFindNodesRecursively(root, leaves, result); |
---|
231 | } |
---|
232 | return result; |
---|
233 | } |
---|
234 | |
---|
235 | /**Function******************************************************************** |
---|
236 | |
---|
237 | Synopsis [Computes the set of latches that each latch transitively |
---|
238 | fanouts to.] |
---|
239 | |
---|
240 | Description [For each latch, builds a list containing those latches which |
---|
241 | can be transitively reached from the fanout of the latch. If a latch |
---|
242 | doesn't have any latches in its TFO, then an empty list will be built. The |
---|
243 | dependencies are returned as a hash table mapping each latch (Ntk_Node_t *) |
---|
244 | to a list (lsList). It is the user's responsibility to free the returned |
---|
245 | hash table and the lists stored as values in the table. NOTE: this function |
---|
246 | name is a misnomer because it does not compute the latches on which a given |
---|
247 | latch depends, but instead computes the latches to which a given latch |
---|
248 | fanouts.] |
---|
249 | |
---|
250 | SideEffects [] |
---|
251 | |
---|
252 | ******************************************************************************/ |
---|
253 | st_table * |
---|
254 | Ntk_NetworkComputeLatchDependencies( |
---|
255 | Ntk_Network_t * network) |
---|
256 | { |
---|
257 | lsGen gen; |
---|
258 | Ntk_Node_t *node; |
---|
259 | Ntk_Node_t *latch; |
---|
260 | st_table *latchDependencies = st_init_table(st_ptrcmp, st_ptrhash); |
---|
261 | |
---|
262 | /* |
---|
263 | * Initialize the TFO latch list of each node to NULL. |
---|
264 | */ |
---|
265 | Ntk_NetworkForEachNode(network, gen, node) { |
---|
266 | NodeSetTfoLatchList(node, (lsList) NULL); |
---|
267 | } |
---|
268 | |
---|
269 | /* |
---|
270 | * For each latch, compute the set of latches in its TFO (including possibly |
---|
271 | * itself). Accumulate this set of latches into a list, and when the list |
---|
272 | * is complete, store the latch and list as the key and value in the hash |
---|
273 | * table. |
---|
274 | */ |
---|
275 | Ntk_NetworkForEachLatch(network, gen, latch) { |
---|
276 | int i; |
---|
277 | Ntk_Node_t *fanout; |
---|
278 | lsList tfoLatchList = lsCreate(); /* allocate a fresh list */ |
---|
279 | |
---|
280 | /* |
---|
281 | * Get the latches in the TFO of each fanout of latch, and accumulate into |
---|
282 | * a list. Note that we can't call NodeComputeTfoLatchList on latch |
---|
283 | * itself, because latches serve as the terminal case of the recursion. |
---|
284 | */ |
---|
285 | Ntk_NodeForEachFanout(latch, i, fanout) { |
---|
286 | lsList fanoutTfoLatchList = NodeComputeTfoLatchList(fanout); |
---|
287 | |
---|
288 | ListAppendList(tfoLatchList, fanoutTfoLatchList); |
---|
289 | } |
---|
290 | |
---|
291 | st_insert(latchDependencies, (char *) latch, (char *) tfoLatchList); |
---|
292 | |
---|
293 | } |
---|
294 | |
---|
295 | /* |
---|
296 | * Free the tfoLatchList stored at the nodes. Only nodes in the transitive |
---|
297 | * fanout of latches will have a non-NULL list, but we just call free |
---|
298 | * tfoLatchList function on each node. Note that the lists being returned |
---|
299 | * in the hash table are distinct from those stored at nodes. |
---|
300 | */ |
---|
301 | Ntk_NetworkForEachNode(network, gen, node) { |
---|
302 | NodeFreeTfoLatchList(node); |
---|
303 | } |
---|
304 | |
---|
305 | return (latchDependencies); |
---|
306 | } |
---|
307 | |
---|
308 | |
---|
309 | /**Function******************************************************************** |
---|
310 | |
---|
311 | Synopsis [Returns 0 if a combinational cycle exists, else returns 1.] |
---|
312 | |
---|
313 | Description [Returns 0 if a cycle exists in the network, else returns 1. |
---|
314 | Latches are considered to break cycles. If a cycle is found, then a message |
---|
315 | is written to error_string (see the error package) giving two nodes in the |
---|
316 | cycle. Use a code fragment like the following to retrieve the error message: |
---|
317 | <pre> |
---|
318 | error_init(); |
---|
319 | status = Ntk_NetworkTestIsAcyclic(network); |
---|
320 | if (status == 0) { |
---|
321 | (void) fprintf(fp, "%s", error_string()); |
---|
322 | } |
---|
323 | </pre>] |
---|
324 | |
---|
325 | SideEffects [] |
---|
326 | |
---|
327 | Comment [This function implements the DFS routine outlined in Cormen, |
---|
328 | Leiserson, Rivest, "Introduction to Algorithms", p. 478. It has been |
---|
329 | specialized to just detect cycles.] |
---|
330 | |
---|
331 | ******************************************************************************/ |
---|
332 | boolean |
---|
333 | Ntk_NetworkTestIsAcyclic( |
---|
334 | Ntk_Network_t * network) |
---|
335 | { |
---|
336 | lsGen gen; |
---|
337 | Ntk_Node_t *node; |
---|
338 | boolean status = 1; /* In case network has no vertices. */ |
---|
339 | |
---|
340 | /* The meaning of the colors is: |
---|
341 | * white: node has not been visited yet |
---|
342 | * grey: node is on the "stack" |
---|
343 | * black: node, and all its descendents, have been visited |
---|
344 | */ |
---|
345 | |
---|
346 | /* |
---|
347 | * Initialize the color of each node to white. |
---|
348 | */ |
---|
349 | Ntk_NetworkForEachNode(network, gen, node) { |
---|
350 | NodeSetColor(node, dfsWhite_c); |
---|
351 | } |
---|
352 | |
---|
353 | /* |
---|
354 | * Recursively visit each unvisited node. The order in which we visit the |
---|
355 | * nodes is immaterial. |
---|
356 | */ |
---|
357 | Ntk_NetworkForEachNode(network, gen, node) { |
---|
358 | if (NodeReadColor(node) == dfsWhite_c) { |
---|
359 | status = NodeTestCannotReachCycle(node); |
---|
360 | if (status == 0) { |
---|
361 | /* A cycle has been found. */ |
---|
362 | break; |
---|
363 | } |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | /* |
---|
368 | * Colors will be left in the undef field of the nodes, but we don't care. |
---|
369 | */ |
---|
370 | return (status); |
---|
371 | } |
---|
372 | |
---|
373 | |
---|
374 | /**Function******************************************************************** |
---|
375 | |
---|
376 | Synopsis [Returns TRUE if leaves cover the support of roots, otherwise |
---|
377 | returns FALSE.] |
---|
378 | |
---|
379 | Description [The function takes as input a network, a hash table of nodes |
---|
380 | called leaves, and an array of nodes called roots. It returns TRUE if the |
---|
381 | nodes in leaves cover the support of the nodes in roots, otherwise it |
---|
382 | returns FALSE. In other words, if there exists a combinational input in the |
---|
383 | transitive fanin of a root, which can be reached from the root without |
---|
384 | passing through a leaf, then FALSE is returned. If FALSE is returned, then |
---|
385 | the message "Node b found in the support of node c" is written to |
---|
386 | error_string, where b is a combinational input not in leaves and c is a |
---|
387 | root. It is allowed that some roots are themselves leaves, and that some |
---|
388 | leaves are in the transitive fanin of other leaves. Combinational cycles |
---|
389 | within the region defined by roots and leaves have no effect on the result. |
---|
390 | If TRUE is returned, then the runtime of this procedure is proportional to |
---|
391 | the number of nodes in the region defined by roots and leaves; if FALSE is |
---|
392 | returned, then the worst case is proportional to the number of nodes in the |
---|
393 | network.] |
---|
394 | |
---|
395 | Comment [The undef field is modified of some of the nodes in the network to |
---|
396 | which node belongs.] |
---|
397 | |
---|
398 | SideEffects [] |
---|
399 | |
---|
400 | ******************************************************************************/ |
---|
401 | boolean |
---|
402 | Ntk_NetworkTestLeavesCoverSupportOfRoots( |
---|
403 | Ntk_Network_t *network, |
---|
404 | array_t *roots, |
---|
405 | st_table *leaves) |
---|
406 | { |
---|
407 | int i; |
---|
408 | Ntk_Node_t *root; |
---|
409 | st_table *visited = st_init_table(st_ptrcmp, st_ptrhash); |
---|
410 | |
---|
411 | /* Perform DFS from the roots. Return FALSE upon the first failure. */ |
---|
412 | arrayForEachItem(Ntk_Node_t *, roots, i, root) { |
---|
413 | boolean status = NodeTestCoveredByLeaves(root, leaves, visited); |
---|
414 | |
---|
415 | if(!status) { |
---|
416 | error_append(Ntk_NodeReadName(root)); |
---|
417 | error_append(".\n"); |
---|
418 | st_free_table(visited); |
---|
419 | return FALSE; |
---|
420 | } |
---|
421 | } |
---|
422 | st_free_table(visited); |
---|
423 | return TRUE; |
---|
424 | } |
---|
425 | |
---|
426 | |
---|
427 | /*---------------------------------------------------------------------------*/ |
---|
428 | /* Definition of internal functions */ |
---|
429 | /*---------------------------------------------------------------------------*/ |
---|
430 | /**Function******************************************************************** |
---|
431 | |
---|
432 | Synopsis [Computes the topological order of nodes in the network |
---|
433 | for a given array of root nodes and the leaf nodes.] |
---|
434 | |
---|
435 | Description [Depth first traversal is used from each node in the |
---|
436 | root node array. The search is terminated when a node in the leaf |
---|
437 | table is reached. It is necessary that all the root nodes eventually |
---|
438 | depend on the leaf nodes. The returned list contains the nodes in |
---|
439 | the topological order.] |
---|
440 | |
---|
441 | SideEffects [] |
---|
442 | |
---|
443 | SeeAlso [] |
---|
444 | |
---|
445 | ******************************************************************************/ |
---|
446 | lsList |
---|
447 | Ntk_NetworkComputeTopologicalOrder(Ntk_Network_t *network, array_t |
---|
448 | *rootNodesArray, st_table |
---|
449 | *leafNodesTable) |
---|
450 | { |
---|
451 | int i; |
---|
452 | lsList topologicalNodeList = lsCreate(); |
---|
453 | Ntk_Node_t *node; |
---|
454 | lsGen gen; |
---|
455 | |
---|
456 | Ntk_NetworkForEachNode(network, gen, node) { |
---|
457 | NodeSetColor(node, dfsWhite_c); |
---|
458 | } |
---|
459 | |
---|
460 | for (i=0; i<array_n(rootNodesArray); i++){ |
---|
461 | node = array_fetch(Ntk_Node_t *, rootNodesArray, i); |
---|
462 | NodeComputeTopologicalOrderRecursively(node, leafNodesTable, |
---|
463 | topologicalNodeList); |
---|
464 | } |
---|
465 | return topologicalNodeList; |
---|
466 | } |
---|
467 | |
---|
468 | |
---|
469 | /*---------------------------------------------------------------------------*/ |
---|
470 | /* Definition of static functions */ |
---|
471 | /*---------------------------------------------------------------------------*/ |
---|
472 | |
---|
473 | /**Function******************************************************************** |
---|
474 | |
---|
475 | Synopsis [Recursively add all fanins of node to result, stopping at leaves |
---|
476 | and constants.] |
---|
477 | |
---|
478 | SideEffects [] |
---|
479 | |
---|
480 | ******************************************************************************/ |
---|
481 | static void |
---|
482 | RegionFindNodesRecursively( |
---|
483 | Ntk_Node_t *node, |
---|
484 | st_table *leaves, |
---|
485 | st_table *result) |
---|
486 | { |
---|
487 | int i; |
---|
488 | Ntk_Node_t *fanin; |
---|
489 | |
---|
490 | if (st_is_member(result, (char *) node)) { |
---|
491 | /* already visited this node */ |
---|
492 | return; |
---|
493 | } |
---|
494 | else { |
---|
495 | /* |
---|
496 | * Add to table before recursing, to avoid infinite loops in presence of |
---|
497 | * combinational cycles. |
---|
498 | */ |
---|
499 | st_insert(result, (char *) node, NIL(char)); |
---|
500 | } |
---|
501 | |
---|
502 | |
---|
503 | if (!st_is_member(leaves, (char *) node) && !Ntk_NodeTestIsConstant(node)) { |
---|
504 | /* not a leaf; recurse */ |
---|
505 | Ntk_NodeForEachFanin(node, i, fanin) { |
---|
506 | RegionFindNodesRecursively(fanin, leaves, result); |
---|
507 | } |
---|
508 | } |
---|
509 | |
---|
510 | return; |
---|
511 | } |
---|
512 | |
---|
513 | /**Function******************************************************************** |
---|
514 | |
---|
515 | Synopsis [Returns 1 if node cannot reach a cycle, else returns 0.] |
---|
516 | |
---|
517 | Description [Visits a node, and recursively all of its children, to |
---|
518 | determine if the node can reach a combinational cycle. If it cannot, the |
---|
519 | function return 1, else it returns 0. If a cycle is found, then a message |
---|
520 | is written to error_string.] |
---|
521 | |
---|
522 | SideEffects [] |
---|
523 | |
---|
524 | ******************************************************************************/ |
---|
525 | static boolean |
---|
526 | NodeTestCannotReachCycle( |
---|
527 | Ntk_Node_t * node) |
---|
528 | { |
---|
529 | Ntk_Node_t *fanout; |
---|
530 | int i; |
---|
531 | |
---|
532 | /* |
---|
533 | * Set the color of node to grey to indicate that it is on the "stack". |
---|
534 | */ |
---|
535 | NodeSetColor(node, dfsGrey_c); |
---|
536 | |
---|
537 | Ntk_NodeForEachFanout(node, i, fanout) { |
---|
538 | /* |
---|
539 | * Traverse fanout if it is *not* a latch; latches break combinational cycles. |
---|
540 | */ |
---|
541 | if (Ntk_NodeTestIsLatch(fanout) == 0) { |
---|
542 | DfsColor fanoutColor = NodeReadColor(fanout); |
---|
543 | |
---|
544 | /* |
---|
545 | * If fanout is white, it has not been visited yet, so visit it, and |
---|
546 | * break the search if it can reach a cycle. Else if fanout is grey, it |
---|
547 | * means that fanout is also on the stack, so a cycle has been found; |
---|
548 | * thus break. Else, the fanout is black, and there is nothing to do. |
---|
549 | */ |
---|
550 | if (fanoutColor == dfsWhite_c) { |
---|
551 | if (NodeTestCannotReachCycle(fanout) == 0) { |
---|
552 | return (0); |
---|
553 | } |
---|
554 | } |
---|
555 | else if (fanoutColor == dfsGrey_c) { |
---|
556 | error_append("("); |
---|
557 | error_append(Ntk_NodeReadName(node)); |
---|
558 | error_append(", "); |
---|
559 | error_append(Ntk_NodeReadName(fanout)); |
---|
560 | error_append(")"); |
---|
561 | return (0); |
---|
562 | } |
---|
563 | } |
---|
564 | } |
---|
565 | |
---|
566 | /* |
---|
567 | * Set the color of node to black to indicate that it has been visited. |
---|
568 | */ |
---|
569 | NodeSetColor(node, dfsBlack_c); |
---|
570 | |
---|
571 | /* |
---|
572 | * No cycles found from node. |
---|
573 | */ |
---|
574 | return (1); |
---|
575 | } |
---|
576 | |
---|
577 | |
---|
578 | /**Function******************************************************************** |
---|
579 | |
---|
580 | Synopsis [Returns FALSE if the support of node contains a combinational |
---|
581 | input that is not a leaf, otherwise returns TRUE.] |
---|
582 | |
---|
583 | Description [The function does a DFS starting from node, never going beyond |
---|
584 | a leaf or a node already visited. If it reaches a combinational input that |
---|
585 | is not a leaf it returns FALSE. If this doesn't happen for all the fanins |
---|
586 | of the node, then TRUE is returned.] |
---|
587 | |
---|
588 | SideEffects [] |
---|
589 | |
---|
590 | SeeAlso [Ntk_NetworkTestLeavesCoverSupportOfRoots] |
---|
591 | |
---|
592 | ******************************************************************************/ |
---|
593 | static boolean |
---|
594 | NodeTestCoveredByLeaves( |
---|
595 | Ntk_Node_t *node, |
---|
596 | st_table *leaves, |
---|
597 | st_table *visited) |
---|
598 | { |
---|
599 | int i; |
---|
600 | Ntk_Node_t *fanin; |
---|
601 | |
---|
602 | /* |
---|
603 | * If node has already been visited, just return. Else, mark it as |
---|
604 | * visited. Note that it is important to mark it as visited BEFORE recursing, |
---|
605 | * in case combinational cycles are present. |
---|
606 | */ |
---|
607 | if (st_is_member(visited, (char *) node)) { |
---|
608 | return TRUE; |
---|
609 | } |
---|
610 | else { |
---|
611 | st_insert(visited, (char *) node, NIL(char)); |
---|
612 | } |
---|
613 | |
---|
614 | if (st_is_member(leaves, (char *) node)) { |
---|
615 | /* |
---|
616 | * Positive termination of recursion: if node is a leaf, then everything |
---|
617 | * is fine. |
---|
618 | */ |
---|
619 | return TRUE; |
---|
620 | } |
---|
621 | else { |
---|
622 | /* Node is not a leaf. */ |
---|
623 | if (Ntk_NodeTestIsCombInput(node)) { |
---|
624 | /* |
---|
625 | * Negative termination of recursion: a combinational input was reached |
---|
626 | * without seeing a leaf. |
---|
627 | */ |
---|
628 | error_append("Node "); |
---|
629 | error_append(Ntk_NodeReadName(node)); |
---|
630 | error_append(" found in the support of node "); |
---|
631 | return FALSE; |
---|
632 | } |
---|
633 | else { |
---|
634 | /* |
---|
635 | * Node is not a leaf nor a combinational input. Recurse over fanins. |
---|
636 | * Return FALSE if any fanins fail the test. |
---|
637 | */ |
---|
638 | Ntk_NodeForEachFanin(node, i, fanin) { |
---|
639 | boolean status = NodeTestCoveredByLeaves(fanin, leaves, visited); |
---|
640 | if (!status) { |
---|
641 | return FALSE; |
---|
642 | } |
---|
643 | } |
---|
644 | /* |
---|
645 | * If the loop terminates without the function returning, then each |
---|
646 | * fanin has already been visited and no dfsWhite_c-labelled comb input |
---|
647 | * can be reached from the fanins. Therefore, return TRUE. |
---|
648 | */ |
---|
649 | return TRUE; |
---|
650 | } |
---|
651 | } |
---|
652 | |
---|
653 | } |
---|
654 | |
---|
655 | |
---|
656 | /**Function******************************************************************** |
---|
657 | |
---|
658 | Synopsis [Gets the color of a node.] |
---|
659 | |
---|
660 | SideEffects [] |
---|
661 | |
---|
662 | SeeAlso [NodeSetColor] |
---|
663 | |
---|
664 | ******************************************************************************/ |
---|
665 | static DfsColor |
---|
666 | NodeReadColor( |
---|
667 | Ntk_Node_t * node) |
---|
668 | { |
---|
669 | return ((DfsColor) (long) Ntk_NodeReadUndef(node)); |
---|
670 | } |
---|
671 | |
---|
672 | |
---|
673 | /**Function******************************************************************** |
---|
674 | |
---|
675 | Synopsis [Sets the color of a node.] |
---|
676 | |
---|
677 | SideEffects [] |
---|
678 | |
---|
679 | SeeAlso [NodeReadColor] |
---|
680 | |
---|
681 | ******************************************************************************/ |
---|
682 | static void |
---|
683 | NodeSetColor( |
---|
684 | Ntk_Node_t * node, |
---|
685 | DfsColor color) |
---|
686 | { |
---|
687 | Ntk_NodeSetUndef(node, (void *) (long) color); |
---|
688 | } |
---|
689 | |
---|
690 | |
---|
691 | /**Function******************************************************************** |
---|
692 | |
---|
693 | Synopsis [Sets the tfoLatchList of a node.] |
---|
694 | |
---|
695 | SideEffects [] |
---|
696 | |
---|
697 | SeeAlso [NodeReadTfoLatchList NodeFreeTfoLatchList] |
---|
698 | |
---|
699 | ******************************************************************************/ |
---|
700 | static void |
---|
701 | NodeSetTfoLatchList( |
---|
702 | Ntk_Node_t * node, |
---|
703 | lsList tfoLatchList) |
---|
704 | { |
---|
705 | Ntk_NodeSetUndef(node, (void *) tfoLatchList); |
---|
706 | } |
---|
707 | |
---|
708 | |
---|
709 | /**Function******************************************************************** |
---|
710 | |
---|
711 | Synopsis [Gets the TfoLatchList of a node.] |
---|
712 | |
---|
713 | SideEffects [] |
---|
714 | |
---|
715 | SeeAlso [NodeSetTfoLatchList NodeFreeTfoLatchList] |
---|
716 | |
---|
717 | ******************************************************************************/ |
---|
718 | static lsList |
---|
719 | NodeReadTfoLatchList( |
---|
720 | Ntk_Node_t * node) |
---|
721 | { |
---|
722 | return ((lsList) Ntk_NodeReadUndef(node)); |
---|
723 | } |
---|
724 | |
---|
725 | |
---|
726 | /**Function******************************************************************** |
---|
727 | |
---|
728 | Synopsis [Frees the tfoLatchList of a node.] |
---|
729 | |
---|
730 | Description [If the node has a non-NULL tfoLatchList, then frees the list |
---|
731 | and sets the tfoLatchList of node to NULL; else, does nothing.] |
---|
732 | |
---|
733 | SideEffects [] |
---|
734 | |
---|
735 | SeeAlso [NodeReadTfoLatchList NodeSetTfoLatchList ] |
---|
736 | |
---|
737 | ******************************************************************************/ |
---|
738 | static void |
---|
739 | NodeFreeTfoLatchList( |
---|
740 | Ntk_Node_t * node) |
---|
741 | { |
---|
742 | lsList tfoLatchList = NodeReadTfoLatchList(node); |
---|
743 | |
---|
744 | if (tfoLatchList != (lsList) NULL) { |
---|
745 | (void) lsDestroy(tfoLatchList, (void (*) (lsGeneric)) NULL); |
---|
746 | Ntk_NodeSetUndef(node, (void *) NULL); |
---|
747 | } |
---|
748 | } |
---|
749 | |
---|
750 | /**Function******************************************************************** |
---|
751 | |
---|
752 | Synopsis [Appends list2 to list1.] |
---|
753 | |
---|
754 | Description [Adds the elements of list2 to the end of list1. The elements |
---|
755 | of list2 are not copied. If an element of list2 already exists in list1, |
---|
756 | then it is not added to the end of list1. List2 is not changed by this |
---|
757 | operation.] |
---|
758 | |
---|
759 | SideEffects [List1 is modified.] |
---|
760 | |
---|
761 | SeeAlso [] |
---|
762 | |
---|
763 | ******************************************************************************/ |
---|
764 | static void |
---|
765 | ListAppendList( |
---|
766 | lsList list1, |
---|
767 | lsList list2) |
---|
768 | { |
---|
769 | lsGen gen; |
---|
770 | lsGeneric data; |
---|
771 | st_table *table1 = st_init_table(st_ptrcmp, st_ptrhash); |
---|
772 | |
---|
773 | /* |
---|
774 | * Load a hash table mapping each item in list1 to NULL. |
---|
775 | */ |
---|
776 | gen = lsStart(list1); |
---|
777 | while (lsNext(gen, &data, LS_NH) == LS_OK) { |
---|
778 | st_insert(table1, (char *) data, (char *) NULL); |
---|
779 | } |
---|
780 | (void) lsFinish(gen); |
---|
781 | |
---|
782 | /* |
---|
783 | * For each item in list2, if it's not already present in list1, then add it |
---|
784 | * to the end of list1. |
---|
785 | */ |
---|
786 | lsForEachItem(list2, gen, data) { |
---|
787 | if (st_is_member(table1, (char *) data) == 0) { |
---|
788 | lsNewEnd(list1, data, LS_NH); |
---|
789 | } |
---|
790 | } |
---|
791 | st_free_table(table1); |
---|
792 | } |
---|
793 | |
---|
794 | |
---|
795 | /**Function******************************************************************** |
---|
796 | |
---|
797 | Synopsis [Computes the set of latches in the TFO of a node.] |
---|
798 | |
---|
799 | Description [Computes the set of latches in the TFO of a node. If there are |
---|
800 | no latches in the TFO, then an empty list is returned. In the special case |
---|
801 | where the node is itself a latch, then a list containing just the node is |
---|
802 | returned; this is one of the terminal cases of the recursion. The other |
---|
803 | terminal case is a node with no immediate fanouts.] |
---|
804 | |
---|
805 | SideEffects [] |
---|
806 | |
---|
807 | ******************************************************************************/ |
---|
808 | static lsList |
---|
809 | NodeComputeTfoLatchList( |
---|
810 | Ntk_Node_t * node) |
---|
811 | { |
---|
812 | lsList tfoLatchList = NodeReadTfoLatchList(node); |
---|
813 | |
---|
814 | /* |
---|
815 | * If node already has a non-NULL tfoLatchList, then just return it (this |
---|
816 | * can happen if the node was already visited via one of its other |
---|
817 | * fanins). Otherwise, create an empty list and fill it appropriately. |
---|
818 | */ |
---|
819 | if (tfoLatchList != (lsList) NULL) { |
---|
820 | return (tfoLatchList); |
---|
821 | } |
---|
822 | else { |
---|
823 | tfoLatchList = lsCreate(); |
---|
824 | |
---|
825 | if (Ntk_NodeTestIsLatch(node)) { |
---|
826 | /* |
---|
827 | * Special case; terminal condition. |
---|
828 | */ |
---|
829 | lsNewEnd(tfoLatchList, (lsGeneric) node, LS_NH); |
---|
830 | } |
---|
831 | else { |
---|
832 | int i; |
---|
833 | Ntk_Node_t *fanout; |
---|
834 | |
---|
835 | /* |
---|
836 | * Get the latches in the TFO of each fanout of node, and accumulate into |
---|
837 | * a list. |
---|
838 | */ |
---|
839 | Ntk_NodeForEachFanout(node, i, fanout) { |
---|
840 | lsList fanoutTfoLatchList = NodeComputeTfoLatchList(fanout); |
---|
841 | |
---|
842 | ListAppendList(tfoLatchList, fanoutTfoLatchList); |
---|
843 | } |
---|
844 | } |
---|
845 | |
---|
846 | /* |
---|
847 | * Store the list with the node, then return the list. |
---|
848 | */ |
---|
849 | NodeSetTfoLatchList(node, tfoLatchList); |
---|
850 | return (tfoLatchList); |
---|
851 | } |
---|
852 | } |
---|
853 | |
---|
854 | |
---|
855 | |
---|
856 | /**Function******************************************************************** |
---|
857 | |
---|
858 | Synopsis [Computes the set of combinational inputs in the TFI of the node.] |
---|
859 | |
---|
860 | Description [Computes the set of combinational inputs in the TFI of the node. |
---|
861 | If stopAtLatches is TRUE, the search terminates at combinational inputs which |
---|
862 | are latches; otherwise it continues, and the search terminates only at primary |
---|
863 | inputs and pseudo inputs.] |
---|
864 | |
---|
865 | SideEffects [] |
---|
866 | |
---|
867 | ******************************************************************************/ |
---|
868 | static void |
---|
869 | NodeRecursivelyComputeTransitiveFaninNodes( |
---|
870 | Ntk_Node_t *node, |
---|
871 | st_table *resultTable, |
---|
872 | boolean stopAtLatches) |
---|
873 | { |
---|
874 | int i; |
---|
875 | Ntk_Node_t * fanin; |
---|
876 | |
---|
877 | /* test if we have already started processing this node */ |
---|
878 | if ( NodeReadColor( node ) == dfsBlack_c ) { |
---|
879 | return; |
---|
880 | } |
---|
881 | NodeSetColor( node, dfsBlack_c ); |
---|
882 | |
---|
883 | if ( Ntk_NodeTestIsCombInput( node ) ) { |
---|
884 | st_insert( resultTable, (char *) node, (char *) 0 ); |
---|
885 | } |
---|
886 | |
---|
887 | if ( Ntk_NodeTestIsInput(node) || ((stopAtLatches == TRUE)&&(Ntk_NodeTestIsLatch(node))) ) { |
---|
888 | return; |
---|
889 | } |
---|
890 | |
---|
891 | Ntk_NodeForEachFanin( node, i, fanin ) { |
---|
892 | NodeRecursivelyComputeTransitiveFaninNodes( fanin, resultTable, stopAtLatches ); |
---|
893 | } |
---|
894 | } |
---|
895 | |
---|
896 | |
---|
897 | |
---|
898 | /**Function******************************************************************** |
---|
899 | |
---|
900 | Synopsis [Recursively performs the depth-first traversal of the |
---|
901 | network starting at the given node.] |
---|
902 | |
---|
903 | Description [Recursively performs the depth-first traversal of the |
---|
904 | network starting at the given node.] |
---|
905 | |
---|
906 | SideEffects [] |
---|
907 | |
---|
908 | SeeAlso [] |
---|
909 | |
---|
910 | ******************************************************************************/ |
---|
911 | static void |
---|
912 | NodeComputeTopologicalOrderRecursively(Ntk_Node_t *node, st_table |
---|
913 | *leafNodesTable, lsList |
---|
914 | topologicalNodeList) |
---|
915 | { |
---|
916 | int i; |
---|
917 | Ntk_Node_t *fanin; |
---|
918 | |
---|
919 | if (NodeReadColor(node) == dfsBlack_c){ |
---|
920 | /* Has already been put in the list. */ |
---|
921 | return; |
---|
922 | } |
---|
923 | if (NodeReadColor(node) == dfsGrey_c){ |
---|
924 | /* Indicates that this node is currently being processed (possibly a |
---|
925 | combinational loop). */ |
---|
926 | return; |
---|
927 | } |
---|
928 | if (st_is_member(leafNodesTable, (char *)node)== 0){ |
---|
929 | NodeSetColor(node, dfsGrey_c); |
---|
930 | Ntk_NodeForEachFanin(node, i, fanin){ |
---|
931 | NodeComputeTopologicalOrderRecursively(fanin, leafNodesTable, |
---|
932 | topologicalNodeList); |
---|
933 | } |
---|
934 | } |
---|
935 | NodeSetColor(node, dfsBlack_c); |
---|
936 | lsNewEnd(topologicalNodeList, (lsGeneric)node, LS_NH); |
---|
937 | return; |
---|
938 | } |
---|
939 | |
---|
940 | /**Function******************************************************************** |
---|
941 | |
---|
942 | Synopsis [Computes the set of nodes in the TFI of the node.] |
---|
943 | |
---|
944 | Description [Computes the set of nodes in the TFI of the node. If |
---|
945 | stopAtLatches is TRUE, the search terminates at combinational inputs |
---|
946 | which are latches; otherwise it continues, and the search terminates |
---|
947 | only at primary inputs and pseudo inputs.] |
---|
948 | |
---|
949 | SideEffects [] |
---|
950 | |
---|
951 | ******************************************************************************/ |
---|
952 | static void |
---|
953 | NodeComputeTransitiveFaninNodes( |
---|
954 | Ntk_Node_t *node, |
---|
955 | st_table *resultTable, |
---|
956 | boolean stopAtLatches) |
---|
957 | { |
---|
958 | int i; |
---|
959 | Ntk_Node_t * fanin; |
---|
960 | |
---|
961 | /* test if we have already started processing this node */ |
---|
962 | if (st_is_member(resultTable, node)) |
---|
963 | return; |
---|
964 | |
---|
965 | st_insert(resultTable, node, (char *)(long)2); |
---|
966 | |
---|
967 | if (Ntk_NodeTestIsInput(node) || (stopAtLatches && Ntk_NodeTestIsLatch(node))) |
---|
968 | return; |
---|
969 | |
---|
970 | Ntk_NodeForEachFanin(node, i, fanin) { |
---|
971 | NodeComputeTransitiveFaninNodes(fanin, resultTable, stopAtLatches); |
---|
972 | } |
---|
973 | } |
---|
974 | |
---|