mirror of https://github.com/VLSIDA/OpenRAM.git
Include new wires while routing the pins
This commit is contained in:
parent
0938e7ec9a
commit
bb35ac2f90
|
|
@ -48,7 +48,7 @@ class hanan_graph:
|
||||||
for blockage in self.graph_blockages:
|
for blockage in self.graph_blockages:
|
||||||
# Check if two shapes overlap
|
# Check if two shapes overlap
|
||||||
# Inflated blockages of pins don't block probes
|
# 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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -69,6 +69,9 @@ class hanan_graph:
|
||||||
# Find the blockages that are in the routing area
|
# Find the blockages that are in the routing area
|
||||||
self.graph_blockages = []
|
self.graph_blockages = []
|
||||||
for blockage in self.router.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
|
# Set the region's lpp to current blockage's lpp so that the
|
||||||
# overlaps method works
|
# overlaps method works
|
||||||
region.lpp = blockage.lpp
|
region.lpp = blockage.lpp
|
||||||
|
|
@ -92,10 +95,9 @@ class hanan_graph:
|
||||||
x_values = set()
|
x_values = set()
|
||||||
y_values = set()
|
y_values = set()
|
||||||
|
|
||||||
# Add the source and target values
|
# Add inner values for blockages of the routed type
|
||||||
offset = self.router.layer_widths[0] / 2
|
x_offset = vector(self.router.offset, 0)
|
||||||
x_offset = vector(offset, 0)
|
y_offset = vector(0, self.router.offset)
|
||||||
y_offset = vector(0, offset)
|
|
||||||
for shape in [self.source, self.target]:
|
for shape in [self.source, self.target]:
|
||||||
aspect_ratio = shape.width() / shape.height()
|
aspect_ratio = shape.width() / shape.height()
|
||||||
# If the pin is tall or fat, add two points on the ends
|
# If the pin is tall or fat, add two points on the ends
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ class hanan_router(router_tech):
|
||||||
self.all_pins = set()
|
self.all_pins = set()
|
||||||
self.blockages = []
|
self.blockages = []
|
||||||
|
|
||||||
|
# Set the offset here
|
||||||
|
self.offset = self.layer_widths[0] / 2
|
||||||
|
|
||||||
|
|
||||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||||
""" Route the given pins in the given order. """
|
""" 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")
|
self.write_debug_gds(gds_name="before.gds")
|
||||||
|
|
||||||
# Prepare gdsMill to find pins and blockages
|
# Prepare gdsMill to find pins and blockages
|
||||||
self.design.gds_write(self.gds_filename)
|
self.prepare_gds_reader()
|
||||||
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
|
||||||
self.reader = gdsMill.Gds2reader(self.layout)
|
|
||||||
self.reader.loadFromFile(self.gds_filename)
|
|
||||||
|
|
||||||
# Find pins to be routed
|
# Find pins to be routed
|
||||||
self.find_pins(vdd_name)
|
self.find_pins(vdd_name)
|
||||||
|
|
@ -50,23 +50,40 @@ class hanan_router(router_tech):
|
||||||
# Find blockages
|
# Find blockages
|
||||||
self.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
|
# Route vdd and gnd
|
||||||
for pin_name in [vdd_name, gnd_name]:
|
for pin_name in [vdd_name, gnd_name]:
|
||||||
pins = self.pins[pin_name]
|
pins = self.pins[pin_name]
|
||||||
# Create minimum spanning tree connecting all pins
|
# Create minimum spanning tree connecting all pins
|
||||||
for source, target in self.get_mst_pairs(list(pins)):
|
for source, target in self.get_mst_pairs(list(pins)):
|
||||||
# Create the hanan graph
|
# Create the Hanan graph
|
||||||
hg = hanan_graph(self)
|
hg = hanan_graph(self)
|
||||||
hg.create_graph(source, target)
|
hg.create_graph(source, target)
|
||||||
# Find the shortest path from source to target
|
# Find the shortest path from source to target
|
||||||
path = hg.find_shortest_path()
|
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
|
# Create the path shapes on layout
|
||||||
self.add_path(path)
|
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")
|
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):
|
def find_pins(self, pin_name):
|
||||||
""" """
|
""" """
|
||||||
debug.info(1, "Finding all pins for {}".format(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])
|
ll = vector(boundary[0], boundary[1])
|
||||||
ur = vector(boundary[2], boundary[3])
|
ur = vector(boundary[2], boundary[3])
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
pin = hanan_shape(pin_name, rect, layer)
|
new_pin = hanan_shape(pin_name, rect, layer)
|
||||||
pin_set.add(pin)
|
# 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
|
# Add these pins to the 'pins' dict
|
||||||
self.pins[pin_name] = pin_set
|
self.pins[pin_name] = pin_set
|
||||||
self.all_pins.update(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 = []
|
blockages = []
|
||||||
for lpp in [self.vert_lpp, self.horiz_lpp]:
|
for lpp in [self.vert_lpp, self.horiz_lpp]:
|
||||||
|
|
@ -100,12 +129,16 @@ class hanan_router(router_tech):
|
||||||
ll = vector(boundary[0], boundary[1])
|
ll = vector(boundary[0], boundary[1])
|
||||||
ur = vector(boundary[2], boundary[3])
|
ur = vector(boundary[2], boundary[3])
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
new_shape = hanan_shape("blockage{}".format(len(blockages)),
|
if shape_name is None:
|
||||||
rect,
|
name = "blockage{}".format(len(blockages))
|
||||||
lpp)
|
else:
|
||||||
|
name = shape_name
|
||||||
|
new_shape = hanan_shape(name, rect, lpp)
|
||||||
# If there is a rectangle that is the same in the pins,
|
# If there is a rectangle that is the same in the pins,
|
||||||
# it isn't a blockage
|
# 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
|
continue
|
||||||
# Remove blockages contained by this new blockage
|
# Remove blockages contained by this new blockage
|
||||||
for i in range(len(blockages) - 1, -1, -1):
|
for i in range(len(blockages) - 1, -1, -1):
|
||||||
|
|
@ -122,14 +155,24 @@ class hanan_router(router_tech):
|
||||||
blockages.append(new_shape)
|
blockages.append(new_shape)
|
||||||
|
|
||||||
# Inflate the shapes to prevent DRC errors
|
# Inflate the shapes to prevent DRC errors
|
||||||
offset = self.layer_widths[0] / 2
|
|
||||||
for blockage in blockages:
|
for blockage in blockages:
|
||||||
self.blockages.append(blockage.inflated_pin(multiple=1, extra_spacing=offset))
|
self.blockages.append(blockage.inflated_pin(multiple=1,
|
||||||
|
extra_spacing=self.offset,
|
||||||
# Add vdd and gnd pins as blockages as well
|
keep_link=shape_name is not None))
|
||||||
# NOTE: This is done to make vdd and gnd pins DRC-safe
|
# Remove blockages contained by this new blockage
|
||||||
for pin in self.all_pins:
|
for i in range(len(prev_blockages) - 1, -1, -1):
|
||||||
self.blockages.append(pin.inflated_pin(multiple=1, extra_spacing=offset, keep_link=True))
|
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):
|
def get_mst_pairs(self, pins):
|
||||||
|
|
@ -214,26 +257,32 @@ class hanan_router(router_tech):
|
||||||
return coordinates
|
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.design.gds_write(gds_name)
|
||||||
self.del_router_info()
|
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
|
# Display the inflated blockage
|
||||||
if "hg" in self.__dict__:
|
if hg:
|
||||||
for blockage in self.hg.graph_blockages:
|
for blockage in self.blockages:
|
||||||
self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp)))
|
if blockage in hg.graph_blockages:
|
||||||
for node in self.hg.nodes:
|
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)
|
offset = (node.center.x, node.center.y)
|
||||||
self.design.add_label(text="n{}".format(node.center.z),
|
self.design.add_label(text="n{}".format(node.center.z),
|
||||||
layer="text",
|
layer="text",
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
else:
|
||||||
|
for blockage in self.blockages:
|
||||||
|
self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp)))
|
||||||
if source:
|
if source:
|
||||||
self.add_object_info(source, "source")
|
self.add_object_info(source, "source")
|
||||||
if target:
|
if target:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue