Mark inaccessible off-grid pins as blocked. Improve on-grid pin analysis, but not quite good enough yet.

This commit is contained in:
mguthaus 2017-06-05 14:42:56 -07:00
parent 16063cc9a0
commit 11bb105545
13 changed files with 262 additions and 182 deletions

View File

@ -22,6 +22,10 @@ class cell:
self.visited=False
self.min_cost=-1
self.min_path=None
self.blocked=False
self.source=False
self.target=False
def get_type(self):
if self.blocked:

View File

@ -36,15 +36,24 @@ class grid:
# priority queue for the maze routing
self.q = Q.PriorityQueue()
def set_blocked(self,n):
self.add_map(n)
self.map[n].blocked=True
def set_source(self,n):
self.add_map(n)
self.map[n].source=True
self.source.append(n)
def set_target(self,n):
self.add_map(n)
self.map[n].target=True
self.target.append(n)
def reinit(self):
""" Reinitialize everything for a new route. """
self.convert_path_to_blockages()
self.convert_pins_to_blockages()
self.reset_cells()
# clear source and target pins
@ -54,33 +63,34 @@ class grid:
# clear the queue
while (not self.q.empty()):
self.q.get(False)
def add_blockage(self,ll,ur,z):
def add_blockage_shape(self,ll,ur,z):
debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
n = vector3d(x,y,z)
self.add_map(n)
self.map[n].blocked=True
self.set_blocked(n)
def add_blockage(self,block_list):
debug.info(3,"Adding blockage list={0}".format(str(block_list)))
for n in block_list:
self.set_blocked(n)
def add_source(self,track_list):
debug.info(3,"Adding source list={0}".format(str(track_list)))
for n in track_list:
self.add_map(n)
self.map[n].source=True
# Can't have a blocked target otherwise it's infeasible
self.map[n].blocked=False
self.source.append(n)
if not self.map[n].blocked:
self.set_source(n)
def add_target(self,track_list):
debug.info(3,"Adding target list={0}".format(str(track_list)))
for n in track_list:
self.add_map(n)
self.map[n].target=True
# Can't have a blocked target otherwise it's infeasible
self.map[n].blocked=False
self.target.append(n)
if not self.map[n].blocked:
self.set_target(n)
def reset_cells(self):
"""
@ -89,25 +99,6 @@ class grid:
for p in self.map.values():
p.reset()
def convert_pins_to_blockages(self):
"""
Convert all the pins to blockages and reset the pin sets.
"""
for p in self.map.values():
if (p.source or p.target):
p.blocked=True
p.source=False
p.target=False
def convert_path_to_blockages(self):
"""
Convert the routed path to blockages and reset the path.
"""
for p in self.map.values():
if (p.path):
p.path=False
p.blocked=True
def add_path(self,path):
"""

View File

