Update signal routing for new blockage and pins.

This commit is contained in:
Matt Guthaus 2018-09-05 16:01:11 -07:00
parent 7ead566154
commit 59956f1446
6 changed files with 148 additions and 121 deletions

View File

@ -713,9 +713,9 @@ class VlsiLayout:
# Convert to user units # Convert to user units
new_boundaries = [] new_boundaries = []
for pin_boundary in pin_boundaries: for pin_boundary in pin_boundaries:
new_boundaries.append([pin_boundary[0]*self.units[0],pin_boundary[1]*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]]) 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 return new_boundaries
def getPinShapeByLabel(self,label_name): def getPinShapeByLabel(self,label_name):

View File

@ -34,15 +34,15 @@ class astar_grid(grid.grid):
def add_source(self,track_list): def add_source(self,track_list):
debug.info(2,"Adding source list={0}".format(str(track_list))) debug.info(2,"Adding source list={0}".format(str(track_list)))
for n in track_list: for n in track_list:
if not self.is_blocked(n): debug.info(3,"Adding source ={0}".format(str(n)))
debug.info(3,"Adding source ={0}".format(str(n))) self.set_source(n)
self.set_source(n)
def add_target(self,track_list): def add_target(self,track_list):
debug.info(2,"Adding target list={0}".format(str(track_list))) debug.info(2,"Adding target list={0}".format(str(track_list)))
for n in track_list: for n in track_list:
if not self.is_blocked(n): debug.info(3,"Adding target ={0}".format(str(n)))
self.set_target(n) self.set_target(n)
def is_target(self,point): 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. We will use an A* search, so this cost must be pessimistic.
Cost so far will be the length of the path. Cost so far will be the length of the path.
""" """
debug.info(4,"Initializing queue.") debug.info(1,"Initializing queue.")
# uniquify the source (and target while we are at it)
self.source = list(set(self.source))
self.target = list(set(self.target))
# Counter is used to not require data comparison in Python 3.x # Counter is used to not require data comparison in Python 3.x
# Items will be returned in order they are added during cost ties # Items will be returned in order they are added during cost ties
self.counter = 0 self.counter = 0
for s in self.source: for s in self.source:
cost = self.cost_to_target(s) 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])) heappush(self.q,(cost,self.counter,[s]))
self.counter+=1 self.counter+=1

View File

@ -63,6 +63,15 @@ class grid:
for p in path: for p in path:
self.map[p].path=True 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): def cost(self,path):
""" """
The cost of the path is the length plus a penalty for the number The cost of the path is the length plus a penalty for the number

View File

