Update router to work with pin_layout structure.

This commit is contained in:
Matt Guthaus 2018-08-22 11:37:24 -07:00
parent ea52af3747
commit 2ae1e0234d
50 changed files with 493 additions and 641 deletions

View File

@ -55,9 +55,12 @@ class geometry:
self.compute_boundary(self.offset,self.mirror,self.rotate) self.compute_boundary(self.offset,self.mirror,self.rotate)
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0): def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" Transform with offset, mirror and rotation to get the absolute pin location. """
We must then re-find the ll and ur. The master is the cell instance. """ Transform with offset, mirror and rotation to get the absolute pin location.
We must then re-find the ll and ur. The master is the cell instance.
"""
(ll,ur) = [vector(0,0),vector(self.width,self.height)] (ll,ur) = [vector(0,0),vector(self.width,self.height)]
if mirror=="MX": if mirror=="MX":
ll=ll.scale(1,-1) ll=ll.scale(1,-1)
ur=ur.scale(1,-1) ur=ur.scale(1,-1)

View File

@ -16,8 +16,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
def __init__(self, name): def __init__(self, name):
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" try:
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.gds_file
except AttributeError:
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds"
try:
self.sp_file
except AttributeError:
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
self.name = name self.name = name
hierarchy_layout.layout.__init__(self, name) hierarchy_layout.layout.__init__(self, name)

View File

@ -322,7 +322,7 @@ class layout(lef.lef):
position_list=coordinates, position_list=coordinates,
width=width) width=width)
def add_route(self, design, layers, coordinates): def add_route(self, layers, coordinates):
"""Connects a routing path on given layer,coordinates,width. The """Connects a routing path on given layer,coordinates,width. The
layers are the (horizontal, via, vertical). add_wire assumes layers are the (horizontal, via, vertical). add_wire assumes
preferred direction routing whereas this includes layers in preferred direction routing whereas this includes layers in

View File

@ -117,7 +117,7 @@ class spice(verilog.verilog):
def sp_read(self): def sp_read(self):
"""Reads the sp file (and parse the pins) from the library """Reads the sp file (and parse the pins) from the library
Otherwise, initialize it to null for dynamic generation""" Otherwise, initialize it to null for dynamic generation"""
if os.path.isfile(self.sp_file): if self.sp_file and os.path.isfile(self.sp_file):
debug.info(3, "opening {0}".format(self.sp_file)) debug.info(3, "opening {0}".format(self.sp_file))
f = open(self.sp_file) f = open(self.sp_file)
self.spice = f.readlines() self.spice = f.readlines()

View File

@ -1,11 +1,12 @@
from tech import drc from tech import drc
import debug import debug
from design import design
from contact import contact from contact import contact
from itertools import tee from itertools import tee
from vector import vector from vector import vector
from vector3d import vector3d from vector3d import vector3d
class route(): class route(design):
""" """
Object route (used by the router module) Object route (used by the router module)
Add a route of minimium metal width between a set of points. Add a route of minimium metal width between a set of points.
@ -14,10 +15,13 @@ class route():
The points are the center of the wire. The points are the center of the wire.
This can have non-preferred direction routing. This can have non-preferred direction routing.
""" """
unique_route_id = 0
def __init__(self, obj, layer_stack, path): def __init__(self, obj, layer_stack, path):
name = "route_{0}".format(route.unique_route_id) name = "route_{0}".format(route.unique_route_id)
route.unique_route_id += 1 route.unique_route_id += 1
design.design.__init__(self, name) design.__init__(self, name)
debug.info(3, "create route obj {0}".format(name)) debug.info(3, "create route obj {0}".format(name))
self.obj = obj self.obj = obj
@ -52,7 +56,7 @@ class route():
next(b, None) next(b, None)
return zip(a, b) return zip(a, b)
plist = pairwise(self.path) plist = list(pairwise(self.path))
for p0,p1 in plist: for p0,p1 in plist:
if p0.z != p1.z: # via if p0.z != p1.z: # via
# offset if not rotated # offset if not rotated
@ -67,6 +71,13 @@ class route():
self.draw_corner_wire(p1) self.draw_corner_wire(p1)
# draw the point to point wire # draw the point to point wire
self.draw_wire(p0,p1) self.draw_wire(p0,p1)
# Draw the layers on the ends of the wires to ensure full width
# connections
self.draw_corner_wire(plist[0][0])
self.draw_corner_wire(plist[-1][1])
@ -99,10 +110,10 @@ class route():
height = end.y - start.y height = end.y - start.y
width = layer_width width = layer_width
deisgn.add_rect(layer=layer_name, self.obj.add_rect(layer=layer_name,
offset=offset, offset=vector(offset.x,offset.y),
width=width, width=width,
height=height) height=height)
def draw_corner_wire(self, p0): def draw_corner_wire(self, p0):

