diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index c5434246..c1e6d79a 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -316,7 +316,43 @@ class pin_layout: return [dx,dy] else: return [0,0] + + def distance(self, other): + """ + Calculate the distance to another pin layout. + """ + (r1_ll,r1_ur) = self.rect + (r2_ll,r2_ur) = other.rect + + def dist(x1, y1, x2, y2): + return sqrt((x2-x1)**2 + (y2-y1)**2) + left = r2_ur.x < r1_ll.x + right = r1_ur.x < r2_ll.x + bottom = r2_ur.y < r1_ll.y + top = r1_ur.y < r2_ll.y + + if top and left: + return dist(r1_ll.x, r1_ur.y, r2_ur.x, r2_ll.y) + elif left and bottom: + return dist(r1_ll.x, r1_ll.y, r2_ur.x, r2_ur.y) + elif bottom and right: + return dist(r1_ur.x, r1_ll.y, r2_ll.x, r2_ur.y) + elif right and top: + return dist(r1_ur.x, r1_ur.y, r2_ll.x, r2_ll.y) + elif left: + return r1_ll.x - r2_ur.x + elif right: + return r2_ll.x - r1.ur.x + elif bottom: + return r1_ll.y - r2_ur.y + elif top: + return r2_ll.y - r1_ur.y + else: + # rectangles intersect + return 0 + + def overlap_length(self, other): """ Calculate the intersection segment and determine its length diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 598805e7..d71c7073 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -566,11 +566,10 @@ class pin_group: debug.info(2," Converting {0}".format(pin)) # Determine which tracks the pin overlaps pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin) - pin_set.update(pin_in_tracks) + # Blockages will be a super-set of pins since it uses the inflated pin shape. blockage_in_tracks = self.router.convert_blockage(pin) - blockage_set.update(blockage_in_tracks) # If we have a blockage, we must remove the grids @@ -578,17 +577,26 @@ class pin_group: shared_set = pin_set & self.router.blocked_grids if len(shared_set)>0: debug.info(2,"Removing pins {}".format(shared_set)) - pin_set.difference_update(self.router.blocked_grids) - + pin_set.difference_update(shared_set) shared_set = blockage_set & self.router.blocked_grids if len(shared_set)>0: debug.info(2,"Removing blocks {}".format(shared_set)) - blockage_set.difference_update(self.router.blocked_grids) + blockage_set.difference_update(shared_set) # At least one of the groups must have some valid tracks if (len(pin_set)==0 and len(blockage_set)==0): - debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) - self.router.write_debug_gds("blocked_pin.gds") + debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) + + for pin_list in self.pins: + for pin in pin_list: + debug.info(2," Converting {0}".format(pin)) + # Determine which tracks the pin overlaps + pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) + pin_set.update(pin_in_tracks) + + if len(pin_set)==0: + debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) + self.router.write_debug_gds("blocked_pin.gds") # We need to route each of the components, so don't combine the groups self.grids = pin_set | blockage_set diff --git a/compiler/router/router.py b/compiler/router/router.py index afe06588..76f2e1cc 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -495,10 +495,11 @@ class router(router_tech): # debug.info(0,"Pin {}".format(pin)) return [ll,ur] - def convert_pin_to_tracks(self, pin_name, pin): + def convert_pin_to_tracks(self, pin_name, pin, expansion=0): """ Convert a rectangular pin shape into a list of track locations,layers. If no pins are "on-grid" (i.e. sufficient overlap) it makes the one with most overlap if it is not blocked. + If expansion>0, expamine areas beyond the current pin when it is blocked. """ (ll,ur) = pin.rect debug.info(3,"Converting pin [ {0} , {1} ]".format(ll,ur)) @@ -512,8 +513,8 @@ class router(router_tech): insufficient_list = set() zindex=self.get_zindex(pin.layer_num) - for x in range(int(ll[0]),int(ur[0])+1): - for y in range(int(ll[1]),int(ur[1])+1): + for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion): + for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion): 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: @@ -523,9 +524,14 @@ class router(router_tech): 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. + elif expansion==0 and len(insufficient_list)>0: + #Remove blockages and return the best to be patched + insufficient_list.difference_update(self.blocked_grids) return self.get_best_offgrid_pin(pin, insufficient_list) + elif expansion>0: + #Remove blockages and return the nearest + insufficient_list.difference_update(self.blocked_grids) + return self.get_nearest_offgrid_pin(pin, insufficient_list) else: debug.error("Unable to find any overlapping grids.", -1) @@ -555,6 +561,24 @@ class router(router_tech): return set([best_coord]) + def get_nearest_offgrid_pin(self, pin, insufficient_list): + """ + Given a pin and a list of grid cells (probably non-overlapping), + return the nearest grid cell (center to center). + """ + #print("INSUFFICIENT LIST",insufficient_list) + # Find the coordinate with the most overlap + best_coord = None + best_dist = math.inf + for coord in insufficient_list: + track_pin = self.convert_track_to_pin(coord) + min_dist = pin.distance(track_pin) + if min_dist