@ -96,12 +96,13 @@ class router:
Pin can either be a label or a location,layer pair: [[x,y],layer]. 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 = [] pin_list = []
for shape in shape_list: for shape in shape_list:
(name,layer,boundary)=shape (name,layer,boundary)=shape
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
pin = pin_layout(pin_name, rect, layer) pin = pin_layout(pin_name, rect, layer)
debug.info(2,"Found pin {}".format(str(pin)))
pin_list.append(pin) pin_list.append(pin)
debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(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: for pin in all_pins:
# If the blockage overlaps the pin and is on the same layer, # If the blockage overlaps the pin and is on the same layer,
# it must be connected, so skip it. # it must be connected, so skip it.
if blockage==pin: if blockage.overlaps(pin):
debug.info(1,"Removing blockage for pin {}".format(str(pin))) debug.info(1,"Removing blockage for pin {}".format(str(pin)))
break break
else: else:
@ -288,7 +289,7 @@ class router:
If a pin has insufficent overlap, it returns the blockage list to avoid it. If a pin has insufficent overlap, it returns the blockage list to avoid it.
""" """
(ll,ur) = pin.rect (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 # scale the size bigger to include neaby tracks
ll=ll.scale(self.track_factor).floor() ll=ll.scale(self.track_factor).floor()
@ -304,31 +305,31 @@ class router:
track_list = [] track_list = []
block_list = [] block_list = []
track_area = self.track_width*self.track_width
for x in range(ll[0],ur[0]): for x in range(ll[0],ur[0]):
for y in range(ll[1],ur[1]): 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, # 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 # we need to block it to prevent routes coming in on that grid
full_rect = self.convert_track_to_shape(vector3d(x,y,zindex)) 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_rect=self.compute_overlap(pin.rect,full_rect)
overlap_area = overlap_rect[0]*overlap_rect[1] 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 # Assume if more than half the area, it is occupied
overlap_ratio = overlap_area/track_area overlap_ratio = overlap_area/track_area
if overlap_ratio > 0.5: if overlap_ratio > 0.25:
track_list.append(vector3d(x,y,zindex)) track_list.append(vector3d(x,y,zindex))
# otherwise, the pin may not be accessible, so block it # otherwise, the pin may not be accessible, so block it
elif overlap_ratio > 0: elif overlap_ratio > 0:
block_list.append(vector3d(x,y,zindex)) block_list.append(vector3d(x,y,zindex))
else: else:
debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap)) debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,overlap_rect,overlap_area))
print("H:",x,y) # print("H:",x,y)
if x>38 and x<42 and y>42 and y<45: # if x>38 and x<42 and y>42 and y<45:
print(pin) # print(pin)
print(full_rect, overlap_rect, overlap_ratio) # print(full_rect, overlap_rect, overlap_ratio)
#debug.warning("Off-grid pin for {0}.".format(str(pin))) #debug.warning("Off-grid pin for {0}.".format(str(pin)))
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return (track_list,block_list) return (track_list,block_list)
@ -479,6 +480,74 @@ class router:
width=ur.x-ll.x, width=ur.x-ll.x,
height=ur.y-ll.y) 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 # FIXME: This should be replaced with vector.snap_to_grid at some point

View File

@ -20,6 +20,8 @@ class signal_router(router):
""" """
router.__init__(self, gds_name, module) router.__init__(self, gds_name, module)
self.pins = {}
# all the paths we've routed so far (to supplement the blockages) # all the paths we've routed so far (to supplement the blockages)
self.paths = [] self.paths = []
@ -45,9 +47,10 @@ class signal_router(router):
""" """
debug.info(1,"Running signal router from {0} to {1}...".format(src,dest)) debug.info(1,"Running signal router from {0} to {1}...".format(src,dest))
self.cell = cell 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 # Clear the pins if we have previously routed
if (hasattr(self,'rg')): if (hasattr(self,'rg')):
self.clear_pins() self.clear_pins()
@ -61,14 +64,15 @@ class signal_router(router):
# This will get all shapes as blockages # This will get all shapes as blockages
self.find_blockages() self.find_blockages()
# Get the pin shapes # Now add the blockages (all shapes except the pins)
self.get_pin(src) self.get_pin(src)
self.get_pin(dest) self.get_pin(dest)
# Now add the blockages (all shapes except the src/tgt pins) # Now add the blockages
self.add_blockages() self.add_blockages()
# Add blockages from previous paths # 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 # Now add the src/tgt if they are not blocked by other shapes
self.add_pin(src,True) self.add_pin(src,True)
@ -91,72 +95,6 @@ class signal_router(router):
return False 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)

View File

@ -34,10 +34,10 @@ class supply_router(router):
self.rg.reinit() self.rg.reinit()
def route(self, cell, layers, vdd_name="vdd", gnd_name="gnd"): def route(self, cell, layers, vdd_name="vdd", gnd_name="gnd"):
""" """
Route a single source-destination net and return Add power supply rails and connect all pins to these rails.
the simplified rectilinear path.
""" """
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
self.cell = cell self.cell = cell
@ -61,11 +61,13 @@ class supply_router(router):
self.get_pin(vdd_name) self.get_pin(vdd_name)
self.get_pin(gnd_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() 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 # source pin will be a specific layout pin
# target pin will be the rails only # target pin will be the rails only
@ -84,7 +86,38 @@ class supply_router(router):
self.write_debug_gds() self.write_debug_gds()
return False 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): def add_route(self,path):
""" """
Add the current wire route to the given design instance. Add the current wire route to the given design instance.
@ -125,22 +158,4 @@ class supply_router(router):
self.rg = supply_grid.supply_grid() 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