View File

@ -37,12 +37,6 @@ def pin_center(boundary):
""" """
return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])] return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])]
def pin_rect(boundary):
"""
This returns a LL,UR point pair.
"""
return [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
def auto_measure_libcell(pin_list, name, units, layer): def auto_measure_libcell(pin_list, name, units, layer):
""" """
Open a GDS file and find the pins in pin_list as text on a given layer. Open a GDS file and find the pins in pin_list as text on a given layer.
@ -66,15 +60,14 @@ def auto_measure_libcell(pin_list, name, units, layer):
def get_libcell_size(name, units, layer): def get_gds_size(name, gds_filename, units, layer):
""" """
Open a GDS file and return the library cell size from either the Open a GDS file and return the size from either the
bounding box or a border layer. bounding box or a border layer.
""" """
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
cell_vlsi = gdsMill.VlsiLayout(units=units) cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi) reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(cell_gds) reader.loadFromFile(gds_filename)
cell = {} cell = {}
measure_result = cell_vlsi.getLayoutBorder(layer) measure_result = cell_vlsi.getLayoutBorder(layer)
@ -83,16 +76,23 @@ def get_libcell_size(name, units, layer):
# returns width,height # returns width,height
return measure_result return measure_result
def get_libcell_size(name, units, layer):
"""
Open a GDS file and return the library cell size from either the
bounding box or a border layer.
"""
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
return(get_gds_size(name, cell_gds, units, layer))
def get_libcell_pins(pin_list, name, units, layer):
def get_gds_pins(pin_list, name, gds_filename, units, layer):
""" """
Open a GDS file and find the pins in pin_list as text on a given layer. Open a GDS file and find the pins in pin_list as text on a given layer.
Return these as a rectangle layer pair for each pin. Return these as a rectangle layer pair for each pin.
""" """
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
cell_vlsi = gdsMill.VlsiLayout(units=units) cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi) reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(cell_gds) reader.loadFromFile(gds_filename)
cell = {} cell = {}
for pin in pin_list: for pin in pin_list:
@ -100,11 +100,19 @@ def get_libcell_pins(pin_list, name, units, layer):
label_list=cell_vlsi.getPinShapeByLabel(str(pin)) label_list=cell_vlsi.getPinShapeByLabel(str(pin))
for label in label_list: for label in label_list:
(name,layer,boundary)=label (name,layer,boundary)=label
rect = pin_rect(boundary) rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
# this is a list because other cells/designs may have must-connect pins # this is a list because other cells/designs may have must-connect pins
cell[str(pin)].append(pin_layout(pin, rect, layer)) cell[str(pin)].append(pin_layout(pin, rect, layer))
return cell return cell
def get_libcell_pins(pin_list, name, units, layer):
"""
Open a GDS file and find the pins in pin_list as text on a given layer.
Return these as a rectangle layer pair for each pin.
"""
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
return(get_gds_pins(pin_list, name, cell_gds, units, layer))

View File

@ -583,6 +583,7 @@ class VlsiLayout:
print("Done\n\n") print("Done\n\n")
def getLayoutBorder(self,borderlayer): def getLayoutBorder(self,borderlayer):
cellSizeMicron=None
for boundary in self.structures[self.rootStructureName].boundaries: for boundary in self.structures[self.rootStructureName].boundaries:
if boundary.drawingLayer==borderlayer: if boundary.drawingLayer==borderlayer:
if self.debug: if self.debug:
@ -722,7 +723,8 @@ class VlsiLayout:
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. Input coordinates should be in DB units.
Returns user unit shapes.
""" """
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer) pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
@ -732,8 +734,7 @@ 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 new_boundaries
return ["p"+str(coordinate)+"_"+str(layer), layer, new_boundaries]
def getPinShapeByLabel(self,label_name): def getPinShapeByLabel(self,label_name):
""" """
@ -758,7 +759,7 @@ class VlsiLayout:
shape_list=[] shape_list=[]
for label in label_list: for label in label_list:
(label_coordinate,label_layer)=label (label_coordinate,label_layer)=label
shape_list.append(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer)) shape_list.extend(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer))
return shape_list return shape_list
def getAllPinShapesInStructureList(self,coordinates,layer): def getAllPinShapesInStructureList(self,coordinates,layer):

