mirror of https://github.com/VLSIDA/OpenRAM.git
Add initial files for navigation router
This commit is contained in:
parent
20744cdbcd
commit
909ac6ce68
|
|
@ -255,6 +255,8 @@ class sram_1bank(design, verilog, lef):
|
|||
return
|
||||
elif OPTS.route_supplies == "grid":
|
||||
from openram.router import supply_grid_router as router
|
||||
elif OPTS.route_supplies == "navigation":
|
||||
from openram.router import navigation_router as router
|
||||
else:
|
||||
from openram.router import supply_tree_router as router
|
||||
rtr=router(layers=self.supply_stack,
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@ from .signal_escape_router import *
|
|||
from .signal_router import *
|
||||
from .supply_grid_router import *
|
||||
from .supply_tree_router import *
|
||||
from .navigation_router import *
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
from openram.base.vector import vector
|
||||
from .navigation_node import navigation_node
|
||||
|
||||
|
||||
class navigation_blockage:
|
||||
""" This class represents a blockage on the navigation graph. """
|
||||
|
||||
def __init__(self, ll, ur):
|
||||
|
||||
self.ll = ll
|
||||
self.ur = ur
|
||||
|
||||
|
||||
def create_corner_nodes(self):
|
||||
""" Create nodes on all 4 corners of this blockage. """
|
||||
|
||||
corners = []
|
||||
corners.append(navigation_node(vector(self.ll[0], self.ll[1])))
|
||||
corners.append(navigation_node(vector(self.ll[0], self.ur[1])))
|
||||
corners.append(navigation_node(vector(self.ur[0], self.ll[1])))
|
||||
corners.append(navigation_node(vector(self.ur[0], self.ur[1])))
|
||||
corners[0].add_neighbor(corners[1])
|
||||
corners[0].add_neighbor(corners[2])
|
||||
corners[3].add_neighbor(corners[1])
|
||||
corners[3].add_neighbor(corners[2])
|
||||
return corners
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
from openram import debug
|
||||
from openram.base.vector import vector
|
||||
from .navigation_node import navigation_node
|
||||
from .navigation_blockage import navigation_blockage
|
||||
|
||||
|
||||
class navigation_graph:
|
||||
""" This is the navigation graph created from the blockages. """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def is_probe_blocked(self, p1, p2):
|
||||
"""
|
||||
Return if a probe sent from p1 to p2 encounters a blockage.
|
||||
The probe must be sent vertically or horizontally.
|
||||
This method assumes that blockages are rectangular.
|
||||
"""
|
||||
|
||||
# Check if any blockage blocks this probe
|
||||
for blockage in self.nav_blockages:
|
||||
right_x = blockage.ur[0]
|
||||
upper_y = blockage.ur[1]
|
||||
left_x = blockage.ll[0]
|
||||
lower_y = blockage.ll[1]
|
||||
# Check if blocked vertically
|
||||
if is_between(left_x, right_x, p1.x) and (is_between(p1.y, p2.y, upper_y) or is_between(p1.y, p2.y, lower_y)):
|
||||
return True
|
||||
# Check if blocked horizontally
|
||||
if is_between(upper_y, lower_y, p1.y) and (is_between(p1.x, p2.x, left_x) or is_between(p1.x, p2.x, right_x)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def create_graph(self, layout_source, layout_target, layout_blockages):
|
||||
""" """
|
||||
debug.info(0, "Creating the navigation graph for source '{0}' and target'{1}'.".format(layout_source, layout_target))
|
||||
|
||||
# Find the region to be routed and only include objects inside that region
|
||||
s_ll, sou_ur = layout_source.rect
|
||||
t_ll, tar_ur = layout_target.rect
|
||||
ll = vector(min(s_ll.x, t_ll.x), max(s_ll.y, t_ll.y))
|
||||
ur = vector(max(sou_ur.x, tar_ur.x), min(sou_ur.y, tar_ur.y))
|
||||
region = (ll, ur)
|
||||
|
||||
# Instantiate "navigation blockage" objects from layout blockages
|
||||
self.nav_blockages = []
|
||||
for layout_blockage in layout_blockages:
|
||||
ll, ur = layout_blockage.rect
|
||||
if (is_between(region[0].x, region[1].x, ll.x) and is_between(region[0].y, region[1].y, ll.y)) or \
|
||||
(is_between(region[0].x, region[1].x, ur.x) and is_between(region[0].y, region[1].y, ur.y)):
|
||||
self.nav_blockages.append(navigation_blockage(ll, ur))
|
||||
|
||||
self.nodes = []
|
||||
|
||||
# Add source and target for this graph
|
||||
self.nodes.append(navigation_node(layout_source.center()))
|
||||
self.nodes.append(navigation_node(layout_target.center()))
|
||||
|
||||
# Create the corner nodes
|
||||
for blockage in self.nav_blockages:
|
||||
self.nodes.extend(blockage.create_corner_nodes())
|
||||
|
||||
# Create intersection nodes
|
||||
# NOTE: Intersection nodes are used to connect boundaries of blockages
|
||||
# perpendicularly.
|
||||
new_nodes = []
|
||||
debug.info(0, "Number of blockages: {}".format(len(self.nav_blockages)))
|
||||
debug.info(0, "Number of nodes: {}".format(len(self.nodes)))
|
||||
for i in range(len(self.nodes)):
|
||||
debug.info(3, "Creating intersections for node #{}".format(i))
|
||||
node1 = self.nodes[i]
|
||||
for j in range(i + 1, len(self.nodes)):
|
||||
node2 = self.nodes[j]
|
||||
# Skip if the nodes are already connected
|
||||
if node1 in node2.neighbors:
|
||||
continue
|
||||
# Try two different corners
|
||||
for k in [0, 1]:
|
||||
# Create a node at the perpendicular corner of these two nodes
|
||||
corner = navigation_node(vector(node1.position[k], node2.position[int(not k)]))
|
||||
# Skip this corner if the perpendicular connection is blocked
|
||||
if self.is_probe_blocked(corner.position, node1.position) or self.is_probe_blocked(corner.position, node2.position):
|
||||
continue
|
||||
corner.add_neighbor(node1)
|
||||
corner.add_neighbor(node2)
|
||||
new_nodes.append(corner)
|
||||
self.nodes.extend(new_nodes)
|
||||
debug.info(0, "Number of nodes after intersections: {}".format(len(self.nodes)))
|
||||
|
||||
|
||||
def is_between(a, b, mid):
|
||||
""" Return if 'mid' is between 'a' and 'b'. """
|
||||
|
||||
return (a < mid and mid < b) or (b < mid and mid < a)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
class navigation_node:
|
||||
""" This class represents a node on the navigation graph. """
|
||||
|
||||
def __init__(self, position):
|
||||
|
||||
self.position = position
|
||||
self.neighbors = []
|
||||
|
||||
|
||||
def add_neighbor(self, node):
|
||||
""" Connect two nodes. """
|
||||
|
||||
self.neighbors.append(node)
|
||||
node.neighbors.append(self)
|
||||
|
||||
|
||||
def remove_neighbor(self, node):
|
||||
""" Disconnect two nodes. """
|
||||
|
||||
if node in self.neighbors:
|
||||
self.neighbors.remove(node)
|
||||
node.neighbors.remove(self)
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
|
||||
# All rights reserved.
|
||||
#
|
||||
from openram import debug
|
||||
from openram.base.pin_layout import pin_layout
|
||||
from openram.base.vector import vector
|
||||
from openram.gdsMill import gdsMill
|
||||
from openram.tech import GDS
|
||||
from openram.tech import layer as tech_layer
|
||||
from openram import OPTS
|
||||
from .router_tech import router_tech
|
||||
from .navigation_graph import navigation_graph
|
||||
|
||||
|
||||
class navigation_router(router_tech):
|
||||
"""
|
||||
This is the router class that implements navigation graph routing algorithm.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, bbox=None, pin_type=None):
|
||||
|
||||
router_tech.__init__(self, layers, route_track_width=1)
|
||||
|
||||
self.layers = layers
|
||||
self.design = design
|
||||
self.gds_filename = OPTS.openram_temp + "temp.gds"
|
||||
self.pins = {}
|
||||
self.all_pins = set()
|
||||
self.blockages = []
|
||||
|
||||
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
""" Route the given pins in the given order. """
|
||||
#debug.info(0, "Running router for {}...".format(pins))
|
||||
|
||||
# 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)
|
||||
|
||||
# Find pins to be routed
|
||||
self.find_pins(vdd_name)
|
||||
self.find_pins(gnd_name)
|
||||
|
||||
# Find blockages
|
||||
self.find_blockages()
|
||||
|
||||
# Create the navigation graph
|
||||
self.nav = navigation_graph()
|
||||
pin_iter = iter(self.pins["vdd"])
|
||||
vdd_0 = next(pin_iter)
|
||||
vdd_1 = next(pin_iter)
|
||||
self.nav.create_graph(vdd_0, vdd_1, self.blockages)
|
||||
|
||||
self.write_debug_gds(source=vdd_0, target=vdd_1)
|
||||
|
||||
|
||||
def find_pins(self, pin_name):
|
||||
""" """
|
||||
debug.info(1, "Finding all pins for {}".format(pin_name))
|
||||
|
||||
shape_list = self.layout.getAllPinShapes(str(pin_name))
|
||||
pin_set = set()
|
||||
for shape in shape_list:
|
||||
layer, boundary = shape
|
||||
# gdsMill boundaries are in (left, bottom, right, top) order
|
||||
# so repack and snap to the grid
|
||||
ll = vector(boundary[0], boundary[1]).snap_to_grid()
|
||||
ur = vector(boundary[2], boundary[3]).snap_to_grid()
|
||||
rect = [ll, ur]
|
||||
pin = pin_layout(pin_name, rect, layer)
|
||||
pin_set.add(pin)
|
||||
# Add these pins to the 'pins' dict
|
||||
self.pins[pin_name] = pin_set
|
||||
self.all_pins.update(pin_set)
|
||||
|
||||
|
||||
def find_blockages(self):
|
||||
""" """
|
||||
debug.info(1, "Finding all blockages")
|
||||
|
||||
for lpp in [self.vert_lpp, self.horiz_lpp]:
|
||||
shapes = self.layout.getAllShapes(lpp)
|
||||
for boundary in shapes:
|
||||
# gdsMill boundaries are in (left, bottom, right, top) order
|
||||
# so repack and snap to the grid
|
||||
ll = vector(boundary[0], boundary[1])
|
||||
ur = vector(boundary[2], boundary[3])
|
||||
rect = [ll, ur]
|
||||
new_shape = pin_layout("blockage{}".format(len(self.blockages)),
|
||||
rect,
|
||||
lpp)
|
||||
|
||||
# If there is a rectangle that is the same in the pins,
|
||||
# it isn't a blockage
|
||||
if new_shape not in self.all_pins and not self.pin_contains(new_shape):
|
||||
self.blockages.append(new_shape)
|
||||
|
||||
|
||||
def pin_contains(self, shape):
|
||||
for pin in self.all_pins:
|
||||
if pin.contains(shape):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def write_debug_gds(self, gds_name="debug_route.gds", source=None, target=None):
|
||||
""" """
|
||||
|
||||
self.add_router_info(source, target)
|
||||
self.design.gds_write(gds_name)
|
||||
self.del_router_info()
|
||||
|
||||
|
||||
def add_router_info(self, source=None, target=None):
|
||||
""" """
|
||||
|
||||
# Display the inflated blockage
|
||||
for blockage in self.nav.nav_blockages:
|
||||
ll, ur = blockage.ll, blockage.ur
|
||||
self.design.add_rect(layer="text",
|
||||
offset=ll,
|
||||
width=ur.x - ll.x,
|
||||
height=ur.y - ll.y)
|
||||
self.design.add_label(text="blockage",
|
||||
layer="text",
|
||||
offset=ll)
|
||||
for node in self.nav.nodes:
|
||||
self.design.add_rect_center(layer="text",
|
||||
offset=node.position,
|
||||
width=1,
|
||||
height=1)
|
||||
self.design.add_label(text="-0-",
|
||||
layer="text",
|
||||
offset=node.position)
|
||||
if source:
|
||||
self.design.add_label(text="source",
|
||||
layer="text",
|
||||
offset=source.rect[0])
|
||||
if target:
|
||||
self.design.add_label(text="target",
|
||||
layer="text",
|
||||
offset=target.rect[0])
|
||||
|
||||
|
||||
def del_router_info(self):
|
||||
""" """
|
||||
|
||||
lpp = tech_layer["text"]
|
||||
self.design.objs = [x for x in self.design.objs if x.lpp != lpp]
|
||||
Loading…
Reference in New Issue