PEP8 formatting

This commit is contained in:
Matthew Guthaus 2019-11-07 16:33:13 +00:00
parent a2422cc8d4
commit 0dea153919
2 changed files with 468 additions and 419 deletions

View File

@ -7,17 +7,15 @@
# #
from direction import direction from direction import direction
from pin_layout import pin_layout from pin_layout import pin_layout
from vector3d import vector3d
from vector import vector from vector import vector
import grid_utils
from tech import drc
import debug import debug
class pin_group: class pin_group:
""" """
A class to represent a group of rectangular design pin. A class to represent a group of rectangular design pin.
It requires a router to define the track widths and blockages which It requires a router to define the track widths and blockages which
determine how pin shapes get mapped to tracks. determine how pin shapes get mapped to tracks.
It is initially constructed with a single set of (touching) pins. It is initially constructed with a single set of (touching) pins.
""" """
def __init__(self, name, pin_set, router): def __init__(self, name, pin_set, router):
@ -30,19 +28,22 @@ class pin_group:
# Remove any redundant pins (i.e. contained in other pins) # Remove any redundant pins (i.e. contained in other pins)
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set)) irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
# This is a list because we can have a pin group of disconnected sets of pins # This is a list because we can have a pin
# group of disconnected sets of pins
# and these are represented by separate lists # and these are represented by separate lists
self.pins = set(irredundant_pin_set) self.pins = set(irredundant_pin_set)
self.router = router self.router = router
# These are the corresponding pin grids for each pin group. # These are the corresponding pin grids for each pin group.
self.grids = set() self.grids = set()
# These are the secondary grids that could or could not be part of the pin # These are the secondary grids that could
# or could not be part of the pin
self.secondary_grids = set() self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group. # The corresponding set of partially blocked grids for each pin group.
# These are blockages for other nets but unblocked for routing this group. # These are blockages for other nets but unblocked
# These are also blockages if we used a simple enclosure to route to a rail. # for routing this group. These are also blockages if we
# used a simple enclosure to route to a rail.
self.blockages = set() self.blockages = set()
# This is a set of pin_layout shapes to cover the grids # This is a set of pin_layout shapes to cover the grids
@ -88,22 +89,23 @@ class pin_group:
""" """
local_debug = False local_debug = False
if local_debug: if local_debug:
debug.info(0,"INITIAL: {}".format(pin_list)) debug.info(0, "INITIAL: {}".format(pin_list))
# Make a copy of the list to start # Make a copy of the list to start
new_pin_list = pin_list.copy() new_pin_list = pin_list.copy()
remove_indices = set() remove_indices = set()
# This is n^2, but the number is small # This is n^2, but the number is small
for index1,pin1 in enumerate(pin_list): for index1, pin1 in enumerate(pin_list):
# If we remove this pin, it can't contain other pins # If we remove this pin, it can't contain other pins
if index1 in remove_indices: if index1 in remove_indices:
continue continue
for index2,pin2 in enumerate(pin_list): for index2, pin2 in enumerate(pin_list):
# Can't contain yourself, but compare the indices and not the pins # Can't contain yourself,
# but compare the indices and not the pins
# so you can remove duplicate copies. # so you can remove duplicate copies.
if index1==index2: if index1 == index2:
continue continue
# If we already removed it, can't remove it again... # If we already removed it, can't remove it again...
if index2 in remove_indices: if index2 in remove_indices:
@ -111,7 +113,7 @@ class pin_group:
if pin1.contains(pin2): if pin1.contains(pin2):
if local_debug: if local_debug:
debug.info(0,"{0} contains {1}".format(pin1,pin2)) debug.info(0, "{0} contains {1}".format(pin1, pin2))
remove_indices.add(index2) remove_indices.add(index2)
# Remove them in decreasing order to not invalidate the indices # Remove them in decreasing order to not invalidate the indices
@ -119,7 +121,7 @@ class pin_group:
del new_pin_list[i] del new_pin_list[i]
if local_debug: if local_debug:
debug.info(0,"FINAL : {}".format(new_pin_list)) debug.info(0, "FINAL : {}".format(new_pin_list))
return new_pin_list return new_pin_list
@ -130,23 +132,26 @@ class pin_group:
# Enumerate every possible enclosure # Enumerate every possible enclosure
pin_list = [] pin_list = []
for seed in self.grids: for seed in self.grids:
(ll, ur) = self.enclose_pin_grids(seed, direction.NORTH, direction.EAST) (ll, ur) = self.enclose_pin_grids(seed,
direction.NORTH,
direction.EAST)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure) pin_list.append(enclosure)
(ll, ur) = self.enclose_pin_grids(seed, direction.EAST, direction.NORTH) (ll, ur) = self.enclose_pin_grids(seed,
direction.EAST,
direction.NORTH)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure) pin_list.append(enclosure)
# Now simplify the enclosure list # Now simplify the enclosure list
new_pin_list = self.remove_redundant_shapes(pin_list) new_pin_list = self.remove_redundant_shapes(pin_list)
return new_pin_list return new_pin_list
def compute_connector(self, pin, enclosure): def compute_connector(self, pin, enclosure):
""" """
Compute a shape to connect the pin to the enclosure shape. Compute a shape to connect the pin to the enclosure shape.
This assumes the shape will be the dimension of the pin. This assumes the shape will be the dimension of the pin.
""" """
if pin.xoverlaps(enclosure): if pin.xoverlaps(enclosure):
@ -154,9 +159,9 @@ class pin_group:
plc = pin.lc() plc = pin.lc()
prc = pin.rc() prc = pin.rc()
elc = enclosure.lc() elc = enclosure.lc()
erc = enclosure.rc() # erc = enclosure.rc()
ymin = min(plc.y,elc.y) ymin = min(plc.y, elc.y)
ymax = max(plc.y,elc.y) ymax = max(plc.y, elc.y)
ll = vector(plc.x, ymin) ll = vector(plc.x, ymin)
ur = vector(prc.x, ymax) ur = vector(prc.x, ymax)
elif pin.yoverlaps(enclosure): elif pin.yoverlaps(enclosure):
@ -164,9 +169,9 @@ class pin_group:
pbc = pin.bc() pbc = pin.bc()
puc = pin.uc() puc = pin.uc()
ebc = enclosure.bc() ebc = enclosure.bc()
euc = enclosure.uc() # euc = enclosure.uc()
xmin = min(pbc.x,ebc.x) xmin = min(pbc.x, ebc.x)
xmax = max(pbc.x,ebc.x) xmax = max(pbc.x, ebc.x)
ll = vector(xmin, pbc.y) ll = vector(xmin, pbc.y)
ur = vector(xmax, puc.y) ur = vector(xmax, puc.y)
else: else:
@ -180,7 +185,7 @@ class pin_group:
ll = vector(xmin, ymin) ll = vector(xmin, ymin)
ur = vector(xmax, ymax) ur = vector(xmax, ymax)
if ll.x==ur.x or ll.y==ur.y: if ll.x == ur.x or ll.y == ur.y:
return None return None
p = pin_layout(pin.name, [ll, ur], pin.layer) p = pin_layout(pin.name, [ll, ur], pin.layer)
return p return p
@ -202,13 +207,13 @@ class pin_group:
# Find the bottom edge that is next to the pin's top edge # Find the bottom edge that is next to the pin's top edge
above_item = None above_item = None
for item in edge_list: for item in edge_list:
if item.by()>=pin.uy(): if item.by() >= pin.uy():
above_item = item above_item = item
else: else:
break break
# There was nothing # There was nothing
if above_item==None: if not above_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if above_item.overlaps(pin): if above_item.overlaps(pin):
@ -219,7 +224,7 @@ class pin_group:
return p return p
def find_below_connector(self, pin, enclosures): def find_below_connector(self, pin, enclosures):
""" """
Find the enclosure that is below the pin Find the enclosure that is below the pin
and make a connector to it's upper edge. and make a connector to it's upper edge.
""" """
@ -235,13 +240,13 @@ class pin_group:
# Find the upper edge that is next to the pin's bottom edge # Find the upper edge that is next to the pin's bottom edge
bottom_item = None bottom_item = None
for item in edge_list: for item in edge_list:
if item.uy()<=pin.by(): if item.uy() <= pin.by():
bottom_item = item bottom_item = item
else: else:
break break
# There was nothing to the left # There was nothing to the left
if bottom_item==None: if not bottom_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if bottom_item.overlaps(pin): if bottom_item.overlaps(pin):
@ -274,7 +279,7 @@ class pin_group:
break break
# There was nothing to the left # There was nothing to the left
if left_item==None: if not left_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if left_item.overlaps(pin): if left_item.overlaps(pin):
@ -301,13 +306,13 @@ class pin_group:
# Find the left edge that is next to the pin's right edge # Find the left edge that is next to the pin's right edge
right_item = None right_item = None
for item in edge_list: for item in edge_list:
if item.lx()>=pin.rx(): if item.lx() >= pin.rx():
right_item = item right_item = item
else: else:
break break
# There was nothing to the right # There was nothing to the right
if right_item==None: if not right_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if right_item.overlaps(pin): if right_item.overlaps(pin):
@ -319,50 +324,50 @@ class pin_group:
def find_smallest_connector(self, pin_list, shape_list): def find_smallest_connector(self, pin_list, shape_list):
""" """
Compute all of the connectors between the overlapping pins and enclosure shape list.. Compute all of the connectors between the overlapping
pins and enclosure shape list.
Return the smallest. Return the smallest.
""" """
smallest = None smallest = None
for pin in pin_list: for pin in pin_list:
for enclosure in shape_list: for enclosure in shape_list:
new_enclosure = self.compute_connector(pin, enclosure) new_enclosure = self.compute_connector(pin, enclosure)
if smallest == None or new_enclosure.area()<smallest.area(): if not smallest or new_enclosure.area() < smallest.area():
smallest = new_enclosure smallest = new_enclosure
return smallest return smallest
def find_smallest_overlapping(self, pin_list, shape_list): def find_smallest_overlapping(self, pin_list, shape_list):
""" """
Find the smallest area shape in shape_list that overlaps with any Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width. pin in pin_list by a min width.
""" """
smallest_shape = None smallest_shape = None
for pin in pin_list: for pin in pin_list:
overlap_shape = self.find_smallest_overlapping_pin(pin,shape_list) overlap_shape = self.find_smallest_overlapping_pin(pin, shape_list)
if overlap_shape: if overlap_shape:
overlap_length = pin.overlap_length(overlap_shape) # overlap_length = pin.overlap_length(overlap_shape)
if smallest_shape == None or overlap_shape.area()<smallest_shape.area(): if not smallest_shape or overlap_shape.area() < smallest_shape.area():
smallest_shape = overlap_shape smallest_shape = overlap_shape
return smallest_shape return smallest_shape
def find_smallest_overlapping_pin(self, pin, shape_list): def find_smallest_overlapping_pin(self, pin, shape_list):
""" """
Find the smallest area shape in shape_list that overlaps with any Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width. pin in pin_list by a min width.
""" """
smallest_shape = None smallest_shape = None
zindex=self.router.get_zindex(pin.layer_num) zindex = self.router.get_zindex(pin.layer_num)
(min_width,min_space) = self.router.get_layer_width_space(zindex) (min_width, min_space) = self.router.get_layer_width_space(zindex)
# Now compare it with every other shape to check how much they overlap # Now compare it with every other shape to check how much they overlap
for other in shape_list: for other in shape_list:
overlap_length = pin.overlap_length(other) overlap_length = pin.overlap_length(other)
if overlap_length > min_width: if overlap_length > min_width:
if smallest_shape == None or other.area()<smallest_shape.area(): if not smallest_shape or other.area() < smallest_shape.area():
smallest_shape = other smallest_shape = other
return smallest_shape return smallest_shape
@ -378,9 +383,8 @@ class pin_group:
return False return False
def max_pin_layout(self, pin_list): def max_pin_layout(self, pin_list):
""" """
Return the max area pin_layout Return the max area pin_layout
""" """
biggest = pin_list[0] biggest = pin_list[0]
@ -398,8 +402,8 @@ class pin_group:
dir1 and dir2 should be two orthogonal directions. dir1 and dir2 should be two orthogonal directions.
""" """
offset1= direction.get_offset(dir1) offset1 = direction.get_offset(dir1)
offset2= direction.get_offset(dir2) offset2 = direction.get_offset(dir2)
# We may have started with an empty set # We may have started with an empty set
if not self.grids: if not self.grids:
@ -410,7 +414,7 @@ class pin_group:
# Move in dir1 while we can # Move in dir1 while we can
while True: while True:
next_cell = row[-1] + offset1 next_cell = row[-1] + offset1
# Can't move if not in the pin shape # Can't move if not in the pin shape
if next_cell in self.grids and next_cell not in self.router.blocked_grids: if next_cell in self.grids and next_cell not in self.router.blocked_grids:
row.append(next_cell) row.append(next_cell)
else: else:
@ -419,7 +423,7 @@ class pin_group:
while True: while True:
next_row = [x+offset2 for x in row] next_row = [x+offset2 for x in row]
for cell in next_row: for cell in next_row:
# Can't move if any cell is not in the pin shape # Can't move if any cell is not in the pin shape
if cell not in self.grids or cell in self.router.blocked_grids: if cell not in self.grids or cell in self.router.blocked_grids:
break break
else: else:
@ -431,13 +435,13 @@ class pin_group:
# Add a shape from ll to ur # Add a shape from ll to ur
ur = row[-1] ur = row[-1]
return (ll,ur) return (ll, ur)
def enclose_pin(self): def enclose_pin(self):
""" """
If there is one set of connected pin shapes, If there is one set of connected pin shapes,
this will find the smallest rectangle enclosure that overlaps with any pin. this will find the smallest rectangle enclosure that
overlaps with any pin.
If there is not, it simply returns all the enclosures. If there is not, it simply returns all the enclosures.
""" """
self.enclosed = True self.enclosed = True
@ -453,40 +457,53 @@ class pin_group:
continue continue
# Find a connector in the cardinal directions # Find a connector in the cardinal directions
# If there is overlap, but it isn't contained, these could all be None # If there is overlap, but it isn't contained,
# These could also be none if the pin is diagonal from the enclosure # these could all be None
# These could also be none if the pin is
# diagonal from the enclosure
left_connector = self.find_left_connector(pin, self.enclosures) left_connector = self.find_left_connector(pin, self.enclosures)
right_connector = self.find_right_connector(pin, self.enclosures) right_connector = self.find_right_connector(pin, self.enclosures)
above_connector = self.find_above_connector(pin, self.enclosures) above_connector = self.find_above_connector(pin, self.enclosures)
below_connector = self.find_below_connector(pin, self.enclosures) below_connector = self.find_below_connector(pin, self.enclosures)
connector_list = [left_connector, right_connector, above_connector, below_connector] connector_list = [left_connector,
filtered_list = list(filter(lambda x: x!=None, connector_list)) right_connector,
if (len(filtered_list)>0): above_connector,
below_connector]
filtered_list = list(filter(lambda x: not x, connector_list))
if (len(filtered_list) > 0):
import copy import copy
bbox_connector = copy.copy(pin) bbox_connector = copy.copy(pin)
bbox_connector.bbox(filtered_list) bbox_connector.bbox(filtered_list)
self.enclosures.append(bbox_connector) self.enclosures.append(bbox_connector)
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. # Now, make sure each pin touches an enclosure.
# This could only happen when there was no enclosure in any cardinal direction from a pin # If not, add another (diagonal) connector.
# This could only happen when there was no enclosure
# in any cardinal direction from a pin
if not self.overlap_any_shape(self.pins, self.enclosures): if not self.overlap_any_shape(self.pins, self.enclosures):
connector = self.find_smallest_connector(self.pins, self.enclosures) connector = self.find_smallest_connector(self.pins,
if connector==None: self.enclosures)
debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures)) if not connector:
debug.error("Could not find a connector for {} with {}".format(self.pins,
self.enclosures))
self.router.write_debug_gds("no_connector.gds") self.router.write_debug_gds("no_connector.gds")
self.enclosures.append(connector) self.enclosures.append(connector)
# At this point, the pins are overlapping, but there might be more than one! # At this point, the pins are overlapping,
# but there might be more than one!
overlap_set = set() overlap_set = set()
for pin in self.pins: for pin in self.pins:
overlap_set.update(self.transitive_overlap(pin, self.enclosures)) overlap_set.update(self.transitive_overlap(pin, self.enclosures))
# Use the new enclosures and recompute the grids that correspond to them # Use the new enclosures and recompute the grids
if len(overlap_set)<len(self.enclosures): # that correspond to them
if len(overlap_set) < len(self.enclosures):
self.enclosures = overlap_set self.enclosures = overlap_set
self.grids=set() self.grids = set()
# Also update the grid locations with the new (possibly pruned) enclosures # Also update the grid locations with the new
# (possibly pruned) enclosures
for enclosure in self.enclosures: for enclosure in self.enclosures:
(sufficient,insufficient) = self.router.convert_pin_to_tracks(self.name,enclosure) (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
enclosure)
self.grids.update(sufficient) self.grids.update(sufficient)
@ -498,7 +515,7 @@ class pin_group:
def transitive_overlap(self, shape, shape_list): def transitive_overlap(self, shape, shape_list):
""" """
Given shape, find the elements in shape_list that overlap transitively. Given shape, find the elements in shape_list that overlap transitively.
I.e. if shape overlaps A and A overlaps B, return both A and B. I.e. if shape overlaps A and A overlaps B, return both A and B.
""" """
augmented_shape_list = set(shape_list) augmented_shape_list = set(shape_list)
@ -512,7 +529,6 @@ class pin_group:
for cur_shape in augmented_shape_list: for cur_shape in augmented_shape_list:
if old_shape.overlaps(cur_shape): if old_shape.overlaps(cur_shape):
connected_set.add(cur_shape) connected_set.add(cur_shape)
# Remove the original shape # Remove the original shape
connected_set.remove(shape) connected_set.remove(shape)
@ -524,19 +540,18 @@ class pin_group:
# pprint.pprint(connected_set) # pprint.pprint(connected_set)
return connected_set return connected_set
def add_enclosure(self, cell): def add_enclosure(self, cell):
""" """
Add the enclosure shape to the given cell. Add the enclosure shape to the given cell.
""" """
for enclosure in self.enclosures: for enclosure in self.enclosures:
debug.info(2,"Adding enclosure {0} {1}".format(self.name, enclosure)) debug.info(2, "Adding enclosure {0} {1}".format(self.name,
enclosure))
cell.add_rect(layer=enclosure.layer, cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(), offset=enclosure.ll(),
width=enclosure.width(), width=enclosure.width(),
height=enclosure.height()) height=enclosure.height())
def perimeter_grids(self): def perimeter_grids(self):
""" """
@ -555,7 +570,7 @@ class pin_group:
return perimeter_set return perimeter_set
def adjacent(self, other): def adjacent(self, other):
""" """
Chck if the two pin groups have at least one adjacent pin grid. Chck if the two pin groups have at least one adjacent pin grid.
""" """
# We could optimize this to just check the boundaries # We could optimize this to just check the boundaries
@ -566,9 +581,8 @@ class pin_group:
return False return False
def adjacent_grids(self, other, separation): def adjacent_grids(self, other, separation):
""" """
Determine the sets of grids that are within a separation distance Determine the sets of grids that are within a separation distance
of any grid in the other set. of any grid in the other set.
""" """
@ -592,53 +606,58 @@ class pin_group:
blockage_set = set() blockage_set = set()
for pin in self.pins: for pin in self.pins:
debug.info(2," Converting {0}".format(pin)) debug.info(2, " Converting {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin) (sufficient, insufficient)=self.router.convert_pin_to_tracks(self.name,
pin)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
# Blockages will be a super-set of pins since it uses the inflated pin shape. # Blockages will be a super-set of pins since
blockage_in_tracks = self.router.convert_blockage(pin) # it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks) blockage_set.update(blockage_in_tracks)
# If we have a blockage, we must remove the grids # If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already # Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids shared_set = pin_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing pins {}".format(shared_set)) debug.info(2, "Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set) pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids shared_set = partial_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing pins {}".format(shared_set)) debug.info(2, "Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set) partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing blocks {}".format(shared_set)) debug.info(2, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set) blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks # At least one of the groups must have some valid tracks
if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0): if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0):
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) # debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins: for pin in self.pins:
debug.warning(" Expanding conversion {0}".format(pin)) debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) (sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name,
pin,
expansion=1)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
if len(pin_set)==0 and len(partial_set)==0: if len(pin_set) == 0 and len(partial_set) == 0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) debug.error("Unable to find unblocked pin {} {}".format(self.name,
self.pins))
self.router.write_debug_gds("blocked_pin.gds") self.router.write_debug_gds("blocked_pin.gds")
# Consider all the grids that would be blocked # Consider all the grids that would be blocked
self.grids = pin_set | partial_set self.grids = pin_set | partial_set
# Remember the secondary grids for removing adjacent pins # Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set self.secondary_grids = partial_set
debug.info(2," pins {}".format(self.grids)) debug.info(2, " pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_grids)) debug.info(2, " secondary {}".format(self.secondary_grids))

File diff suppressed because it is too large Load Diff