DRC clean supply grid routing on control logic.

This commit is contained in:
Matt Guthaus 2018-09-20 16:00:13 -07:00
parent fd9ffe30d6
commit 87502374c5
5 changed files with 483 additions and 167 deletions

View File

@ -63,7 +63,7 @@ class pin_layout:
and return the new rectangle.
"""
if not spacing:
spacing = drc["{0}_to_{0}".format(self.layer)]
spacing = 0.5*drc["{0}_to_{0}".format(self.layer)]
(ll,ur) = self.rect
spacing = vector(spacing, spacing)

View File

@ -1,3 +1,4 @@
import sys
import gdsMill
import tech
from contact import contact
@ -36,18 +37,26 @@ class router:
self.reader.loadFromFile(gds_name)
self.top_name = self.layout.rootStructureName
### The pin data structures
# A map of pin names to pin structures
self.pins = {}
# This is a set of all pins so that we don't create blockages for these shapes.
self.all_pins = set()
# A set of connected pin groups
self.pin_groups = {}
# The corresponding sets (components) of grids for each pin
self.pin_components = {}
### The blockage data structures
# A list of pin layout shapes that are blockages
self.blockages=[]
# A set of blocked grids
self.blocked_grids = set()
# The corresponding set of partially blocked grids for each component.
# These are blockages for other nets but unblocked for this component.
self.pin_component_blockages = {}
# A list of pin layout shapes that are blocked
self.blockages=[]
### The routed data structures
# A list of paths that have been "routed"
self.paths = []
# The list of supply rails that may be routed
@ -65,10 +74,13 @@ class router:
Keep the other blockages unchanged.
"""
self.pins = {}
self.all_pins = set()
self.pin_groups = {}
self.pin_grids = {}
self.pin_paritals = {}
self.reinit()
# DO NOT clear the blockages as these don't change
self.rg.reinit()
def set_top(self,top_name):
""" If we want to route something besides the top-level cell."""
@ -103,11 +115,11 @@ class router:
self.layers = layers
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
self.vert_layer_width = tech.drc["minwidth_{0}".format(self.vert_layer_name)]
self.vert_layer_minwidth = tech.drc["minwidth_{0}".format(self.vert_layer_name)]
self.vert_layer_spacing = tech.drc[str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name)]
self.vert_layer_number = tech.layer[self.vert_layer_name]
self.horiz_layer_width = tech.drc["minwidth_{0}".format(self.horiz_layer_name)]
self.horiz_layer_minwidth = tech.drc["minwidth_{0}".format(self.horiz_layer_name)]
self.horiz_layer_spacing = tech.drc[str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)]
self.horiz_layer_number = tech.layer[self.horiz_layer_name]
@ -143,6 +155,7 @@ class router:
debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name)))
self.pins[pin_name] = pin_set
self.all_pins.update(pin_set)
def find_pins(self,pin_name):
"""
@ -151,7 +164,6 @@ class router:
"""
self.retrieve_pins(pin_name)
self.analyze_pins(pin_name)
self.convert_pins(pin_name)
def find_blockages(self):
@ -165,18 +177,16 @@ class router:
self.convert_blockages()
def reinit(self):
"""
Reset the source and destination pins to start a new routing.
Convert the source/dest pins to blockages.
Convert the routed path to blockages.
Keep the other blockages unchanged.
"""
self.pins = {}
self.pin_groups = {}
self.pin_components = {}
# DO NOT clear the blockages as these don't change
self.rg.reinit()
# # def reinit(self):
# # """
# # Reset the source and destination pins to start a new routing.
# # Convert the source/dest pins to blockages.
# # Convert the routed path to blockages.
# # Keep the other blockages unchanged.
# # """
# # self.clear_pins()
# # # DO NOT clear the blockages as these don't change
# # self.rg.reinit()
@ -268,10 +278,10 @@ class router:
"""
Convert a pin layout blockage shape to routing grid tracks.
"""
# Inflate the blockage by spacing rule
# Inflate the blockage by half a spacing rule
[ll,ur]=self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.layer_num)
blockage_tracks = self.get_blockage_tracks(ll,ur,zlayer)
blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer)
return blockage_tracks
def convert_blockages(self):
@ -294,7 +304,9 @@ class router:
ur = vector(boundary[2],boundary[3])
rect = [ll,ur]
new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num)
self.blockages.append(new_pin)
# If there is a rectangle that is the same in the pins, it isn't a blockage!
if new_pin not in self.all_pins:
self.blockages.append(new_pin)
def convert_point_to_units(self, p):
@ -317,8 +329,8 @@ class router:
Convert a rectangular blockage shape into track units.
"""
(ll,ur) = shape
# ll = snap_to_grid(ll)
# ur = snap_to_grid(ur)
ll = snap_to_grid(ll)
ur = snap_to_grid(ur)
# to scale coordinates to tracks
debug.info(3,"Converting [ {0} , {1} ]".format(ll,ur))
@ -337,11 +349,10 @@ class router:
# debug.info(0,"Pin {}".format(pin))
return [ll,ur]
def convert_pin_to_tracks(self, pin):
def convert_pin_to_tracks(self, pin_name, pin):
"""
Convert a rectangular pin shape into a list of track locations,layers.
If no on-grid pins are found, it searches for the nearest off-grid pin(s).
If a pin has insufficent overlap, it returns the blockage list to avoid it.
If no pins are "on-grid" (i.e. sufficient overlap) it makes the one with most overlap if it is not blocked.
"""
(ll,ur) = pin.rect
debug.info(3,"Converting pin [ {0} , {1} ]".format(ll,ur))
@ -350,39 +361,94 @@ class router:
ll=ll.scale(self.track_factor).floor()
ur=ur.scale(self.track_factor).ceil()
# width depends on which layer it is
# Keep tabs on tracks with sufficient and insufficient overlap
sufficient_list = set()
insufficient_list = set()
zindex=self.get_zindex(pin.layer_num)
if zindex:
width = self.vert_layer_width
spacing = self.vert_layer_spacing
else:
width = self.horiz_layer_width
spacing = self.horiz_layer_spacing
track_list = []
block_list = []
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
debug.info(4,"Converting [ {0} , {1} ]".format(x,y))
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
if full_overlap:
sufficient_list.update([full_overlap])
if partial_overlap:
insufficient_list.update([partial_overlap])
# however, if there is not enough overlap, then if there is any overlap at all,
# we need to block it to prevent routes coming in on that grid
full_rect = self.convert_track_to_shape(vector3d(x,y,zindex))
overlap_rect=self.compute_overlap(pin.rect,full_rect)
min_overlap = min(overlap_rect)
debug.info(3,"Check overlap: {0} . {1} = {2}".format(pin.rect,full_rect,overlap_rect))
if len(sufficient_list)>0:
return sufficient_list
elif len(insufficient_list)>0:
# If there wasn't a sufficient grid, find the best and patch it to be on grid.
return self.get_best_offgrid_pin(pin, insufficient_list)
else:
debug.error("Unable to find any overlapping grids.", -1)
def get_best_offgrid_pin(self, pin, insufficient_list):
"""
Given a pin and a list of partial overlap grids:
1) Find the unblocked grids.
2) If one, use it.
3) If not, find the greatest overlap.
4) Add a pin with the most overlap to make it "on grid"
that is not blocked.
"""
#print("INSUFFICIENT LIST",insufficient_list)
# Find the coordinate with the most overlap
best_coord = None
best_overlap = -math.inf
for coord in insufficient_list:
full_rect = self.convert_track_to_pin(coord)
# Compute the overlap with that rectangle
overlap_rect=self.compute_overlap(pin.rect,full_rect)
# Determine the min x or y overlap
min_overlap = min(overlap_rect)
if min_overlap>best_overlap:
best_overlap=min_overlap
best_coord=coord
return set([best_coord])
def get_layer_width_space(self, zindex):
"""
Return the width and spacing of a given layer.
"""
if zindex==1:
width = self.vert_layer_minwidth
spacing = self.vert_layer_spacing
elif zindex==0:
width = self.horiz_layer_minwidth
spacing = self.horiz_layer_spacing
else:
debug.error("Invalid zindex for track", -1)
return (width,spacing)
def convert_pin_coord_to_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".
If it doesn't, add it to the blocked grid list.
"""
(width, spacing) = self.get_layer_width_space(coord.z)
# This is the rectangle if we put a pin in the center of the track
track_rect = self.convert_track_to_pin(coord)
overlap_width = self.compute_overlap_width(pin.rect, track_rect)
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_rect, overlap_width))
# If it overlaps by more than the min width DRC, we can just use the track
if overlap_width==math.inf or snap_val_to_grid(overlap_width) >= snap_val_to_grid(width):
debug.info(3," Overlap: {0} >? {1}".format(overlap_width,spacing))
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_width,spacing))
return (None, coord)
if min_overlap > spacing:
debug.info(3," Overlap: {0} {1} >? {2}".format(overlap_rect,min_overlap,spacing))
track_list.append(vector3d(x,y,zindex))
# otherwise, the pin may not be accessible, so block it
elif min_overlap > 0:
debug.info(3," Insufficient overlap: {0} {1} >? {2}".format(overlap_rect,min_overlap,spacing))
block_list.append(vector3d(x,y,zindex))
else:
debug.info(4," No overlap: {0} {1} max={2}".format(overlap_rect,min_overlap,spacing))
return (tuple(track_list),tuple(block_list))
def compute_overlap(self, r1, r2):
""" Calculate the rectangular overlap of two rectangles. """
@ -399,7 +465,116 @@ class router:
return [dx,dy]
else:
return [0,0]
def compute_overlap_width(self, r1, r2):
"""
Calculate the intersection segment and determine its width.
"""
intersections = self.compute_overlap_segment(r1,r2)
if len(intersections)==2:
(p1,p2) = intersections
return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2))
else:
# we either have no overlap or complete overlap
# Compute the width of the overlap of the two rectangles
overlap_rect=self.compute_overlap(r1, r2)
# Determine the min x or y overlap
min_overlap = min(overlap_rect)
if min_overlap>0:
return math.inf
else:
return 0
def compute_overlap_segment(self, r1, r2):
"""
Calculate the intersection segment of two rectangles
(if any)
"""
(r1_ll,r1_ur) = r1
(r2_ll,r2_ur) = r2
# The other corners besides ll and ur
r1_ul = vector(r1_ll.x, r1_ur.y)
r1_lr = vector(r1_ur.x, r1_ll.y)
r2_ul = vector(r2_ll.x, r2_ur.y)
r2_lr = vector(r2_ur.x, r2_ll.y)
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
# R1 edges CW
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
r1_edges = []
for (p,q) in pairwise(r1_cw_points):
r1_edges.append([p,q])
# R2 edges CW
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
r2_edges = []
for (p,q) in pairwise(r2_cw_points):
r2_edges.append([p,q])
# There are 4 edges on each rectangle
# so just brute force check intersection of each
# Two pairs of them should intersect
intersections = []
for r1e in r1_edges:
for r2e in r2_edges:
i = self.segment_intersection(r1e, r2e)
if i:
intersections.append(i)
return intersections
def on_segment(self, p, q, r):
"""
Given three co-linear points, determine if q lies on segment pr
"""
if q[0] <= max(p[0], r[0]) and \
q[0] >= min(p[0], r[0]) and \
q[1] <= max(p[1], r[1]) and \
q[1] >= min(p[1], r[1]):
return True
return False
def segment_intersection(self, s1, s2):
"""
Determine the intersection point of two segments
Return the a segment if they overlap.
Return None if they don't.
"""
(a,b) = s1
(c,d) = s2
# Line AB represented as a1x + b1y = c1
a1 = b.y - a.y
b1 = a.x - b.x
c1 = a1*a.x + b1*a.y
# Line CD represented as a2x + b2y = c2
a2 = d.y - c.y
b2 = c.x - d.x
c2 = a2*c.x + b2*c.y
determinant = a1*b2 - a2*b1
if determinant!=0:
x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant
r = [x,y]
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return [x, y]
return None
def convert_track_to_pin(self, track):
"""
@ -506,20 +681,25 @@ class router:
self.pin_components[pin_name]
except:
self.pin_components[pin_name] = []
try:
self.pin_component_blockages[pin_name]
except:
self.pin_component_blockages[pin_name] = []
found_pin = False
for pg in self.pin_groups[pin_name]:
print("PG ",pg)
#print("PG ",pg)
# Keep the same groups for each pin
pin_set = set()
blockage_set = set()
for pin in pg:
debug.info(2," Converting {0}".format(pin))
(pin_in_tracks,partial_in_tracks)=self.convert_pin_to_tracks(pin)
blockage_in_tracks = self.convert_blockage(pin)
# Determine which tracks the pin overlaps
pin_in_tracks=self.convert_pin_to_tracks(pin_name, pin)
pin_set.update(pin_in_tracks)
pin_set.update(partial_in_tracks)
# Blockages will be a super-set of pins since it uses the inflated pin shape.
blockage_in_tracks = self.convert_blockage(pin)
blockage_set.update(blockage_in_tracks)
debug.info(2," pins {}".format(pin_set))
@ -534,12 +714,74 @@ class router:
self.pin_components[pin_name].append(pin_set)
# Add all of the blocked grids to the set for the design
self.blocked_grids.update(blockage_set)
partial_set = blockage_set - pin_set
self.pin_component_blockages[pin_name].append(partial_set)
# Remove the pins from the blockages since we didn't know
# they were pins when processing blockages
self.blocked_grids.difference_update(pin_set)
# Remove the blockage set from the blockages since these
# will either be pins or partial pin blockges
self.blocked_grids.difference_update(blockage_set)
def enclose_pin_grids(self, grids):
"""
This encloses a single pin component with a rectangle.
It returns the set of the unenclosed pins.
"""
# We may have started with an empty set
if not grids:
return
# Start with lowest left element
ll = min(grids)
grids.remove(ll)
# Start with the ll and make the widest row
row = [ll]
# Move right while we can
while True:
right = row[-1] + vector3d(1,0,0)
# Can't move if not in the pin shape or blocked
if right in grids and right not in self.blocked_grids:
grids.remove(right)
row.append(right)
else:
break
# Move up while we can
while True:
next_row = [x+vector3d(0,1,0) for x in row]
for cell in next_row:
# Can't move if any cell is not in the pin shape or blocked
if cell not in grids or cell in self.blocked_grids:
break
else:
grids.difference_update(set(next_row))
row = next_row
# Skips the second break
continue
# Breaks from the nested break
break
# Add a shape from ll to ur
ur = row[-1]
self.add_enclosure(ll, ur, ll.z)
# Return the remaining grid set
return grids
def enclose_pins(self):
"""
This will find the biggest rectangle enclosing some grid squares and
put a rectangle over it. It does not enclose grid squares that are blocked
by other shapes.
"""
# FIXME: This could be optimized, but we just do a simple greedy biggest shape
# for now.
for pin_name in self.pin_components.keys():
for pin_set,partial_set in zip(self.pin_components[pin_name],self.pin_component_blockages[pin_name]):
total_pin_grids = pin_set | partial_set
while self.enclose_pin_grids(total_pin_grids):
pass
self.write_debug_gds("pin_debug.gds", False)
def add_source(self, pin_name):
@ -619,71 +861,6 @@ class router:
self.set_blockages(component, value)
def write_debug_gds(self):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
# Only add the debug info to the gds file if we have any debugging on.
# This is because we may reroute a wire with detours and don't want the debug information.
if OPTS.debug_level==0: return
self.add_router_info()
debug.error("Writing debug_route.gds")
self.cell.gds_write("debug_route.gds")
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
the boundary layer for debugging purposes. This can only be
called once or the labels will overlap.
"""
debug.info(0,"Adding router info")
if OPTS.debug_level>0:
for blockage in self.blockages:
# Display the inflated blockage
(ll,ur) = blockage.inflate()
self.cell.add_rect(layer="text",
offset=ll,
width=ur.x-ll.x,
height=ur.y-ll.y)
if OPTS.debug_level>1:
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
shape = self.convert_track_to_shape(g)
self.cell.add_rect(layer="text",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
# These are the on grid pins
#rect = self.convert_track_to_pin(g)
#self.cell.add_rect(layer="boundary",
# offset=rect[0],
# width=rect[1].x-rect[0].x,
# height=rect[1].y-rect[0].y)
t=self.rg.map[g].get_type()
# midpoint offset
off=vector((shape[1].x+shape[0].x)/2,
(shape[1].y+shape[0].y)/2)
if g[2]==1:
# Upper layer is upper right label
type_off=off+partial_track
else:
# Lower layer is lower left label
type_off=off-partial_track
if t!=None:
self.cell.add_label(text=str(t),
layer="text",
offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text",
offset=shape[0],
zoom=0.05)
def prepare_path(self,path):
"""
Prepare a path or wave for routing ebedding.
@ -722,14 +899,14 @@ class router:
# If it is only a square, add an enclosure to the track
if len(path)==1:
self.add_enclosure(abs_path[0])
self.add_single_enclosure(abs_path[0])
else:
# Otherwise, add the route which includes enclosures
self.cell.add_route(layers=self.layers,
coordinates=abs_path,
layer_widths=self.layer_widths)
def add_enclosure(self, loc):
def add_single_enclosure(self, loc):
"""
Add a metal enclosure that is the size of the routing grid minus a spacing on each side.
"""
@ -755,19 +932,45 @@ class router:
def add_wavepath(self, name, path):
"""
Add the current wave to the given design instance.
This is a single layer path that is multiple tracks wide.
"""
path=self.prepare_path(path)
# convert the path back to absolute units from tracks
abs_path = [self.convert_wave_to_units(i) for i in path]
ll = path[0][0]
ur = path[-1][-1]
z = ll.z
pin = self.add_enclosure(ll, ur, z, name)
return pin
ur = abs_path[-1][-1]
ll = abs_path[0][0]
pin = self.cell.add_layout_pin(name,
layer=self.get_layer(path[0][0].z),
offset=vector(ll.x,ll.y),
width=ur.x-ll.x,
height=ur.y-ll.y)
def add_enclosure(self, ll, ur, zindex, name=""):
"""
Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
If name is supplied, it is added as a pin and not just a rectangle.
"""
# 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
(abs_ll,unused) = self.convert_track_to_pin(ll)
(unused,abs_ur) = self.convert_track_to_pin(ur)
#print("enclose ll={0} ur={1}".format(ll,ur))
#print("enclose ll={0} ur={1}".format(abs_ll,abs_ur))
if name:
pin = self.cell.add_layout_pin(name,
layer=layer,
offset=abs_ll,
width=abs_ur.x-abs_ll.x,
height=abs_ur.y-abs_ll.y)
else:
pin = self.cell.add_rect(layer=layer,
offset=abs_ll,
width=abs_ur.x-abs_ll.x,
height=abs_ur.y-abs_ll.y)
return pin
@ -832,20 +1035,105 @@ class router:
self.reinit()
return False
return True
def annotate_pin_and_tracks(self, pin, tracks):
""""
Annotate some shapes for debug purposes
"""
debug.info(0,"Annotating\n pin {0}\n tracks {1}".format(pin,tracks))
for coord in tracks:
(ll,ur) = self.convert_track_to_shape(coord)
self.cell.add_rect(layer="text",
offset=ll,
width=ur[0]-ll[0],
height=ur[1]-ll[1])
(ll,ur) = self.convert_track_to_pin(coord)
self.cell.add_rect(layer="boundary",
offset=ll,
width=ur[0]-ll[0],
height=ur[1]-ll[1])
(ll,ur) = pin.rect
self.cell.add_rect(layer="text",
offset=ll,
width=ur[0]-ll[0],
height=ur[1]-ll[1])
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
# Only add the debug info to the gds file if we have any debugging on.
# This is because we may reroute a wire with detours and don't want the debug information.
if OPTS.debug_level==0: return
self.add_router_info()
self.cell.gds_write(gds_name)
if stop_program:
import sys
sys.exit(1)
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
the boundary layer for debugging purposes. This can only be
called once or the labels will overlap.
"""
debug.info(0,"Adding router info")
if OPTS.debug_level==0:
# Display the inflated blockage
for blockage in self.blockages:
debug.info(1,"Adding {}".format(blockage))
(ll,ur) = blockage.inflate()
self.cell.add_rect(layer="text",
offset=ll,
width=ur.x-ll.x,
height=ur.y-ll.y)
if OPTS.debug_level>1:
#self.set_blockages(self.blocked_grids,True)
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
shape = self.convert_track_to_shape(g)
self.cell.add_rect(layer="text",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
t=self.rg.map[g].get_type()
# midpoint offset
off=vector((shape[1].x+shape[0].x)/2,
(shape[1].y+shape[0].y)/2)
if g[2]==1:
# Upper layer is upper right label
type_off=off+partial_track
else:
# Lower layer is lower left label
type_off=off-partial_track
if t!=None:
self.cell.add_label(text=str(t),
layer="text",
offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text",
offset=shape[0],
zoom=0.05)
# FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset):
"""
Changes the coodrinate to match the grid settings
"""
grid = tech.drc["grid"]
x = offset[0]
y = offset[1]
# this gets the nearest integer value
xgrid = int(round(round((x / grid), 2), 0))
ygrid = int(round(round((y / grid), 2), 0))
xoff = xgrid * grid
yoff = ygrid * grid
xoff = snap_val_to_grid(offset[0])
yoff = snap_val_to_grid(offset[1])
return vector(xoff, yoff)
def snap_val_to_grid(x):
grid = tech.drc["grid"]
xgrid = int(round(round((x / grid), 2), 0))
xoff = xgrid * grid
return xoff

View File

@ -58,13 +58,14 @@ class signal_router(router):
# FIXME: This could be created only over the routing region,
# but this is simplest for now.
self.create_routing_grid()
# This will get all shapes as blockages
self.find_blockages()
# Now add the blockages (all shapes except the pins)
self.find_pins(src)
self.find_pins(dest)
# This will get all shapes as blockages
self.find_blockages()
# Now add the blockages
self.set_blockages(self.blocked_grids,True)
#self.set_blockages(self.pin_partials[src],True)

View File

@ -57,13 +57,10 @@ class supply_router(router):
# FIXME: This could be created only over the routing region,
# but this is simplest for now.
self.create_routing_grid()
# This will get all shapes as blockages
self.find_blockages()
# Get the pin shapes
self.find_pins(self.vdd_name)
self.find_pins(self.gnd_name)
self.find_pins_and_blockages()
# Add the supply rails in a mesh network and connect H/V with vias
# Block everything
self.prepare_blockages()
@ -84,9 +81,30 @@ class supply_router(router):
self.route_pins_to_rails(gnd_name)
self.route_pins_to_rails(vdd_name)
self.write_debug_gds()
self.write_debug_gds(stop_program=False)
return True
def find_pins_and_blockages(self):
"""
Find the pins and blockages in teh design
"""
# This finds the pin shapes and sorts them into "groups" that are connected
self.find_pins(self.vdd_name)
self.find_pins(self.gnd_name)
# This will get all shapes as blockages and convert to grid units
# This ignores shapes that were pins
self.find_blockages()
# This will convert the pins to grid units
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
self.convert_pins(self.vdd_name)
self.convert_pins(self.gnd_name)
# Enclose the continguous grid units in a metal rectangle to fix some DRCs
self.enclose_pins()
def prepare_blockages(self):
"""
Reset and add all of the blockages in the design.
@ -104,7 +122,11 @@ class supply_router(router):
# Block all of the pin components (some will be unblocked if they're a source/target)
for name in self.pin_components.keys():
self.set_blockages(self.pin_components[name],True)
# Block all of the pin component partial blockages
for name in self.pin_component_blockages.keys():
self.set_blockages(self.pin_component_blockages[name],True)
# These are the paths that have already been routed.
self.set_path_blockages()
@ -234,11 +256,11 @@ class supply_router(router):
num_components = self.num_pin_components(pin_name)
debug.info(0,"Pin {0} has {1} components to route.".format(pin_name, num_components))
debug.info(1,"Pin {0} has {1} components to route.".format(pin_name, num_components))
# For every component
for index in range(num_components):
debug.info(0,"Routing component {0} {1}".format(pin_name, index))
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
self.rg.reinit()
@ -253,12 +275,8 @@ class supply_router(router):
self.add_supply_rail_target(pin_name)
# Actually run the A* router
self.run_router(detour_scale=5)
#if index==1:
# self.write_debug_gds()
# import sys
# sys.exit(1)
if not self.run_router(detour_scale=5):
self.write_debug_gds()

View File

@ -142,6 +142,15 @@ class vector3d():
return self.x==other.x and self.y==other.y and self.z==other.z
return False
def __lt__(self, other):
"""Override the default less than behavior"""
if isinstance(other, self.__class__):
if self.x<other.x:
return True
if self.x==other.x and self.y<other.y:
return True
return False
def __ne__(self, other):
"""Override the default non-equality behavior"""
return not self.__eq__(other)