View File

@ -6,11 +6,7 @@ from vector3d import vector3d
from cell import cell from cell import cell
import os import os
try: from heapq import heappush,heappop
import Queue as Q # ver. < 3.0
except ImportError:
import queue as Q
class grid: class grid:
"""A two layer routing map. Each cell can be blocked in the vertical """A two layer routing map. Each cell can be blocked in the vertical
@ -36,7 +32,7 @@ class grid:
self.map={} self.map={}
# priority queue for the maze routing # priority queue for the maze routing
self.q = Q.PriorityQueue() self.q = []
def set_blocked(self,n): def set_blocked(self,n):
self.add_map(n) self.add_map(n)
@ -66,30 +62,34 @@ class grid:
self.target=[] self.target=[]
# clear the queue # clear the queue
while (not self.q.empty()): while len(self.q)>0:
self.q.get(False) heappop(self.q)
self.counter = 0
def add_blockage_shape(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)) debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
block_list = []
for x in range(int(ll[0]),int(ur[0])+1): for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1): for y in range(int(ll[1]),int(ur[1])+1):
n = vector3d(x,y,z) block_list.append(vector3d(x,y,z))
self.set_blocked(n)
self.add_blockage(block_list)
def add_blockage(self,block_list): def add_blockage(self,block_list):
debug.info(3,"Adding blockage list={0}".format(str(block_list))) debug.info(2,"Adding blockage list={0}".format(str(block_list)))
for n in block_list: for n in block_list:
self.set_blocked(n) self.set_blocked(n)
def add_source(self,track_list): def add_source(self,track_list):
debug.info(3,"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): if not self.is_blocked(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(3,"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): if not self.is_blocked(n):
self.set_target(n) self.set_target(n)
@ -120,8 +120,8 @@ class grid:
cost_bound = detour_scale*self.cost_to_target(self.source[0])*self.PREFERRED_COST cost_bound = detour_scale*self.cost_to_target(self.source[0])*self.PREFERRED_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 len(self.q)>0:
self.q.get() heappop(self.q)
# Put the source items into the queue # Put the source items into the queue
self.init_queue() self.init_queue()
@ -129,10 +129,10 @@ class grid:
cheapest_cost = None cheapest_cost = None
# Keep expanding and adding to the priority queue until we are done # Keep expanding and adding to the priority queue until we are done
while not self.q.empty(): while len(self.q)>0:
# should we keep the path in the queue as well or just the final node? # should we keep the path in the queue as well or just the final node?
(cost,path) = self.q.get() (cost,count,path) = heappop(self.q)
debug.info(2,"Queue size: size=" + str(self.q.qsize()) + " " + str(cost)) debug.info(2,"Queue size: size=" + str(len(self.q)) + " " + str(cost))
debug.info(3,"Expanding: cost=" + str(cost) + " " + str(path)) debug.info(3,"Expanding: cost=" + str(cost) + " " + str(path))
# expand the last element # expand the last element
@ -158,7 +158,8 @@ class grid:
self.map[n].min_cost = predicted_cost self.map[n].min_cost = predicted_cost
debug.info(3,"Enqueuing: cost=" + str(current_cost) + "+" + str(target_cost) + " " + str(newpath)) debug.info(3,"Enqueuing: cost=" + str(current_cost) + "+" + str(target_cost) + " " + str(newpath))
# add the cost to get to this point if we haven't reached it yet # add the cost to get to this point if we haven't reached it yet
self.q.put((predicted_cost,newpath)) heappush(self.q,(predicted_cost,self.counter,newpath))
self.counter += 1
debug.warning("Unable to route path. Expand the detour_scale to allow detours.") debug.warning("Unable to route path. Expand the detour_scale to allow detours.")
return (None,None) return (None,None)
@ -227,11 +228,16 @@ class grid:
# uniquify the source (and target while we are at it) # uniquify the source (and target while we are at it)
self.source = list(set(self.source)) self.source = list(set(self.source))
self.target = list(set(self.target)) self.target = list(set(self.target))
# 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: for s in self.source:
cost = self.cost_to_target(s) cost = self.cost_to_target(s)
debug.info(4,"Init: cost=" + str(cost) + " " + str([s])) debug.info(1,"Init: cost=" + str(cost) + " " + str([s]))
self.q.put((cost,[s])) heappush(self.q,(cost,self.counter,[s]))
self.counter+=1
def hpwl(self, src, dest): def hpwl(self, src, dest):
""" """

