from vector3d import vector3d from tech import drc import debug class pin_group: """ A class to represent a group of touching rectangular design pin. It requires a router to define the track widths and blockages which determine how pin shapes get mapped to tracks. """ def __init__(self, name, pin_shapes, router): self.name = name # Flag for when it is routed self.routed = False self.shapes = pin_shapes self.router = router # These are the corresponding pin grids for each pin group. self.grids = set() # The corresponding set of partially blocked grids for each pin group. # These are blockages for other nets but unblocked for routing this group. self.blockages = set() def set_routed(self, value=True): self.routed = value def is_routed(self): return self.routed def remove_redundant_shapes(self, pin_list): """ Remove any pin layout that is contained within another. """ local_debug = False if local_debug: debug.info(0,"INITIAL:",pin_list) # Make a copy of the list to start new_pin_list = pin_list.copy() # This is n^2, but the number is small for pin1 in pin_list: for pin2 in pin_list: # Can't contain yourself if pin1 == pin2: continue if pin2.contains(pin1): # It may have already been removed by being enclosed in another pin if pin1 in new_pin_list: new_pin_list.remove(pin1) if local_debug: debug.info(0,"FINAL :",new_pin_list) return new_pin_list # FIXME: This relies on some technology parameters from router which is not clearn. def compute_enclosures(self): """ Find the minimum rectangle enclosures of the given tracks. """ # Enumerate every possible enclosure pin_list = [] for seed in self.grids: (ll, ur) = self.enclose_pin_grids(seed) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z) pin_list.append(enclosure) #return pin_list # We used to do this, but smaller enclosures can be return self.remove_redundant_shapes(pin_list) def compute_enclosure(self, pin, enclosure): """ Compute an enclosure to connect the pin to the enclosure shape. This assumes the shape will be the dimension of the pin. """ if pin.xoverlaps(enclosure): # Is it vertical overlap, extend pin shape to enclosure plc = pin.lc() prc = pin.rc() elc = enclosure.lc() erc = enclosure.rc() ymin = min(plc.y,elc.y) 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() puc = pin.uc() ebc = enclosure.bc() euc = enclosure.uc() xmin = min(pbc.x,ebc.x) 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() ec = enclosure.center() xmin = min(pc.x, ec.x) xmax = max(pc.x, ec.x) ymin = min(pc.y, ec.y) ymax = max(pc.y, ec.y) ll = vector(xmin, ymin) ur = vector(xmax, ymax) p = pin_layout(pin.name, [ll, ur], pin.layer) return p def find_smallest_connector(self, enclosure_list): """ Compute all of the connectors between non-overlapping pins and enclosures. Return the smallest. """ smallest = None for pin in self.shapes: for enclosure in enclosure_list: new_enclosure = self.compute_enclosure(pin, enclosure) if smallest == None or new_enclosure.area() min_width: if smallest_shape == None or other.area() biggest.area(): biggest = pin return pin def enclose_pin_grids(self, seed): """ This encloses a single pin component with a rectangle starting with the seed and expanding right until blocked and then up until blocked. """ # We may have started with an empty set if not self.grids: return None # Start with the seed ll = seed # 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 if right in self.grids and right not in self.router.blocked_grids: 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 if cell not in self.grids or cell in self.router.blocked_grids: break else: row = next_row # Skips the second break continue # Breaks from the nested break break # Add a shape from ll to ur ur = row[-1] return (ll,ur) def enclose_pin(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. """ # Compute the enclosure pin_layout list of the set of tracks enclosure_list = self.compute_enclosures() self.enclosure = self.find_smallest_overlapping(enclosure_list) if not self.enclosure: self.enclosure = self.find_smallest_connector(enclosure_list) debug.info(2,"Computed enclosure {0} {1}".format(self.name, self.enclosure)) def add_enclosure(self, cell): """ Add the enclosure shape to the given cell. """ debug.info(2,"Adding enclosure {0} {1}".format(self.name, self.enclosure)) self.router.cell.add_rect(layer=self.enclosure.layer, offset=self.enclosure.ll(), width=self.enclosure.width(), height=self.enclosure.height())