From 59956f1446ee9bb72c89cd384d839fbc38e050f8 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 5 Sep 2018 16:01:11 -0700 Subject: [PATCH] Update signal routing for new blockage and pins. --- compiler/gdsMill/gdsMill/vlsiLayout.py | 6 +- compiler/router/astar_grid.py | 18 ++--- compiler/router/grid.py | 9 +++ compiler/router/router.py | 93 ++++++++++++++++++++++---- compiler/router/signal_router.py | 80 +++------------------- compiler/router/supply_router.py | 63 ++++++++++------- 6 files changed, 148 insertions(+), 121 deletions(-) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 5e12619c..93436a73 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -713,9 +713,9 @@ class VlsiLayout: # Convert to user units new_boundaries = [] for pin_boundary in pin_boundaries: - new_boundaries.append([pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0], - pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]) - + new_pin_boundary = [pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0], + pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]] + new_boundaries.append(["p"+str(coordinate)+"_"+str(layer), layer, new_pin_boundary]) return new_boundaries def getPinShapeByLabel(self,label_name): diff --git a/compiler/router/astar_grid.py b/compiler/router/astar_grid.py index 65d9e245..06e67151 100644 --- a/compiler/router/astar_grid.py +++ b/compiler/router/astar_grid.py @@ -34,15 +34,15 @@ class astar_grid(grid.grid): def add_source(self,track_list): debug.info(2,"Adding source list={0}".format(str(track_list))) for n in track_list: - if not self.is_blocked(n): - debug.info(3,"Adding source ={0}".format(str(n))) - self.set_source(n) + debug.info(3,"Adding source ={0}".format(str(n))) + self.set_source(n) + def add_target(self,track_list): debug.info(2,"Adding target list={0}".format(str(track_list))) for n in track_list: - if not self.is_blocked(n): - self.set_target(n) + debug.info(3,"Adding target ={0}".format(str(n))) + self.set_target(n) def is_target(self,point): """ @@ -73,18 +73,14 @@ class astar_grid(grid.grid): We will use an A* search, so this cost must be pessimistic. Cost so far will be the length of the path. """ - debug.info(4,"Initializing queue.") - - # uniquify the source (and target while we are at it) - self.source = list(set(self.source)) - self.target = list(set(self.target)) + debug.info(1,"Initializing queue.") # Counter is used to not require data comparison in Python 3.x # Items will be returned in order they are added during cost ties self.counter = 0 for s in self.source: cost = self.cost_to_target(s) - debug.info(1,"Init: cost=" + str(cost) + " " + str([s])) + debug.info(2,"Init: cost=" + str(cost) + " " + str([s])) heappush(self.q,(cost,self.counter,[s])) self.counter+=1 diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 8eb063cf..ef8cbdca 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -63,6 +63,15 @@ class grid: for p in path: self.map[p].path=True + def block_path(self,path): + """ + Mark the path in the routing grid as blocked. + Also unsets the path flag. + """ + for p in path: + self.map[p].path=False + self.map[p].blocked=True + def cost(self,path): """ The cost of the path is the length plus a penalty for the number diff --git a/compiler/router/router.py b/compiler/router/router.py index 73c0681d..09f94361 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -96,12 +96,13 @@ class router: Pin can either be a label or a location,layer pair: [[x,y],layer]. """ - shape_list=self.layout.getPinShapeByLabel(str(pin_name)) + shape_list=self.layout.getAllPinShapesByLabel(str(pin_name)) pin_list = [] for shape in shape_list: (name,layer,boundary)=shape rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] pin = pin_layout(pin_name, rect, layer) + debug.info(2,"Found pin {}".format(str(pin))) pin_list.append(pin) debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin))) @@ -219,7 +220,7 @@ class router: for pin in all_pins: # If the blockage overlaps the pin and is on the same layer, # it must be connected, so skip it. - if blockage==pin: + if blockage.overlaps(pin): debug.info(1,"Removing blockage for pin {}".format(str(pin))) break else: @@ -288,7 +289,7 @@ class router: If a pin has insufficent overlap, it returns the blockage list to avoid it. """ (ll,ur) = pin.rect - #debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur)) + debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur)) # scale the size bigger to include neaby tracks ll=ll.scale(self.track_factor).floor() @@ -304,31 +305,31 @@ class router: track_list = [] block_list = [] - track_area = self.track_width*self.track_width for x in range(ll[0],ur[0]): for y in range(ll[1],ur[1]): - #debug.info(1,"Converting [ {0} , {1} ]".format(x,y)) + debug.info(1,"Converting [ {0} , {1} ]".format(x,y)) # 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)) + track_area = (full_rect[1].x-full_rect[0].x)*(full_rect[1].y-full_rect[0].y) overlap_rect=self.compute_overlap(pin.rect,full_rect) overlap_area = overlap_rect[0]*overlap_rect[1] - #debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) + debug.info(1,"Check overlap: {0} {1} max={2}".format(pin.rect,overlap_rect,overlap_area)) # Assume if more than half the area, it is occupied overlap_ratio = overlap_area/track_area - if overlap_ratio > 0.5: + if overlap_ratio > 0.25: track_list.append(vector3d(x,y,zindex)) # otherwise, the pin may not be accessible, so block it elif overlap_ratio > 0: block_list.append(vector3d(x,y,zindex)) else: - debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap)) - print("H:",x,y) - if x>38 and x<42 and y>42 and y<45: - print(pin) - print(full_rect, overlap_rect, overlap_ratio) + debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,overlap_rect,overlap_area)) + # print("H:",x,y) + # if x>38 and x<42 and y>42 and y<45: + # print(pin) + # print(full_rect, overlap_rect, overlap_ratio) #debug.warning("Off-grid pin for {0}.".format(str(pin))) #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) return (track_list,block_list) @@ -479,6 +480,74 @@ class router: width=ur.x-ll.x, height=ur.y-ll.y) + + def add_route(self,path): + """ + Add the current wire route to the given design instance. + """ + debug.info(3,"Set path: " + str(path)) + + # Keep track of path for future blockages + self.paths.append(path) + + # This is marked for debug + self.rg.add_path(path) + + # For debugging... if the path failed to route. + if False or path==None: + self.write_debug_gds() + + + # First, simplify the path for + #debug.info(1,str(self.path)) + contracted_path = self.contract_path(path) + debug.info(1,str(contracted_path)) + + # convert the path back to absolute units from tracks + abs_path = map(self.convert_point_to_units,contracted_path) + debug.info(1,str(abs_path)) + self.cell.add_route(self.layers,abs_path) + + + def get_inertia(self,p0,p1): + """ + Sets the direction based on the previous direction we came from. + """ + # direction (index) of movement + if p0.x!=p1.x: + return 0 + elif p0.y!=p1.y: + return 1 + else: + # z direction + return 2 + + def contract_path(self,path): + """ + Remove intermediate points in a rectilinear path. + """ + newpath = [path[0]] + for i in range(1,len(path)-1): + prev_inertia=self.get_inertia(path[i-1],path[i]) + next_inertia=self.get_inertia(path[i],path[i+1]) + # if we switch directions, add the point, otherwise don't + if prev_inertia!=next_inertia: + newpath.append(path[i]) + + # always add the last path + newpath.append(path[-1]) + return newpath + + + def add_path_blockages(self): + """ + Go through all of the past paths and add them as blockages. + This is so we don't have to write/reload the GDS. + """ + for path in self.paths: + self.rg.block_path(path) + + # FIXME: This should be replaced with vector.snap_to_grid at some point diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index ebc85eb6..1ad21467 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -20,6 +20,8 @@ class signal_router(router): """ router.__init__(self, gds_name, module) + self.pins = {} + # all the paths we've routed so far (to supplement the blockages) self.paths = [] @@ -45,9 +47,10 @@ class signal_router(router): """ debug.info(1,"Running signal router from {0} to {1}...".format(src,dest)) self.cell = cell - self.source_pin_name = src - self.target_pin_name = dest + self.pins[src] = [] + self.pins[dest] = [] + # Clear the pins if we have previously routed if (hasattr(self,'rg')): self.clear_pins() @@ -61,14 +64,15 @@ class signal_router(router): # This will get all shapes as blockages self.find_blockages() - # Get the pin shapes + # Now add the blockages (all shapes except the pins) self.get_pin(src) self.get_pin(dest) - # Now add the blockages (all shapes except the src/tgt pins) + # Now add the blockages self.add_blockages() # Add blockages from previous paths - self.add_path_blockages() + self.add_path_blockages() + # Now add the src/tgt if they are not blocked by other shapes self.add_pin(src,True) @@ -91,72 +95,6 @@ class signal_router(router): return False - def add_route(self,path): - """ - Add the current wire route to the given design instance. - """ - debug.info(3,"Set path: " + str(path)) - - # Keep track of path for future blockages - self.paths.append(path) - - # This is marked for debug - self.rg.add_path(path) - - # For debugging... if the path failed to route. - if False or path==None: - self.write_debug_gds() - - - # First, simplify the path for - #debug.info(1,str(self.path)) - contracted_path = self.contract_path(path) - debug.info(1,str(contracted_path)) - - # convert the path back to absolute units from tracks - abs_path = map(self.convert_point_to_units,contracted_path) - debug.info(1,str(abs_path)) - self.cell.add_route(self.layers,abs_path) - - - def get_inertia(self,p0,p1): - """ - Sets the direction based on the previous direction we came from. - """ - # direction (index) of movement - if p0.x!=p1.x: - return 0 - elif p0.y!=p1.y: - return 1 - else: - # z direction - return 2 - - def contract_path(self,path): - """ - Remove intermediate points in a rectilinear path. - """ - newpath = [path[0]] - for i in range(1,len(path)-1): - prev_inertia=self.get_inertia(path[i-1],path[i]) - next_inertia=self.get_inertia(path[i],path[i+1]) - # if we switch directions, add the point, otherwise don't - if prev_inertia!=next_inertia: - newpath.append(path[i]) - - # always add the last path - newpath.append(path[-1]) - return newpath - - - def add_path_blockages(self): - """ - Go through all of the past paths and add them as blockages. - This is so we don't have to write/reload the GDS. - """ - for path in self.paths: - for grid in path: - self.rg.set_blocked(grid) diff --git a/compiler/router/supply_router.py b/compiler/router/supply_router.py index 908e8686..3599c5ae 100644 --- a/compiler/router/supply_router.py +++ b/compiler/router/supply_router.py @@ -34,10 +34,10 @@ class supply_router(router): self.rg.reinit() + def route(self, cell, layers, vdd_name="vdd", gnd_name="gnd"): """ - Route a single source-destination net and return - the simplified rectilinear path. + Add power supply rails and connect all pins to these rails. """ debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) self.cell = cell @@ -61,11 +61,13 @@ class supply_router(router): self.get_pin(vdd_name) self.get_pin(gnd_name) - # Now add the blockages (all shapes except the src/tgt pins) + # Now add the blockages (all shapes except the pins) self.add_blockages() - # Add blockages from previous routes - self.add_path_blockages() + #self.route_supply_rails() + + #self.route_supply_pins() + # source pin will be a specific layout pin # target pin will be the rails only @@ -84,7 +86,38 @@ class supply_router(router): self.write_debug_gds() return False - + def route_supply_rails(self): + """ + Add supply rails for vdd and gnd alternating in both layers. + Connect cross-over points with vias. + """ + # vdd will be the even grids + + # gnd will be the odd grids + + + pass + + def route_supply_pins(self, pin): + """ + This will route all the supply pins to supply rails one at a time. + After each one, it adds the cells to the blockage list. + """ + for pin_name in self.pins.keys(): + for pin in self.pins[pin_name]: + route_supply_pin(pin) + + + + def route_supply_pin(self, pin): + """ + This will take a single pin and route it to the appropriate supply rail. + Do not allow other pins to be destinations so that everything is connected + to the rails. + """ + pass + + def add_route(self,path): """ Add the current wire route to the given design instance. @@ -125,22 +158,4 @@ class supply_router(router): self.rg = supply_grid.supply_grid() - ########################## - # Gridded supply route functions - ########################## - def create_grid(self, ll, ur): - """ Create alternating vdd/gnd lines horizontally """ - - self.create_horizontal_grid() - self.create_vertical_grid() - - - def create_horizontal_grid(self): - """ Create alternating vdd/gnd lines horizontally """ - - pass - - def create_vertical_grid(self): - """ Create alternating vdd/gnd lines horizontally """ - pass