View File

@ -4,6 +4,7 @@ from contact import contact
import math import math
import debug import debug
import grid import grid
from pin_layout import pin_layout
from vector import vector from vector import vector
from vector3d import vector3d from vector3d import vector3d
from globals import OPTS from globals import OPTS
@ -24,13 +25,11 @@ class router:
self.reader.loadFromFile(gds_name) self.reader.loadFromFile(gds_name)
self.top_name = self.layout.rootStructureName self.top_name = self.layout.rootStructureName
self.source_pin_shapes = [] self.source_pins = []
self.source_pin_zindex = None self.target_pins = []
self.target_pin_shapes = []
self.target_pin_zindex = None
# the list of all blockage shapes # the list of all blockage shapes
self.blockages = [] self.blockages = []
# all thepaths 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 = []
# 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
@ -94,20 +93,18 @@ 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].
""" """
if type(pin)==str: label_list=self.layout.getPinShapeByLabel(str(pin))
(pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLabel(str(pin)) pin_list = []
else: for label in label_list:
(pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLocLayer(pin[0],pin[1]) (name,layer,boundary)=label
rect = [vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
# this is a list because other cells/designs may have must-connect pins
pin_list.append(pin_layout(pin, rect, layer))
debug.check(len(pin_list)>0,"Did not find any pin shapes for {0}.".format(str(pin)))
return pin_list
new_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)))
# repack the shape as a pair of vectors rather than four values
new_pin_shapes.append([vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])])
debug.check(len(new_pin_shapes)>0,"Did not find any pin shapes for {0}.".format(str(pin)))
return (pin_layer,new_pin_shapes)
def find_blockages(self): def find_blockages(self):
""" """
@ -126,17 +123,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 = None self.source_pin_name = None
self.source_pin_shapes = [] self.source_pins = []
self.source_pin_zindex = None self.target_pin_name = None
self.target_pin = None self.target_pins = [] # DO NOT clear the blockages as these don't change
self.target_pin_shapes = []
self.target_pin_zindex = None
# DO NOT clear the blockages as these don't change
self.rg.reinit() self.rg.reinit()
def route(self, cell, layers, src, dest, detour_scale=2): def route(self, cell, layers, src, dest, detour_scale=5):
""" """
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.
@ -186,7 +180,7 @@ class router:
return False return False
def write_debug_gds(self,): def write_debug_gds(self):
""" """
Write out a GDS file with the routing grid and search information annotated on it. Write out a GDS file with the routing grid and search information annotated on it.
""" """
@ -195,7 +189,7 @@ class router:
if OPTS.debug_level==0: return if OPTS.debug_level==0: return
self.add_router_info() self.add_router_info()
debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin,self.target_pin)) debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin_name,self.target_pin_name))
self.cell.gds_write("debug_route.gds") self.cell.gds_write("debug_route.gds")
def add_router_info(self): def add_router_info(self):
@ -204,7 +198,7 @@ class router:
the boundary layer for debugging purposes. This can only be the boundary layer for debugging purposes. This can only be
called once or the labels will overlap. called once or the labels will overlap.
""" """
debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin,self.target_pin)) debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin_name,self.target_pin_name))
grid_keys=self.rg.map.keys() grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0) partial_track=vector(0,self.track_width/6.0)
for g in grid_keys: for g in grid_keys:
@ -237,7 +231,8 @@ class router:
offset=type_off) offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]), self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text", layer="text",
offset=shape[0]) offset=shape[0],
zoom=0.05)
def add_route(self,path): def add_route(self,path):
""" """
@ -255,7 +250,7 @@ class router:
if False or path==None: if False or path==None:
self.write_debug_gds() self.write_debug_gds()
if 'Xout_4_1' in [self.source_pin, self.target_pin]: if 'Xout_4_1' in [self.source_pin_name, self.target_pin_name]:
self.write_debug_gds() self.write_debug_gds()
@ -263,12 +258,6 @@ class router:
#debug.info(1,str(self.path)) #debug.info(1,str(self.path))
contracted_path = self.contract_path(path) contracted_path = self.contract_path(path)
debug.info(1,str(contracted_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(contracted_path[0],add_src_via)
add_tgt_via = contracted_path[-1].z!=self.target_pin_zindex
self.add_grid_pin(contracted_path[-1],add_tgt_via)
# convert the path back to absolute units from tracks # convert the path back to absolute units from tracks
abs_path = map(self.convert_point_to_units,contracted_path) abs_path = map(self.convert_point_to_units,contracted_path)
@ -382,14 +371,12 @@ class router:
self.rg.set_blocked(grid) self.rg.set_blocked(grid)
def get_source(self,pin): def get_source(self,pin_name):
""" """
Gets the source pin shapes only. Doesn't add to grid. Gets the source pin shapes only. Doesn't add to grid.
""" """
self.source_pin = pin self.source_pin_name = pin_name
(self.source_pin_layer,self.source_pin_shapes) = self.find_pin(pin) self.source_pins = self.find_pin(pin_name)
zindex = 0 if self.source_pin_layer==self.horiz_layer_number else 1
self.source_pin_zindex = zindex
def add_source(self): def add_source(self):
""" """
@ -398,10 +385,11 @@ class router:
""" """
found_pin = False found_pin = False
for shape in self.source_pin_shapes: for pin in self.source_pins:
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.source_pin_zindex,self.source_pin) (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(pin)
if (len(pin_in_tracks)>0): found_pin=True if (len(pin_in_tracks)>0):
debug.info(1,"Set source: " + str(self.source_pin) + " " + str(pin_in_tracks) + " z=" + str(self.source_pin_zindex)) found_pin=True
debug.info(1,"Set source: " + str(self.source_pin_name) + " " + str(pin_in_tracks))
self.rg.add_source(pin_in_tracks) self.rg.add_source(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks) self.rg.add_blockage(blockage_in_tracks)
@ -409,14 +397,12 @@ class router:
self.write_debug_gds() self.write_debug_gds()
debug.check(found_pin,"Unable to find source pin on grid.") debug.check(found_pin,"Unable to find source pin on grid.")
def get_target(self,pin): def get_target(self,pin_name):
""" """
Gets the target pin shapes only. Doesn't add to grid. Gets the target pin shapes only. Doesn't add to grid.
""" """
self.target_pin = pin self.target_pin_name = pin_name
(self.target_pin_layer,self.target_pin_shapes) = self.find_pin(pin) self.target_pins = self.find_pin(pin_name)
zindex = 0 if self.target_pin_layer==self.horiz_layer_number else 1
self.target_pin_zindex = zindex
def add_target(self): def add_target(self):
""" """
@ -424,10 +410,11 @@ class router:
pin can be a location or a label. pin can be a location or a label.
""" """
found_pin=False found_pin=False
for shape in self.target_pin_shapes: for pin in self.target_pins:
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.target_pin_zindex,self.target_pin) (pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(pin)
if (len(pin_in_tracks)>0): found_pin=True if (len(pin_in_tracks)>0):
debug.info(1,"Set target: " + str(self.target_pin) + " " + str(pin_in_tracks) + " z=" + str(self.target_pin_zindex)) found_pin=True
debug.info(1,"Set target: " + str(self.target_pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks) self.rg.add_target(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks) self.rg.add_blockage(blockage_in_tracks)
@ -438,15 +425,15 @@ class router:
def add_blockages(self): def add_blockages(self):
""" Add the blockages except the pin shapes """ """ Add the blockages except the pin shapes """
for blockage in self.blockages: for blockage in self.blockages:
(shape,zlayer) = blockage is_nonpin_blockage = True
# Skip source pin shapes # Skip source pin shapes
if zlayer==self.source_pin_zindex and shape in self.source_pin_shapes: for pin in self.source_pins + self.target_pins:
continue if blockage.overlaps(pin):
# Skip target pin shapes break
if zlayer==self.target_pin_zindex and shape in self.target_pin_shapes: else:
continue [ll,ur]=self.convert_blockage_to_tracks(blockage.rect)
[ll,ur]=self.convert_blockage_to_tracks(shape) zlayer = 0 if blockage.layer_num==self.horiz_layer_number else 1
self.rg.add_blockage_shape(ll,ur,zlayer) self.rg.add_blockage_shape(ll,ur,zlayer)
def get_blockages(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)):
@ -461,8 +448,8 @@ class router:
# only consider the two layers that we are routing on # only consider the two layers that we are routing on
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]: if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1 # store the blockages as pin layouts so they are easy to compare etc.
self.blockages.append((shape,zlayer)) self.blockages.append(pin_layout("blockage",shape,boundary.drawingLayer))
# recurse given the mirror, angle, etc. # recurse given the mirror, angle, etc.
@ -507,13 +494,13 @@ class router:
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur)) #debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return [ll,ur] return [ll,ur]
def convert_pin_to_tracks(self,shape,zindex,pin): def convert_pin_to_tracks(self, pin):
""" """
Convert a rectangular pin shape into a list of track locations,layers. 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 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. If a pin has insufficent overlap, it returns the blockage list to avoid it.
""" """
[ll,ur] = shape [ll,ur] = pin.rect
ll = snap_to_grid(ll) ll = snap_to_grid(ll)
ur = snap_to_grid(ur) ur = snap_to_grid(ur)
@ -524,6 +511,7 @@ class router:
ur=ur.scale(self.track_factor).ceil() ur=ur.scale(self.track_factor).ceil()
# width depends on which layer it is # width depends on which layer it is
zindex = 0 if pin.layer_num==self.horiz_layer_number else 1
if zindex==0: if zindex==0:
width = self.horiz_layer_width width = self.horiz_layer_width
else: else:
@ -539,12 +527,12 @@ class router:
# if dimension of overlap is greater than min width in any dimension, # if dimension of overlap is greater than min width in any dimension,
# it will be an on-grid pin # it will be an on-grid pin
rect = self.convert_track_to_pin(vector3d(x,y,zindex)) rect = self.convert_track_to_pin(vector3d(x,y,zindex))
max_overlap=max(self.compute_overlap(shape,rect)) max_overlap=max(self.compute_overlap(pin.rect,rect))
# 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_full_track_to_shape(vector3d(x,y,zindex)) full_rect = self.convert_full_track_to_shape(vector3d(x,y,zindex))
full_overlap=max(self.compute_overlap(shape,full_rect)) full_overlap=max(self.compute_overlap(pin.rect,full_rect))
#debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) #debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
if max_overlap >= width: if max_overlap >= width:
@ -552,7 +540,7 @@ class router:
elif full_overlap>0: elif full_overlap>0:
block_list.append(vector3d(x,y,zindex)) block_list.append(vector3d(x,y,zindex))
else: else:
debug.info(1,"No overlap: {0} {1} max={2}".format(shape,rect,max_overlap)) debug.info(4,"No overlap: {0} {1} max={2}".format(pin.rect,rect,max_overlap))
#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))

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header,openram_test
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
OPTS = globals.OPTS
class no_blockages_test(openram_test):
"""
Simplest two pin route test with no blockages.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
class routing(design, openram_test):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.__init__(self, "top")
# Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r=routing("01_no_blockages_test_{0}".format(OPTS.tech_name))
self.local_drc_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
# 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()

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header,openram_test
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
OPTS = globals.OPTS
class blockages_test(openram_test):
"""
Simple two pin route test with multilayer blockages.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
class routing(design, openram_test):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.__init__(self, "top")
# Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r=routing("02_blockages_test_{0}".format(OPTS.tech_name))
self.local_drc_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
# 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()

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header,openram_test
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
OPTS = globals.OPTS
class same_layer_pins_test(openram_test):
"""
Checks two pins on the same layer with positive and negative coordinates.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
class routing(design, openram_test):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.__init__(self, "top")
# Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_drc_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
# 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()

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header,openram_test
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
OPTS = globals.OPTS
class diff_layer_pins_test(openram_test):
"""
Two pin route test with pins on different layers and blockages.
Pins are smaller than grid size.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
class routing(design, openram_test):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.__init__(self, "top")
# Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_drc_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
# 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()

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header,openram_test
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
OPTS = globals.OPTS
class two_nets_test(openram_test):
"""
Route two nets in the same GDS file. The routes will interact,
so they must block eachother.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
class routing(design, openram_test):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.__init__(self, "top")
# Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
r=router(gds_file)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
self.assertTrue(r.route(self,layer_stack,src="C",dest="D"))
r = routing("05_two_nets_test_{0}".format(OPTS.tech_name))
self.local_drc_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
# 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()

View File

@ -1,57 +1,43 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python3
"Run a regresion test the library cells for DRC" "Run a regresion test the library cells for DRC"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
import debug import debug
import calibre
OPTS = globals.OPTS OPTS = globals.OPTS
class pin_location_test(unittest.TestCase): class pin_location_test(openram_test):
""" """
Simplest two pin route test with no blockages using the pin locations instead of labels. Simplest two pin route test with no blockages using the pin locations instead of labels.
""" """
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
import design class routing(design, openram_test):
import router
class gdscell(design.design):
""" """
A generic GDS design that we can route on. A generic GDS design that we can route on.
""" """
def __init__(self, name): def __init__(self, name):
#design.design.__init__(self, name) design.__init__(self, "top")
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,unittest.TestCase):
"""
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))
cell = gdscell(name) # Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name, self.add_inst(name=name,
mod=cell, mod=cell,
offset=[0,0]) offset=[0,0])
self.connect_inst([]) self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) r=router(gds_file)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2") layer_stack =("metal1","via1","metal2")
# these are user coordinates and layers # these are user coordinates and layers
src_pin = [[0.52, 4.099],11] src_pin = [[0.52, 4.099],11]
@ -62,21 +48,12 @@ class pin_location_test(unittest.TestCase):
# This only works for freepdk45 since the coordinates are hard coded # This only works for freepdk45 since the coordinates are hard coded
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
r = routing("06_pin_location_test_{0}".format(OPTS.tech_name)) r = routing("06_pin_location_test_{0}".format(OPTS.tech_name))
self.local_check(r) self.local_drc_check(r)
else: else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name)) debug.warning("This test does not support technology {0}".format(OPTS.tech_name))
# fails if there are any DRC errors on any cells # fails if there are any DRC errors on any cells
globals.end_openram() 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)

