diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 78b2a7dd..041c63bf 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -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) diff --git a/compiler/router/router.py b/compiler/router/router.py index 062dba5d..b9bc3597 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -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 diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index 664f8305..ff813125 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -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) diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 37b9ff76..47e0c7f5 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -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() diff --git a/compiler/router/vector3d.py b/compiler/router/vector3d.py index b0277ea0..42bc35d4 100644 --- a/compiler/router/vector3d.py +++ b/compiler/router/vector3d.py @@ -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