Debugged and tested route by pin location,layer

This commit is contained in:
mguthaus 2017-05-17 15:58:29 -07:00
parent a1496e70a8
commit 68ce3843fe
4 changed files with 138 additions and 56 deletions

View File

@ -656,7 +656,7 @@ class VlsiLayout:
for Text in self.structures[self.rootStructureName].texts: for Text in self.structures[self.rootStructureName].texts:
if Text.textString == label_name or Text.textString == label_name+"\x00": if Text.textString == label_name or Text.textString == label_name+"\x00":
label_layer = Text.drawingLayer label_layer = Text.drawingLayer
label_coordinate = Text.coordinates label_coordinate = Text.coordinates[0]
return (label_coordinate, label_layer) return (label_coordinate, label_layer)
@ -665,22 +665,22 @@ class VlsiLayout:
""" """
Return the coordinates in USER units and layer of a label Return the coordinates in USER units and layer of a label
""" """
(label_coordinate,label_layer)=getLabelDBInfo(label_name) (label_coordinate,label_layer)=self.getLabelDBInfo(label_name)
user_coordinates = [x*self.units[0] for x in label_coordinates] user_coordinates = [x*self.units[0] for x in label_coordinate]
return (user_coordinates,layer) return (user_coordinates,label_layer)
def getPinShapeByLocLayer(self, coordinate, layer): def getPinShapeByLocLayer(self, coordinate, layer):
""" """
Return the largest enclosing rectangle on a layer and at a location. Return the largest enclosing rectangle on a layer and at a location.
Coordinates should be in user units. Coordinates should be in USER units.
""" """
db_coordinates = [x/self.units[0] for x in coordinate] db_coordinate = [x/self.units[0] for x in coordinate]
return self.getPinShapeByDBLocLayer(db_coordinate, layer) return self.getPinShapeByDBLocLayer(db_coordinate, layer)
def getPinShapeByDBLocLayer(self, coordinate, layer): def getPinShapeByDBLocLayer(self, coordinate, layer):
""" """
Return the largest enclosing rectangle on a layer and at a location. Return the largest enclosing rectangle on a layer and at a location.
Coordinates should be in db units. Coordinates should be in DB units.
""" """
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer) pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
@ -688,24 +688,25 @@ class VlsiLayout:
pin_boundaries.sort(cmpBoundaryAreas,reverse=True) pin_boundaries.sort(cmpBoundaryAreas,reverse=True)
pin_boundary=pin_boundaries[0] pin_boundary=pin_boundaries[0]
# Convert to user units # Convert to USER units
pin_boundary=[pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0], 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]]
return [None, layer, pin_boundary] # Make a name if we don't have the pin name
return ["p"+str(coordinate)+"_"+str(layer), layer, pin_boundary]
def getAllPinShapesByLocLayer(self, coordinate, layer): def getAllPinShapesByLocLayer(self, coordinate, layer):
""" """
Return ALL the enclosing rectangles on the same layer Return ALL the enclosing rectangles on the same layer
at the given coordinate. Coordinates should be in user units. at the given coordinate. Coordinates should be in USER units.
""" """
db_coordinates = [x/self.units[0] for x in coordinate] db_coordinate = [int(x/self.units[0]) for x in coordinate]
return self.getAllPinShapesByDBLocLayer(db_coordinate, layer) return self.getAllPinShapesByDBLocLayer(db_coordinate, layer)
def getAllPinShapesByDBLocLayer(self, coordinate, layer): def getAllPinShapesByDBLocLayer(self, coordinate, layer):
""" """
Return ALL the enclosing rectangles on the same layer Return ALL the enclosing rectangles on the same layer
at the given coordinate. Coordinates should be in db units. at the given coordinate. Coordinates should be in DB units.
""" """
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer) pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
@ -715,6 +716,8 @@ class VlsiLayout:
new_boundaries.append([pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0], 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]]) pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]])
# Make a name if we don't have the pin name
return ["p"+str(coordinate)+"_"+str(layer), layer, new_boundaries]
def getPinShapeByLabel(self,label_name): def getPinShapeByLabel(self,label_name):
""" """
@ -766,7 +769,7 @@ class VlsiLayout:
MetalBoundary=[MetalBoundary[0]+StructureOrigin[0],MetalBoundary[1]+StructureOrigin[1], MetalBoundary=[MetalBoundary[0]+StructureOrigin[0],MetalBoundary[1]+StructureOrigin[1],
MetalBoundary[2]+StructureOrigin[0],MetalBoundary[3]+StructureOrigin[1]] MetalBoundary[2]+StructureOrigin[0],MetalBoundary[3]+StructureOrigin[1]]
if self.labelInRectangle(coordinates[0],MetalBoundary): if self.labelInRectangle(coordinates,MetalBoundary):
boundaries.append(MetalBoundary) boundaries.append(MetalBoundary)
return boundaries return boundaries