View File

@ -1,58 +1,44 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python3
"Run a regresion test the library cells for DRC" "Run a regresion test the library cells for DRC"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
import debug import debug
import calibre
OPTS = globals.OPTS OPTS = globals.OPTS
class big_test(unittest.TestCase): class big_test(openram_test):
""" """
Simplest two pin route test with no blockages using the pin locations instead of labels. Simplest two pin route test with no blockages using the pin locations instead of labels.
""" """
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
import design class routing(design, openram_test):
import router
class gdscell(design.design):
""" """
A generic GDS design that we can route on. A generic GDS design that we can route on.
""" """
def __init__(self, name): def __init__(self, name):
#design.design.__init__(self, name) design.__init__(self, "top")
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,unittest.TestCase):
"""
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))
cell = gdscell(name) # Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name, self.add_inst(name=name,
mod=cell, mod=cell,
offset=[0,0]) offset=[0,0])
self.connect_inst([]) self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) r=router(gds_file)
r=router.router(self.gdsname) layer_stack =("metal1","via1","metal2")
layer_stack =("metal3","via2","metal2")
connections=[('out_0_2', 'a_0_0'), connections=[('out_0_2', 'a_0_0'),
('out_0_3', 'b_0_0'), ('out_0_3', 'b_0_0'),
('out_0_0', 'a_0_1'), ('out_0_0', 'a_0_1'),
@ -80,21 +66,12 @@ class big_test(unittest.TestCase):
# This test only runs on scn3me_subm tech # This test only runs on scn3me_subm tech
if OPTS.tech_name=="scn3me_subm": if OPTS.tech_name=="scn3me_subm":
r = routing("07_big_test_{0}".format(OPTS.tech_name)) r = routing("07_big_test_{0}".format(OPTS.tech_name))
self.local_check(r) self.local_drc_check(r)
else: else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name)) debug.warning("This test does not support technology {0}".format(OPTS.tech_name))
# fails if there are any DRC errors on any cells # fails if there are any DRC errors on any cells
globals.end_openram() 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)

View File

@ -1,57 +1,43 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python3
"Run a regresion test the library cells for DRC" "Run a regresion test the library cells for DRC"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"../..")) sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
import debug import debug
import calibre
OPTS = globals.OPTS OPTS = globals.OPTS
class expand_region_test(unittest.TestCase): class expand_region_test(openram_test):
""" """
Test an infeasible route followed by a feasible route with an expanded region. Test an infeasible route followed by a feasible route with an expanded region.
""" """
def runTest(self): def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name)) globals.init_openram("config_{0}".format(OPTS.tech_name))
from gds_cell import gds_cell
from design import design
from router import router
import design class routing(design, openram_test):
import router
class gdscell(design.design):
""" """
A generic GDS design that we can route on. A generic GDS design that we can route on.
""" """
def __init__(self, name): def __init__(self, name):
#design.design.__init__(self, name) design.__init__(self, "top")
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,unittest.TestCase):
"""
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))
cell = gdscell(name) # Instantiate a GDS cell with the design
gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
cell = gds_cell(name, gds_file)
self.add_inst(name=name, self.add_inst(name=name,
mod=cell, mod=cell,
offset=[0,0]) offset=[0,0])
self.connect_inst([]) self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name) r=router(gds_file)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2") layer_stack =("metal1","via1","metal2")
# This should be infeasible because it is blocked without a detour. # This should be infeasible because it is blocked without a detour.
self.assertFalse(r.route(self,layer_stack,src="A",dest="B",detour_scale=1)) self.assertFalse(r.route(self,layer_stack,src="A",dest="B",detour_scale=1))
@ -59,22 +45,12 @@ class expand_region_test(unittest.TestCase):
self.assertTrue(r.route(self,layer_stack,src="A",dest="B",detour_scale=3)) self.assertTrue(r.route(self,layer_stack,src="A",dest="B",detour_scale=3))
r = routing("08_expand_region_test_{0}".format(OPTS.tech_name)) r = routing("08_expand_region_test_{0}".format(OPTS.tech_name))
self.local_check(r) self.local_drc_check(r)
# fails if there are any DRC errors on any cells # fails if there are any DRC errors on any cells
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -0,0 +1,16 @@
from design import design
class gds_cell(design):
"""
A generic GDS design.
"""
def __init__(self, name, gds_file):
self.name = name
self.gds_file = gds_file
self.sp_file = None
design.__init__(self, name)
# The dimensions will not be defined, so do this...
self.width=0
self.height=0

