mirror of https://github.com/VLSIDA/OpenRAM.git
Cleanup graph router
This commit is contained in:
parent
3b0997e7cf
commit
821c763a1e
|
|
@ -46,6 +46,7 @@ class graph:
|
||||||
def get_safe_pin_values(self, pin):
|
def get_safe_pin_values(self, pin):
|
||||||
""" Get the safe x and y values of the given pin. """
|
""" Get the safe x and y values of the given pin. """
|
||||||
|
|
||||||
|
# Constant values
|
||||||
pin = pin.get_core()
|
pin = pin.get_core()
|
||||||
offset = self.router.offset
|
offset = self.router.offset
|
||||||
spacing = self.router.track_space
|
spacing = self.router.track_space
|
||||||
|
|
@ -53,6 +54,9 @@ class graph:
|
||||||
|
|
||||||
x_values = []
|
x_values = []
|
||||||
y_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:
|
if pin.width() > size_limit:
|
||||||
x_values.append(snap(pin.lx() + offset))
|
x_values.append(snap(pin.lx() + offset))
|
||||||
x_values.append(snap(pin.rx() - offset))
|
x_values.append(snap(pin.rx() - offset))
|
||||||
|
|
@ -105,14 +109,16 @@ class graph:
|
||||||
spacing = self.router.track_space + offset + drc["grid"]
|
spacing = self.router.track_space + offset + drc["grid"]
|
||||||
blocked = False
|
blocked = False
|
||||||
for blockage in self.graph_blockages:
|
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 self.inside_shape(node.center, blockage):
|
||||||
if not self.is_routable(blockage):
|
if not self.is_routable(blockage):
|
||||||
blocked = True
|
blocked = True
|
||||||
continue
|
continue
|
||||||
blockage = blockage.get_core()
|
blockage = blockage.get_core()
|
||||||
|
# Check if the node is inside the blockage's core
|
||||||
if self.inside_shape(node.center, blockage):
|
if self.inside_shape(node.center, blockage):
|
||||||
p = node.center
|
p = node.center
|
||||||
|
# Check if the node is too close to one edge of the shape
|
||||||
lengths = [blockage.width(), blockage.height()]
|
lengths = [blockage.width(), blockage.height()]
|
||||||
centers = blockage.center()
|
centers = blockage.center()
|
||||||
ll, ur = blockage.rect
|
ll, ur = blockage.rect
|
||||||
|
|
@ -127,6 +133,7 @@ class graph:
|
||||||
if not all(safe):
|
if not all(safe):
|
||||||
blocked = True
|
blocked = True
|
||||||
continue
|
continue
|
||||||
|
# Check if the node is in a safe region of the shape
|
||||||
xs, ys = self.get_safe_pin_values(blockage)
|
xs, ys = self.get_safe_pin_values(blockage)
|
||||||
xdiff = closest(p.x, xs)
|
xdiff = closest(p.x, xs)
|
||||||
ydiff = closest(p.y, ys)
|
ydiff = closest(p.y, ys)
|
||||||
|
|
@ -251,6 +258,7 @@ class graph:
|
||||||
for shape in self.graph_blockages:
|
for shape in self.graph_blockages:
|
||||||
if not self.is_routable(shape):
|
if not self.is_routable(shape):
|
||||||
continue
|
continue
|
||||||
|
# Get the safe pin values
|
||||||
xs, ys = self.get_safe_pin_values(shape)
|
xs, ys = self.get_safe_pin_values(shape)
|
||||||
x_values.update(xs)
|
x_values.update(xs)
|
||||||
y_values.update(ys)
|
y_values.update(ys)
|
||||||
|
|
@ -259,9 +267,9 @@ class graph:
|
||||||
offset = vector(drc["grid"], drc["grid"])
|
offset = vector(drc["grid"], drc["grid"])
|
||||||
for blockage in self.graph_blockages:
|
for blockage in self.graph_blockages:
|
||||||
ll, ur = blockage.rect
|
ll, ur = blockage.rect
|
||||||
|
# Add minimum offset to the blockage corner nodes to prevent overlap
|
||||||
nll = snap(ll - offset)
|
nll = snap(ll - offset)
|
||||||
nur = snap(ur + offset)
|
nur = snap(ur + offset)
|
||||||
# Add minimum offset to the blockage corner nodes to prevent overlap
|
|
||||||
x_values.update([nll.x, nur.x])
|
x_values.update([nll.x, nur.x])
|
||||||
y_values.update([nll.y, nur.y])
|
y_values.update([nll.y, nur.y])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class graph_router(router_tech):
|
||||||
self.fake_pins = []
|
self.fake_pins = []
|
||||||
|
|
||||||
# Set the offset here
|
# 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"):
|
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||||
|
|
@ -149,8 +149,11 @@ class graph_router(router_tech):
|
||||||
merger_core = merger.get_core()
|
merger_core = merger.get_core()
|
||||||
for shape in list(shape_list):
|
for shape in list(shape_list):
|
||||||
shape_core = shape.get_core()
|
shape_core = shape.get_core()
|
||||||
|
# If merger contains the shape, remove it from the list
|
||||||
if merger_core.contains(shape_core):
|
if merger_core.contains(shape_core):
|
||||||
shape_list.remove(shape)
|
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):
|
elif merger_core.aligns(shape_core):
|
||||||
merger.bbox([shape])
|
merger.bbox([shape])
|
||||||
merger_core.bbox([shape_core])
|
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
|
# Skip this pin if it's contained by another pin of the same type
|
||||||
if new_pin.core_contained_by_any(pin_set):
|
if new_pin.core_contained_by_any(pin_set):
|
||||||
continue
|
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)
|
self.merge_shapes(new_pin, pin_set)
|
||||||
pin_set.add(new_pin)
|
pin_set.add(new_pin)
|
||||||
# Add these pins to the 'pins' dict
|
# Add these pins to the 'pins' dict
|
||||||
|
|
@ -181,7 +184,7 @@ class graph_router(router_tech):
|
||||||
self.all_pins.update(pin_set)
|
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. """
|
""" Find all blockages in the routing layers. """
|
||||||
debug.info(2, "Finding blockages...")
|
debug.info(2, "Finding blockages...")
|
||||||
|
|
||||||
|
|
@ -192,19 +195,14 @@ class graph_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]
|
||||||
if shape_name is None:
|
|
||||||
name = "blockage"
|
|
||||||
else:
|
|
||||||
name = shape_name
|
|
||||||
new_shape = graph_shape(name, rect, lpp)
|
new_shape = graph_shape(name, rect, lpp)
|
||||||
new_shape = self.inflate_shape(new_shape)
|
new_shape = self.inflate_shape(new_shape)
|
||||||
# If there is a rectangle that is the same in the pins,
|
# Skip this blockage if it's contained by a pin or an existing
|
||||||
# it isn't a blockage
|
# blockage
|
||||||
# Also ignore the new pins
|
|
||||||
if new_shape.core_contained_by_any(self.all_pins) or \
|
if new_shape.core_contained_by_any(self.all_pins) or \
|
||||||
new_shape.core_contained_by_any(self.blockages):
|
new_shape.core_contained_by_any(self.blockages):
|
||||||
continue
|
continue
|
||||||
# Remove blockages contained by this new blockage
|
# Merge previous blockages into this one if possible
|
||||||
self.merge_shapes(new_shape, self.blockages)
|
self.merge_shapes(new_shape, self.blockages)
|
||||||
self.blockages.append(new_shape)
|
self.blockages.append(new_shape)
|
||||||
|
|
||||||
|
|
@ -225,43 +223,47 @@ class graph_router(router_tech):
|
||||||
ur = vector(boundary[2], boundary[3])
|
ur = vector(boundary[2], boundary[3])
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
new_shape = graph_shape("via", rect, valid_lpp)
|
new_shape = graph_shape("via", rect, valid_lpp)
|
||||||
# If there is a rectangle that is the same in the pins,
|
# Skip this via if it's contained by an existing via blockage
|
||||||
# it isn't a blockage
|
|
||||||
# Also ignore the new pins
|
|
||||||
if new_shape.contained_by_any(self.vias):
|
if new_shape.contained_by_any(self.vias):
|
||||||
continue
|
continue
|
||||||
self.vias.append(self.inflate_shape(new_shape, is_via=True))
|
self.vias.append(self.inflate_shape(new_shape, is_via=True))
|
||||||
|
|
||||||
|
|
||||||
def convert_vias(self):
|
def convert_vias(self):
|
||||||
""" Convert the vias that overlap a pin. """
|
""" Convert vias that overlap a pin. """
|
||||||
|
|
||||||
for via in self.vias:
|
for via in self.vias:
|
||||||
via_core = via.get_core()
|
via_core = via.get_core()
|
||||||
for pin in self.all_pins:
|
for pin in self.all_pins:
|
||||||
pin_core = pin.get_core()
|
pin_core = pin.get_core()
|
||||||
via_core.lpp = pin_core.lpp
|
via_core.lpp = pin_core.lpp
|
||||||
|
# If the via overlaps a pin, change its name
|
||||||
if via_core.overlaps(pin_core):
|
if via_core.overlaps(pin_core):
|
||||||
via.rename(pin.name)
|
via.rename(pin.name)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def convert_blockages(self):
|
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:
|
for blockage in self.blockages:
|
||||||
blockage_core = blockage.get_core()
|
blockage_core = blockage.get_core()
|
||||||
for pin in self.all_pins:
|
for pin in self.all_pins:
|
||||||
pin_core = pin.get_core()
|
pin_core = pin.get_core()
|
||||||
|
# If the blockage overlaps a pin, change its name
|
||||||
if blockage_core.overlaps(pin_core):
|
if blockage_core.overlaps(pin_core):
|
||||||
blockage.rename(pin.name)
|
blockage.rename(pin.name)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
for via in self.vias:
|
for via in self.vias:
|
||||||
|
# Skip if this via isn't connected to a pin
|
||||||
if via.name == "via":
|
if via.name == "via":
|
||||||
continue
|
continue
|
||||||
via_core = via.get_core()
|
via_core = via.get_core()
|
||||||
via_core.lpp = blockage_core.lpp
|
via_core.lpp = blockage_core.lpp
|
||||||
|
# If the blockage overlaps a pin via, change its name
|
||||||
if blockage_core.overlaps(via_core):
|
if blockage_core.overlaps(via_core):
|
||||||
blockage.rename(via.name)
|
blockage.rename(via.name)
|
||||||
break
|
break
|
||||||
|
|
@ -297,11 +299,14 @@ class graph_router(router_tech):
|
||||||
extra_spacing=self.offset)
|
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. """
|
""" Calculate the ring-safe bounding box of the layout. """
|
||||||
|
|
||||||
ll, ur = self.design.get_bbox()
|
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
|
total_wideness = wideness * 4
|
||||||
for blockage in self.blockages:
|
for blockage in self.blockages:
|
||||||
bll, bur = blockage.rect
|
bll, bur = blockage.rect
|
||||||
|
|
@ -322,7 +327,7 @@ class graph_router(router_tech):
|
||||||
self.ring_bbox = [ll, ur]
|
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. """
|
""" Add supply pin to one side of the layout. """
|
||||||
|
|
||||||
ll, ur = self.ring_bbox
|
ll, ur = self.ring_bbox
|
||||||
|
|
@ -330,7 +335,7 @@ class graph_router(router_tech):
|
||||||
inner = pin_name == self.gnd_name
|
inner = pin_name == self.gnd_name
|
||||||
|
|
||||||
# Calculate wires' wideness
|
# 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
|
# Calculate the offset for the inner ring
|
||||||
if inner:
|
if inner:
|
||||||
|
|
@ -373,12 +378,12 @@ class graph_router(router_tech):
|
||||||
# Add fake pins on this new pin evenly
|
# Add fake pins on this new pin evenly
|
||||||
fake_pins = []
|
fake_pins = []
|
||||||
if vertical:
|
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)
|
start_offset = vector(offset.x, offset.y + wideness)
|
||||||
else:
|
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)
|
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:
|
if vertical:
|
||||||
offset = vector(start_offset.x, start_offset.y + i * (space + self.track_wire))
|
offset = vector(start_offset.x, start_offset.y + i * (space + self.track_wire))
|
||||||
ll = vector(offset.x, offset.y - 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
|
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 the supply ring to the layout. """
|
||||||
|
|
||||||
# Add side pins
|
# Add side pins
|
||||||
new_pins = []
|
new_pins = []
|
||||||
for side in ["top", "bottom", "right", "left"]:
|
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
|
ll, ur = new_shape.rect
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
layer = self.get_layer(side in ["left", "right"])
|
layer = self.get_layer(side in ["left", "right"])
|
||||||
|
|
@ -418,11 +423,11 @@ class graph_router(router_tech):
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
ll, ur = new_pins[i].rect
|
ll, ur = new_pins[i].rect
|
||||||
if i % 2:
|
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:
|
else:
|
||||||
top_left = vector(ll.x + half_wide, ur.y - half_wide)
|
top_left = vector(ll.x + half_wide, ur.y - half_wide)
|
||||||
for j in range(width):
|
for j in range(num_vias):
|
||||||
for k in range(width):
|
for k in range(num_vias):
|
||||||
offset = vector(top_left.x + j * shift, top_left.y - k * shift)
|
offset = vector(top_left.x + j * shift, top_left.y - k * shift)
|
||||||
self.design.add_via_center(layers=self.layers,
|
self.design.add_via_center(layers=self.layers,
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
|
@ -572,6 +577,9 @@ class graph_router(router_tech):
|
||||||
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)
|
||||||
|
#debug.info(0, "Neighbors of {}".format(node.center))
|
||||||
|
#for neighbor in node.neighbors:
|
||||||
|
# debug.info(0, " {}".format(neighbor.center))
|
||||||
else:
|
else:
|
||||||
for blockage in self.blockages:
|
for blockage in self.blockages:
|
||||||
self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp)))
|
self.add_object_info(blockage, "blockage{}".format(self.get_zindex(blockage.lpp)))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue