OpenRAM/compiler/base/graph_util.py

145 lines
4.5 KiB
Python
Raw Normal View History

2020-09-29 20:13:58 +02:00
import copy
2019-04-19 10:27:06 +02:00
from collections import defaultdict
import debug
2020-09-29 20:13:58 +02:00
2020-11-03 15:29:17 +01:00
class timing_graph():
2019-07-25 22:25:58 +02:00
"""
Implements a directed graph
Nodes are currently just Strings.
"""
2020-11-03 15:29:17 +01:00
2019-04-19 10:27:06 +02:00
def __init__(self):
self.graph = defaultdict(set)
self.all_paths = []
self.edge_mods = {}
2019-04-19 10:27:06 +02:00
def add_edge(self, src_node, dest_node, edge_mod):
"""Adds edge to graph. Nodes added as well if they do not exist.
Module which defines the edge must be provided for timing information."""
2020-11-03 15:29:17 +01:00
src_node = src_node.lower()
dest_node = dest_node.lower()
self.graph[src_node].add(dest_node)
self.edge_mods[(src_node, dest_node)] = edge_mod
2019-04-19 10:27:06 +02:00
def add_node(self, node):
2019-04-19 10:27:06 +02:00
"""Add node to graph with no edges"""
2020-11-03 15:29:17 +01:00
node = node.lower()
2020-09-29 20:13:58 +02:00
if node not in self.graph:
self.graph[node] = set()
2020-11-03 15:29:17 +01:00
2019-04-19 10:27:06 +02:00
def remove_edges(self, node):
"""Helper function to remove edges, useful for removing vdd/gnd"""
2020-11-03 15:29:17 +01:00
node = node.lower()
self.graph[node] = set()
2020-11-03 15:29:17 +01:00
def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True):
"""Traverse all paths from source to destination"""
2020-11-03 15:29:17 +01:00
src_node = src_node.lower()
dest_node = dest_node.lower()
2020-11-03 15:29:17 +01:00
2019-07-25 22:25:58 +02:00
# Remove vdd and gnd by default
# Will require edits if separate supplies are implemented.
if remove_rail_nodes:
# Names are also assumed.
self.remove_edges('vdd')
self.remove_edges('gnd')
2020-11-03 15:29:17 +01:00
# Mark all the vertices as not visited
2019-04-19 10:27:06 +02:00
visited = set()
2020-11-03 15:29:17 +01:00
# Create an array to store paths
path = []
self.all_paths = []
2020-11-03 15:29:17 +01:00
# Call the recursive helper function to print all paths
self.get_all_paths_util(src_node, dest_node, visited, path)
debug.info(2, "Paths found={}".format(len(self.all_paths)))
2019-07-25 22:25:58 +02:00
if reduce_paths:
self.reduce_paths()
2020-11-03 15:29:17 +01:00
return self.all_paths
2019-07-25 22:25:58 +02:00
def reduce_paths(self):
""" Remove any path that is a subset of another path """
2020-11-03 15:29:17 +01:00
2019-07-25 22:25:58 +02:00
self.all_paths = [p1 for p1 in self.all_paths if not any(set(p1)<=set(p2) for p2 in self.all_paths if p1 is not p2)]
2020-11-03 15:29:17 +01:00
def get_all_paths_util(self, cur_node, dest_node, visited, path):
"""Recursive function to find all paths in a Depth First Search manner"""
2020-11-03 15:29:17 +01:00
# Mark the current node as visited and store in path
visited.add(cur_node)
path.append(cur_node)
2020-11-03 15:29:17 +01:00
# If current vertex is same as destination, then print
# current path[]
if cur_node == dest_node:
self.all_paths.append(copy.deepcopy(path))
else:
2020-11-03 15:29:17 +01:00
# If current vertex is not destination
# Recur for all the vertices adjacent to this vertex
for node in self.graph[cur_node]:
if node not in visited:
self.get_all_paths_util(node, dest_node, visited, path)
2020-11-03 15:29:17 +01:00
# Remove current vertex from path[] and mark it as unvisited
path.pop()
visited.remove(cur_node)
def get_timing(self, path, corner, slew, load):
"""Returns the analytical delays in the input path"""
2020-11-03 15:29:17 +01:00
if len(path) == 0:
return []
2020-11-03 15:29:17 +01:00
delays = []
cur_slew = slew
for i in range(len(path) - 1):
2020-11-03 15:29:17 +01:00
path_edge_mod = self.edge_mods[(path[i], path[i + 1])]
2020-11-03 15:29:17 +01:00
# On the output of the current stage, get COUT from all other mods connected
cout = 0
for node in self.graph[path[i + 1]]:
output_edge_mod = self.edge_mods[(path[i + 1], node)]
cout+=output_edge_mod.get_cin()
2020-11-03 15:29:17 +01:00
# If at the last output, include the final output load
if i == len(path) - 2:
cout += load
2020-11-03 15:29:17 +01:00
#delays.append(path_edge_mod.analytical_delay(corner, cur_slew, cout))
delays.append(path_edge_mod.cacti_delay(corner, cur_slew, cout))
cur_slew = delays[-1].slew
2020-11-03 15:29:17 +01:00
return delays
def get_edge_mods(self, path):
"""Return all edge mods associated with path"""
if len(path) == 0:
return []
return [self.edge_mods[(path[i], path[i+1])] for i in range(len(path)-1)]
2020-11-03 15:29:17 +01:00
2019-04-19 10:27:06 +02:00
def __str__(self):
""" override print function output """
2019-07-25 22:25:58 +02:00
str = ""
for n in self.graph:
str += n + "\n"
for d in self.graph[n]:
str += "\t\t-> " + d + "\n"
return str
def __repr__(self):
""" override print function output """
return str(self)
2020-11-03 15:29:17 +01:00