View File

@ -1,6 +1,6 @@
import unittest,warnings import unittest,warnings
import sys,os,glob,copy import sys,os,glob,copy
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],"../.."))
from globals import OPTS from globals import OPTS
import debug import debug
@ -19,7 +19,8 @@ class openram_test(unittest.TestCase):
if result != 0: if result != 0:
self.fail("DRC failed: {}".format(w.name)) self.fail("DRC failed: {}".format(w.name))
self.cleanup() if OPTS.purge_temp:
self.cleanup()
def local_check(self, a, final_verification=False): def local_check(self, a, final_verification=False):

View File

@ -86,6 +86,10 @@ def write_magic_script(cell_name, gds_name, extract=False):
f.write("gds warning default\n") f.write("gds warning default\n")
f.write("gds read {}\n".format(gds_name)) f.write("gds read {}\n".format(gds_name))
f.write("load {}\n".format(cell_name)) f.write("load {}\n".format(cell_name))
# Flatten the cell to get rid of DRCs spanning multiple layers
# (e.g. with routes)
f.write("flatten {}_new\n".format(cell_name))
f.write("load {}_new\n".format(cell_name))
f.write("writeall force\n") f.write("writeall force\n")
f.write("drc check\n") f.write("drc check\n")
f.write("drc catchup\n") f.write("drc catchup\n")

