Simplifying supply router to single grid track

This commit is contained in:
Matt Guthaus 2018-12-04 08:41:57 -08:00
parent 2a68b57215
commit 389bb91af4
6 changed files with 187 additions and 172 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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