diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 13368d12..0600561b 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -25,7 +25,7 @@ class pin_group: # This is a list because we can have a pin group of disconnected sets of pins # and these are represented by separate lists - self.pins = [set(irredundant_pin_set)] + self.pins = set(irredundant_pin_set) self.router = router # These are the corresponding pin grids for each pin group. @@ -55,7 +55,7 @@ class pin_group: total_string += grids_string if self.enclosed: - enlosure_string = "\n enclose={}".format(self.enclosures) + enclosure_string = "\n enclose={}".format(self.enclosures) total_string += enclosure_string total_string += ")" @@ -74,25 +74,6 @@ class pin_group: def is_routed(self): return self.routed - def pins_enclosed(self): - """ - Check if all of the pin shapes are enclosed. - Does not check if the DRC is correct, but just touching. - """ - for pin_list in self.pins: - pin_is_enclosed=False - for pin in pin_list: - if pin_is_enclosed: - break - for encosure in self.enclosures: - if pin.overlaps(enclosure): - pin_is_enclosed=True - break - else: - return False - - return True - def remove_redundant_shapes(self, pin_list): """ Remove any pin layout that is contained within another. @@ -135,7 +116,6 @@ class pin_group: return new_pin_list - # FIXME: This relies on some technology parameters from router which is not clean. def compute_enclosures(self): """ Find the minimum rectangle enclosures of the given tracks. @@ -406,8 +386,8 @@ class pin_group: def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST): """ This encloses a single pin component with a rectangle - starting with the seed and expanding right until blocked - and then up until blocked. + starting with the seed and expanding dir1 until blocked + and then dir2 until blocked. dir1 and dir2 should be two orthogonal directions. """ @@ -458,61 +438,86 @@ class pin_group: # Compute the enclosure pin_layout list of the set of tracks self.enclosures = self.compute_enclosures() - for pin_list in self.pins: - for pin in pin_list: + # Find a connector to every pin and add it to the enclosures + for pin in self.pins: - # If it is contained, it won't need a connector - if pin.contained_by_any(self.enclosures): - continue + # If it is contained, it won't need a connector + if pin.contained_by_any(self.enclosures): + continue - # Find a connector in the cardinal directions - # If there is overlap, but it isn't contained, 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) - right_connector = self.find_right_connector(pin, self.enclosures) - above_connector = self.find_above_connector(pin, self.enclosures) - below_connector = self.find_below_connector(pin, self.enclosures) - connector_list = [left_connector, right_connector, above_connector, below_connector] - filtered_list = list(filter(lambda x: x!=None, connector_list)) - if (len(filtered_list)>0): - import copy - bbox_connector = copy.copy(pin) - bbox_connector.bbox(filtered_list) - self.enclosures.append(bbox_connector) + # Find a connector in the cardinal directions + # If there is overlap, but it isn't contained, 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) + right_connector = self.find_right_connector(pin, self.enclosures) + above_connector = self.find_above_connector(pin, self.enclosures) + below_connector = self.find_below_connector(pin, self.enclosures) + connector_list = [left_connector, right_connector, above_connector, below_connector] + filtered_list = list(filter(lambda x: x!=None, connector_list)) + if (len(filtered_list)>0): + import copy + bbox_connector = copy.copy(pin) + bbox_connector.bbox(filtered_list) + self.enclosures.append(bbox_connector) # Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. # This could only happen when there was no enclosure in any cardinal direction from a pin - 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) - 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) - + if not self.overlap_any_shape(self.pins, self.enclosures): + connector = self.find_smallest_connector(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) + + # At this point, the pins are overlapping, but there might be more than one! + overlap_set = set() + for pin in self.pins: + overlap_set.update(self.transitive_overlap(pin, self.enclosures)) + # Use the new enclosures and recompute the grids that correspond to them + if len(overlap_set) len(old_connected_set): + old_connected_set = connected_set + connected_set = set([shape]) + for old_shape in old_connected_set: + for cur_shape in augmented_shape_list: + if old_shape.overlaps(cur_shape): + connected_set.add(cur_shape) + + + # Remove the original shape + connected_set.remove(shape) + + # if len(connected_set) {0}\n {1}".format(combined.pins,combined.grids)) + # new_pin_groups.append(combined) + + # # Add the pin groups that weren't added to the new set + # for index in all_indices: + # new_pin_groups.append(self.pin_groups[pin_name][index]) + + # old_size = len(self.pin_groups[pin_name]) + # # Use the new pin group! + # self.pin_groups[pin_name] = new_pin_groups + # removed_pairs = old_size - len(new_pin_groups) + # debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name)) - # Now reconstruct the new groups - new_pin_groups = [] - for index1,index2_set in adjacent_pins.items(): - # Remove the indices if they are added to the new set - all_indices.discard(index1) - all_indices.difference_update(index2_set) - - # Create the combined group starting with the first item - combined = self.pin_groups[pin_name][index1] - # Add all of the other items that overlapped - for index2 in index2_set: - pg = self.pin_groups[pin_name][index2] - combined.add_group(pg) - debug.info(3,"Combining {0} {1}:".format(pin_name, index2)) - debug.info(3, " {0}\n {1}".format(combined.pins, pg.pins)) - debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids)) - new_pin_groups.append(combined) - - # Add the pin groups that weren't added to the new set - for index in all_indices: - new_pin_groups.append(self.pin_groups[pin_name][index]) - - old_size = len(self.pin_groups[pin_name]) - # Use the new pin group! - self.pin_groups[pin_name] = new_pin_groups - removed_pairs = old_size - len(new_pin_groups) - debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name)) - - return removed_pairs + # return removed_pairs def separate_adjacent_pins(self, separation): @@ -748,44 +752,10 @@ class router(router_tech): if gid not in group_map: group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self) # We always add it to the first set since they are touching - group_map[gid].pins[0].add(pin) + group_map[gid].pins.add(pin) self.pin_groups[pin_name] = list(group_map.values()) - # This is the old O(n^2) implementation - # def analyze_pins(self, pin_name): - # """ - # Analyze the shapes of a pin and combine them into pin_groups which are connected. - # """ - # debug.info(2,"Analyzing pin groups for {}.".format(pin_name)) - - # pin_set = self.pins[pin_name] - - # # Put each pin in an equivalence class of it's own - # equiv_classes = [set([x]) for x in pin_set] - # def combine_classes(equiv_classes): - # for class1 in equiv_classes: - # for class2 in equiv_classes: - # if class1 == class2: - # continue - # # Compare each pin in each class, - # # and if any overlap, update equiv_classes to include the combined the class - # for p1 in class1: - # for p2 in class2: - # if p1.overlaps(p2): - # combined_class = class1 | class2 - # equiv_classes.remove(class1) - # equiv_classes.remove(class2) - # equiv_classes.append(combined_class) - # return(equiv_classes) - # return(equiv_classes) - - # old_length = math.inf - # while (len(equiv_classes){2} {3}".format(name,ll,ur,pin)) + debug.info(3,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin)) self.cell.add_layout_pin(text=name, layer=pin.layer, offset=pin.ll(), @@ -379,7 +392,10 @@ class supply_router(router): # Actually run the A* router if not self.run_router(detour_scale=5): - self.write_debug_gds() + self.write_debug_gds("debug_route.gds",False) + + #if index==3 and pin_name=="vdd": + # self.write_debug_gds("route.gds",False) def add_supply_rail_target(self, pin_name):