mirror of https://github.com/VLSIDA/OpenRAM.git
Mark inaccessible off-grid pins as blocked. Improve on-grid pin analysis, but not quite good enough yet.
This commit is contained in:
parent
16063cc9a0
commit
11bb105545
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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. """
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue