mirror of https://github.com/VLSIDA/OpenRAM.git
Simplifying supply router to single grid track
This commit is contained in:
parent
2a68b57215
commit
389bb91af4
|
|
@ -13,8 +13,8 @@ class options(optparse.Values):
|
|||
# This is the name of the technology.
|
||||
tech_name = ""
|
||||
# This is the temp directory where all intermediate results are stored.
|
||||
#openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
#openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
|
||||
# This is the verbosity level to control debug information. 0 is none, 1
|
||||
# is minimal, etc.
|
||||
debug_level = 0
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ class pin_group:
|
|||
ymax = max(plc.y,elc.y)
|
||||
ll = vector(plc.x, ymin)
|
||||
ur = vector(prc.x, ymax)
|
||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||
elif pin.yoverlaps(enclosure):
|
||||
# Is it horizontal overlap, extend pin shape to enclosure
|
||||
pbc = pin.bc()
|
||||
|
|
@ -183,7 +182,6 @@ class pin_group:
|
|||
xmax = max(pbc.x,ebc.x)
|
||||
ll = vector(xmin, pbc.y)
|
||||
ur = vector(xmax, puc.y)
|
||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||
else:
|
||||
# Neither, so we must do a corner-to corner
|
||||
pc = pin.center()
|
||||
|
|
@ -194,8 +192,10 @@ class pin_group:
|
|||
ymax = max(pc.y, ec.y)
|
||||
ll = vector(xmin, ymin)
|
||||
ur = vector(xmax, ymax)
|
||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||
|
||||
if ll.x==ur.x or ll.y==ur.y:
|
||||
return None
|
||||
p = pin_layout(pin.name, [ll, ur], pin.layer)
|
||||
return p
|
||||
|
||||
def find_above_connector(self, pin, enclosures):
|
||||
|
|
@ -485,7 +485,9 @@ class pin_group:
|
|||
for pin_list in self.pins:
|
||||
if not self.overlap_any_shape(pin_list, self.enclosures):
|
||||
connector = self.find_smallest_connector(pin_list, self.enclosures)
|
||||
debug.check(connector!=None, "Could not find a connector for {} with {}".format(pin_list, self.enclosures))
|
||||
if connector==None:
|
||||
debug.error("Could not find a connector for {} with {}".format(pin_list, self.enclosures))
|
||||
self.router.write_debug_gds("no_connector.gds")
|
||||
self.enclosures.append(connector)
|
||||
|
||||
|
||||
|
|
@ -623,61 +625,61 @@ class pin_group:
|
|||
debug.info(2," pins {}".format(self.grids))
|
||||
debug.info(2," secondary {}".format(self.secondary_grids))
|
||||
|
||||
def recurse_simple_overlap_enclosure(self, start_set, direct):
|
||||
"""
|
||||
Recursive function to return set of tracks that connects to
|
||||
the actual supply rail wire in a given direction (or terminating
|
||||
when any track is no longer in the supply rail.
|
||||
"""
|
||||
next_set = grid_utils.expand_border(start_set, direct)
|
||||
# def recurse_simple_overlap_enclosure(self, start_set, direct):
|
||||
# """
|
||||
# Recursive function to return set of tracks that connects to
|
||||
# the actual supply rail wire in a given direction (or terminating
|
||||
# when any track is no longer in the supply rail.
|
||||
# """
|
||||
# next_set = grid_utils.expand_border(start_set, direct)
|
||||
|
||||
supply_tracks = self.router.supply_rail_tracks[self.name]
|
||||
supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name]
|
||||
# supply_tracks = self.router.supply_rail_tracks[self.name]
|
||||
# supply_wire_tracks = self.router.supply_rail_wire_tracks[self.name]
|
||||
|
||||
supply_overlap = next_set & supply_tracks
|
||||
wire_overlap = next_set & supply_wire_tracks
|
||||
# supply_overlap = next_set & supply_tracks
|
||||
# wire_overlap = next_set & supply_wire_tracks
|
||||
|
||||
# If the rail overlap is the same, we are done, since we connected to the actual wire
|
||||
if len(wire_overlap)==len(start_set):
|
||||
new_set = start_set | wire_overlap
|
||||
# If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
|
||||
elif len(supply_overlap)==len(start_set):
|
||||
recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct)
|
||||
new_set = start_set | supply_overlap | recurse_set
|
||||
else:
|
||||
# If we got no next set, we are done, can't expand!
|
||||
new_set = set()
|
||||
# # If the rail overlap is the same, we are done, since we connected to the actual wire
|
||||
# if len(wire_overlap)==len(start_set):
|
||||
# new_set = start_set | wire_overlap
|
||||
# # If the supply overlap is the same, keep expanding unti we hit the wire or move out of the rail region
|
||||
# elif len(supply_overlap)==len(start_set):
|
||||
# recurse_set = self.recurse_simple_overlap_enclosure(supply_overlap, direct)
|
||||
# new_set = start_set | supply_overlap | recurse_set
|
||||
# else:
|
||||
# # If we got no next set, we are done, can't expand!
|
||||
# new_set = set()
|
||||
|
||||
return new_set
|
||||
# return new_set
|
||||
|
||||
def create_simple_overlap_enclosure(self, start_set):
|
||||
"""
|
||||
This takes a set of tracks that overlap a supply rail and creates an enclosure
|
||||
that is ensured to overlap the supply rail wire.
|
||||
It then adds rectangle(s) for the enclosure.
|
||||
"""
|
||||
additional_set = set()
|
||||
# Check the layer of any element in the pin to determine which direction to route it
|
||||
e = next(iter(start_set))
|
||||
new_set = start_set.copy()
|
||||
if e.z==0:
|
||||
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH)
|
||||
if not new_set:
|
||||
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH)
|
||||
else:
|
||||
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST)
|
||||
if not new_set:
|
||||
new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST)
|
||||
# def create_simple_overlap_enclosure(self, start_set):
|
||||
# """
|
||||
# This takes a set of tracks that overlap a supply rail and creates an enclosure
|
||||
# that is ensured to overlap the supply rail wire.
|
||||
# It then adds rectangle(s) for the enclosure.
|
||||
# """
|
||||
# additional_set = set()
|
||||
# # Check the layer of any element in the pin to determine which direction to route it
|
||||
# e = next(iter(start_set))
|
||||
# new_set = start_set.copy()
|
||||
# if e.z==0:
|
||||
# new_set = self.recurse_simple_overlap_enclosure(start_set, direction.NORTH)
|
||||
# if not new_set:
|
||||
# new_set = self.recurse_simple_overlap_enclosure(start_set, direction.SOUTH)
|
||||
# else:
|
||||
# new_set = self.recurse_simple_overlap_enclosure(start_set, direction.EAST)
|
||||
# if not new_set:
|
||||
# new_set = self.recurse_simple_overlap_enclosure(start_set, direction.WEST)
|
||||
|
||||
# Expand the pin grid set to include some extra grids that connect the supply rail
|
||||
self.grids.update(new_set)
|
||||
# # Expand the pin grid set to include some extra grids that connect the supply rail
|
||||
# self.grids.update(new_set)
|
||||
|
||||
# Add the inflated set so we don't get wide metal spacing issues (if it exists)
|
||||
self.blockages.update(grid_utils.inflate_set(new_set,self.router.supply_rail_space_width))
|
||||
# # Block the grids
|
||||
# self.blockages.update(new_set)
|
||||
|
||||
# Add the polygon enclosures and set this pin group as routed
|
||||
self.set_routed()
|
||||
self.enclosures = self.compute_enclosures()
|
||||
# # Add the polygon enclosures and set this pin group as routed
|
||||
# self.set_routed()
|
||||
# self.enclosures = self.compute_enclosures()
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ class router(router_tech):
|
|||
It populates blockages on a grid class.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
|
||||
"""
|
||||
This will instantiate a copy of the gds file or the module at (0,0) and
|
||||
route on top of this. The blockages from the gds/module will be considered.
|
||||
"""
|
||||
router_tech.__init__(self, layers)
|
||||
router_tech.__init__(self, layers, rail_track_width)
|
||||
|
||||
self.cell = design
|
||||
|
||||
|
|
@ -177,15 +177,15 @@ class router(router_tech):
|
|||
#print_time("Convert pins",datetime.now(), start_time)
|
||||
|
||||
#start_time = datetime.now()
|
||||
for pin in pin_list:
|
||||
self.combine_adjacent_pins(pin)
|
||||
#for pin in pin_list:
|
||||
# self.combine_adjacent_pins(pin)
|
||||
#print_time("Combine pins",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
|
||||
|
||||
# Separate any adjacent grids of differing net names to prevent wide metal DRC violations
|
||||
# Must be done before enclosing pins
|
||||
#start_time = datetime.now()
|
||||
self.separate_adjacent_pins(self.supply_rail_space_width)
|
||||
#self.separate_adjacent_pins(self.supply_rail_space_width)
|
||||
#print_time("Separate pins",datetime.now(), start_time)
|
||||
# For debug
|
||||
#self.separate_adjacent_pins(1)
|
||||
|
|
@ -201,7 +201,7 @@ class router(router_tech):
|
|||
"""
|
||||
Find pins that have adjacent routing tracks and merge them into a
|
||||
single pin_group. The pins themselves may not be touching, but
|
||||
enclose_pis in the next step will ensure they are touching.
|
||||
enclose_pins in the next step will ensure they are touching.
|
||||
"""
|
||||
debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
|
||||
# Find all adjacencies
|
||||
|
|
@ -528,7 +528,7 @@ class router(router_tech):
|
|||
sufficient_list.update([full_overlap])
|
||||
if partial_overlap:
|
||||
insufficient_list.update([partial_overlap])
|
||||
debug.info(4,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap))
|
||||
debug.info(3,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap))
|
||||
|
||||
# Remove the blocked grids
|
||||
sufficient_list.difference_update(self.blocked_grids)
|
||||
|
|
@ -620,7 +620,7 @@ class router(router_tech):
|
|||
return set([best_coord])
|
||||
|
||||
|
||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||
def convert_pin_coord_to_minimal_tracks(self, pin, coord):
|
||||
"""
|
||||
Given a pin and a track coordinate, determine if the pin overlaps enough.
|
||||
If it does, add additional metal to make the pin "on grid".
|
||||
|
|
@ -643,6 +643,25 @@ class router(router_tech):
|
|||
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,spacing))
|
||||
return (None, coord)
|
||||
|
||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||
"""
|
||||
Return all tracks that an inflated pin overlaps
|
||||
"""
|
||||
|
||||
# This is the rectangle if we put a pin in the center of the track
|
||||
track_pin = self.convert_track_to_inflated_pin(coord)
|
||||
overlap_length = pin.overlap_length(track_pin)
|
||||
|
||||
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
|
||||
# If it overlaps by more than the min width DRC, we can just use the track
|
||||
if overlap_length==math.inf or snap_val_to_grid(overlap_length) > 0:
|
||||
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,0))
|
||||
return (coord, None)
|
||||
# Otherwise, keep track of the partial overlap grids in case we need to patch it later.
|
||||
else:
|
||||
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,0))
|
||||
return (None, coord)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -653,20 +672,14 @@ class router(router_tech):
|
|||
Convert a grid point into a rectangle shape that is centered
|
||||
track in the track and leaves half a DRC space in each direction.
|
||||
"""
|
||||
# space depends on which layer it is
|
||||
if self.get_layer(track[2])==self.horiz_layer_name:
|
||||
space = 0.5*self.horiz_layer_spacing
|
||||
else:
|
||||
space = 0.5*self.vert_layer_spacing
|
||||
|
||||
# calculate lower left
|
||||
x = track.x*self.track_width - 0.5*self.track_width + space
|
||||
y = track.y*self.track_width - 0.5*self.track_width + space
|
||||
x = track.x*self.track_width - 0.5*self.track_width + 0.5*self.track_space
|
||||
y = track.y*self.track_width - 0.5*self.track_width + 0.5*self.track_space
|
||||
ll = snap_to_grid(vector(x,y))
|
||||
|
||||
# calculate upper right
|
||||
x = track.x*self.track_width + 0.5*self.track_width - space
|
||||
y = track.y*self.track_width + 0.5*self.track_width - space
|
||||
x = track.x*self.track_width + 0.5*self.track_width - 0.5*self.track_space
|
||||
y = track.y*self.track_width + 0.5*self.track_width - 0.5*self.track_space
|
||||
ur = snap_to_grid(vector(x,y))
|
||||
|
||||
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
|
||||
|
|
@ -686,6 +699,23 @@ class router(router_tech):
|
|||
|
||||
return [ll,ur]
|
||||
|
||||
def convert_track_to_inflated_pin(self, track):
|
||||
"""
|
||||
Convert a grid point into a rectangle shape that is inflated by a half DRC space.
|
||||
"""
|
||||
# calculate lower left
|
||||
x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space
|
||||
y = track.y*self.track_width - 0.5*self.track_width - 0.5*self.track_space
|
||||
ll = snap_to_grid(vector(x,y))
|
||||
|
||||
# calculate upper right
|
||||
x = track.x*self.track_width + 0.5*self.track_width + 0.5*self.track_space
|
||||
y = track.y*self.track_width + 0.5*self.track_width + 0.5*self.track_space
|
||||
ur = snap_to_grid(vector(x,y))
|
||||
|
||||
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
|
||||
return p
|
||||
|
||||
def analyze_pins(self, pin_name):
|
||||
"""
|
||||
Analyze the shapes of a pin and combine them into groups which are connected.
|
||||
|
|
@ -877,8 +907,6 @@ class router(router_tech):
|
|||
Enclose the tracks from ll to ur in a single rectangle that meets
|
||||
the track DRC rules.
|
||||
"""
|
||||
# Get the layer information
|
||||
(width, space) = self.get_layer_width_space(zindex)
|
||||
layer = self.get_layer(zindex)
|
||||
|
||||
# This finds the pin shape enclosed by the track with DRC spacing on the sides
|
||||
|
|
@ -894,35 +922,35 @@ class router(router_tech):
|
|||
return pin
|
||||
|
||||
|
||||
def compute_wide_enclosure(self, ll, ur, zindex, name=""):
|
||||
"""
|
||||
Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
|
||||
"""
|
||||
# def compute_wide_enclosure(self, ll, ur, zindex, name=""):
|
||||
# """
|
||||
# Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
|
||||
# """
|
||||
|
||||
# Find the pin enclosure of the whole track shape (ignoring DRCs)
|
||||
(abs_ll,unused) = self.convert_track_to_shape(ll)
|
||||
(unused,abs_ur) = self.convert_track_to_shape(ur)
|
||||
# # Find the pin enclosure of the whole track shape (ignoring DRCs)
|
||||
# (abs_ll,unused) = self.convert_track_to_shape(ll)
|
||||
# (unused,abs_ur) = self.convert_track_to_shape(ur)
|
||||
|
||||
# Get the layer information
|
||||
x_distance = abs(abs_ll.x-abs_ur.x)
|
||||
y_distance = abs(abs_ll.y-abs_ur.y)
|
||||
shape_width = min(x_distance, y_distance)
|
||||
shape_length = max(x_distance, y_distance)
|
||||
# # Get the layer information
|
||||
# x_distance = abs(abs_ll.x-abs_ur.x)
|
||||
# y_distance = abs(abs_ll.y-abs_ur.y)
|
||||
# shape_width = min(x_distance, y_distance)
|
||||
# shape_length = max(x_distance, y_distance)
|
||||
|
||||
# Get the DRC rule for the grid dimensions
|
||||
(width, space) = self.get_layer_width_space(zindex, shape_width, shape_length)
|
||||
layer = self.get_layer(zindex)
|
||||
# # Get the DRC rule for the grid dimensions
|
||||
# (width, space) = self.get_supply_layer_width_space(zindex)
|
||||
# layer = self.get_layer(zindex)
|
||||
|
||||
if zindex==0:
|
||||
spacing = vector(0.5*self.track_width, 0.5*space)
|
||||
else:
|
||||
spacing = vector(0.5*space, 0.5*self.track_width)
|
||||
# Compute the shape offsets with correct spacing
|
||||
new_ll = abs_ll + spacing
|
||||
new_ur = abs_ur - spacing
|
||||
pin = pin_layout(name, [new_ll, new_ur], layer)
|
||||
# if zindex==0:
|
||||
# spacing = vector(0.5*self.track_width, 0.5*space)
|
||||
# else:
|
||||
# spacing = vector(0.5*space, 0.5*self.track_width)
|
||||
# # Compute the shape offsets with correct spacing
|
||||
# new_ll = abs_ll + spacing
|
||||
# new_ur = abs_ur - spacing
|
||||
# pin = pin_layout(name, [new_ll, new_ur], layer)
|
||||
|
||||
return pin
|
||||
# return pin
|
||||
|
||||
|
||||
def contract_path(self,path):
|
||||
|
|
@ -963,8 +991,7 @@ class router(router_tech):
|
|||
self.add_route(path)
|
||||
|
||||
path_set = grid_utils.flatten_set(path)
|
||||
inflated_path = grid_utils.inflate_set(path_set,self.supply_rail_space_width)
|
||||
self.path_blockages.append(inflated_path)
|
||||
self.path_blockages.append(path_set)
|
||||
else:
|
||||
self.write_debug_gds("failed_route.gds")
|
||||
# clean up so we can try a reroute
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ class router_tech:
|
|||
"""
|
||||
This is a class to hold the router tech constants.
|
||||
"""
|
||||
def __init__(self, layers, supply_router=False):
|
||||
def __init__(self, layers, rail_track_width):
|
||||
"""
|
||||
Allows us to change the layers that we are routing on. First layer
|
||||
is always horizontal, middle is via, and last is always
|
||||
vertical.
|
||||
"""
|
||||
self.layers = layers
|
||||
self.rail_track_width = rail_track_width
|
||||
|
||||
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
|
||||
# This is the minimum routed track spacing
|
||||
via_connect = contact(self.layers, (1, 1))
|
||||
|
|
@ -24,9 +26,9 @@ class router_tech:
|
|||
self.horiz_layer_number = layer[self.horiz_layer_name]
|
||||
self.vert_layer_number = layer[self.vert_layer_name]
|
||||
|
||||
if supply_router:
|
||||
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1,2)
|
||||
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0,2)
|
||||
if self.rail_track_width>1:
|
||||
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
|
||||
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
|
||||
|
||||
# For supplies, we will make the wire wider than the vias
|
||||
self.vert_layer_minwidth = max(self.vert_layer_minwidth, max_via_size)
|
||||
|
|
@ -45,13 +47,17 @@ class router_tech:
|
|||
# We'll keep horizontal and vertical tracks the same for simplicity.
|
||||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||
debug.info(1,"Track width: "+str(self.track_width))
|
||||
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing)
|
||||
debug.info(1,"Track spacing: "+str(self.track_space))
|
||||
self.track_wire = self.track_width - self.track_space
|
||||
debug.info(1,"Wire width: "+str(self.track_wire))
|
||||
|
||||
self.track_widths = vector([self.track_width] * 2)
|
||||
self.track_factor = vector([1/self.track_width] * 2)
|
||||
debug.info(2,"Track factor: {0}".format(self.track_factor))
|
||||
|
||||
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
||||
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
|
||||
self.layer_widths = [self.track_wire, 1, self.track_wire]
|
||||
|
||||
def get_zindex(self,layer_num):
|
||||
if layer_num==self.horiz_layer_number:
|
||||
|
|
@ -85,7 +91,7 @@ class router_tech:
|
|||
return (min_width,min_spacing)
|
||||
|
||||
|
||||
def get_supply_layer_width_space(self, zindex, widths=2):
|
||||
def get_supply_layer_width_space(self, zindex):
|
||||
"""
|
||||
These are the width and spacing of a supply layer given a supply rail
|
||||
of the given number of min wire widths.
|
||||
|
|
@ -97,10 +103,10 @@ class router_tech:
|
|||
else:
|
||||
debug.error("Invalid zindex for track", -1)
|
||||
|
||||
wire_width = widths*drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
||||
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
||||
|
||||
min_width = drc("minwidth_{0}".format(layer_name), wire_width, math.inf)
|
||||
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), wire_width, math.inf)
|
||||
min_width = drc("minwidth_{0}".format(layer_name), self.rail_track_width*min_wire_width, math.inf)
|
||||
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.rail_track_width*min_wire_width, math.inf)
|
||||
|
||||
return (min_width,min_spacing)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,17 +24,16 @@ class supply_router(router):
|
|||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, layers, design, gds_filename)
|
||||
# Power rail width in minimum wire widths
|
||||
self.rail_track_width = 3
|
||||
|
||||
router.__init__(self, layers, design, gds_filename, self.rail_track_width)
|
||||
|
||||
# The list of supply rails (grid sets) that may be routed
|
||||
self.supply_rails = {}
|
||||
self.supply_rail_wires = {}
|
||||
# This is the same as above but as a sigle set for the all the rails
|
||||
self.supply_rail_tracks = {}
|
||||
self.supply_rail_wire_tracks = {}
|
||||
|
||||
# Power rail width in grid units.
|
||||
self.rail_track_width = 2
|
||||
|
||||
|
||||
|
||||
|
|
@ -116,9 +115,7 @@ class supply_router(router):
|
|||
debug.info(1,"Routing simple overlap pins for {0}".format(pin_name))
|
||||
|
||||
# These are the wire tracks
|
||||
wire_tracks = self.supply_rail_wire_tracks[pin_name]
|
||||
# These are the wire and space tracks
|
||||
supply_tracks = self.supply_rail_tracks[pin_name]
|
||||
wire_tracks = self.supply_rail_tracks[pin_name]
|
||||
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
if pg.is_routed():
|
||||
|
|
@ -131,11 +128,8 @@ class supply_router(router):
|
|||
continue
|
||||
|
||||
# Else, if we overlap some of the space track, we can patch it with an enclosure
|
||||
common_set = supply_tracks & pg.grids
|
||||
if len(common_set)>0:
|
||||
pg.create_simple_overlap_enclosure(common_set)
|
||||
pg.add_enclosure(self.cell)
|
||||
|
||||
#pg.create_simple_overlap_enclosure(pg.grids)
|
||||
#pg.add_enclosure(self.cell)
|
||||
|
||||
|
||||
|
||||
|
|
@ -146,7 +140,7 @@ class supply_router(router):
|
|||
NOTE: It is still possible though unlikely that there are disconnected groups of rails.
|
||||
"""
|
||||
|
||||
all_rails = self.supply_rail_wires[name]
|
||||
all_rails = self.supply_rails[name]
|
||||
|
||||
connections = set()
|
||||
via_areas = []
|
||||
|
|
@ -186,8 +180,8 @@ class supply_router(router):
|
|||
# the indices to determine a rail is connected to another
|
||||
# the overlap area for placement of a via
|
||||
overlap = new_r1 & new_r2
|
||||
if len(overlap) >= self.supply_rail_wire_width**2:
|
||||
debug.info(3,"Via overlap {0} {1} {2}".format(len(overlap),self.supply_rail_wire_width**2,overlap))
|
||||
if len(overlap) >= 1:
|
||||
debug.info(3,"Via overlap {0} {1}".format(len(overlap),overlap))
|
||||
connections.update([i1,i2])
|
||||
via_areas.append(overlap)
|
||||
|
||||
|
|
@ -196,7 +190,7 @@ class supply_router(router):
|
|||
ll = grid_utils.get_lower_left(area)
|
||||
ur = grid_utils.get_upper_right(area)
|
||||
center = (ll + ur).scale(0.5,0.5,0)
|
||||
self.add_via(center,self.rail_track_width)
|
||||
self.add_via(center,1)
|
||||
|
||||
# Determien which indices were not connected to anything above
|
||||
missing_indices = set([x for x in range(len(self.supply_rails[name]))])
|
||||
|
|
@ -209,7 +203,6 @@ class supply_router(router):
|
|||
ur = grid_utils.get_upper_right(all_rails[rail_index])
|
||||
debug.info(1,"Removing disconnected supply rail {0} .. {1}".format(ll,ur))
|
||||
self.supply_rails[name].pop(rail_index)
|
||||
self.supply_rail_wires[name].pop(rail_index)
|
||||
|
||||
# Make the supply rails into a big giant set of grids for easy blockages.
|
||||
# Must be done after we determine which ones are connected.
|
||||
|
|
@ -226,7 +219,7 @@ class supply_router(router):
|
|||
ll = grid_utils.get_lower_left(rail)
|
||||
ur = grid_utils.get_upper_right(rail)
|
||||
z = ll.z
|
||||
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
||||
pin = self.compute_pin_enclosure(ll, ur, z, name)
|
||||
debug.info(2,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
|
||||
self.cell.add_layout_pin(text=name,
|
||||
layer=pin.layer,
|
||||
|
|
@ -242,33 +235,30 @@ class supply_router(router):
|
|||
self.max_yoffset = self.rg.ur.y
|
||||
self.max_xoffset = self.rg.ur.x
|
||||
|
||||
# Longest length is conservative
|
||||
rail_length = max(self.max_yoffset,self.max_xoffset)
|
||||
# Convert the number of tracks to dimensions to get the design rule spacing
|
||||
rail_width = self.track_width*self.rail_track_width
|
||||
# # Longest length is conservative
|
||||
# rail_length = max(self.max_yoffset,self.max_xoffset)
|
||||
# # Convert the number of tracks to dimensions to get the design rule spacing
|
||||
# rail_width = self.track_width*self.rail_track_width
|
||||
|
||||
# Get the conservative width and spacing of the top rails
|
||||
(horizontal_width, horizontal_space) = self.get_supply_layer_width_space(0,2)
|
||||
(vertical_width, vertical_space) = self.get_supply_layer_width_space(1,2)
|
||||
width = max(horizontal_width, vertical_width)
|
||||
space = max(horizontal_space, vertical_space)
|
||||
# # Get the conservative width and spacing of the top rails
|
||||
# (horizontal_width, horizontal_space) = self.get_supply_layer_width_space(0)
|
||||
# (vertical_width, vertical_space) = self.get_supply_layer_width_space(1)
|
||||
# width = max(horizontal_width, vertical_width)
|
||||
# space = max(horizontal_space, vertical_space)
|
||||
|
||||
# This is the supply rail pitch in terms of routing grids
|
||||
# i.e. a rail of self.rail_track_width needs this many tracks including
|
||||
# space
|
||||
track_pitch = self.rail_track_width*width + space
|
||||
# track_pitch = width + space
|
||||
|
||||
# Determine the pitch (in tracks) of the rail wire + spacing
|
||||
self.supply_rail_width = math.ceil(track_pitch/self.track_width)
|
||||
debug.info(1,"Rail step: {}".format(self.supply_rail_width))
|
||||
# # Determine the pitch (in tracks) of the rail wire + spacing
|
||||
# self.supply_rail_width = math.ceil(track_pitch/self.track_width)
|
||||
# debug.info(1,"Rail step: {}".format(self.supply_rail_width))
|
||||
|
||||
# Conservatively determine the number of tracks that the rail actually occupies
|
||||
space_tracks = math.ceil(space/self.track_width)
|
||||
self.supply_rail_wire_width = self.supply_rail_width - space_tracks
|
||||
debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width))
|
||||
total_space = self.supply_rail_width - self.supply_rail_wire_width
|
||||
self.supply_rail_space_width = math.floor(0.5*total_space)
|
||||
debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width))
|
||||
# # Conservatively determine the number of tracks that the rail actually occupies
|
||||
# space_tracks = math.ceil(space/self.track_width)
|
||||
# self.supply_rail_wire_width = self.supply_rail_width - space_tracks
|
||||
# debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width))
|
||||
# total_space = self.supply_rail_width - self.supply_rail_wire_width
|
||||
# self.supply_rail_space_width = math.floor(0.5*total_space)
|
||||
# debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width))
|
||||
|
||||
|
||||
def compute_supply_rails(self, name, supply_number):
|
||||
|
|
@ -279,14 +269,13 @@ class supply_router(router):
|
|||
"""
|
||||
|
||||
self.supply_rails[name]=[]
|
||||
self.supply_rail_wires[name]=[]
|
||||
|
||||
start_offset = supply_number*self.supply_rail_width
|
||||
start_offset = supply_number
|
||||
|
||||
# Horizontal supply rails
|
||||
for offset in range(start_offset, self.max_yoffset, 2*self.supply_rail_width):
|
||||
for offset in range(start_offset, self.max_yoffset, 2):
|
||||
# Seed the function at the location with the given width
|
||||
wave = [vector3d(0,offset+i,0) for i in range(self.supply_rail_width)]
|
||||
wave = [vector3d(0,offset,0)]
|
||||
# While we can keep expanding east in this horizontal track
|
||||
while wave and wave[0].x < self.max_xoffset:
|
||||
added_rail = self.find_supply_rail(name, wave, direction.EAST)
|
||||
|
|
@ -299,9 +288,9 @@ class supply_router(router):
|
|||
|
||||
# Vertical supply rails
|
||||
max_offset = self.rg.ur.x
|
||||
for offset in range(start_offset, self.max_xoffset, 2*self.supply_rail_width):
|
||||
for offset in range(start_offset, self.max_xoffset, 2):
|
||||
# Seed the function at the location with the given width
|
||||
wave = [vector3d(offset+i,0,1) for i in range(self.supply_rail_width)]
|
||||
wave = [vector3d(offset,0,1)]
|
||||
# While we can keep expanding north in this vertical track
|
||||
while wave and wave[0].y < self.max_yoffset:
|
||||
added_rail = self.find_supply_rail(name, wave, direction.NORTH)
|
||||
|
|
@ -378,11 +367,6 @@ class supply_router(router):
|
|||
if len(wave_path)>=4*self.rail_track_width:
|
||||
grid_set = wave_path.get_grids()
|
||||
self.supply_rails[name].append(grid_set)
|
||||
|
||||
start_wire_index = self.supply_rail_space_width
|
||||
end_wire_index = self.supply_rail_width - self.supply_rail_space_width
|
||||
wire_set = wave_path.get_wire_grids(start_wire_index,end_wire_index)
|
||||
self.supply_rail_wires[name].append(wire_set)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
@ -417,10 +401,6 @@ class supply_router(router):
|
|||
rail_set.update(rail)
|
||||
self.supply_rail_tracks[pin_name] = rail_set
|
||||
|
||||
wire_set = set()
|
||||
for rail in self.supply_rail_wires[pin_name]:
|
||||
wire_set.update(rail)
|
||||
self.supply_rail_wire_tracks[pin_name] = wire_set
|
||||
|
||||
|
||||
def route_pins_to_rails(self, pin_name):
|
||||
|
|
@ -465,7 +445,7 @@ class supply_router(router):
|
|||
"""
|
||||
debug.info(4,"Add supply rail target {}".format(pin_name))
|
||||
# Add the wire itself as the target
|
||||
self.rg.set_target(self.supply_rail_wire_tracks[pin_name])
|
||||
self.rg.set_target(self.supply_rail_tracks[pin_name])
|
||||
# But unblock all the rail tracks including the space
|
||||
self.rg.set_blocked(self.supply_rail_tracks[pin_name],False)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ class no_blockages_test(openram_test):
|
|||
if False:
|
||||
from control_logic import control_logic
|
||||
cell = control_logic(16)
|
||||
layer_stack =("metal3","via3","metal4")
|
||||
rtr=router(layer_stack, cell)
|
||||
self.assertTrue(rtr.route())
|
||||
else:
|
||||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
|
|
@ -33,9 +36,6 @@ class no_blockages_test(openram_test):
|
|||
sram = sram(c, "sram1")
|
||||
cell = sram.s
|
||||
|
||||
layer_stack =("metal3","via3","metal4")
|
||||
rtr=router(layer_stack, cell)
|
||||
self.assertTrue(rtr.route())
|
||||
self.local_check(cell,True)
|
||||
|
||||
# fails if there are any DRC errors on any cells
|
||||
|
|
|
|||
Loading…
Reference in New Issue