View File

@ -1,81 +0,0 @@
#!/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
OPTS = globals.OPTS
class no_blockages_test(unittest.TestCase):
"""
Simplest two pin route test with no blockages.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
global verify
import verify
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,unittest.TestCase):
"""
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))
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__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
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
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()

View File

@ -1,80 +0,0 @@
#!/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 blockages_test(unittest.TestCase):
"""
Simple two pin route test with multilayer blockages.
"""
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,unittest.TestCase):
"""
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))
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__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("02_blockages_test_{0}".format(OPTS.tech_name))
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()

View File

@ -1,80 +0,0 @@
#!/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 same_layer_pins_test(unittest.TestCase):
"""
Checks two pins on the same layer with positive and negative coordinates.
"""
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,unittest.TestCase):
"""
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))
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__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name))
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()

View File

@ -1,81 +0,0 @@
#!/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 diff_layer_pins_test(unittest.TestCase):
"""
Two pin route test with pins on different layers and blockages.
Pins are smaller than grid size.
"""
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,unittest.TestCase):
"""
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))
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__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
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
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()

View File

@ -1,82 +0,0 @@
#!/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 two_nets_test(unittest.TestCase):
"""
Route two nets in the same GDS file. The routes will interact,
so they must block eachother.
"""
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,unittest.TestCase):
"""
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))
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__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
self.assertTrue(r.route(self,layer_stack,src="C",dest="D"))
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
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()