From 821c763a1e06cf787284d94e6f0487528e46ff51 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sat, 29 Jul 2023 20:01:58 -0700 Subject: [PATCH] Cleanup graph router --- compiler/router/graph.py | 12 +++++-- compiler/router/graph_router.py | 64 ++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/compiler/router/graph.py b/compiler/router/graph.py index 9cbf8292..d65f8d48 100644 --- a/compiler/router/graph.py +++ b/compiler/router/graph.py @@ -46,6 +46,7 @@ class graph: def get_safe_pin_values(self, pin): """ Get the safe x and y values of the given pin. """ + # Constant values pin = pin.get_core() offset = self.router.offset spacing = self.router.track_space @@ -53,6 +54,9 @@ class graph: x_values = [] y_values = [] + # If one axis size of the pin is greater than the limit, we will take + # two points at both ends. Otherwise, we will only take the center of + # this pin. if pin.width() > size_limit: x_values.append(snap(pin.lx() + offset)) x_values.append(snap(pin.rx() - offset)) @@ -105,14 +109,16 @@ class graph: spacing = self.router.track_space + offset + drc["grid"] blocked = False for blockage in self.graph_blockages: - # Check if two shapes overlap + # Check if the node is inside the blockage if self.inside_shape(node.center, blockage): if not self.is_routable(blockage): blocked = True continue blockage = blockage.get_core() + # Check if the node is inside the blockage's core if self.inside_shape(node.center, blockage): p = node.center + # Check if the node is too close to one edge of the shape lengths = [blockage.width(), blockage.height()] centers = blockage.center() ll, ur = blockage.rect @@ -127,6 +133,7 @@ class graph: if not all(safe): blocked = True continue + # Check if the node is in a safe region of the shape xs, ys = self.get_safe_pin_values(blockage) xdiff = closest(p.x, xs) ydiff = closest(p.y, ys) @@ -251,6 +258,7 @@ class graph: for shape in self.graph_blockages: if not self.is_routable(shape): continue + # Get the safe pin values xs, ys = self.get_safe_pin_values(shape) x_values.update(xs) y_values.update(ys) @@ -259,9 +267,9 @@ class graph: offset = vector(drc["grid"], drc["grid"]) for blockage in self.graph_blockages: ll, ur = blockage.rect + # Add minimum offset to the blockage corner nodes to prevent overlap nll = snap(ll - offset) nur = snap(ur + offset) - # Add minimum offset to the blockage corner nodes to prevent overlap x_values.update([nll.x, nur.x]) y_values.update([nll.y, nur.y]) diff --git a/compiler/router/graph_router.py b/compiler/router/graph_router.py index 27a903ff..b7bb81cb 100644 --- a/compiler/router/graph_router.py +++ b/compiler/router/graph_router.py @@ -53,7 +53,7 @@ class graph_router(router_tech): self.fake_pins = [] # Set the offset here - self.offset = snap(self.layer_widths[0] / 2) + self.offset = snap(self.track_wire / 2) def route(self, vdd_name="vdd", gnd_name="gnd"): @@ -149,8 +149,11 @@ class graph_router(router_tech): merger_core = merger.get_core() for shape in list(shape_list): shape_core = shape.get_core() + # If merger contains the shape, remove it from the list if merger_core.contains(shape_core): shape_list.remove(shape) + # If the merger aligns with the shape, expand the merger and remove + # the shape from the list elif merger_core.aligns(shape_core): merger.bbox([shape]) merger_core.bbox([shape_core]) @@ -173,7 +176,7 @@ class graph_router(router_tech): # Skip this pin if it's contained by another pin of the same type if new_pin.core_contained_by_any(pin_set): continue - # Remove any previous pin of the same type contained by this new pin + # Merge previous pins into this one if possible self.merge_shapes(new_pin, pin_set) pin_set.add(new_pin) # Add these pins to the 'pins' dict @@ -181,7 +184,7 @@ class graph_router(router_tech): self.all_pins.update(pin_set) - def find_blockages(self, shape_name=None): + def find_blockages(self, name="blockage"): """ Find all blockages in the routing layers. """ debug.info(2, "Finding blockages...") @@ -192,19 +195,14 @@ class graph_router(router_tech): ll = vector(boundary[0], boundary[1]) ur = vector(boundary[2], boundary[3]) rect = [ll, ur] - if shape_name is None: - name = "blockage" - else: - name = shape_name new_shape = graph_shape(name, rect, lpp) new_shape = self.inflate_shape(new_shape) - # If there is a rectangle that is the same in the pins, - # it isn't a blockage - # Also ignore the new pins + # Skip this blockage if it's contained by a pin or an existing + # blockage if new_shape.core_contained_by_any(self.all_pins) or \ new_shape.core_contained_by_any(self.blockages): continue - # Remove blockages contained by this new blockage + # Merge previous blockages into this one if possible self.merge_shapes(new_shape, self.blockages) self.blockages.append(new_shape) @@ -225,43 +223,47 @@ class graph_router(router_tech): ur = vector(boundary[2], boundary[3]) rect = [ll, ur] new_shape = graph_shape("via", rect, valid_lpp) - # If there is a rectangle that is the same in the pins, - # it isn't a blockage - # Also ignore the new pins + # Skip this via if it's contained by an existing via blockage if new_shape.contained_by_any(self.vias): continue self.vias.append(self.inflate_shape(new_shape, is_via=True)) def convert_vias(self): - """ Convert the vias that overlap a pin. """ + """ Convert vias that overlap a pin. """ for via in self.vias: via_core = via.get_core() for pin in self.all_pins: pin_core = pin.get_core() via_core.lpp = pin_core.lpp + # If the via overlaps a pin, change its name if via_core.overlaps(pin_core): via.rename(pin.name) break def convert_blockages(self): - """ Convert the blockages that overlap a pin. """ + """ Convert blockages that overlap a pin. """ + # NOTE: You need to run `convert_vias()` before since a blockage may + # be connected to a pin through a via. for blockage in self.blockages: blockage_core = blockage.get_core() for pin in self.all_pins: pin_core = pin.get_core() + # If the blockage overlaps a pin, change its name if blockage_core.overlaps(pin_core): blockage.rename(pin.name) break else: for via in self.vias: + # Skip if this via isn't connected to a pin if via.name == "via": continue via_core = via.get_core() via_core.lpp = blockage_core.lpp + # If the blockage overlaps a pin via, change its name if blockage_core.overlaps(via_core): blockage.rename(via.name) break @@ -297,11 +299,14 @@ class graph_router(router_tech): extra_spacing=self.offset) - def calculate_ring_bbox(self, width=3): + def calculate_ring_bbox(self, num_vias=3): """ Calculate the ring-safe bounding box of the layout. """ ll, ur = self.design.get_bbox() - wideness = self.track_wire * width + self.track_space * (width - 1) + # Calculate the "wideness" of a side supply pin + wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1) + # Total wideness is used to find it any pin overlaps in this region. If + # so, the bbox is shifted to prevent this overlap. total_wideness = wideness * 4 for blockage in self.blockages: bll, bur = blockage.rect @@ -322,7 +327,7 @@ class graph_router(router_tech): self.ring_bbox = [ll, ur] - def add_side_pin(self, pin_name, side, width=3, num_connects=4): + def add_side_pin(self, pin_name, side, num_vias=3, num_fake_pins=4): """ Add supply pin to one side of the layout. """ ll, ur = self.ring_bbox @@ -330,7 +335,7 @@ class graph_router(router_tech): inner = pin_name == self.gnd_name # Calculate wires' wideness - wideness = self.track_wire * width + self.track_space * (width - 1) + wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1) # Calculate the offset for the inner ring if inner: @@ -373,12 +378,12 @@ class graph_router(router_tech): # Add fake pins on this new pin evenly fake_pins = [] if vertical: - space = (shape_height - (2 * wideness) - num_connects * self.track_wire) / (num_connects + 1) + space = (shape_height - (2 * wideness) - num_fake_pins * self.track_wire) / (num_fake_pins + 1) start_offset = vector(offset.x, offset.y + wideness) else: - space = (shape_width - (2 * wideness) - num_connects * self.track_wire) / (num_connects + 1) + space = (shape_width - (2 * wideness) - num_fake_pins * self.track_wire) / (num_fake_pins + 1) start_offset = vector(offset.x + wideness, offset.y) - for i in range(1, num_connects + 1): + for i in range(1, num_fake_pins + 1): if vertical: offset = vector(start_offset.x, start_offset.y + i * (space + self.track_wire)) ll = vector(offset.x, offset.y - self.track_wire) @@ -395,13 +400,13 @@ class graph_router(router_tech): return pin, fake_pins - def add_ring_pin(self, pin_name, width=3, num_connects=4): + def add_ring_pin(self, pin_name, num_vias=3, num_fake_pins=4): """ Add the supply ring to the layout. """ # Add side pins new_pins = [] for side in ["top", "bottom", "right", "left"]: - new_shape, fake_pins = self.add_side_pin(pin_name, side, width, num_connects) + new_shape, fake_pins = self.add_side_pin(pin_name, side, num_vias, num_fake_pins) ll, ur = new_shape.rect rect = [ll, ur] layer = self.get_layer(side in ["left", "right"]) @@ -418,11 +423,11 @@ class graph_router(router_tech): for i in range(4): ll, ur = new_pins[i].rect if i % 2: - top_left = vector(ur.x - (width - 1) * shift - half_wide, ll.y + (width - 1) * shift + half_wide) + top_left = vector(ur.x - (num_vias - 1) * shift - half_wide, ll.y + (num_vias - 1) * shift + half_wide) else: top_left = vector(ll.x + half_wide, ur.y - half_wide) - for j in range(width): - for k in range(width): + for j in range(num_vias): + for k in range(num_vias): offset = vector(top_left.x + j * shift, top_left.y - k * shift) self.design.add_via_center(layers=self.layers, offset=offset) @@ -572,6 +577,9 @@ class graph_router(router_tech): self.design.add_label(text="n{}".format(node.center.z), layer="text", offset=offset) + #debug.info(0, "Neighbors of {}".format(node.center)) + #for neighbor in node.neighbors: + # debug.info(0, " {}".format(neighbor.center)) else: for blockage in self.blockages: self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp)))