@ -28,13 +28,16 @@ class router:
self.source_pin_zindex = None
self.target_pin_shapes = []
self.target_pin_zindex = None
# the list of all blockage shapes
self.blockages = []
# all thepaths we've routed so far (to supplement the blockages)
self.paths = []
# The boundary will determine the limits to the size of the routing grid
self.boundary = self.layout.measureBoundary(self.top_name)
self.ll = vector(self.boundary[0])
self.ur = vector(self.boundary[1])
def set_top(self,top_name):
""" If we want to route something besides the top-level cell."""
self.top_name = top_name
@ -113,7 +116,7 @@ class router:
if they are not actually a blockage.
"""
for layer in self.layers:
self.write_obstacle(self.top_name)
self.get_blockages(self.top_name)
def clear_pins(self):
@ -123,19 +126,24 @@ class router:
Convert the routed path to blockages.
Keep the other blockages unchanged.
"""
self.source_pin = None
self.source_pin_shapes = []
self.source_pin_zindex = None
self.target_pin = None
self.target_pin_shapes = []
self.target_pin_zindex = None
# DO NOT clear the blockages as these don't change
self.rg.reinit()
def route(self, layers, src, dest, cost_bound_scale=1):
def route(self, cell, layers, src, dest, cost_bound_scale=1):
"""
Route a single source-destination net and return
the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route.
This is used to speed up the routing when there is not much detouring needed.
"""
self.cell = cell
# Clear the pins if we have previously routed
if (hasattr(self,'rg')):
self.clear_pins()
@ -146,97 +154,137 @@ class router:
# FIXME: This could be created only over the routing region,
# but this is simplest for now.
self.create_routing_grid()
# This will write all shapes as blockages, but setting pins will
# clear the blockage attribute
# This will get all shapes as blockages
self.find_blockages()
self.add_source(src)
# Get the pin shapes
self.get_source(src)
self.get_target(dest)
# Now add the blockages (all shapes except the src/tgt pins)
self.add_blockages()
# Add blockages from previous paths
self.add_path_blockages()
self.add_target(dest)
# Now add the src/tgt if they are not blocked by other shapes
self.add_source()
self.add_target()
# returns the path in tracks
(self.path,cost) = self.rg.route(cost_bound_scale)
if self.path!=None:
(path,cost) = self.rg.route(cost_bound_scale)
if path:
debug.info(1,"Found path: cost={0} ".format(cost))
debug.info(2,str(self.path))
self.add_path(self.path)
debug.info(2,str(path))
self.add_route(path)
return True
else:
self.write_debug_gds()
return False
def add_router_info(self,cell):
def write_debug_gds(self,):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
self.add_router_info()
debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin,self.target_pin))
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 for {0} to {1}".format(self.source_pin,self.target_pin))
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
shape = self.convert_full_track_to_shape(g)
cell.add_rect(layer="boundary",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
self.cell.add_rect(layer="boundary",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
# These rae 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()
if t == None: continue
# 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
off+=partial_track
type_off=off+partial_track
else:
# Lower layer is lower left label
off-=partial_track
cell.add_label(text=str(t),
layer="text",
offset=off)
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])
def add_route(self,cell):
def add_route(self,path):
"""
Add the current wire route to the given design instance.
"""
debug.info(3,"Set path: " + str(path))
# For debugging...
#self.add_router_info(cell)
# 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()
if 'Xout_4_1' in [self.source_pin, self.target_pin]:
self.write_debug_gds()
# First, simplify the path for
#debug.info(1,str(self.path))
contracted_path = self.contract_path(self.path)
contracted_path = self.contract_path(path)
debug.info(1,str(contracted_path))
# Make sure there's a pin enclosure on the source and dest
add_src_via = contracted_path[0].z!=self.source_pin_zindex
self.add_grid_pin(cell,contracted_path[0],add_src_via)
self.add_grid_pin(contracted_path[0],add_src_via)
add_tgt_via = contracted_path[-1].z!=self.target_pin_zindex
self.add_grid_pin(cell,contracted_path[-1],add_tgt_via)
self.add_grid_pin(contracted_path[-1],add_tgt_via)
# 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))
cell.add_route(self.layers,abs_path)
self.cell.add_route(self.layers,abs_path)
def add_grid_pin(self,cell,point,add_via=False):
def add_grid_pin(self,point,add_via=False):
"""
Create a rectangle at the grid 3D point that is 1/2 DRC smaller
than the routing grid on all sides.
"""
pin = self.convert_track_to_pin(point)
cell.add_rect(layer=self.layers[2*point.z],
offset=pin[0],
width=pin[1].x-pin[0].x,
height=pin[1].y-pin[0].y)
self.cell.add_rect(layer=self.layers[2*point.z],
offset=pin[0],
width=pin[1].x-pin[0].x,
height=pin[1].y-pin[0].y)
if add_via:
# offset this by 1/2 the via size
c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height)
cell.add_via(self.layers,vector(point[0],point[1])+via_offset)
self.cell.add_via(self.layers,vector(point[0],point[1])+via_offset)
def create_steiner_routes(self,pins):
@ -316,56 +364,87 @@ class router:
newpath.append(path[-1])
return newpath
def add_path(self,path):
"""
Mark the path in the routing grid.
"""
debug.info(3,"Set path: " + str(path))
self.rg.add_path(path)
def add_source(self,pin):
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)
def get_source(self,pin):
"""
Gets the source pin shapes only. Doesn't add to grid.
"""
self.source_pin = pin
(self.source_pin_layer,self.source_pin_shapes) = self.find_pin(pin)
zindex = 0 if self.source_pin_layer==self.horiz_layer_number else 1
self.source_pin_zindex = zindex
def add_source(self):
"""
Mark the grids that are in the pin rectangle ranges to have the source property.
pin can be a location or a label.
"""
(pin_layer,self.source_pin_shapes) = self.find_pin(pin)
zindex = 0 if pin_layer==self.horiz_layer_number else 1
self.source_pin_zindex = zindex
found_pin = False
for shape in self.source_pin_shapes:
pin_in_tracks=self.convert_pin_to_tracks(shape,zindex,pin)
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.source_pin_zindex,self.source_pin)
if (len(pin_in_tracks)>0): found_pin=True
debug.info(1,"Set source: " + str(pin) + " " + str(pin_in_tracks) + " z=" + str(zindex))
debug.info(1,"Set source: " + str(self.source_pin) + " " + str(pin_in_tracks) + " z=" + str(self.source_pin_zindex))
self.rg.add_source(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks)
if not found_pin:
self.write_debug_gds()
debug.check(found_pin,"Unable to find source pin on grid.")
def add_target(self,pin):
def get_target(self,pin):
"""
Gets the target pin shapes only. Doesn't add to grid.
"""
self.target_pin = pin
(self.target_pin_layer,self.target_pin_shapes) = self.find_pin(pin)
zindex = 0 if self.target_pin_layer==self.horiz_layer_number else 1
self.target_pin_zindex = zindex
def add_target(self):
"""
Mark the grids that are in the pin rectangle ranges to have the target property.
pin can be a location or a label.
"""
(pin_layer,self.target_pin_shapes) = self.find_pin(pin)
zindex = 0 if pin_layer==self.horiz_layer_number else 1
self.target_pin_zindex = zindex
found_pin=False
for shape in self.target_pin_shapes:
pin_in_tracks=self.convert_pin_to_tracks(shape,zindex,pin)
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.target_pin_zindex,self.target_pin)
if (len(pin_in_tracks)>0): found_pin=True
debug.info(1,"Set target: " + str(pin) + " " + str(pin_in_tracks) + " z=" + str(zindex))
debug.info(1,"Set target: " + str(self.target_pin) + " " + str(pin_in_tracks) + " z=" + str(self.target_pin_zindex))
self.rg.add_target(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks)
debug.check(found_pin,"Unable to find source pin on grid.")
if not found_pin:
self.write_debug_gds()
debug.check(found_pin,"Unable to find target pin on grid.")
def add_blockages(self):
""" Add the blockages except the pin shapes """
for blockage in self.blockages:
(shape,zlayer) = blockage
# Skip source pin shapes
if zlayer==self.source_pin_zindex and shape in self.source_pin_shapes:
continue
# Skip target pin shapes
if zlayer==self.target_pin_zindex and shape in self.target_pin_shapes:
continue
[ll,ur]=self.convert_blockage_to_tracks(shape)
self.rg.add_blockage_shape(ll,ur,zlayer)
def write_obstacle(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
def get_blockages(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
"""
Recursive write boundaries as blockages to the routing grid.
Recursive find boundaries as blockages to the routing grid.
Recurses for each Structure in GDS.
"""
for boundary in self.layout.structures[sref].boundaries:
@ -376,8 +455,7 @@ class router:
# only consider the two layers that we are routing on
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
[ll,ur]=self.convert_blockage_to_tracks(shape)
self.rg.add_blockage(ll,ur,zlayer)
self.blockages.append((shape,zlayer))
# recurse given the mirror, angle, etc.
@ -395,7 +473,7 @@ class router:
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
sxyShift = (newX, newY)
self.write_obstacle(cur_sref.sName, sMirr, sAngle, sxyShift)
self.get_blockages(cur_sref.sName, sMirr, sAngle, sxyShift)
def convert_point_to_units(self,p):
"""
@ -426,6 +504,7 @@ class router:
"""
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.
"""
[ll,ur] = shape
ll = snap_to_grid(ll)
@ -444,24 +523,33 @@ class router:
width = self.vert_layer_width
track_list = []
# include +- 1 track for neighors
for x in range(int(ll[0])-1,int(ur[0])+1):
for y in range(int(ll[1])-1,int(ur[1])+1):
block_list = []
# include +- 1 so when a shape is less than one grid
for x in range(ll[0]-1,ur[0]+1):
for y in range(ll[1]-1,ur[1]+1):
#debug.info(1,"Converting [ {0} , {1} ]".format(x,y))
# get the rectangular pin at a track location
# if dimension of overlap is greater than min width in any dimension,
# it will be an on-grid pin
rect = self.convert_track_to_pin(vector3d(x,y,zindex))
#debug.info(1,"Rect {0}".format(rect))
# find the rectangular overlap shape (if any)
# if dimension of overlap is greater than min width in any dimension, add it
max_overlap=max(self.compute_overlap(shape,rect))
# 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_full_track_to_shape(vector3d(x,y,zindex))
full_overlap=max(self.compute_overlap(shape,full_rect))
#debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
if max_overlap >= width:
track_list.append(vector3d(x,y,zindex))
elif full_overlap>0:
block_list.append(vector3d(x,y,zindex))
else:
debug.info(1,"No overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
#debug.warning("Off-grid pin for {0}.".format(str(pin)))
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return track_list
return (track_list,block_list)
def compute_overlap(self,r1,r2):
""" Calculate the rectangular overlap of two rectangles. """

View File

@ -36,29 +36,26 @@ class no_blockages_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
if r.route(layer_stack,src="A",dest="B"):
r.add_route(self)
else:
self.assertTrue(False)
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("test1", "01_no_blockages_test_{0}".format(OPTS.tech_name))
r = routing("01_no_blockages_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells

View File

@ -36,29 +36,26 @@ class blockages_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
if r.route(layer_stack,src="A",dest="B"):
r.add_route(self)
else:
self.assertTrue(False)
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("test1", "02_blockages_test_{0}".format(OPTS.tech_name))
r = routing("02_blockages_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells

View File

@ -35,29 +35,26 @@ class same_layer_pins_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
if r.route(layer_stack,src="A",dest="B"):
r.add_route(self)
else:
self.assertTrue(False)
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("test1", "03_same_layer_pins_test_{0}".format(OPTS.tech_name))
r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_check(r)

View File

@ -37,29 +37,26 @@ class diff_layer_pins_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
if r.route(layer_stack,src="A",dest="B"):
r.add_route(self)
else:
self.assertTrue(False)
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("test1", "04_diff_layer_pins_test_{0}".format(OPTS.tech_name))
r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells

View File

@ -37,34 +37,27 @@ class two_nets_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
if r.route(layer_stack,src="A",dest="B"):
r.add_route(self)
else:
self.assertTrue(False)
if r.route(layer_stack,src="C",dest="D"):
r.add_route(self)
else:
debug.error("Unable to route")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
self.assertTrue(r.route(self,layer_stack,src="C",dest="D"))
r = routing("test1", "05_two_nets_test_{0}".format(OPTS.tech_name))
r = routing("05_two_nets_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells

View File

@ -36,35 +36,32 @@ class pin_location_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
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="A",dest="B")
if r.route(layer_stack,src=src_pin,dest=tgt_pin):
r.add_route(self)
else:
debug.error("Unable to route")
self.assertTrue(r.route(self,layer_stack,src=src_pin,dest=tgt_pin))
# This only works for freepdk45 since the coordinates are hard coded
if OPTS.tech_name == "freepdk45":
r = routing("test1", "06_pin_location_test_{0}".format(OPTS.tech_name))
r = routing("06_pin_location_test_{0}".format(OPTS.tech_name))
self.local_check(r)
else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name))

View File

@ -36,31 +36,50 @@ class big_test(unittest.TestCase):
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design):
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name, gdsname):
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(gdsname)
self.add_inst(name=gdsname,
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),gdsname)
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal3","via2","metal2")
# first pin doesn't overlap a rectangle
#r.route(layer_stack,src="a_2_7",dest="B")
r.route(layer_stack,src="A",dest="B")
r.add_route(self)
connections=[('out_0_2', 'a_0_0'),
('out_0_3', 'b_0_0'),
('out_0_0', 'a_0_1'),
('out_1_2', 'a_1_0'),
('out_1_3', 'b_1_0'),
('out_1_0', 'a_1_1'),
('out_2_1', 'a_2_0'),
('out_2_2', 'b_2_0'),
('out_3_1', 'a_3_0'),
('out_3_2', 'b_3_0'),
('out_4_6', 'a_4_0'),
('out_4_7', 'b_4_0'),
('out_4_8', 'a_4_2'),
('out_4_9', 'b_4_2'),
('out_4_10', 'a_4_4'),
('out_4_11', 'b_4_4'),
('out_4_0', 'a_4_1'),
('out_4_2', 'b_4_1'),
('out_4_4', 'a_4_5'),
('out_4_1', 'a_4_3'),
('out_4_5', 'b_4_3')]
for (src,tgt) in connections:
self.assertTrue(r.route(self,layer_stack,src=src,dest=tgt))
# This test only runs on scn3me_subm tech
if OPTS.tech_name=="scn3me_subm":
r = routing("test1", "07_big_test_{0}".format(OPTS.tech_name))
r = routing("07_big_test_{0}".format(OPTS.tech_name))
self.local_check(r)
else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name))