diff --git a/compiler/router/hanan_graph.py b/compiler/router/hanan_graph.py index fa92e4bf..02b17aa5 100644 --- a/compiler/router/hanan_graph.py +++ b/compiler/router/hanan_graph.py @@ -48,7 +48,7 @@ class hanan_graph: for blockage in self.graph_blockages: # Check if two shapes overlap # Inflated blockages of pins don't block probes - if blockage.overlaps(probe_shape) and blockage.name != self.source.name: + if blockage.overlaps(probe_shape) and (blockage.name != self.source.name or not blockage.inflated_from.overlaps(probe_shape)): return True return False @@ -69,6 +69,9 @@ class hanan_graph: # Find the blockages that are in the routing area self.graph_blockages = [] for blockage in self.router.blockages: + # FIXME: Include pins as blockages as well to prevent DRC errors + if blockage.name == self.source.name: + continue # Set the region's lpp to current blockage's lpp so that the # overlaps method works region.lpp = blockage.lpp @@ -92,10 +95,9 @@ class hanan_graph: x_values = set() y_values = set() - # Add the source and target values - offset = self.router.layer_widths[0] / 2 - x_offset = vector(offset, 0) - y_offset = vector(0, offset) + # Add inner values for blockages of the routed type + x_offset = vector(self.router.offset, 0) + y_offset = vector(0, self.router.offset) for shape in [self.source, self.target]: aspect_ratio = shape.width() / shape.height() # If the pin is tall or fat, add two points on the ends diff --git a/compiler/router/hanan_router.py b/compiler/router/hanan_router.py index d222b37e..439d113b 100644 --- a/compiler/router/hanan_router.py +++ b/compiler/router/hanan_router.py @@ -31,6 +31,9 @@ class hanan_router(router_tech): self.all_pins = set() self.blockages = [] + # Set the offset here + self.offset = self.layer_widths[0] / 2 + def route(self, vdd_name="vdd", gnd_name="gnd"): """ Route the given pins in the given order. """ @@ -38,10 +41,7 @@ class hanan_router(router_tech): self.write_debug_gds(gds_name="before.gds") # Prepare gdsMill to find pins and blockages - self.design.gds_write(self.gds_filename) - self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) - self.reader = gdsMill.Gds2reader(self.layout) - self.reader.loadFromFile(self.gds_filename) + self.prepare_gds_reader() # Find pins to be routed self.find_pins(vdd_name) @@ -50,23 +50,40 @@ class hanan_router(router_tech): # Find blockages self.find_blockages() + # Add vdd and gnd pins as blockages as well + # NOTE: This is done to make vdd and gnd pins DRC-safe + for pin in self.all_pins: + self.blockages.append(pin.inflated_pin(multiple=1, extra_spacing=self.offset, keep_link=True)) + # Route vdd and gnd for pin_name in [vdd_name, gnd_name]: pins = self.pins[pin_name] # Create minimum spanning tree connecting all pins for source, target in self.get_mst_pairs(list(pins)): - # Create the hanan graph + # Create the Hanan graph hg = hanan_graph(self) hg.create_graph(source, target) # Find the shortest path from source to target path = hg.find_shortest_path() - debug.check(path is not None, "Couldn't route {} to {}".format(source, target)) + debug.check(path is not None, "Couldn't route from {} to {}".format(source, target)) # 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.write_debug_gds(gds_name="after.gds") + def prepare_gds_reader(self): + """ """ + + self.design.gds_write(self.gds_filename) + self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) + self.reader = gdsMill.Gds2reader(self.layout) + self.reader.loadFromFile(self.gds_filename) + + def find_pins(self, pin_name): """ """ debug.info(1, "Finding all pins for {}".format(pin_name)) @@ -80,16 +97,28 @@ class hanan_router(router_tech): ll = vector(boundary[0], boundary[1]) ur = vector(boundary[2], boundary[3]) rect = [ll, ur] - pin = hanan_shape(pin_name, rect, layer) - pin_set.add(pin) + new_pin = hanan_shape(pin_name, rect, layer) + # Skip this pin if it's contained by another pin of the same type + if new_pin.contained_by_any(pin_set): + continue + # Remove any previous pin of the same type contained by this new pin + for pin in list(pin_set): + if new_pin.contains(pin): + pin_set.remove(pin) + elif new_pin.aligns(pin): + new_pin.bbox([pin]) + pin_set.remove(pin) + pin_set.add(new_pin) # Add these pins to the 'pins' dict self.pins[pin_name] = pin_set self.all_pins.update(pin_set) - def find_blockages(self): + def find_blockages(self, shape_name=None): """ """ - debug.info(1, "Finding all blockages...") + debug.info(1, "Finding blockages...") + + prev_blockages = self.blockages[:] blockages = [] for lpp in [self.vert_lpp, self.horiz_lpp]: @@ -100,12 +129,16 @@ class hanan_router(router_tech): ll = vector(boundary[0], boundary[1]) ur = vector(boundary[2], boundary[3]) rect = [ll, ur] - new_shape = hanan_shape("blockage{}".format(len(blockages)), - rect, - lpp) + if shape_name is None: + name = "blockage{}".format(len(blockages)) + else: + name = shape_name + new_shape = hanan_shape(name, rect, lpp) # If there is a rectangle that is the same in the pins, # it isn't a blockage - if new_shape.contained_by_any(self.all_pins) or new_shape.contained_by_any(blockages): + if new_shape.contained_by_any(self.all_pins) or \ + new_shape.contained_by_any(prev_blockages) or \ + new_shape.contained_by_any(blockages): continue # Remove blockages contained by this new blockage for i in range(len(blockages) - 1, -1, -1): @@ -122,14 +155,24 @@ class hanan_router(router_tech): blockages.append(new_shape) # Inflate the shapes to prevent DRC errors - offset = self.layer_widths[0] / 2 for blockage in blockages: - self.blockages.append(blockage.inflated_pin(multiple=1, extra_spacing=offset)) - - # Add vdd and gnd pins as blockages as well - # NOTE: This is done to make vdd and gnd pins DRC-safe - for pin in self.all_pins: - self.blockages.append(pin.inflated_pin(multiple=1, extra_spacing=offset, keep_link=True)) + self.blockages.append(blockage.inflated_pin(multiple=1, + extra_spacing=self.offset, + keep_link=shape_name is not None)) + # Remove blockages contained by this new blockage + for i in range(len(prev_blockages) - 1, -1, -1): + prev_blockage = prev_blockages[i] + # Remove the previous blockage contained by this new + # blockage + if blockage.contains(prev_blockage): + prev_blockages.remove(prev_blockage) + self.blockages.remove(prev_blockage) + # Merge the previous blockage into this new blockage if + # they are aligning + elif blockage.aligns(prev_blockage): + blockage.bbox([prev_blockage]) + prev_blockages.remove(prev_blockage) + self.blockages.remove(prev_blockage) def get_mst_pairs(self, pins): @@ -214,26 +257,32 @@ class hanan_router(router_tech): return coordinates - def write_debug_gds(self, gds_name="debug_route.gds", source=None, target=None): + def write_debug_gds(self, gds_name="debug_route.gds", hg=None, source=None, target=None): """ """ - self.add_router_info(source, target) + self.add_router_info(hg, source, target) self.design.gds_write(gds_name) self.del_router_info() - def add_router_info(self, source=None, target=None): + def add_router_info(self, hg=None, source=None, target=None): """ """ # Display the inflated blockage - if "hg" in self.__dict__: - for blockage in self.hg.graph_blockages: - self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp))) - for node in self.hg.nodes: + if hg: + for blockage in self.blockages: + if blockage in hg.graph_blockages: + self.add_object_info(blockage, "blockage{}++[{}]".format(self.get_zindex(blockage.lpp), blockage.name)) + else: + self.add_object_info(blockage, "blockage{}[{}]".format(self.get_zindex(blockage.lpp), blockage.name)) + for node in hg.nodes: offset = (node.center.x, node.center.y) self.design.add_label(text="n{}".format(node.center.z), layer="text", offset=offset) + else: + for blockage in self.blockages: + self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp))) if source: self.add_object_info(source, "source") if target: