OpenRAM/compiler/router/navigation_graph.py

102 lines
4.2 KiB
Python
Raw Normal View History

# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from openram import debug
from openram.base.vector import vector
from .navigation_node import navigation_node
from .navigation_blockage import navigation_blockage
class navigation_graph:
""" This is the navigation graph created from the blockages. """
def __init__(self):
pass
def is_probe_blocked(self, p1, p2):
"""
Return if a probe sent from p1 to p2 encounters a blockage.
The probe must be sent vertically or horizontally.
This method assumes that blockages are rectangular.
"""
# Check if any blockage blocks this probe
for blockage in self.nav_blockages:
right_x = blockage.ur[0]
upper_y = blockage.ur[1]
left_x = blockage.ll[0]
lower_y = blockage.ll[1]
# Check if blocked vertically
if is_between(left_x, right_x, p1.x) and (is_between(p1.y, p2.y, upper_y) or is_between(p1.y, p2.y, lower_y)):
return True
# Check if blocked horizontally
if is_between(upper_y, lower_y, p1.y) and (is_between(p1.x, p2.x, left_x) or is_between(p1.x, p2.x, right_x)):
return True
return False
def create_graph(self, layout_source, layout_target, layout_blockages):
""" """
debug.info(0, "Creating the navigation graph for source '{0}' and target'{1}'.".format(layout_source, layout_target))
# Find the region to be routed and only include objects inside that region
s_ll, sou_ur = layout_source.rect
t_ll, tar_ur = layout_target.rect
ll = vector(min(s_ll.x, t_ll.x), max(s_ll.y, t_ll.y))
ur = vector(max(sou_ur.x, tar_ur.x), min(sou_ur.y, tar_ur.y))
region = (ll, ur)
# Instantiate "navigation blockage" objects from layout blockages
self.nav_blockages = []
for layout_blockage in layout_blockages:
ll, ur = layout_blockage.rect
if (is_between(region[0].x, region[1].x, ll.x) and is_between(region[0].y, region[1].y, ll.y)) or \
(is_between(region[0].x, region[1].x, ur.x) and is_between(region[0].y, region[1].y, ur.y)):
self.nav_blockages.append(navigation_blockage(ll, ur))
self.nodes = []
# Add source and target for this graph
self.nodes.append(navigation_node(layout_source.center()))
self.nodes.append(navigation_node(layout_target.center()))
# Create the corner nodes
for blockage in self.nav_blockages:
self.nodes.extend(blockage.create_corner_nodes())
# Create intersection nodes
# NOTE: Intersection nodes are used to connect boundaries of blockages
# perpendicularly.
new_nodes = []
debug.info(0, "Number of blockages: {}".format(len(self.nav_blockages)))
debug.info(0, "Number of nodes: {}".format(len(self.nodes)))
for i in range(len(self.nodes)):
debug.info(3, "Creating intersections for node #{}".format(i))
node1 = self.nodes[i]
for j in range(i + 1, len(self.nodes)):
node2 = self.nodes[j]
# Skip if the nodes are already connected
if node1 in node2.neighbors:
continue
# Try two different corners
for k in [0, 1]:
# Create a node at the perpendicular corner of these two nodes
corner = navigation_node(vector(node1.position[k], node2.position[int(not k)]))
# Skip this corner if the perpendicular connection is blocked
if self.is_probe_blocked(corner.position, node1.position) or self.is_probe_blocked(corner.position, node2.position):
continue
corner.add_neighbor(node1)
corner.add_neighbor(node2)
new_nodes.append(corner)
self.nodes.extend(new_nodes)
debug.info(0, "Number of nodes after intersections: {}".format(len(self.nodes)))
def is_between(a, b, mid):
""" Return if 'mid' is between 'a' and 'b'. """
return (a < mid and mid < b) or (b < mid and mid < a)