From ca5ca0c7a8c9bc49200d9b943b43b41850bf2e5a Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sat, 26 Aug 2023 15:29:08 -0500 Subject: [PATCH 1/9] bump sram library commit to fix colenda gds --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 18768dd4..dc07a5b1 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git # Use this for development #SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_LIB_GIT_COMMIT ?= 060f3638be6269dd9aa82cfbbdfd9525943c1582 +SRAM_LIB_GIT_COMMIT ?= 9fcf3a78398037583b6d6c1ebac71957343c4bd8 # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks From 0ac2922573acde8440255e7e05d243abf5db1404 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Sat, 26 Aug 2023 22:17:23 +0000 Subject: [PATCH 2/9] Bump version: 1.2.29 -> 1.2.30 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 550c9e96..d20e7484 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.29 +1.2.30 From 141a4e3380feb1e499cd0978cf72f2b162e9994c Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 27 Aug 2023 15:42:09 -0700 Subject: [PATCH 3/9] Don't scale the routing region if no path is found --- compiler/router/graph.py | 6 +--- compiler/router/graph_shape.py | 11 ------ compiler/router/signal_escape_router.py | 46 +++++++++---------------- compiler/router/supply_router.py | 44 ++++++++--------------- 4 files changed, 32 insertions(+), 75 deletions(-) diff --git a/compiler/router/graph.py b/compiler/router/graph.py index 132681c9..68454937 100644 --- a/compiler/router/graph.py +++ b/compiler/router/graph.py @@ -184,7 +184,7 @@ class graph: return False - def create_graph(self, source, target, scale=1): + def create_graph(self, source, target): """ Create the graph to run routing on later. """ debug.info(2, "Creating the graph for source '{}' and target'{}'.".format(source, target)) @@ -195,7 +195,6 @@ 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)) @@ -221,9 +220,6 @@ class graph: 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))) - # Return the region to scale later if no path is found - return region.rect - def find_graph_blockages(self, region): """ Find blockages that overlap the routing region. """ diff --git a/compiler/router/graph_shape.py b/compiler/router/graph_shape.py index 1221dabe..0f950ae4 100644 --- a/compiler/router/graph_shape.py +++ b/compiler/router/graph_shape.py @@ -72,17 +72,6 @@ class graph_shape(pin_layout): return graph_shape(self.name, inflated_area, self.layer, self) - def multiply(self, scale): - """ Multiply the width and height with the scale value. """ - - width = (self.width() * (scale - 1)) / 2 - height = (self.height() * (scale - 1)) / 2 - ll, ur = self.rect - newll = vector(ll.x - width, ll.y - height) - newur = vector(ur.x + width, ur.y + height) - self.rect = [snap(newll), snap(newur)] - - def core_contained_by_any(self, shape_list): """ Return if the core of this shape is contained by any shape's core in the diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 5e4ae66e..047dcfee 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -56,36 +56,22 @@ class signal_escape_router(router): 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_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() self.replace_layout_pins() diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index f6acd24c..037e8868 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -71,35 +71,21 @@ class supply_router(router): 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) + region = 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 + self.add_path(path) + # Find the recently added shapes + self.prepare_gds_reader() + self.find_blockages(pin_name) + self.find_vias() def add_side_pin(self, pin_name, side, num_vias=3, num_fake_pins=4): From 9df3c2ac5997cedbb6b9a220c48d67743b4defb4 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 27 Aug 2023 21:15:25 -0700 Subject: [PATCH 4/9] Return the path in source-to-target order --- compiler/router/graph.py | 1 + compiler/router/signal_escape_router.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/router/graph.py b/compiler/router/graph.py index 68454937..dc9f5c40 100644 --- a/compiler/router/graph.py +++ b/compiler/router/graph.py @@ -418,6 +418,7 @@ class graph: path.append(current) current = came_from[current.id] path.append(current) + path.reverse() return path # Get the previous node to better calculate the next costs diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 047dcfee..86999158 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -67,7 +67,7 @@ class signal_escape_router(router): debug.error("Couldn't route from {} to {}.".format(source, target), -1) # Create the path shapes on layout new_shapes = self.add_path(path) - self.new_pins[source.name] = new_shapes[0] + self.new_pins[source.name] = new_shapes[-1] # Find the recently added shapes self.prepare_gds_reader() self.find_blockages(name) From 53cc99f5c1ec5a2401c70e5e7c6831282a46250a Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 27 Aug 2023 21:16:34 -0700 Subject: [PATCH 5/9] Perform signal escape routing in smaller regions --- compiler/router/signal_escape_router.py | 92 ++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) 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]) From e12ab68362f30cc3cbec495798d08aeaa5a72680 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 28 Aug 2023 10:38:53 -0700 Subject: [PATCH 6/9] Simplify closest edge calculation in signal escape router --- compiler/router/signal_escape_router.py | 57 ++++++++++++++----------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 7612220b..18a3d45e 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -76,6 +76,27 @@ class signal_escape_router(router): 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 @@ -88,28 +109,20 @@ class signal_escape_router(router): 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: + edge, _ = self.get_closest_edge(c) + if edge == "left": fake_center = vector3d(ll.x + self.half_wire, c.y, c.z) - if min_diff == ll_diff_y: + if edge == "bottom": fake_center = vector3d(c.x, ll.y + self.half_wire, c.z) - if min_diff == ur_diff_x: + if edge == "right": fake_center = vector3d(ur.x - self.half_wire, c.y, c.z) - if min_diff == ur_diff_y: + if edge == "top": fake_center = vector3d(c.x, ur.y - self.half_wire, c.z) - node.center = fake_center new_nodes.append(node) break @@ -168,26 +181,18 @@ class signal_escape_router(router): 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) + 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 min_diff == ll_diff_x: + if edge == "left": fake_center = vector(ll.x - self.track_wire * 2, c.y) - vertical = True - if min_diff == ll_diff_y: + if edge == "bottom": fake_center = vector(c.x, ll.y - self.track_wire * 2) - vertical = False - if min_diff == ur_diff_x: + if edge == "right": fake_center = vector(ur.x + self.track_wire * 2, c.y) - vertical = True - if min_diff == ur_diff_y: + if edge == "top": 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)) From b525ba60a09a155612b7556f236a810249c1d404 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Mon, 28 Aug 2023 21:12:21 +0000 Subject: [PATCH 7/9] Bump version: 1.2.30 -> 1.2.31 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d20e7484..0848465b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.30 +1.2.31 From 56bee27ee32596f2aead7d2bd0eceb6d6d5745dd Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Tue, 29 Aug 2023 21:45:52 -0700 Subject: [PATCH 8/9] Don't write/read gds files unnecessarily for router --- compiler/router/router.py | 62 +++++++++++++++++-------- compiler/router/signal_escape_router.py | 9 ++-- compiler/router/supply_router.py | 9 ++-- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index fe445ae1..c498a815 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -59,6 +59,8 @@ class router(router_tech): def prepare_gds_reader(self): """ Write the current layout to a temporary file to read the layout. """ + # NOTE: Avoid using this function if possible since it is too slow to + # write/read these files self.design.gds_write(self.gds_filename) self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) self.reader = gdsMill.Gds2reader(self.layout) @@ -109,16 +111,26 @@ class router(router_tech): self.all_pins.update(pin_set) - def find_blockages(self, name="blockage"): + def find_blockages(self, name="blockage", shape_list=None): """ Find all blockages in the routing layers. """ debug.info(2, "Finding blockages...") for lpp in [self.vert_lpp, self.horiz_lpp]: - shapes = self.layout.getAllShapes(lpp) + # If the list of shapes is given, don't get them from gdsMill + if shape_list is None: + shapes = self.layout.getAllShapes(lpp) + else: + shapes = shape_list for boundary in shapes: - # gdsMill boundaries are in (left, bottom, right, top) order - ll = vector(boundary[0], boundary[1]) - ur = vector(boundary[2], boundary[3]) + if shape_list is not None: + if boundary.lpp != lpp: + continue + ll = boundary.ll() + ur = boundary.ur() + else: + # gdsMill boundaries are in (left, bottom, right, top) order + ll = vector(boundary[0], boundary[1]) + ur = vector(boundary[2], boundary[3]) rect = [ll, ur] new_shape = graph_shape(name, rect, lpp) new_shape = self.inflate_shape(new_shape) @@ -132,20 +144,28 @@ class router(router_tech): self.blockages.append(new_shape) - def find_vias(self): + def find_vias(self, shape_list=None): """ Find all vias in the routing layers. """ debug.info(2, "Finding vias...") # Prepare lpp values here from openram.tech import layer via_lpp = layer[self.via_layer_name] - valid_lpp = self.horiz_lpp + valid_lpp = self.horiz_lpp # Just a temporary lpp to prevent errors - shapes = self.layout.getAllShapes(via_lpp) + # If the list of shapes is given, don't get them from gdsMill + if shape_list is None: + shapes = self.layout.getAllShapes(via_lpp) + else: + shapes = shape_list for boundary in shapes: - # gdsMill boundaries are in (left, bottom, right, top) order - ll = vector(boundary[0], boundary[1]) - ur = vector(boundary[2], boundary[3]) + if shape_list is not None: + ll = boundary.ll() + ur = boundary.ur() + else: + # gdsMill boundaries are in (left, bottom, right, top) order + ll = vector(boundary[0], boundary[1]) + ur = vector(boundary[2], boundary[3]) rect = [ll, ur] new_shape = graph_shape("via", rect, valid_lpp) # Skip this via if it's contained by an existing via blockage @@ -264,7 +284,8 @@ class router(router_tech): working for this router. """ - new_shapes = [] + new_wires = [] + new_vias = [] for i in range(0, len(nodes) - 1): start = nodes[i].center end = nodes[i + 1].center @@ -275,15 +296,16 @@ class router(router_tech): offset.y - self.half_wire) if direction == (1, 1): # Via offset = vector(start.x, start.y) - self.design.add_via_center(layers=self.layers, - offset=offset) + via = self.design.add_via_center(layers=self.layers, + offset=offset) + new_vias.append(via) else: # Wire - shape = self.design.add_rect(layer=self.get_layer(start.z), - offset=offset, - width=abs(diff.x) + self.track_wire, - height=abs(diff.y) + self.track_wire) - new_shapes.append(shape) - return new_shapes + wire = self.design.add_rect(layer=self.get_layer(start.z), + offset=offset, + width=abs(diff.x) + self.track_wire, + height=abs(diff.y) + self.track_wire) + new_wires.append(wire) + return new_wires, new_vias def write_debug_gds(self, gds_name, g=None, source=None, target=None): diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 18a3d45e..21cae924 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -67,12 +67,11 @@ class signal_escape_router(router): 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_shapes = self.add_path(path) - self.new_pins[source.name] = new_shapes[-1] + new_wires, new_vias = self.add_path(path) + self.new_pins[source.name] = new_wires[-1] # Find the recently added shapes - self.prepare_gds_reader() - self.find_blockages(name) - self.find_vias() + self.find_blockages(name, new_wires) + self.find_vias(new_vias) self.replace_layout_pins() diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 037e8868..3cdcc4e6 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -73,7 +73,7 @@ class supply_router(router): for source, target in self.get_mst_pairs(list(pins)): # Create the graph g = graph(self) - region = g.create_graph(source, target) + 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 @@ -81,11 +81,10 @@ class supply_router(router): 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 - self.add_path(path) + new_wires, new_vias = self.add_path(path) # Find the recently added shapes - self.prepare_gds_reader() - self.find_blockages(pin_name) - self.find_vias() + self.find_blockages(pin_name, new_wires) + self.find_vias(new_vias) def add_side_pin(self, pin_name, side, num_vias=3, num_fake_pins=4): From b2817717530ee64fba2065f95558938ce60f7546 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Wed, 30 Aug 2023 16:52:07 +0000 Subject: [PATCH 9/9] Bump version: 1.2.31 -> 1.2.32 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0848465b..37258517 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.31 +1.2.32