diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 86999158..7612220b 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -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 @@ -75,9 +76,51 @@ class signal_escape_router(router): self.replace_layout_pins() + 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 + ll_diff_x = abs(c.x - ll.x) + ll_diff_y = abs(c.y - ll.y) + ur_diff_x = abs(c.x - ur.x) + ur_diff_y = abs(c.y - ur.y) + min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y) + + if min_diff == ll_diff_x: + fake_center = vector3d(ll.x + self.half_wire, c.y, c.z) + if min_diff == ll_diff_y: + fake_center = vector3d(c.x, ll.y + self.half_wire, c.z) + if min_diff == ur_diff_x: + fake_center = vector3d(ur.x - self.half_wire, c.y, c.z) + if min_diff == ur_diff_y: + 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 @@ -118,17 +161,44 @@ 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 + ll_diff_x = abs(c.x - ll.x) + ll_diff_y = abs(c.y - ll.y) + ur_diff_x = abs(c.x - ur.x) + ur_diff_y = abs(c.y - ur.y) + min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y) + + # 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 min_diff == ll_diff_x: + fake_center = vector(ll.x - self.track_wire * 2, c.y) + vertical = True + if min_diff == ll_diff_y: + fake_center = vector(c.x, ll.y - self.track_wire * 2) + vertical = False + if min_diff == ur_diff_x: + fake_center = vector(ur.x + self.track_wire * 2, c.y) + vertical = True + if min_diff == ur_diff_y: + fake_center = vector(c.x, ur.y + self.track_wire * 2) + vertical = False + + # 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): @@ -137,7 +207,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])