mirror of https://github.com/VLSIDA/OpenRAM.git
Update router to work with pin_layout structure.
This commit is contained in:
parent
ea52af3747
commit
2ae1e0234d
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
@ -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))
|
||||||
|
|
@ -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()
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -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()
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -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()
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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):
|
||||||
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
@ -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()
|
|
||||||
|
|
@ -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()
|
|
||||||
Loading…
Reference in New Issue