mirror of https://github.com/VLSIDA/OpenRAM.git
Implement signal escape router using the new gridless router
This commit is contained in:
parent
dd152da5c2
commit
887a66553b
|
|
@ -31,6 +31,10 @@ class router(router_tech):
|
||||||
self.design = design
|
self.design = design
|
||||||
# Temporary GDSII file name to find pins and blockages
|
# Temporary GDSII file name to find pins and blockages
|
||||||
self.gds_filename = OPTS.openram_temp + "temp.gds"
|
self.gds_filename = OPTS.openram_temp + "temp.gds"
|
||||||
|
# Bounding box can be given with margin, or created by default
|
||||||
|
if bbox is None:
|
||||||
|
bbox = self.design.get_bbox()
|
||||||
|
self.bbox = bbox
|
||||||
# Dictionary for vdd and gnd pins
|
# Dictionary for vdd and gnd pins
|
||||||
self.pins = {}
|
self.pins = {}
|
||||||
# Set of all the pins
|
# Set of all the pins
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
# 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 openram import OPTS
|
||||||
|
from .graph import graph
|
||||||
|
from .router import router
|
||||||
|
from .graph_shape import graph_shape
|
||||||
|
|
||||||
|
|
||||||
|
class signal_escape_router(router):
|
||||||
|
"""
|
||||||
|
This is the signal escape router that uses the Hanan grid graph method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, layers, design, bbox=None, pin_type=None):
|
||||||
|
|
||||||
|
# `router_tech` contains tech constants for the router
|
||||||
|
router.__init__(self, layers, design, bbox)
|
||||||
|
|
||||||
|
# New pins are the side supply pins
|
||||||
|
self.new_pins = {}
|
||||||
|
|
||||||
|
|
||||||
|
def route(self, pin_names):
|
||||||
|
""" Route the given pins to the perimeter. """
|
||||||
|
debug.info(1, "Running signal escape router...")
|
||||||
|
|
||||||
|
# Prepare gdsMill to find pins and blockages
|
||||||
|
self.prepare_gds_reader()
|
||||||
|
|
||||||
|
# Find pins to be routed
|
||||||
|
for name in pin_names:
|
||||||
|
self.find_pins(name)
|
||||||
|
|
||||||
|
# Find blockages and vias
|
||||||
|
self.find_blockages()
|
||||||
|
self.find_vias()
|
||||||
|
|
||||||
|
# Convert blockages and vias if they overlap a pin
|
||||||
|
self.convert_vias()
|
||||||
|
self.convert_blockages()
|
||||||
|
|
||||||
|
# Add fake pins on the perimeter to do the escape routing on
|
||||||
|
self.add_perimeter_fake_pins()
|
||||||
|
|
||||||
|
# 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(self.inflate_shape(pin, is_pin=True))
|
||||||
|
|
||||||
|
# Route vdd and gnd
|
||||||
|
for name in pin_names:
|
||||||
|
# Route each pin to the perimeter
|
||||||
|
source = next(iter(self.pins[name]))
|
||||||
|
target = self.get_closest_perimeter_fake_pin(source)
|
||||||
|
# Change fake pin's name so the graph will treat it as routable
|
||||||
|
target.name = source.name
|
||||||
|
# This is the routing region scale
|
||||||
|
scale = 1
|
||||||
|
while True:
|
||||||
|
# Create the graph
|
||||||
|
g = graph(self)
|
||||||
|
region = g.create_graph(source, target, scale)
|
||||||
|
# Find the shortest path from source to target
|
||||||
|
path = g.find_shortest_path()
|
||||||
|
# If there is no path found, exponentially try again with a
|
||||||
|
# larger routing region
|
||||||
|
if path is None:
|
||||||
|
rll, rur = region
|
||||||
|
bll, bur = self.bbox
|
||||||
|
# Stop scaling the region and throw an error
|
||||||
|
if rll.x < bll.x and rll.y < bll.y and \
|
||||||
|
rur.x > bur.x and rur.y > bur.y:
|
||||||
|
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
|
||||||
|
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
|
||||||
|
# Exponentially scale the region
|
||||||
|
scale *= 2
|
||||||
|
debug.info(0, "Retry routing in larger routing region with scale {}".format(scale))
|
||||||
|
continue
|
||||||
|
# Create the path shapes on layout
|
||||||
|
self.add_path(path)
|
||||||
|
# Find the recently added shapes
|
||||||
|
self.prepare_gds_reader()
|
||||||
|
self.find_blockages(name)
|
||||||
|
self.find_vias()
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def add_perimeter_fake_pins(self):
|
||||||
|
"""
|
||||||
|
Add the fake pins on the perimeter to where the signals will be routed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ll, ur = self.bbox
|
||||||
|
wide = self.track_wire
|
||||||
|
|
||||||
|
for side in ["top", "bottom", "left", "right"]:
|
||||||
|
vertical = side in ["left", "right"]
|
||||||
|
|
||||||
|
# Calculate the lower left coordinate
|
||||||
|
if side == "top":
|
||||||
|
offset = vector(ll.x, ur.y - wide)
|
||||||
|
elif side == "bottom":
|
||||||
|
offset = vector(ll.x, ll.y)
|
||||||
|
elif side == "left":
|
||||||
|
offset = vector(ll.x, ll.y)
|
||||||
|
elif side == "right":
|
||||||
|
offset = vector(ur.x - wide, ll.y)
|
||||||
|
|
||||||
|
# Calculate width and height
|
||||||
|
shape = ur - ll
|
||||||
|
if vertical:
|
||||||
|
shape_width = wide
|
||||||
|
shape_height = shape.y
|
||||||
|
else:
|
||||||
|
shape_width = shape.x
|
||||||
|
shape_height = wide
|
||||||
|
|
||||||
|
# Add this new pin
|
||||||
|
# They must lie on the non-preferred direction since the side supply
|
||||||
|
# pins will lie on the preferred direction
|
||||||
|
layer = self.get_layer(int(not vertical))
|
||||||
|
nll = vector(offset.x, offset.y)
|
||||||
|
nur = vector(offset.x + shape_width, offset.y + shape_height)
|
||||||
|
rect = [nll, nur]
|
||||||
|
pin = graph_shape(name="fake",
|
||||||
|
rect=rect,
|
||||||
|
layer_name_pp=layer)
|
||||||
|
self.fake_pins.append(pin)
|
||||||
|
|
||||||
|
|
||||||
|
def get_closest_perimeter_fake_pin(self, pin):
|
||||||
|
""" Return the closest fake pin for the given pin. """
|
||||||
|
|
||||||
|
min_dist = float("inf")
|
||||||
|
close_fake = None
|
||||||
|
for fake in self.fake_pins:
|
||||||
|
dist = pin.distance(fake)
|
||||||
|
if dist < min_dist:
|
||||||
|
min_dist = dist
|
||||||
|
close_fake = fake
|
||||||
|
return close_fake
|
||||||
Loading…
Reference in New Issue