View File

@ -198,14 +198,14 @@ class grid:
for p in path: for p in path:
self.map[p].path=True self.map[p].path=True
def route(self,factor): def route(self,cost_bound_factor):
""" """
This does the A* maze routing with preferred direction routing. This does the A* maze routing with preferred direction routing.
""" """
# We set a cost bound of the HPWL for run-time. This can be # We set a cost bound of the HPWL for run-time. This can be
# over-ridden if the route fails due to pruning a feasible solution. # over-ridden if the route fails due to pruning a feasible solution.
cost_bound = factor*self.cost_to_target(self.source[0])*self.NONPREFERRED_COST cost_bound = cost_bound_factor*self.cost_to_target(self.source[0])*self.NONPREFERRED_COST
# Make sure the queue is empty if we run another route # Make sure the queue is empty if we run another route
while not self.q.empty(): while not self.q.empty():

View File

@ -24,12 +24,10 @@ class router:
self.reader.loadFromFile(gds_name) self.reader.loadFromFile(gds_name)
self.top_name = self.layout.rootStructureName self.top_name = self.layout.rootStructureName
# A list of pin names for source and dest self.source_pin_shapes = []
self.pin_names = [] self.source_pin_zindex = None
# The map of pin names to list of all pin shapes for a pin. self.target_pin_shapes = []
self.pin_shapes = {} self.target_pin_zindex = None
# The corresponding layers of the above pin shapes
self.pin_layers = {}
# The boundary will determine the limits to the size of the routing grid # The boundary will determine the limits to the size of the routing grid
self.boundary = self.layout.measureBoundary(self.top_name) self.boundary = self.layout.measureBoundary(self.top_name)
@ -86,24 +84,22 @@ class router:
def find_pin(self,pin): def find_pin(self,pin):
""" """
Finds the pin shapes and converts to tracks Finds the pin shapes and converts to tracks.
Pin can either be a label or a location,layer pair: [[x,y],layer].
""" """
# Returns all the shapes that enclose a pin on a given layer if type(pin)==str:
(pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapes(str(pin)) (pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLabel(str(pin))
else:
self.pin_shapes[str(pin)]=[] (pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLocLayer(pin[0],pin[1])
self.pin_names.append(pin_name)
self.pin_layers[str(pin)] = pin_layer
new_pin_shapes = []
for pin_shape in pin_shapes: for pin_shape in pin_shapes:
debug.info(2,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape))) debug.info(2,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape)))
# repack the shape as a pair of vectors rather than four values # repack the shape as a pair of vectors rather than four values
shape=[vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])] new_pin_shapes.append([vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])])
# convert the pin coordinates to tracks and round the sizes down
self.pin_shapes[str(pin)].append(shape)
return self.pin_shapes[str(pin)] return (pin_layer,new_pin_shapes)
def find_blockages(self): def find_blockages(self):
""" """
@ -122,15 +118,14 @@ class router:
Convert the routed path to blockages. Convert the routed path to blockages.
Keep the other blockages unchanged. Keep the other blockages unchanged.
""" """
self.source_pin_shapes = []
self.pin_names = [] self.source_pin_zindex = None
self.pin_shapes = {} self.target_pin_shapes = []
self.pin_layers = {} self.target_pin_zindex = None
self.rg.reinit() self.rg.reinit()
def route(self, layers, src, dest, cost_factor=1): def route(self, layers, src, dest, cost_bound_scale=1):
""" """
Route a single source-destination net and return Route a single source-destination net and return
the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route. the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route.
@ -158,7 +153,7 @@ class router:
#self.rg.view() #self.rg.view()
# returns the path in tracks # returns the path in tracks
(self.path,cost) = self.rg.route(cost_factor) (self.path,cost) = self.rg.route(cost_bound_scale)
debug.info(1,"Found path: cost={0} ".format(cost)) debug.info(1,"Found path: cost={0} ".format(cost))
debug.info(2,str(self.path)) debug.info(2,str(self.path))
self.set_path(self.path) self.set_path(self.path)
@ -196,14 +191,14 @@ class router:
cell.add_route(self.layers,abs_path) cell.add_route(self.layers,abs_path)
# Check if a via is needed at the start point # Check if a via is needed at the start point
if (contracted_path[0].z!=self.source_pin_layer): if (contracted_path[0].z!=self.source_pin_zindex):
# offset this by 1/2 the via size # offset this by 1/2 the via size
c=contact(self.layers, (1, 1)) c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height) via_offset = vector(-0.5*c.width,-0.5*c.height)
cell.add_via(self.layers,abs_path[0]+via_offset) cell.add_via(self.layers,abs_path[0]+via_offset)
# Check if a via is needed at the end point # Check if a via is needed at the end point
if (contracted_path[-1].z!=self.target_pin_layer): if (contracted_path[-1].z!=self.target_pin_zindex):
# offset this by 1/2 the via size # offset this by 1/2 the via size
c=contact(self.layers, (1, 1)) c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height) via_offset = vector(-0.5*c.width,-0.5*c.height)
@ -295,31 +290,29 @@ class router:
debug.info(3,"Set path: " + str(path)) debug.info(3,"Set path: " + str(path))
self.rg.set_path(path) self.rg.set_path(path)
def set_source(self,name): def set_source(self,src):
""" """
Mark the grids that are in the pin rectangle ranges to have the source property. Mark the grids that are in the pin rectangle ranges to have the source property.
""" """
self.source_pin_name = name (pin_layer,self.source_pin_shapes) = self.find_pin(src)
shapes = self.find_pin(name) zindex = 0 if pin_layer==self.horiz_layer_number else 1
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 self.source_pin_zindex = zindex
self.source_pin_layer = zindex for shape in self.source_pin_shapes:
for shape in shapes:
shape_in_tracks=self.convert_shape_to_tracks(shape) shape_in_tracks=self.convert_shape_to_tracks(shape)
debug.info(1,"Set source: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) debug.info(1,"Set source: " + str(src) + " " + str(shape_in_tracks) + " z=" + str(zindex))
self.rg.set_source(shape_in_tracks[0],shape_in_tracks[1],zindex) self.rg.set_source(shape_in_tracks[0],shape_in_tracks[1],zindex)
def set_target(self,name): def set_target(self,src):
""" """
Mark the grids that are in the pin rectangle ranges to have the target property. Mark the grids that are in the pin rectangle ranges to have the target property.
""" """
self.target_pin_name = name (pin_layer,self.target_pin_shapes) = self.find_pin(src)
shapes = self.find_pin(name) zindex = 0 if pin_layer==self.horiz_layer_number else 1
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1 self.target_pin_zindex = zindex
self.target_pin_layer = zindex for shape in self.target_pin_shapes:
for shape in shapes:
shape_in_tracks=self.convert_shape_to_tracks(shape) shape_in_tracks=self.convert_shape_to_tracks(shape)
debug.info(1,"Set target: " + str(name) + " " + str(shape_in_tracks) + " z=" + str(zindex)) debug.info(1,"Set target: " + str(src) + " " + str(shape_in_tracks) + " z=" + str(zindex))
self.rg.set_target(shape_in_tracks[0],shape_in_tracks[1],zindex) self.rg.set_target(shape_in_tracks[0],shape_in_tracks[1],zindex)
def write_obstacle(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)): def write_obstacle(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):

View File

@ -0,0 +1,86 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class pin_location_test(unittest.TestCase):
"""
Simplest two pin route test with no blockages using the pin locations instead of labels.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
# these are user coordinates and layers
src_pin = [[0.52, 4.099],11]
tgt_pin = [[3.533, 1.087],11]
r.route(layer_stack,src=src_pin,dest=tgt_pin)
#r.route(layer_stack,src="A",dest="B")
r.add_route(self)
r = routing("test1", "01_no_blockages_test")
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()