Prevent multiple dog-legs in non-preferred direction

This commit is contained in:
Eren Dogan 2023-06-15 11:08:13 -07:00
parent 15b4e4dbe8
commit a47bc7ebee
4 changed files with 36 additions and 22 deletions

View File

@ -96,7 +96,7 @@ class hanan_graph:
if name == pin_name: if name == pin_name:
continue continue
for pin in pins: for pin in pins:
blockages.append(deepcopy(pin).inflated_pin(spacing=offset, multiple=1)) blockages.append(deepcopy(pin).inflated_pin(multiple=1, extra_spacing=offset))
return blockages return blockages
@ -110,13 +110,16 @@ class hanan_graph:
y_values = set() y_values = set()
# Add the source and target values # Add the source and target values
offset = self.router.layer_widths[0] / 2
x_offset = vector(offset, 0)
y_offset = vector(0, offset)
for shape in [self.source, self.target]: for shape in [self.source, self.target]:
aspect_ratio = shape.width() / shape.height() aspect_ratio = shape.width() / shape.height()
# If the pin is tall or fat, add two points on the ends # If the pin is tall or fat, add two points on the ends
if aspect_ratio <= 0.5: # Tall pin if aspect_ratio <= 0.5: # Tall pin
points = [shape.uc(), shape.bc()] points = [shape.bc() + y_offset, shape.uc() - y_offset]
elif aspect_ratio >= 2: # Fat pin elif aspect_ratio >= 2: # Fat pin
points = [shape.lc(), shape.rc()] points = [shape.lc() + x_offset, shape.rc() - x_offset]
else: # Square-like pin else: # Square-like pin
points = [shape.center()] points = [shape.center()]
for p in points: for p in points:
@ -251,9 +254,14 @@ class hanan_graph:
path.append(current) path.append(current)
return path return path
# Get the previous node to better calculate the next costs
prev_node = None
if current.id in came_from:
prev_node = came_from[current.id]
# Update neighbor scores # Update neighbor scores
for node in current.neighbors: for node in current.neighbors:
tentative_score = current.get_edge_cost(node) + g_scores[current.id] tentative_score = current.get_edge_cost(node, prev_node) + g_scores[current.id]
if node.id not in g_scores or tentative_score < g_scores[node.id]: if node.id not in g_scores or tentative_score < g_scores[node.id]:
came_from[node.id] = current came_from[node.id] = current
g_scores[node.id] = tentative_score g_scores[node.id] = tentative_score

View File

@ -5,6 +5,7 @@
# #
from openram.base.vector import vector from openram.base.vector import vector
from openram.base.vector3d import vector3d from openram.base.vector3d import vector3d
from openram.tech import drc
class hanan_node: class hanan_node:
@ -48,14 +49,28 @@ class hanan_node:
neighbor.neighbors.remove(self) neighbor.neighbors.remove(self)
def get_edge_cost(self, other): def get_direction(self, b):
""" Return the direction of path from a to b. """
horiz = self.center.x == b.center.x
vert = self.center.y == b.center.y
return (horiz, vert)
def get_edge_cost(self, other, prev_node=None):
""" Get the cost of going from this node to the other node. """ """ Get the cost of going from this node to the other node. """
if other in self.neighbors: if other in self.neighbors:
is_vertical = self.center.x == other.center.x is_vertical = self.center.x == other.center.x
layer_dist = self.center.distance(other.center) layer_dist = self.center.distance(other.center)
# Edge is on non-preferred direction
if is_vertical != bool(self.center.z): if is_vertical != bool(self.center.z):
layer_dist *= 2 layer_dist *= 2
# Wire bends towards non-preferred direction
# NOTE: Adding a fixed cost prevents multiple dog-legs in
# non-preferred direction
if prev_node and self.get_direction(prev_node) != self.get_direction(other):
layer_dist += drc["grid"]
via_dist = abs(self.center.z - other.center.z) * 2 via_dist = abs(self.center.z - other.center.z) * 2
return layer_dist + via_dist return layer_dist + via_dist
return float("inf") return float("inf")

View File

@ -142,7 +142,7 @@ class hanan_router(router_tech):
# Inflate the shapes to prevent DRC errors # Inflate the shapes to prevent DRC errors
offset = self.layer_widths[0] / 2 offset = self.layer_widths[0] / 2
for blockage in blockages: for blockage in blockages:
self.blockages.append(blockage.inflated_pin(spacing=offset, multiple=1)) self.blockages.append(blockage.inflated_pin(multiple=1, extra_spacing=offset))
def add_path(self, path): def add_path(self, path):
@ -160,19 +160,13 @@ class hanan_router(router_tech):
the layout. the layout.
""" """
def get_direction(a, b):
""" Return the direction of path from a to b. """
horiz = a.center.x == b.center.x
vert = a.center.y == b.center.y
return (horiz, vert)
last_added = path[0] last_added = path[0]
coordinates = [path[0].center] coordinates = [path[0].center]
direction = get_direction(path[0], path[1]) direction = path[0].get_direction(path[1])
candidate = path[1] candidate = path[1]
for i in range(2, len(path)): for i in range(2, len(path)):
node = path[i] node = path[i]
current_direction = get_direction(candidate, node) current_direction = node.get_direction(candidate)
# Skip the previous candidate since the current node follows the # Skip the previous candidate since the current node follows the
# same direction # same direction
if direction == current_direction: if direction == current_direction:

View File

@ -19,16 +19,13 @@ class hanan_shape(pin_layout):
pin_layout.__init__(self, name, rect, layer_name_pp) pin_layout.__init__(self, name, rect, layer_name_pp)
def inflated_pin(self, spacing=None, multiple=0.5): def inflated_pin(self, spacing=None, multiple=0.5, extra_spacing=0):
""" Override the default inflated_pin behavior. """ """ Override the default inflated_pin behavior. """
if not spacing: ll, ur = self.inflate(spacing, multiple)
spacing = 0 extra = vector([extra_spacing] * 2)
drc_spacing = multiple * drc("{0}_to_{0}".format(self.layer)) newll = ll - extra
spacing = vector([spacing + drc_spacing] * 2) newur = ur + extra
(ll, ur) = self.rect
newll = ll - spacing
newur = ur + spacing
inflated_area = (newll, newur) inflated_area = (newll, newur)
return hanan_shape(self.name, inflated_area, self.layer) return hanan_shape(self.name, inflated_area, self.layer)