mirror of https://github.com/VLSIDA/OpenRAM.git
merge dev
This commit is contained in:
commit
5605154cc2
|
|
@ -0,0 +1,63 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
from openram.base.vector import vector
|
||||
from .graph_utils import snap
|
||||
|
||||
|
||||
class bbox:
|
||||
"""
|
||||
This class represents a bounding box object that is used in `bbox_node`
|
||||
class. We are using bbox objects to group shapes in the router graphs.
|
||||
"""
|
||||
|
||||
def __init__(self, shape=None):
|
||||
|
||||
self.shape = shape
|
||||
self.rect = None
|
||||
if self.shape:
|
||||
self.rect = self.shape.rect
|
||||
|
||||
|
||||
def area(self):
|
||||
""" Return the area of this bbox. """
|
||||
|
||||
ll, ur = self.rect
|
||||
width = ur.x - ll.x
|
||||
height = ur.y - ll.y
|
||||
return snap(width * height)
|
||||
|
||||
|
||||
def merge(self, other):
|
||||
""" Return the bbox created by merging two bbox objects. """
|
||||
|
||||
ll, ur = self.rect
|
||||
oll, our = other.rect
|
||||
min_x = min(ll.x, oll.x)
|
||||
max_x = max(ur.x, our.x)
|
||||
min_y = min(ll.y, oll.y)
|
||||
max_y = max(ur.y, our.y)
|
||||
rect = [vector(min_x, min_y), vector(max_x, max_y)]
|
||||
merged = bbox()
|
||||
merged.rect = rect
|
||||
return merged
|
||||
|
||||
|
||||
def overlap(self, other):
|
||||
""" Return the bbox created by overlapping two bbox objects. """
|
||||
|
||||
ll, ur = self.rect
|
||||
oll, our = other.rect
|
||||
min_x = max(ll.x, oll.x)
|
||||
max_x = min(ur.x, our.x)
|
||||
min_y = max(ll.y, oll.y)
|
||||
max_y = min(ur.y, our.y)
|
||||
if max_x >= min_x and max_y >= min_y:
|
||||
rect = [vector(min_x, min_y), vector(max_x, max_y)]
|
||||
else:
|
||||
return None
|
||||
overlapped = bbox()
|
||||
overlapped.rect = rect
|
||||
return overlapped
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
from .bbox import bbox
|
||||
|
||||
|
||||
class bbox_node:
|
||||
"""
|
||||
This class represents a node in the bbox tree structure. Bbox trees are
|
||||
binary trees we use to partition the shapes in the routing region so that
|
||||
we can detect overlaps faster in a binary search-like manner.
|
||||
"""
|
||||
|
||||
def __init__(self, bbox, left=None, right=None):
|
||||
|
||||
self.bbox = bbox
|
||||
self.is_leaf = not left and not right
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
|
||||
def iterate_point(self, point, check_done=False):
|
||||
""" Iterate over shapes in the tree that overlap the given point. """
|
||||
|
||||
px, py = point.x, point.y
|
||||
# Return this shape if it's a leaf
|
||||
if self.is_leaf:
|
||||
ll, ur = self.bbox.rect
|
||||
if check_done or (ll.x <= px and px <= ur.x and ll.y <= py and py <= ur.y):
|
||||
yield self.bbox.shape
|
||||
else:
|
||||
# Check the left child
|
||||
if self.left:
|
||||
ll, ur = self.left.bbox.rect
|
||||
if ll.x <= px and px <= ur.x and ll.y <= py and py <= ur.y:
|
||||
yield from self.left.iterate_point(point, True)
|
||||
# Check the right child
|
||||
if self.right:
|
||||
ll, ur = self.right.bbox.rect
|
||||
if ll.x <= px and px <= ur.x and ll.y <= py and py <= ur.y:
|
||||
yield from self.right.iterate_point(point, True)
|
||||
|
||||
|
||||
def iterate_shape(self, shape, check_done=False):
|
||||
""" Iterate over shapes in the tree that overlap the given shape. """
|
||||
|
||||
sll, sur = shape.rect
|
||||
# Return this shape if it's a leaf
|
||||
if self.is_leaf:
|
||||
ll, ur = self.bbox.rect
|
||||
if check_done or (ll.x <= sur.x and sll.x <= ur.x and ll.y <= sur.y and sll.y <= ur.y):
|
||||
yield self.bbox.shape
|
||||
else:
|
||||
# Check the left child
|
||||
if self.left:
|
||||
ll, ur = self.left.bbox.rect
|
||||
if ll.x <= sur.x and sll.x <= ur.x and ll.y <= sur.y and sll.y <= ur.y:
|
||||
yield from self.left.iterate_shape(shape, True)
|
||||
# Check the right child
|
||||
if self.right:
|
||||
ll, ur = self.right.bbox.rect
|
||||
if ll.x <= sur.x and sll.x <= ur.x and ll.y <= sur.y and sll.y <= ur.y:
|
||||
yield from self.right.iterate_shape(shape, True)
|
||||
|
||||
|
||||
def get_costs(self, bbox):
|
||||
""" Return the costs of bbox nodes after merging the given bbox. """
|
||||
|
||||
# Find the new areas for all possible cases
|
||||
self_merge = bbox.merge(self.bbox)
|
||||
left_merge = bbox.merge(self.left.bbox)
|
||||
right_merge = bbox.merge(self.right.bbox)
|
||||
|
||||
# Add the change in areas as cost
|
||||
self_cost = self_merge.area()
|
||||
left_cost = self_merge.area() - self.bbox.area()
|
||||
left_cost += left_merge.area() - self.left.bbox.area()
|
||||
right_cost = self_merge.area() - self.bbox.area()
|
||||
right_cost += right_merge.area() - self.right.bbox.area()
|
||||
|
||||
# Add the overlaps in areas as cost
|
||||
self_overlap = self.bbox.overlap(bbox)
|
||||
left_overlap = left_merge.overlap(self.right.bbox)
|
||||
right_overlap = right_merge.overlap(self.left.bbox)
|
||||
if self_overlap:
|
||||
self_cost += self_overlap.area()
|
||||
if left_overlap:
|
||||
left_cost += left_overlap.area()
|
||||
if right_overlap:
|
||||
right_cost += right_overlap.area()
|
||||
|
||||
return self_cost, left_cost, right_cost
|
||||
|
||||
|
||||
def insert(self, bbox):
|
||||
""" Insert a bbox to the bbox tree. """
|
||||
|
||||
if self.is_leaf:
|
||||
# Put the current bbox to the left child
|
||||
self.left = bbox_node(self.bbox)
|
||||
# Put the new bbox to the right child
|
||||
self.right = bbox_node(bbox)
|
||||
else:
|
||||
# Calculate the costs of adding the new bbox
|
||||
self_cost, left_cost, right_cost = self.get_costs(bbox)
|
||||
if self_cost < left_cost and self_cost < right_cost: # Add here
|
||||
self.left = bbox_node(self.bbox, left=self.left, right=self.right)
|
||||
self.right = bbox_node(bbox)
|
||||
elif left_cost < right_cost: # Add to the left
|
||||
self.left.insert(bbox)
|
||||
else: # Add to the right
|
||||
self.right.insert(bbox)
|
||||
# Update the current bbox
|
||||
self.bbox = self.left.bbox.merge(self.right.bbox)
|
||||
self.is_leaf = False
|
||||
|
|
@ -9,6 +9,8 @@ from openram import debug
|
|||
from openram.base.vector import vector
|
||||
from openram.base.vector3d import vector3d
|
||||
from openram.tech import drc
|
||||
from .bbox import bbox
|
||||
from .bbox_node import bbox_node
|
||||
from .graph_node import graph_node
|
||||
from .graph_probe import graph_probe
|
||||
from .graph_utils import snap
|
||||
|
|
@ -80,11 +82,8 @@ class graph:
|
|||
probe_shape = graph_probe(p1, p2, self.router.get_lpp(p1.z))
|
||||
pll, pur = probe_shape.rect
|
||||
# Check if any blockage blocks this probe
|
||||
for blockage in self.graph_blockages:
|
||||
for blockage in self.blockage_bbox_tree.iterate_shape(probe_shape):
|
||||
bll, bur = blockage.rect
|
||||
# Not overlapping
|
||||
if bll.x > pur.x or pll.x > bur.x or bll.y > pur.y or pll.y > bur.y:
|
||||
continue
|
||||
# Not on the same layer
|
||||
if not blockage.same_lpp(blockage.lpp, probe_shape.lpp):
|
||||
continue
|
||||
|
|
@ -116,11 +115,8 @@ class graph:
|
|||
half_wide = self.router.half_wire
|
||||
spacing = snap(self.router.track_space + half_wide + drc["grid"])
|
||||
blocked = False
|
||||
for blockage in self.graph_blockages:
|
||||
for blockage in self.blockage_bbox_tree.iterate_point(p):
|
||||
ll, ur = blockage.rect
|
||||
# Not overlapping
|
||||
if ll.x > x or x > ur.x or ll.y > y or y > ur.y:
|
||||
continue
|
||||
# Not on the same layer
|
||||
if self.router.get_zindex(blockage.lpp) != z:
|
||||
continue
|
||||
|
|
@ -168,11 +164,16 @@ class graph:
|
|||
for node in nodes:
|
||||
if self.is_node_blocked(node, pin_safe=False):
|
||||
return True
|
||||
|
||||
# Skip if no via is present
|
||||
if len(self.graph_vias) == 0:
|
||||
return False
|
||||
|
||||
# If the nodes are blocked by a via
|
||||
x = node.center.x
|
||||
y = node.center.y
|
||||
z = node.center.z
|
||||
for via in self.graph_vias:
|
||||
for via in self.via_bbox_tree.iterate_point(node.center):
|
||||
ll, ur = via.rect
|
||||
# Not overlapping
|
||||
if ll.x > x or x > ur.x or ll.y > y or y > ur.y:
|
||||
|
|
@ -186,7 +187,7 @@ class graph:
|
|||
|
||||
def create_graph(self, source, target, scale=1):
|
||||
""" Create the graph to run routing on later. """
|
||||
debug.info(2, "Creating the graph for source '{}' and target'{}'.".format(source, target))
|
||||
debug.info(3, "Creating the graph for source '{}' and target'{}'.".format(source, target))
|
||||
|
||||
# Save source and target information
|
||||
self.source = source
|
||||
|
|
@ -195,9 +196,8 @@ class graph:
|
|||
# Find the region to be routed and only include objects inside that region
|
||||
region = deepcopy(source)
|
||||
region.bbox([target])
|
||||
region.multiply(scale)
|
||||
region = region.inflated_pin(spacing=self.router.track_space)
|
||||
debug.info(3, "Routing region is {}".format(region.rect))
|
||||
region = region.inflated_pin(spacing=self.router.track_width + self.router.track_space)
|
||||
debug.info(4, "Routing region is {}".format(region.rect))
|
||||
|
||||
# Find the blockages that are in the routing area
|
||||
self.graph_blockages = []
|
||||
|
|
@ -213,13 +213,15 @@ class graph:
|
|||
region.bbox(self.graph_blockages)
|
||||
# Find and include edge shapes to prevent DRC errors
|
||||
self.find_graph_blockages(region)
|
||||
# Build the bbox tree
|
||||
self.build_bbox_trees()
|
||||
# Generate the graph nodes from cartesian values
|
||||
self.generate_graph_nodes(x_values, y_values)
|
||||
# Save the graph nodes that lie in source and target shapes
|
||||
self.save_end_nodes()
|
||||
debug.info(3, "Number of blockages detected in the routing region: {}".format(len(self.graph_blockages)))
|
||||
debug.info(3, "Number of vias detected in the routing region: {}".format(len(self.graph_vias)))
|
||||
debug.info(3, "Number of nodes in the routing graph: {}".format(len(self.nodes)))
|
||||
debug.info(4, "Number of blockages detected in the routing region: {}".format(len(self.graph_blockages)))
|
||||
debug.info(4, "Number of vias detected in the routing region: {}".format(len(self.graph_vias)))
|
||||
debug.info(4, "Number of nodes in the routing graph: {}".format(len(self.nodes)))
|
||||
|
||||
# Return the region to scale later if no path is found
|
||||
return region.rect
|
||||
|
|
@ -261,6 +263,21 @@ class graph:
|
|||
self.graph_vias.append(via)
|
||||
|
||||
|
||||
def build_bbox_trees(self):
|
||||
""" Build bbox trees for blockages and vias in the routing region. """
|
||||
|
||||
# Bbox tree for blockages
|
||||
self.blockage_bbox_tree = bbox_node(bbox(self.graph_blockages[0]))
|
||||
for i in range(1, len(self.graph_blockages)):
|
||||
self.blockage_bbox_tree.insert(bbox(self.graph_blockages[i]))
|
||||
# Bbox tree for vias
|
||||
if len(self.graph_vias) == 0:
|
||||
return
|
||||
self.via_bbox_tree = bbox_node(bbox(self.graph_vias[0]))
|
||||
for i in range(1, len(self.graph_vias)):
|
||||
self.via_bbox_tree.insert(bbox(self.graph_vias[i]))
|
||||
|
||||
|
||||
def generate_cartesian_values(self):
|
||||
"""
|
||||
Generate x and y values from all the corners of the shapes in the
|
||||
|
|
|
|||
|
|
@ -65,10 +65,10 @@ class graph_node:
|
|||
layer_dist = self.center.distance(other.center)
|
||||
# Double the cost if the edge is in non-preferred direction
|
||||
if is_vertical != bool(self.center.z):
|
||||
layer_dist *= 2
|
||||
layer_dist *= 4
|
||||
# Add a constant wire cost to prevent dog-legs
|
||||
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)
|
||||
via_dist = abs(self.center.z - other.center.z) * 2
|
||||
return layer_dist + via_dist
|
||||
return float("inf")
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class router(router_tech):
|
|||
|
||||
def find_pins(self, pin_name):
|
||||
""" Find the pins with the given name. """
|
||||
debug.info(2, "Finding all pins for {}".format(pin_name))
|
||||
debug.info(4, "Finding all pins for {}".format(pin_name))
|
||||
|
||||
shape_list = self.layout.getAllPinShapes(str(pin_name))
|
||||
pin_set = set()
|
||||
|
|
@ -111,7 +111,7 @@ class router(router_tech):
|
|||
|
||||
def find_blockages(self, name="blockage"):
|
||||
""" Find all blockages in the routing layers. """
|
||||
debug.info(2, "Finding blockages...")
|
||||
debug.info(4, "Finding blockages...")
|
||||
|
||||
for lpp in [self.vert_lpp, self.horiz_lpp]:
|
||||
shapes = self.layout.getAllShapes(lpp)
|
||||
|
|
@ -134,7 +134,7 @@ class router(router_tech):
|
|||
|
||||
def find_vias(self):
|
||||
""" Find all vias in the routing layers. """
|
||||
debug.info(2, "Finding vias...")
|
||||
debug.info(4, "Finding vias...")
|
||||
|
||||
# Prepare lpp values here
|
||||
from openram.tech import layer
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
from openram import debug
|
||||
from openram.base.vector import vector
|
||||
from openram.base.vector3d import vector3d
|
||||
from openram import OPTS
|
||||
from .graph import graph
|
||||
from .graph_shape import graph_shape
|
||||
|
|
@ -53,45 +54,89 @@ class signal_escape_router(router):
|
|||
self.blockages.append(self.inflate_shape(pin))
|
||||
|
||||
# Route vdd and gnd
|
||||
routed_count = 0
|
||||
routed_max = len(pin_names)
|
||||
for source, target, _ in self.get_route_pairs(pin_names):
|
||||
# Change fake pin's name so the graph will treat it as routable
|
||||
target.name = source.name
|
||||
# This is the routing region scale
|
||||
scale = 1
|
||||
while True:
|
||||
# Create the graph
|
||||
g = graph(self)
|
||||
region = g.create_graph(source, target, scale)
|
||||
# Find the shortest path from source to target
|
||||
path = g.find_shortest_path()
|
||||
# If there is no path found, exponentially try again with a
|
||||
# larger routing region
|
||||
if path is None:
|
||||
rll, rur = region
|
||||
bll, bur = self.bbox
|
||||
# Stop scaling the region and throw an error
|
||||
if rll.x < bll.x and rll.y < bll.y and \
|
||||
rur.x > bur.x and rur.y > bur.y:
|
||||
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
|
||||
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
|
||||
# Exponentially scale the region
|
||||
scale *= 2
|
||||
debug.info(0, "Retry routing in larger routing region with scale {}".format(scale))
|
||||
continue
|
||||
# Create the path shapes on layout
|
||||
new_shapes = self.add_path(path)
|
||||
self.new_pins[source.name] = new_shapes[0]
|
||||
# Find the recently added shapes
|
||||
self.prepare_gds_reader()
|
||||
self.find_blockages(name)
|
||||
self.find_vias()
|
||||
break
|
||||
# Create the graph
|
||||
g = graph(self)
|
||||
g.create_graph(source, target)
|
||||
# Find the shortest path from source to target
|
||||
path = g.find_shortest_path()
|
||||
# If no path is found, throw an error
|
||||
if path is None:
|
||||
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
|
||||
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
|
||||
# Create the path shapes on layout
|
||||
new_wires, new_vias = self.add_path(path)
|
||||
self.new_pins[source.name] = new_wires[-1]
|
||||
# Find the recently added shapes
|
||||
self.find_blockages(name, new_wires)
|
||||
self.find_vias(new_vias)
|
||||
routed_count += 1
|
||||
debug.info(2, "Routed {} of {} signal pins".format(routed_count, routed_max))
|
||||
self.replace_layout_pins()
|
||||
|
||||
|
||||
def get_closest_edge(self, point):
|
||||
""" Return a point's the closest edge and the edge's axis direction. """
|
||||
|
||||
ll, ur = self.bbox
|
||||
|
||||
# Snap the pin to the perimeter and break the iteration
|
||||
ll_diff_x = abs(point.x - ll.x)
|
||||
ll_diff_y = abs(point.y - ll.y)
|
||||
ur_diff_x = abs(point.x - ur.x)
|
||||
ur_diff_y = abs(point.y - ur.y)
|
||||
min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y)
|
||||
|
||||
if min_diff == ll_diff_x:
|
||||
return "left", True
|
||||
if min_diff == ll_diff_y:
|
||||
return "bottom", False
|
||||
if min_diff == ur_diff_x:
|
||||
return "right", True
|
||||
return "top", False
|
||||
|
||||
|
||||
def prepare_path(self, path):
|
||||
"""
|
||||
Override the `prepare_path` method from the `router` class to prevent
|
||||
overflows from the SRAM layout area.
|
||||
"""
|
||||
|
||||
ll, ur = self.bbox
|
||||
nodes = super().prepare_path(path)
|
||||
new_nodes = []
|
||||
for i in range(len(nodes)):
|
||||
node = nodes[i]
|
||||
c = node.center
|
||||
# Haven't overflown yet
|
||||
if ll.x < c.x and c.x < ur.x and ll.y < c.y and c.y < ur.y:
|
||||
new_nodes.append(node)
|
||||
continue
|
||||
# Snap the pin to the perimeter and break the iteration
|
||||
edge, _ = self.get_closest_edge(c)
|
||||
if edge == "left":
|
||||
fake_center = vector3d(ll.x + self.half_wire, c.y, c.z)
|
||||
if edge == "bottom":
|
||||
fake_center = vector3d(c.x, ll.y + self.half_wire, c.z)
|
||||
if edge == "right":
|
||||
fake_center = vector3d(ur.x - self.half_wire, c.y, c.z)
|
||||
if edge == "top":
|
||||
fake_center = vector3d(c.x, ur.y - self.half_wire, c.z)
|
||||
node.center = fake_center
|
||||
new_nodes.append(node)
|
||||
break
|
||||
return new_nodes
|
||||
|
||||
|
||||
def add_perimeter_fake_pins(self):
|
||||
"""
|
||||
Add the fake pins on the perimeter to where the signals will be routed.
|
||||
These perimeter fake pins are only used to replace layout pins at the
|
||||
end of routing.
|
||||
"""
|
||||
|
||||
ll, ur = self.bbox
|
||||
|
|
@ -132,17 +177,36 @@ class signal_escape_router(router):
|
|||
self.fake_pins.append(pin)
|
||||
|
||||
|
||||
def get_closest_perimeter_fake_pin(self, pin):
|
||||
""" Return the closest fake pin for the given pin. """
|
||||
def create_fake_pin(self, pin):
|
||||
""" Create a fake pin on the perimeter orthogonal to the given pin. """
|
||||
|
||||
min_dist = float("inf")
|
||||
close_fake = None
|
||||
for fake in self.fake_pins:
|
||||
dist = pin.distance(fake)
|
||||
if dist < min_dist:
|
||||
min_dist = dist
|
||||
close_fake = fake
|
||||
return close_fake
|
||||
ll, ur = self.bbox
|
||||
c = pin.center()
|
||||
|
||||
# Find the closest edge
|
||||
edge, vertical = self.get_closest_edge(c)
|
||||
|
||||
# Keep the fake pin out of the SRAM layout are so that they won't be
|
||||
# blocked by previous signals if they're on the same orthogonal line
|
||||
if edge == "left":
|
||||
fake_center = vector(ll.x - self.track_wire * 2, c.y)
|
||||
if edge == "bottom":
|
||||
fake_center = vector(c.x, ll.y - self.track_wire * 2)
|
||||
if edge == "right":
|
||||
fake_center = vector(ur.x + self.track_wire * 2, c.y)
|
||||
if edge == "top":
|
||||
fake_center = vector(c.x, ur.y + self.track_wire * 2)
|
||||
|
||||
# Create the fake pin shape
|
||||
layer = self.get_layer(int(not vertical))
|
||||
half_wire_vector = vector([self.half_wire] * 2)
|
||||
nll = fake_center - half_wire_vector
|
||||
nur = fake_center + half_wire_vector
|
||||
rect = [nll, nur]
|
||||
pin = graph_shape(name="fake",
|
||||
rect=rect,
|
||||
layer_name_pp=layer)
|
||||
return pin
|
||||
|
||||
|
||||
def get_route_pairs(self, pin_names):
|
||||
|
|
@ -151,7 +215,7 @@ class signal_escape_router(router):
|
|||
to_route = []
|
||||
for name in pin_names:
|
||||
pin = next(iter(self.pins[name]))
|
||||
fake = self.get_closest_perimeter_fake_pin(pin)
|
||||
fake = self.create_fake_pin(pin)
|
||||
to_route.append((pin, fake, pin.distance(fake)))
|
||||
return sorted(to_route, key=lambda x: x[2])
|
||||
|
||||
|
|
|
|||
|
|
@ -67,39 +67,29 @@ class supply_router(router):
|
|||
self.blockages.append(self.inflate_shape(pin))
|
||||
|
||||
# Route vdd and gnd
|
||||
routed_count = 0
|
||||
routed_max = len(self.pins[vdd_name]) + len(self.pins[gnd_name])
|
||||
for pin_name in [vdd_name, gnd_name]:
|
||||
pins = self.pins[pin_name]
|
||||
# Route closest pins according to the minimum spanning tree
|
||||
for source, target in self.get_mst_pairs(list(pins)):
|
||||
# This is the routing region scale
|
||||
scale = 1
|
||||
while True:
|
||||
# Create the graph
|
||||
g = graph(self)
|
||||
region = g.create_graph(source, target, scale)
|
||||
# Find the shortest path from source to target
|
||||
path = g.find_shortest_path()
|
||||
# If there is no path found, exponentially try again with a
|
||||
# larger routing region
|
||||
if path is None:
|
||||
rll, rur = region
|
||||
bll, bur = self.bbox
|
||||
# Stop scaling the region and throw an error
|
||||
if rll.x < bll.x and rll.y < bll.y and \
|
||||
rur.x > bur.x and rur.y > bur.y:
|
||||
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
|
||||
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
|
||||
# Exponentially scale the region
|
||||
scale *= 2
|
||||
debug.info(0, "Retry routing in larger routing region with scale {}".format(scale))
|
||||
continue
|
||||
# Create the path shapes on layout
|
||||
self.add_path(path)
|
||||
# Find the recently added shapes
|
||||
self.prepare_gds_reader()
|
||||
self.find_blockages(pin_name)
|
||||
self.find_vias()
|
||||
break
|
||||
# Create the graph
|
||||
g = graph(self)
|
||||
g.create_graph(source, target)
|
||||
# Find the shortest path from source to target
|
||||
path = g.find_shortest_path()
|
||||
# If no path is found, throw an error
|
||||
if path is None:
|
||||
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
|
||||
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
|
||||
# Create the path shapes on layout
|
||||
new_wires, new_vias = self.add_path(path)
|
||||
# Find the recently added shapes
|
||||
self.find_blockages(pin_name, new_wires)
|
||||
self.find_vias(new_vias)
|
||||
# Report routed count
|
||||
routed_count += 1
|
||||
debug.info(2, "Routed {} of {} supply pins".format(routed_count, routed_max))
|
||||
|
||||
|
||||
def add_side_pin(self, pin_name, side, num_vias=3, num_fake_pins=4):
|
||||
|
|
|
|||
Loading…
Reference in New Issue