@@ -421,47 +421,52 @@ def find_longest_path(self):
421
421
self .tstart ()
422
422
lp = nx .dag_longest_path (self .G , weight = 'wirelength' )
423
423
424
- # The final edge in the path returned by Networkx's longest path
425
- # algorithm always has a non-zero weight. This means that, the final
426
- # node in the longest path may be an ancestor to subsequent edges as
427
- # as long as these subsequent edges have zero weight. In the context
428
- # of the wirelength analyzer this means that the terminal cell in the
429
- # longest path reported by Networkx may be a combinatorial driver for
430
- # subsequent routeSegments that do not appear in the reported path. To
431
- # avoid this scenario we perform a Depth First Search from the final
432
- # node in the Networkx longest path, stopping at the first cell/bel
433
- # that is not a combinatorial driver of any subsequent routeSegments
434
-
435
- def search_for_first_valid_sink (source , path = ()):
424
+ # NetworkX's longest path algorithm will return the longest path by
425
+ # wirelength, but it is not necessarily a path that terminates in a
426
+ # timing endpoint (e.g. a FF).
427
+ # Consider the example where the tail of such a longest path consists
428
+ # of a LUT followed by an intra-site connection to a FF.
429
+ # NetworkX will return a path that terminates at the LUT, since the
430
+ # intra-site connection to the FF incurs no additional wirelength.
431
+ # Rather than present this truncated path to the user, attempt to
432
+ # extend this longest path to include connections to downstream cells.
433
+
434
+ def search_for_first_valid_sink (source , path = []):
436
435
"""
437
436
Run a Depth First Search from the provided source returning the
438
437
first path found to a cell that is not a combinatorial driver for
439
438
any further routeSegments.
440
439
441
440
Args:
442
441
source: the source node to begin searching from
443
- path: an empty tuple that will containt the path found
442
+ path: the current list of nodes leading to source
444
443
Returns:
445
- a tuple of nodes (starting at the source node) forming a path
446
- if a valid path can be found.
444
+ a list of nodes (starting at the source node) forming a path
445
+ to the first sink, empty list if one cannot be found.
447
446
"""
448
447
out_edges = self .G .out_edges (source )
449
- path = ( * path , source )
448
+ path = path + [ source ]
450
449
if len (out_edges ) == 0 :
451
450
source_seg = self .G .nodes [source ]['segment' ]
452
451
if source_seg .which () == 'belPin' :
453
- if self . placements . get (( source_seg .belPin .site , source_seg .belPin .bel )) is not None :
452
+ if ( source_seg .belPin .site , source_seg .belPin .bel ) in self . placements :
454
453
return path
455
- return None
456
- return None
454
+ return []
457
455
for oe in out_edges :
458
456
ret = search_for_first_valid_sink (oe [1 ], path )
459
- if ret is not None :
457
+ if ret :
460
458
return ret
461
- return None
462
-
463
- tail = search_for_first_valid_sink (lp [- 1 ])
464
- lp = lp + list (tail )[1 :]
459
+ return []
460
+
461
+ last = lp [- 1 ]
462
+ tail = search_for_first_valid_sink (last )
463
+ if tail :
464
+ lp = lp + tail [1 :]
465
+ else :
466
+ seg = self .G .nodes [last ]['segment' ]
467
+ cell = self .placements [(seg .belPin .site , seg .belPin .bel )]
468
+ sl = self .phys .strList
469
+ warnings .warn ("No valid sink found from cell " + sl [cell .cellName ] + "; assuming that it drives a hierarchical port." )
465
470
return lp
466
471
467
472
def expand_edge (self , source , sink ):
0 commit comments