OpenRAM v1.1.3

Mucho PEP8 corrections.
Add layer-purpose to tech files.
Enable colon delimited OPENRAM_TECH list.
Add general config files for unit tests.
This commit is contained in:
Matt Guthaus 2019-11-21 16:20:33 -08:00
commit 7556872a75
143 changed files with 1904 additions and 1222 deletions

View File

@ -167,7 +167,7 @@ class instance(geometry):
debug.info(4, "creating instance: " + self.name)
def get_blockages(self, layer, top=False):
def get_blockages(self, lpp, top=False):
""" Retrieve blockages of all modules in this instance.
Apply the transform of the instance placement to give absolute blockages."""
angle = math.radians(float(self.rotate))
@ -191,11 +191,11 @@ class instance(geometry):
if self.mod.is_library_cell:
# Writes library cell blockages as shapes instead of a large metal blockage
blockages = []
blockages = self.mod.gds.getBlockages(layer)
blockages = self.mod.gds.getBlockages(lpp)
for b in blockages:
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
else:
blockages = self.mod.get_blockages(layer)
blockages = self.mod.get_blockages(lpp)
for b in blockages:
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
return new_blockages
@ -266,11 +266,12 @@ class instance(geometry):
class path(geometry):
"""Represents a Path"""
def __init__(self, layerNumber, coordinates, path_width):
def __init__(self, lpp, coordinates, path_width):
"""Initializes a path for the specified layer"""
geometry.__init__(self)
self.name = "path"
self.layerNumber = layerNumber
self.layerNumber = lpp[0]
self.layerPurpose = lpp[1]
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
self.coordinates = vector(self.coordinates).snap_to_grid()
self.path_width = path_width
@ -283,7 +284,7 @@ class path(geometry):
"""Writes the path to GDS"""
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
new_layout.addPath(layerNumber=self.layerNumber,
purposeNumber=0,
purposeNumber=self.layerPurpose,
coordinates=self.coordinates,
width=self.path_width)
@ -303,12 +304,13 @@ class path(geometry):
class label(geometry):
"""Represents a text label"""
def __init__(self, text, layerNumber, offset, zoom=-1):
def __init__(self, text, lpp, offset, zoom=-1):
"""Initializes a text label for specified layer"""
geometry.__init__(self)
self.name = "label"
self.text = text
self.layerNumber = layerNumber
self.layerNumber = lpp[0]
self.layerPurpose = lpp[1]
self.offset = vector(offset).snap_to_grid()
if zoom<0:
@ -325,7 +327,7 @@ class label(geometry):
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
new_layout.addText(text=self.text,
layerNumber=self.layerNumber,
purposeNumber=0,
purposeNumber=self.layerPurpose,
offsetInMicrons=self.offset,
magnification=self.zoom,
rotate=None)
@ -346,11 +348,12 @@ class label(geometry):
class rectangle(geometry):
"""Represents a rectangular shape"""
def __init__(self, layerNumber, offset, width, height):
def __init__(self, lpp, offset, width, height):
"""Initializes a rectangular shape for specified layer"""
geometry.__init__(self)
self.name = "rect"
self.layerNumber = layerNumber
self.layerNumber = lpp[0]
self.layerPurpose = lpp[1]
self.offset = vector(offset).snap_to_grid()
self.size = vector(width, height).snap_to_grid()
self.width = round_to_grid(self.size.x)
@ -374,7 +377,7 @@ class rectangle(geometry):
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
new_layout.addBox(layerNumber=self.layerNumber,
purposeNumber=0,
purposeNumber=self.layerPurpose,
offsetInMicrons=self.offset,
width=self.width,
height=self.height,

View File

@ -150,9 +150,9 @@ class layout():
if not height:
height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology
layer_num = techlayer[layer]
if layer_num >= 0:
self.objs.append(geometry.rectangle(layer_num, offset, width, height))
lpp = techlayer[layer]
if lpp[0] >= 0:
self.objs.append(geometry.rectangle(lpp, offset, width, height))
return self.objs[-1]
return None
@ -165,10 +165,10 @@ class layout():
if not height:
height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology
layer_num = techlayer[layer]
lpp = techlayer[layer]
corrected_offset = offset - vector(0.5*width,0.5*height)
if layer_num >= 0:
self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height))
if lpp[0] >= 0:
self.objs.append(geometry.rectangle(lpp, corrected_offset, width, height))
return self.objs[-1]
return None
@ -334,9 +334,9 @@ class layout():
"""Adds a text label on the given layer,offset, and zoom level"""
# negative layers indicate "unused" layers in a given technology
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
layer_num = techlayer[layer]
if layer_num >= 0:
self.objs.append(geometry.label(text, layer_num, offset, zoom))
lpp = techlayer[layer]
if lpp[0] >= 0:
self.objs.append(geometry.label(text, lpp, offset, zoom))
return self.objs[-1]
return None
@ -347,9 +347,9 @@ class layout():
import wire_path
# NOTE: (UNTESTED) add_path(...) is currently not used
# negative layers indicate "unused" layers in a given technology
#layer_num = techlayer[layer]
#if layer_num >= 0:
# self.objs.append(geometry.path(layer_num, coordinates, width))
#lpp = techlayer[layer]
#if lpp[0] >= 0:
# self.objs.append(geometry.path(lpp, coordinates, width))
wire_path.wire_path(obj=self,
layer=layer,
@ -539,21 +539,21 @@ class layout():
Do not write the pins since they aren't obstructions.
"""
if type(layer)==str:
layer_num = techlayer[layer]
lpp = techlayer[layer]
else:
layer_num = layer
lpp = layer
blockages = []
for i in self.objs:
blockages += i.get_blockages(layer_num)
blockages += i.get_blockages(lpp)
for i in self.insts:
blockages += i.get_blockages(layer_num)
blockages += i.get_blockages(lpp)
# Must add pin blockages to non-top cells
if not top_level:
blockages += self.get_pin_blockages(layer_num)
blockages += self.get_pin_blockages(lpp)
return blockages
def get_pin_blockages(self, layer_num):
def get_pin_blockages(self, lpp):
""" Return the pin shapes as blockages for non-top-level blocks. """
# FIXME: We don't have a body contact in ptx, so just ignore it for now
import copy
@ -565,33 +565,57 @@ class layout():
for pin_name in pin_names:
pin_list = self.get_pins(pin_name)
for pin in pin_list:
if pin.layer_num==layer_num:
if pin.same_lpp(pin.lpp, lpp):
blockages += [pin.rect]
return blockages
def create_horizontal_pin_bus(self, layer, pitch, offset, names, length):
""" Create a horizontal bus of pins. """
return self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=True)
return self.create_bus(layer,
pitch,
offset,
names,
length,
vertical=False,
make_pins=True)
def create_vertical_pin_bus(self, layer, pitch, offset, names, length):
""" Create a horizontal bus of pins. """
return self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=True)
return self.create_bus(layer,
pitch,
offset,
names,
length,
vertical=True,
make_pins=True)
def create_vertical_bus(self, layer, pitch, offset, names, length):
""" Create a horizontal bus. """
return self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=False)
return self.create_bus(layer,
pitch,
offset,
names,
length,
vertical=True,
make_pins=False)
def create_horizontal_bus(self, layer, pitch, offset, names, length):
""" Create a horizontal bus. """
return self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=False)
return self.create_bus(layer,
pitch,
offset,
names,
length,
vertical=False,
make_pins=False)
def create_bus(self, layer, pitch, offset, names, length, vertical, make_pins):
"""
"""
Create a horizontal or vertical bus. It can be either just rectangles, or actual
layout pins. It returns an map of line center line positions indexed by name.
The other coordinate is a 0 since the bus provides a range.
The other coordinate is a 0 since the bus provides a range.
TODO: combine with channel router.
"""

View File

@ -11,42 +11,55 @@ from vector import vector
from tech import layer
import math
class pin_layout:
"""
A class to represent a rectangular design pin. It is limited to a
single shape.
"""
def __init__(self, name, rect, layer_name_num):
def __init__(self, name, rect, layer_name_pp):
self.name = name
# repack the rect as a vector, just in case
if type(rect[0])==vector:
if type(rect[0]) == vector:
self.rect = rect
else:
self.rect = [vector(rect[0]),vector(rect[1])]
self.rect = [vector(rect[0]), vector(rect[1])]
# snap the rect to the grid
self.rect = [x.snap_to_grid() for x in self.rect]
debug.check(self.width()>0,"Zero width pin.")
debug.check(self.height()>0,"Zero height pin.")
debug.check(self.width() > 0, "Zero width pin.")
debug.check(self.height() > 0, "Zero height pin.")
# if it's a layer number look up the layer name. this assumes a unique layer number.
if type(layer_name_num)==int:
self.layer = list(layer.keys())[list(layer.values()).index(layer_name_num)]
# if it's a string, use the name
if type(layer_name_pp) == str:
self.layer = layer_name_pp
# else it is required to be a lpp
else:
self.layer=layer_name_num
self.layer_num = layer[self.layer]
for (layer_name, lpp) in layer.items():
if self.same_lpp(layer_name_pp, lpp):
self.layer = layer_name
break
else:
debug.error("Couldn't find layer {}".format(layer_name_pp), -1)
self.lpp = layer[self.layer]
def __str__(self):
""" override print function output """
return "({} layer={} ll={} ur={})".format(self.name,self.layer,self.rect[0],self.rect[1])
return "({} layer={} ll={} ur={})".format(self.name,
self.layer,
self.rect[0],
self.rect[1])
def __repr__(self):
"""
override repr function output (don't include
"""
override repr function output (don't include
name since pin shapes could have same shape but diff name e.g. blockage vs A)
"""
return "(layer={} ll={} ur={})".format(self.layer,self.rect[0],self.rect[1])
return "(layer={} ll={} ur={})".format(self.layer,
self.rect[0],
self.rect[1])
def __hash__(self):
""" Implement the hash function for sets etc. """
@ -65,15 +78,15 @@ class pin_layout:
def __eq__(self, other):
""" Check if these are the same pins for duplicate checks """
if isinstance(other, self.__class__):
return (self.layer==other.layer and self.rect == other.rect)
return (self.lpp == other.lpp and self.rect == other.rect)
else:
return False
return False
def bbox(self, pin_list):
"""
Given a list of layout pins, create a bounding box layout.
"""
(ll, ur) = self.rect
(ll, ur) = self.rect
min_x = ll.x
max_x = ur.x
min_y = ll.y
@ -85,17 +98,17 @@ class pin_layout:
min_y = min(min_y, pin.ll().y)
max_y = max(max_y, pin.ur().y)
self.rect = [vector(min_x,min_y),vector(max_x,max_y)]
self.rect = [vector(min_x, min_y), vector(max_x, max_y)]
def inflate(self, spacing=None):
"""
Inflate the rectangle by the spacing (or other rule)
and return the new rectangle.
"""
Inflate the rectangle by the spacing (or other rule)
and return the new rectangle.
"""
if not spacing:
spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
(ll,ur) = self.rect
(ll, ur) = self.rect
spacing = vector(spacing, spacing)
newll = ll - spacing
newur = ur + spacing
@ -104,20 +117,20 @@ class pin_layout:
def intersection(self, other):
""" Check if a shape overlaps with a rectangle """
(ll,ur) = self.rect
(oll,our) = other.rect
(ll, ur) = self.rect
(oll, our) = other.rect
min_x = max(ll.x, oll.x)
max_x = min(ll.x, oll.x)
min_y = max(ll.y, oll.y)
max_y = min(ll.y, oll.y)
return [vector(min_x,min_y),vector(max_x,max_y)]
return [vector(min_x, min_y), vector(max_x, max_y)]
def xoverlaps(self, other):
""" Check if shape has x overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
(ll, ur) = self.rect
(oll, our) = other.rect
x_overlaps = False
# check if self is within other x range
if (ll.x >= oll.x and ll.x <= our.x) or (ur.x >= oll.x and ur.x <= our.x):
@ -130,8 +143,8 @@ class pin_layout:
def yoverlaps(self, other):
""" Check if shape has x overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
(ll, ur) = self.rect
(oll, our) = other.rect
y_overlaps = False
# check if self is within other y range
@ -145,15 +158,15 @@ class pin_layout:
def xcontains(self, other):
""" Check if shape contains the x overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
(ll, ur) = self.rect
(oll, our) = other.rect
return (oll.x >= ll.x and our.x <= ur.x)
def ycontains(self, other):
""" Check if shape contains the y overlap """
(ll,ur) = self.rect
(oll,our) = other.rect
(ll, ur) = self.rect
(oll, our) = other.rect
return (oll.y >= ll.y and our.y <= ur.y)
@ -164,7 +177,7 @@ class pin_layout:
return True
# Can only overlap on the same layer
if self.layer != other.layer:
if not self.same_lpp(self.lpp, other.lpp):
return False
if not self.xcontains(other):
@ -182,11 +195,10 @@ class pin_layout:
return True
return False
def overlaps(self, other):
""" Check if a shape overlaps with a rectangle """
# Can only overlap on the same layer
if self.layer != other.layer:
if not self.same_lpp(self.lpp, other.lpp):
return False
x_overlaps = self.xoverlaps(other)
@ -208,40 +220,45 @@ class pin_layout:
def normalize(self):
""" Re-find the LL and UR points after a transform """
(first,second)=self.rect
ll = vector(min(first[0],second[0]),min(first[1],second[1]))
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
self.rect=[ll,ur]
(first, second) = self.rect
ll = vector(min(first[0], second[0]), min(first[1], second[1]))
ur = vector(max(first[0], second[0]), max(first[1], second[1]))
self.rect=[ll, ur]
def transform(self,offset,mirror,rotate):
""" 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) = self.rect
if mirror=="MX":
ll=ll.scale(1,-1)
ur=ur.scale(1,-1)
elif mirror=="MY":
ll=ll.scale(-1,1)
ur=ur.scale(-1,1)
elif mirror=="XY":
ll=ll.scale(-1,-1)
ur=ur.scale(-1,-1)
def transform(self, offset, mirror, rotate):
"""
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) = self.rect
if mirror == "MX":
ll = ll.scale(1, -1)
ur = ur.scale(1, -1)
elif mirror == "MY":
ll = ll.scale(-1, 1)
ur = ur.scale(-1, 1)
elif mirror == "XY":
ll = ll.scale(-1, -1)
ur = ur.scale(-1, -1)
if rotate==90:
ll=ll.rotate_scale(-1,1)
ur=ur.rotate_scale(-1,1)
elif rotate==180:
ll=ll.scale(-1,-1)
ur=ur.scale(-1,-1)
elif rotate==270:
ll=ll.rotate_scale(1,-1)
ur=ur.rotate_scale(1,-1)
if rotate == 90:
ll = ll.rotate_scale(-1, 1)
ur = ur.rotate_scale(-1, 1)
elif rotate == 180:
ll = ll.scale(-1, -1)
ur = ur.scale(-1, -1)
elif rotate == 270:
ll = ll.rotate_scale(1, -1)
ur = ur.rotate_scale(1, -1)
self.rect=[offset+ll,offset+ur]
self.rect = [offset + ll, offset + ur]
self.normalize()
def center(self):
return vector(0.5*(self.rect[0].x+self.rect[1].x),0.5*(self.rect[0].y+self.rect[1].y))
return vector(0.5*(self.rect[0].x+self.rect[1].x),
0.5*(self.rect[0].y+self.rect[1].y))
def cx(self):
""" Center x """
@ -258,17 +275,17 @@ class pin_layout:
def ul(self):
""" Upper left point """
return vector(self.rect[0].x,self.rect[1].y)
return vector(self.rect[0].x, self.rect[1].y)
def lr(self):
""" Lower right point """
return vector(self.rect[1].x,self.rect[0].y)
return vector(self.rect[1].x, self.rect[0].y)
def ur(self):
""" Upper right point """
return self.rect[1]
# The possible y edge values
# The possible y edge values
def uy(self):
""" Upper y value """
return self.rect[1].y
@ -287,67 +304,71 @@ class pin_layout:
""" Right x value """
return self.rect[1].x
# The edge centers
def rc(self):
""" Right center point """
return vector(self.rect[1].x,0.5*(self.rect[0].y+self.rect[1].y))
return vector(self.rect[1].x,
0.5*(self.rect[0].y+self.rect[1].y))
def lc(self):
""" Left center point """
return vector(self.rect[0].x,0.5*(self.rect[0].y+self.rect[1].y))
return vector(self.rect[0].x,
0.5*(self.rect[0].y+self.rect[1].y))
def uc(self):
""" Upper center point """
return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[1].y)
return vector(0.5*(self.rect[0].x+self.rect[1].x),
self.rect[1].y)
def bc(self):
""" Bottom center point """
return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[0].y)
return vector(0.5*(self.rect[0].x+self.rect[1].x),
self.rect[0].y)
def gds_write_file(self, newLayout):
"""Writes the pin shape and label to GDS"""
debug.info(4, "writing pin (" + str(self.layer) + "):"
+ str(self.width()) + "x" + str(self.height()) + " @ " + str(self.ll()))
newLayout.addBox(layerNumber=layer[self.layer],
purposeNumber=0,
debug.info(4, "writing pin (" + str(self.layer) + "):"
+ str(self.width()) + "x"
+ str(self.height()) + " @ " + str(self.ll()))
(layer_num, purpose) = layer[self.layer]
newLayout.addBox(layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.ll(),
width=self.width(),
height=self.height(),
center=False)
# Add the tet in the middle of the pin.
# This fixes some pin label offsetting when GDS gets imported into Magic.
# This fixes some pin label offsetting when GDS gets
# imported into Magic.
newLayout.addText(text=self.name,
layerNumber=layer[self.layer],
purposeNumber=0,
layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.center(),
magnification=GDS["zoom"],
rotate=None)
def compute_overlap(self, other):
""" Calculate the rectangular overlap of two rectangles. """
(r1_ll,r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect
(r1_ll, r1_ur) = self.rect
(r2_ll, r2_ur) = other.rect
#ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y))
#ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y))
# ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y))
# ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y))
dy = min(r1_ur.y,r2_ur.y)-max(r1_ll.y,r2_ll.y)
dx = min(r1_ur.x,r2_ur.x)-max(r1_ll.x,r2_ll.x)
dy = min(r1_ur.y, r2_ur.y) - max(r1_ll.y, r2_ll.y)
dx = min(r1_ur.x, r2_ur.x) - max(r1_ll.x, r2_ll.x)
if dx>=0 and dy>=0:
return [dx,dy]
if dx >= 0 and dy >= 0:
return [dx, dy]
else:
return [0,0]
return [0, 0]
def distance(self, other):
"""
"""
Calculate the distance to another pin layout.
"""
(r1_ll,r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect
(r1_ll, r1_ur) = self.rect
(r2_ll, r2_ur) = other.rect
def dist(x1, y1, x2, y2):
return math.sqrt((x2-x1)**2 + (y2-y1)**2)
@ -368,7 +389,7 @@ class pin_layout:
elif left:
return r1_ll.x - r2_ur.x
elif right:
return r2_ll.x - r1.ur.x
return r2_ll.x - r1_ur.x
elif bottom:
return r1_ll.y - r2_ur.y
elif top:
@ -377,9 +398,8 @@ class pin_layout:
# rectangles intersect
return 0
def overlap_length(self, other):
"""
"""
Calculate the intersection segment and determine its length
"""
@ -391,21 +411,21 @@ class pin_layout:
intersections = self.compute_overlap_segment(other)
# This is the common case where two pairs of edges overlap
# at two points, so just find the distance between those two points
if len(intersections)==2:
(p1,p2) = intersections
return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2))
if len(intersections) == 2:
(p1, p2) = intersections
return math.sqrt(pow(p1[0]-p2[0], 2) + pow(p1[1]-p2[1], 2))
else:
# This is where we had a corner intersection or none
return 0
def compute_overlap_segment(self, other):
"""
Calculate the intersection segment of two rectangles
"""
Calculate the intersection segment of two rectangles
(if any)
"""
(r1_ll,r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect
(r1_ll, r1_ur) = self.rect
(r2_ll, r2_ur) = other.rect
# The other corners besides ll and ur
r1_ul = vector(r1_ll.x, r1_ur.y)
@ -414,6 +434,7 @@ class pin_layout:
r2_lr = vector(r2_ur.x, r2_ll.y)
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
@ -423,14 +444,14 @@ class pin_layout:
# R1 edges CW
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
r1_edges = []
for (p,q) in pairwise(r1_cw_points):
r1_edges.append([p,q])
for (p, q) in pairwise(r1_cw_points):
r1_edges.append([p, q])
# R2 edges CW
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
r2_edges = []
for (p,q) in pairwise(r2_cw_points):
r2_edges.append([p,q])
for (p, q) in pairwise(r2_cw_points):
r2_edges.append([p, q])
# There are 4 edges on each rectangle
# so just brute force check intersection of each
@ -452,18 +473,18 @@ class pin_layout:
q.x >= min(p.x, r.x) and \
q.y <= max(p.y, r.y) and \
q.y >= min(p.y, r.y):
return True
return True
return False
def segment_intersection(self, s1, s2):
"""
"""
Determine the intersection point of two segments
Return the a segment if they overlap.
Return None if they don't.
"""
(a,b) = s1
(c,d) = s2
(a, b) = s1
(c, d) = s2
# Line AB represented as a1x + b1y = c1
a1 = b.y - a.y
b1 = a.x - b.x
@ -476,12 +497,22 @@ class pin_layout:
determinant = a1*b2 - a2*b1
if determinant!=0:
if determinant != 0:
x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant
r = vector(x,y).snap_to_grid()
r = vector(x, y).snap_to_grid()
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return r
return None
def same_lpp(self, lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import os
import gdsMill
import tech
import math
@ -16,6 +15,7 @@ from pin_layout import pin_layout
OPTS = globals.OPTS
def ceil(decimal):
"""
Performs a ceiling function on the decimal place specified by the DRC grid.
@ -23,29 +23,35 @@ def ceil(decimal):
grid = tech.drc["grid"]
return math.ceil(decimal * 1 / grid) / (1 / grid)
def round_to_grid(number):
"""
Rounds an arbitrary number to the grid.
"""
grid = tech.drc["grid"]
grid = tech.drc["grid"]
# this gets the nearest integer value
number_grid = int(round(round((number / grid), 2), 0))
number_off = number_grid * grid
return number_off
def snap_to_grid(offset):
"""
Changes the coodrinate to match the grid settings
"""
return [round_to_grid(offset[0]),round_to_grid(offset[1])]
return [round_to_grid(offset[0]),
round_to_grid(offset[1])]
def pin_center(boundary):
"""
This returns the center of a pin shape in the vlsiLayout border format.
"""
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 auto_measure_libcell(pin_list, name, units, layer):
def auto_measure_libcell(pin_list, name, units, lpp):
"""
Open a GDS file and find the pins in pin_list as text on a given layer.
Return these as a set of properties including the cell width/height too.
@ -56,43 +62,42 @@ def auto_measure_libcell(pin_list, name, units, layer):
reader.loadFromFile(cell_gds)
cell = {}
measure_result = cell_vlsi.getLayoutBorder(layer)
if measure_result == None:
measure_result = cell_vlsi.getLayoutBorder(lpp[0])
if measure_result:
measure_result = cell_vlsi.measureSize(name)
[cell["width"], cell["height"]] = measure_result
for pin in pin_list:
(name,layer,boundary)=cell_vlsi.getPinShapeByLabel(str(pin))
(name, lpp, boundary) = cell_vlsi.getPinShapeByLabel(str(pin))
cell[str(pin)] = pin_center(boundary)
return cell
def get_gds_size(name, gds_filename, units, layer):
def get_gds_size(name, gds_filename, units, lpp):
"""
Open a GDS file and return the size from either the
bounding box or a border layer.
"""
debug.info(4,"Creating VLSI layout for {}".format(name))
debug.info(4, "Creating VLSI layout for {}".format(name))
cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(gds_filename)
cell = {}
measure_result = cell_vlsi.getLayoutBorder(layer)
if measure_result == None:
debug.info(2,"Layout border failed. Trying to measure size for {}".format(name))
measure_result = cell_vlsi.getLayoutBorder(lpp)
if not measure_result:
debug.info(2, "Layout border failed. Trying to measure size for {}".format(name))
measure_result = cell_vlsi.measureSize(name)
# returns width,height
return measure_result
def get_libcell_size(name, units, layer):
def get_libcell_size(name, units, lpp):
"""
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))
return(get_gds_size(name, cell_gds, units, lpp))
def get_gds_pins(pin_names, name, gds_filename, units):
@ -106,15 +111,18 @@ def get_gds_pins(pin_names, name, gds_filename, units):
cell = {}
for pin_name in pin_names:
cell[str(pin_name)]=[]
pin_list=cell_vlsi.getPinShape(str(pin_name))
cell[str(pin_name)] = []
pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list:
(layer,boundary)=pin_shape
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
# this is a list because other cells/designs may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, layer))
(lpp, boundary) = pin_shape
rect = [vector(boundary[0], boundary[1]),
vector(boundary[2], boundary[3])]
# this is a list because other cells/designs
# may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
return cell
def get_libcell_pins(pin_list, name, units):
"""
Open a GDS file and find the pins in pin_list as text on a given layer.

View File

@ -26,6 +26,9 @@ def check(check, str):
log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0:
import pdb
pdb.set_trace()
assert 0
@ -37,6 +40,9 @@ def error(str, return_value=0):
log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0:
import pdb
pdb.set_trace()
assert return_value == 0

View File

@ -686,10 +686,6 @@ class Gds2reader:
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
elif(idBits==('\x06','\x06')):
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
# print(''.[x for x in structName if ord(x) < 128])
# stripped = (c for c in structName if 0 < ord(c) < 127)
# structName = "".join(stripped)
# print(self.stripNonASCII(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming!
thisStructure.name = structName
if(findStructName==thisStructure.name):
wantedStruct=1
@ -767,10 +763,6 @@ class Gds2reader:
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
elif(idBits==('\x06','\x06')):
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
# print(''.[x for x in structName if ord(x) < 128])
# stripped = (c for c in structName if 0 < ord(c) < 127)
# structName = "".join(stripped)
# print(self.stripNonASCIIx(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming!
thisStructure.name = structName
if(self.debugToTerminal==1):
print("\tStructure Name: "+structName)

View File

@ -19,7 +19,8 @@ class VlsiLayout:
self.layerNumbersInUse = []
self.debug = False
if name:
self.rootStructureName=name
#take the root structure and copy it to a new structure with the new name
self.rootStructureName=self.padText(name)
#create the ROOT structure
self.structures[self.rootStructureName] = GdsStructure()
self.structures[self.rootStructureName].name = name
@ -82,13 +83,9 @@ class VlsiLayout:
return coordinatesRotate
def rename(self,newName):
#make sure the newName is a multiple of 2 characters
if(len(newName)%2 == 1):
#pad with a zero
newName = newName + '\x00'
#take the root structure and copy it to a new structure with the new name
self.structures[newName] = self.structures[self.rootStructureName]
self.structures[newName].name = newName
self.structures[newName].name = self.padText(newName)
#and delete the old root
del self.structures[self.rootStructureName]
self.rootStructureName = newName
@ -159,13 +156,14 @@ class VlsiLayout:
debug.check(len(structureNames)==1,"Multiple possible root structures in the layout: {}".format(str(structureNames)))
self.rootStructureName = structureNames[0]
def traverseTheHierarchy(self, startingStructureName=None, delegateFunction = None,
transformPath = [], rotateAngle = 0, transFlags = [0,0,0], coordinates = (0,0)):
#since this is a recursive function, must deal with the default
#parameters explicitly
if startingStructureName == None:
startingStructureName = self.rootStructureName
#set up the rotation matrix
if(rotateAngle == None or rotateAngle == ""):
angle = 0
@ -193,17 +191,21 @@ class VlsiLayout:
delegateFunction(startingStructureName, transformPath)
#starting with a particular structure, we will recursively traverse the tree
#********might have to set the recursion level deeper for big layouts!
if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others?
#if so, go through each and call this function again
#if not, return back to the caller (caller can be this function)
for sref in self.structures[startingStructureName].srefs:
#here, we are going to modify the sref coordinates based on the parent objects rotation
self.traverseTheHierarchy(startingStructureName = sref.sName,
delegateFunction = delegateFunction,
transformPath = transformPath,
rotateAngle = sref.rotateAngle,
transFlags = sref.transFlags,
coordinates = sref.coordinates)
try:
if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others?
#if so, go through each and call this function again
#if not, return back to the caller (caller can be this function)
for sref in self.structures[startingStructureName].srefs:
#here, we are going to modify the sref coordinates based on the parent objects rotation
self.traverseTheHierarchy(startingStructureName = sref.sName,
delegateFunction = delegateFunction,
transformPath = transformPath,
rotateAngle = sref.rotateAngle,
transFlags = sref.transFlags,
coordinates = sref.coordinates)
except KeyError:
debug.error("Could not find structure {} in GDS file.".format(startingStructureName),-1)
#MUST HANDLE AREFs HERE AS WELL
#when we return, drop the last transform from the transformPath
del transformPath[-1]
@ -211,11 +213,11 @@ class VlsiLayout:
def initialize(self):
self.deduceHierarchy()
#self.traverseTheHierarchy()
# self.traverseTheHierarchy()
self.populateCoordinateMap()
for layerNumber in self.layerNumbersInUse:
self.processLabelPins(layerNumber)
self.processLabelPins((layerNumber, None))
def populateCoordinateMap(self):
@ -243,21 +245,24 @@ class VlsiLayout:
self.xyTree.append((startingStructureName,origin,uVector,vVector))
self.traverseTheHierarchy(delegateFunction = addToXyTree)
def microns(self,userUnits):
def microns(self, userUnits):
"""Utility function to convert user units to microns"""
userUnit = self.units[1]/self.units[0]
userUnitsPerMicron = userUnit / (userunit)
userUnitsPerMicron = userUnit / userunit
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
return userUnits / layoutUnitsPerMicron
def userUnits(self,microns):
def userUnits(self, microns):
"""Utility function to convert microns to user units"""
userUnit = self.units[1]/self.units[0]
#userUnitsPerMicron = userUnit / 1e-6
# userUnitsPerMicron = userUnit / 1e-6
userUnitsPerMicron = userUnit / (userUnit)
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
#print("userUnit:",userUnit,"userUnitsPerMicron",userUnitsPerMicron,"layoutUnitsPerMicron",layoutUnitsPerMicron,[microns,microns*layoutUnitsPerMicron])
return round(microns*layoutUnitsPerMicron,0)
# print("userUnit:",userUnit,
# "userUnitsPerMicron",userUnitsPerMicron,
# "layoutUnitsPerMicron",layoutUnitsPerMicron,
# [microns,microns*layoutUnitsPerMicron])
return round(microns*layoutUnitsPerMicron, 0)
def changeRoot(self,newRoot, create=False):
"""
@ -384,7 +389,7 @@ class VlsiLayout:
#add the sref to the root structure
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
def addPath(self, layerNumber=0, purposeNumber = None, coordinates=[(0,0)], width=1.0):
def addPath(self, layerNumber=0, purposeNumber=None, coordinates=[(0,0)], width=1.0):
"""
Method to add a path to a layout
"""
@ -396,24 +401,22 @@ class VlsiLayout:
cY = self.userUnits(coordinate[1])
layoutUnitCoordinates.append((cX,cY))
pathToAdd = GdsPath()
pathToAdd.drawingLayer=layerNumber
pathToAdd.drawingLayer = layerNumber
pathToAdd.purposeLayer = purposeNumber
pathToAdd.pathWidth=widthInLayoutUnits
pathToAdd.coordinates=layoutUnitCoordinates
pathToAdd.pathWidth = widthInLayoutUnits
pathToAdd.coordinates = layoutUnitCoordinates
#add the sref to the root structure
self.structures[self.rootStructureName].paths.append(pathToAdd)
def addText(self, text, layerNumber=0, purposeNumber = None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
def addText(self, text, layerNumber=0, purposeNumber=None, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
textToAdd = GdsText()
textToAdd.drawingLayer = layerNumber
textToAdd.purposeLayer = purposeNumber
textToAdd.dataType = 0
textToAdd.coordinates = [offsetInLayoutUnits]
textToAdd.transFlags = [0,0,0]
if(len(text)%2 == 1):
text = text + '\x00'
textToAdd.textString = text
textToAdd.transFlags = [0,0,0]
textToAdd.textString = self.padText(text)
#textToAdd.transFlags[1] = 1
textToAdd.magFactor = magnification
if rotate:
@ -421,7 +424,13 @@ class VlsiLayout:
textToAdd.rotateAngle = rotate
#add the sref to the root structure
self.structures[self.rootStructureName].texts.append(textToAdd)
def padText(self, text):
if(len(text)%2 == 1):
return text + '\x00'
else:
return text
def isBounded(self,testPoint,startPoint,endPoint):
#these arguments are touples of (x,y) coordinates
if testPoint == None:
@ -587,41 +596,50 @@ class VlsiLayout:
passFailIndex += 1
print("Done\n\n")
def getLayoutBorder(self,borderlayer):
cellSizeMicron=None
def getLayoutBorder(self, lpp):
cellSizeMicron = None
for boundary in self.structures[self.rootStructureName].boundaries:
if boundary.drawingLayer==borderlayer:
if sameLPP((boundary.drawingLayer, boundary.purposeLayer),
lpp):
if self.debug:
debug.info(1,"Find border "+str(boundary.coordinates))
left_bottom=boundary.coordinates[0]
right_top=boundary.coordinates[2]
cellSize=[right_top[0]-left_bottom[0],right_top[1]-left_bottom[1]]
cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]]
if not(cellSizeMicron):
print("Error: "+str(self.rootStructureName)+".cell_size information not found yet")
debug.info(1, "Find border "+str(boundary.coordinates))
left_bottom = boundary.coordinates[0]
right_top = boundary.coordinates[2]
cellSize = [right_top[0]-left_bottom[0],
right_top[1]-left_bottom[1]]
cellSizeMicron = [cellSize[0]*self.units[0],
cellSize[1]*self.units[0]]
debug.check(cellSizeMicron,
"Error: "+str(self.rootStructureName)+".cell_size information not found yet")
return cellSizeMicron
def measureSize(self,startStructure):
self.rootStructureName=startStructure
def measureSize(self, startStructure):
self.rootStructureName = self.padText(startStructure)
self.populateCoordinateMap()
cellBoundary = [None, None, None, None]
for TreeUnit in self.xyTree:
cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary)
cellSize=[cellBoundary[2]-cellBoundary[0],cellBoundary[3]-cellBoundary[1]]
cellSizeMicron=[cellSize[0]*self.units[0],cellSize[1]*self.units[0]]
cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary)
cellSize = [cellBoundary[2]-cellBoundary[0],
cellBoundary[3]-cellBoundary[1]]
cellSizeMicron = [cellSize[0]*self.units[0],
cellSize[1]*self.units[0]]
return cellSizeMicron
def measureBoundary(self,startStructure):
self.rootStructureName=startStructure
def measureBoundary(self, startStructure):
self.rootStructureName = self.padText(startStructure)
self.populateCoordinateMap()
cellBoundary = [None, None, None, None]
for TreeUnit in self.xyTree:
cellBoundary=self.measureSizeInStructure(TreeUnit,cellBoundary)
return [[self.units[0]*cellBoundary[0],self.units[0]*cellBoundary[1]],
[self.units[0]*cellBoundary[2],self.units[0]*cellBoundary[3]]]
cellBoundary = self.measureSizeInStructure(TreeUnit, cellBoundary)
return [[self.units[0]*cellBoundary[0],
self.units[0]*cellBoundary[1]],
[self.units[0]*cellBoundary[2],
self.units[0]*cellBoundary[3]]]
def measureSizeInStructure(self,structure,cellBoundary):
(structureName,structureOrigin,structureuVector,structurevVector)=structure
def measureSizeInStructure(self, structure, cellBoundary):
(structureName, structureOrigin,
structureuVector, structurevVector) = structure
for boundary in self.structures[str(structureName)].boundaries:
left_bottom=boundary.coordinates[0]
right_top=boundary.coordinates[2]
@ -648,14 +666,14 @@ class VlsiLayout:
cellBoundary[3]=right_top_Y
return cellBoundary
def getTexts(self, layer):
def getTexts(self, lpp):
"""
Get all of the labels on a given layer only at the root level.
"""
text_list = []
for Text in self.structures[self.rootStructureName].texts:
if Text.drawingLayer == layer:
if sameLPP((Text.drawingLayer, Text.purposeLayer),
lpp):
text_list.append(Text)
return text_list
@ -671,9 +689,9 @@ class VlsiLayout:
max_pin = None
max_area = 0
for pin in pin_list:
(layer,boundary) = pin
(layer, boundary) = pin
new_area = boundaryArea(boundary)
if max_pin == None or new_area>max_area:
if not max_pin or new_area > max_area:
max_pin = pin
max_area = new_area
max_pins.append(max_pin)
@ -690,32 +708,33 @@ class VlsiLayout:
pin_map = self.pins[pin_name]
for pin_list in pin_map:
for pin in pin_list:
(pin_layer, boundary) = pin
(pin_layer, boundary) = pin
shape_list.append(pin)
return shape_list
def processLabelPins(self, layer):
def processLabelPins(self, lpp):
"""
Find all text labels and create a map to a list of shapes that
they enclose on the given layer.
"""
# Get the labels on a layer in the root level
labels = self.getTexts(layer)
labels = self.getTexts(lpp)
# Get all of the shapes on the layer at all levels
# and transform them to the current level
shapes = self.getAllShapes(layer)
shapes = self.getAllShapes(lpp)
for label in labels:
label_coordinate = label.coordinates[0]
user_coordinate = [x*self.units[0] for x in label_coordinate]
pin_shapes = []
for boundary in shapes:
if self.labelInRectangle(user_coordinate,boundary):
pin_shapes.append((layer, boundary))
if self.labelInRectangle(user_coordinate, boundary):
pin_shapes.append((lpp, boundary))
label_text = label.textString
# Remove the padding if it exists
if label_text[-1] == "\x00":
label_text = label_text[0:-1]
@ -725,81 +744,97 @@ class VlsiLayout:
except KeyError:
self.pins[label_text] = []
self.pins[label_text].append(pin_shapes)
def getBlockages(self,layer):
def getBlockages(self, lpp):
"""
Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and
Return all blockages on a given layer in
[coordinate 1, coordinate 2,...] format and
user units.
"""
blockages = []
shapes = self.getAllShapes(layer)
shapes = self.getAllShapes(lpp)
for boundary in shapes:
vectors = []
for i in range(0,len(boundary),2):
vectors.append(vector(boundary[i],boundary[i+1]))
for i in range(0, len(boundary), 2):
vectors.append(vector(boundary[i], boundary[i+1]))
blockages.append(vectors)
return blockages
return blockages
def getAllShapes(self,layer):
def getAllShapes(self, lpp):
"""
Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles
and [coordinate 1, coordinate 2,...] format and user units for polygons.
Return all shapes on a given layer in [llx, lly, urx, ury]
format and user units for rectangles
and [coordinate 1, coordinate 2,...] format and user
units for polygons.
"""
boundaries = set()
for TreeUnit in self.xyTree:
#print(TreeUnit[0])
boundaries.update(self.getShapesInStructure(layer,TreeUnit))
# print(TreeUnit[0])
boundaries.update(self.getShapesInStructure(lpp, TreeUnit))
# Convert to user units
user_boundaries = []
for boundary in boundaries:
boundaries_list = []
for i in range(0,len(boundary)):
for i in range(0, len(boundary)):
boundaries_list.append(boundary[i]*self.units[0])
user_boundaries.append(boundaries_list)
return user_boundaries
def getShapesInStructure(self,layer,structure):
"""
Go through all the shapes in a structure and return the list of shapes in
the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons.
def getShapesInStructure(self, lpp, structure):
"""
(structureName,structureOrigin,structureuVector,structurevVector)=structure
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose())
Go through all the shapes in a structure and
return the list of shapes in
the form [llx, lly, urx, ury] for rectangles
and [coordinate 1, coordinate 2,...] for polygons.
"""
(structureName, structureOrigin,
structureuVector, structurevVector) = structure
# print(structureName,
# "u", structureuVector.transpose(),
# "v",structurevVector.transpose(),
# "o",structureOrigin.transpose())
boundaries = []
for boundary in self.structures[str(structureName)].boundaries:
if layer==boundary.drawingLayer:
if len(boundary.coordinates)!=5:
if sameLPP((boundary.drawingLayer, boundary.purposeLayer),
lpp):
if len(boundary.coordinates) != 5:
# if shape is a polygon (used in DFF)
boundaryPolygon = []
# Polygon is a list of coordinates going ccw
for coord in range(0,len(boundary.coordinates)):
for coord in range(0, len(boundary.coordinates)):
boundaryPolygon.append(boundary.coordinates[coord][0])
boundaryPolygon.append(boundary.coordinates[coord][1])
# perform the rotation
boundaryPolygon=self.transformPolygon(boundaryPolygon,structureuVector,structurevVector)
# add the offset
boundaryPolygon = self.transformPolygon(boundaryPolygon,
structureuVector,
structurevVector)
# add the offset
polygon = []
for i in range(0,len(boundaryPolygon),2):
polygon.append(boundaryPolygon[i]+structureOrigin[0].item())
polygon.append(boundaryPolygon[i+1]+structureOrigin[1].item())
for i in range(0, len(boundaryPolygon), 2):
polygon.append(boundaryPolygon[i] + structureOrigin[0].item())
polygon.append(boundaryPolygon[i+1] + structureOrigin[1].item())
# make it a tuple
polygon = tuple(polygon)
boundaries.append(polygon)
else:
# else shape is a rectangle
left_bottom=boundary.coordinates[0]
right_top=boundary.coordinates[2]
left_bottom = boundary.coordinates[0]
right_top = boundary.coordinates[2]
# Rectangle is [leftx, bottomy, rightx, topy].
boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
boundaryRect = [left_bottom[0], left_bottom[1],
right_top[0], right_top[1]]
# perform the rotation
boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
boundaryRect = self.transformRectangle(boundaryRect,
structureuVector,
structurevVector)
# add the offset and make it a tuple
boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item())
boundaryRect = (boundaryRect[0]+structureOrigin[0].item(),
boundaryRect[1]+structureOrigin[1].item(),
boundaryRect[2]+structureOrigin[0].item(),
boundaryRect[3]+structureOrigin[1].item())
boundaries.append(boundaryRect)
return boundaries
@ -861,6 +896,17 @@ class VlsiLayout:
else:
return False
def sameLPP(lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
def boundaryArea(A):
"""

View File

@ -6,8 +6,8 @@
# All rights reserved.
#
"""
This is called globals.py, but it actually parses all the arguments and performs
the global OpenRAM setup as well.
This is called globals.py, but it actually parses all the arguments
and performs the global OpenRAM setup as well.
"""
import os
import debug
@ -19,12 +19,13 @@ import re
import copy
import importlib
VERSION = "1.1.0"
VERSION = "1.1.3"
NAME = "OpenRAM v{}".format(VERSION)
USAGE = "openram.py [options] <config file>\nUse -h for help.\n"
OPTS = options.options()
CHECKPOINT_OPTS=None
CHECKPOINT_OPTS = None
def parse_args():
""" Parse the optional arguments for OpenRAM """
@ -32,27 +33,55 @@ def parse_args():
global OPTS
option_list = {
optparse.make_option("-b", "--backannotated", action="store_true", dest="use_pex",
optparse.make_option("-b",
"--backannotated",
action="store_true",
dest="use_pex",
help="Back annotate simulation"),
optparse.make_option("-o", "--output", dest="output_name",
help="Base output file name(s) prefix", metavar="FILE"),
optparse.make_option("-p", "--outpath", dest="output_path",
optparse.make_option("-o",
"--output",
dest="output_name",
help="Base output file name(s) prefix",
metavar="FILE"),
optparse.make_option("-p", "--outpath",
dest="output_path",
help="Output file(s) location"),
optparse.make_option("-i", "--inlinecheck", action="store_true",
help="Enable inline LVS/DRC checks", dest="inline_lvsdrc"),
optparse.make_option("-n", "--nocheck", action="store_false",
help="Disable all LVS/DRC checks", dest="check_lvsdrc"),
optparse.make_option("-v", "--verbose", action="count", dest="debug_level",
optparse.make_option("-i",
"--inlinecheck",
action="store_true",
help="Enable inline LVS/DRC checks",
dest="inline_lvsdrc"),
optparse.make_option("-n", "--nocheck",
action="store_false",
help="Disable all LVS/DRC checks",
dest="check_lvsdrc"),
optparse.make_option("-v",
"--verbose",
action="count",
dest="debug_level",
help="Increase the verbosity level"),
optparse.make_option("-t", "--tech", dest="tech_name",
optparse.make_option("-t",
"--tech",
dest="tech_name",
help="Technology name"),
optparse.make_option("-s", "--spice", dest="spice_name",
optparse.make_option("-s",
"--spice",
dest="spice_name",
help="Spice simulator executable name"),
optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist",
optparse.make_option("-r",
"--remove_netlist_trimming",
action="store_false",
dest="trim_netlist",
help="Disable removal of noncritical memory cells during characterization"),
optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay",
optparse.make_option("-c",
"--characterize",
action="store_false",
dest="analytical_delay",
help="Perform characterization to calculate delays (default is analytical models)"),
optparse.make_option("-d", "--dontpurge", action="store_false", dest="purge_temp",
optparse.make_option("-d",
"--dontpurge",
action="store_false",
dest="purge_temp",
help="Don't purge the contents of the temp directory after a successful run")
# -h --help is implicit.
}
@ -73,6 +102,7 @@ def parse_args():
return (options, args)
def print_banner():
""" Conditionally print the banner to stdout """
global OPTS
@ -117,13 +147,13 @@ def check_versions():
except:
OPTS.coverage = 0
def init_openram(config_file, is_unit_test=True):
"""Initialize the technology, paths, simulators, etc."""
""" Initialize the technology, paths, simulators, etc. """
check_versions()
debug.info(1,"Initializing OpenRAM...")
debug.info(1, "Initializing OpenRAM...")
setup_paths()
@ -146,10 +176,11 @@ def init_openram(config_file, is_unit_test=True):
# This is a hack. If we are running a unit test and have checkpointed
# the options, load them rather than reading the config file.
# This way, the configuration is reloaded at the start of every unit test.
# If a unit test fails, we don't have to worry about restoring the old config values
# If a unit test fails,
# we don't have to worry about restoring the old config values
# that may have been tested.
if is_unit_test and CHECKPOINT_OPTS:
OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy()
OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy()
return
# Import these to find the executables for checkpointing
@ -159,7 +190,8 @@ def init_openram(config_file, is_unit_test=True):
# after each unit test
if not CHECKPOINT_OPTS:
CHECKPOINT_OPTS = copy.copy(OPTS)
def setup_bitcell():
"""
Determine the correct custom or parameterized bitcell for the design.
@ -169,30 +201,29 @@ def setup_bitcell():
# If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use
if (OPTS.bitcell=="bitcell"):
if (OPTS.bitcell == "bitcell"):
if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0):
if (OPTS.num_rw_ports == 1 and OPTS.num_w_ports == 0 and OPTS.num_r_ports == 0):
OPTS.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell"
OPTS.dummy_bitcell = "dummy_bitcell"
else:
ports = ""
if OPTS.num_rw_ports>0:
if OPTS.num_rw_ports > 0:
ports += "{}rw_".format(OPTS.num_rw_ports)
if OPTS.num_w_ports>0:
if OPTS.num_w_ports > 0:
ports += "{}w_".format(OPTS.num_w_ports)
if OPTS.num_r_ports>0:
if OPTS.num_r_ports > 0:
ports += "{}r".format(OPTS.num_r_ports)
OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports
OPTS.dummy_bitcell = "dummy_bitcell_"+ports
else:
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
# See if bitcell exists
from importlib import find_loader
try:
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
@ -206,7 +237,7 @@ def setup_bitcell():
OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1,"Using bitcell: {}".format(OPTS.bitcell))
debug.info(1, "Using bitcell: {}".format(OPTS.bitcell))
def get_tool(tool_type, preferences, default_name=None):
@ -215,63 +246,73 @@ def get_tool(tool_type, preferences, default_name=None):
one selected and its full path. If default is specified,
find that one only and error otherwise.
"""
debug.info(2,"Finding {} tool...".format(tool_type))
debug.info(2, "Finding {} tool...".format(tool_type))
if default_name:
exe_name=find_exe(default_name)
exe_name = find_exe(default_name)
if exe_name == None:
debug.error("{0} not found. Cannot find {1} tool.".format(default_name,tool_type),2)
debug.error("{0} not found. Cannot find {1} tool.".format(default_name,
tool_type),
2)
else:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
return(default_name,exe_name)
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(default_name, exe_name)
else:
for name in preferences:
exe_name = find_exe(name)
if exe_name != None:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
return(name,exe_name)
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(name, exe_name)
else:
debug.info(1, "Could not find {0}, trying next {1} tool.".format(name,tool_type))
debug.info(1,
"Could not find {0}, trying next {1} tool.".format(name,
tool_type))
else:
return(None,"")
return(None, "")
def read_config(config_file, is_unit_test=True):
"""
"""
Read the configuration file that defines a few parameters. The
config file is just a Python file that defines some config
options. This will only actually get read the first time. Subsequent
reads will just restore the previous copy (ask mrg)
"""
global OPTS
# Create a full path relative to current dir unless it is already an abs path
# it is already not an abs path, make it one
if not os.path.isabs(config_file):
config_file = os.getcwd() + "/" + config_file
# Make it a python file if the base name was only given
config_file = re.sub(r'\.py$', "", config_file)
# Expand the user if it is used
config_file = os.path.expanduser(config_file)
OPTS.config_file = config_file
# Add the path to the system path so we can import things in the other directory
OPTS.config_file = config_file + ".py"
# Add the path to the system path
# so we can import things in the other directory
dir_name = os.path.dirname(config_file)
file_name = os.path.basename(config_file)
module_name = os.path.basename(config_file)
# Prepend the path to avoid if we are using the example config
sys.path.insert(0,dir_name)
sys.path.insert(0, dir_name)
# Import the configuration file of which modules to use
debug.info(1, "Configuration file is " + config_file + ".py")
try:
config = importlib.import_module(file_name)
config = importlib.import_module(module_name)
except:
debug.error("Unable to read configuration file: {0}".format(config_file),2)
for k,v in config.__dict__.items():
for k, v in config.__dict__.items():
# The command line will over-ride the config file
# except in the case of the tech name! This is because the tech name
# is sometimes used to specify the config file itself (e.g. unit tests)
# Note that if we re-read a config file, nothing will get read again!
if not k in OPTS.__dict__ or k=="tech_name":
OPTS.__dict__[k]=v
if k not in OPTS.__dict__ or k == "tech_name":
OPTS.__dict__[k] = v
# Massage the output path to be an absolute one
if not OPTS.output_path.endswith('/'):
@ -281,20 +322,20 @@ def read_config(config_file, is_unit_test=True):
debug.info(1, "Output saved in " + OPTS.output_path)
# Remember if we are running unit tests to reduce output
OPTS.is_unit_test=is_unit_test
OPTS.is_unit_test = is_unit_test
# If we are only generating a netlist, we can't do DRC/LVS
if OPTS.netlist_only:
OPTS.check_lvsdrc=False
OPTS.check_lvsdrc = False
# If config didn't set output name, make a reasonable default.
if (OPTS.output_name == ""):
ports = ""
if OPTS.num_rw_ports>0:
if OPTS.num_rw_ports > 0:
ports += "{}rw_".format(OPTS.num_rw_ports)
if OPTS.num_w_ports>0:
if OPTS.num_w_ports > 0:
ports += "{}w_".format(OPTS.num_w_ports)
if OPTS.num_r_ports>0:
if OPTS.num_r_ports > 0:
ports += "{}r_".format(OPTS.num_r_ports)
OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size,
OPTS.num_words,
@ -302,8 +343,6 @@ def read_config(config_file, is_unit_test=True):
OPTS.tech_name)
def end_openram():
""" Clean up openram for a proper exit """
cleanup_paths()
@ -312,9 +351,7 @@ def end_openram():
import verify
verify.print_drc_stats()
verify.print_lvs_stats()
verify.print_pex_stats()
verify.print_pex_stats()
def cleanup_paths():
@ -323,40 +360,44 @@ def cleanup_paths():
"""
global OPTS
if not OPTS.purge_temp:
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
debug.info(0,
"Preserving temp directory: {}".format(OPTS.openram_temp))
return
elif os.path.exists(OPTS.openram_temp):
debug.info(1,"Purging temp directory: {}".format(OPTS.openram_temp))
# This annoyingly means you have to re-cd into the directory each debug iteration
#shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
debug.info(1,
"Purging temp directory: {}".format(OPTS.openram_temp))
# This annoyingly means you have to re-cd into
# the directory each debug iteration
# shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)]
for i in contents:
if os.path.isfile(i) or os.path.islink(i):
os.remove(i)
else:
shutil.rmtree(i)
def setup_paths():
""" Set up the non-tech related paths. """
debug.info(2,"Setting up paths...")
debug.info(2, "Setting up paths...")
global OPTS
try:
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
except:
debug.error("$OPENRAM_HOME is not properly defined.",1)
debug.check(os.path.isdir(OPENRAM_HOME),"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
debug.error("$OPENRAM_HOME is not properly defined.", 1)
debug.check(os.path.isdir(OPENRAM_HOME),
"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
# Add all of the subdirs to the python path
# These subdirs are modules and don't need to be added: characterizer, verify
# These subdirs are modules and don't need
# to be added: characterizer, verify
subdirlist = [ item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item)) ]
for subdir in subdirlist:
full_path = "{0}/{1}".format(OPENRAM_HOME,subdir)
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
debug.check(os.path.isdir(full_path),
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir,full_path))
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
sys.path.append("{0}".format(full_path))
if not OPTS.openram_temp.endswith('/'):
@ -364,13 +405,16 @@ def setup_paths():
debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
def is_exe(fpath):
""" Return true if the given is an executable file that exists. """
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
def find_exe(check_exe):
""" Check if the binary exists in any path dir and return the full path. """
"""
Check if the binary exists in any path dir
and return the full path.
"""
# Check if the preferred spice option exists in the path
for path in os.environ["PATH"].split(os.pathsep):
exe = os.path.join(path, check_exe)
@ -379,12 +423,14 @@ def find_exe(check_exe):
return exe
return None
def init_paths():
""" Create the temp and output directory if it doesn't exist """
# make the directory if it doesn't exist
try:
debug.info(1,"Creating temp directory: {}".format(OPTS.openram_temp))
debug.info(1,
"Creating temp directory: {}".format(OPTS.openram_temp))
os.makedirs(OPTS.openram_temp, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
@ -398,8 +444,9 @@ def init_paths():
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750)
except:
debug.error("Unable to make output directory.",-1)
debug.error("Unable to make output directory.", -1)
def set_default_corner():
""" Set the default corner. """
@ -416,17 +463,19 @@ def import_tech():
""" Dynamically adds the tech directory to the path and imports it. """
global OPTS
debug.info(2,"Importing technology: " + OPTS.tech_name)
debug.info(2,
"Importing technology: " + OPTS.tech_name)
# environment variable should point to the technology dir
try:
OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH"))
except:
debug.error("$OPENRAM_TECH environment variable is not defined.",1)
debug.error("$OPENRAM_TECH environment variable is not defined.", 1)
# Add all of the paths
for tech_path in OPENRAM_TECH.split(":"):
debug.check(os.path.isdir(tech_path),"$OPENRAM_TECH does not exist: {0}".format(tech_path))
debug.check(os.path.isdir(tech_path),
"$OPENRAM_TECH does not exist: {0}".format(tech_path))
sys.path.append(tech_path)
debug.info(1, "Adding technology path: {}".format(tech_path))
@ -438,7 +487,6 @@ def import_tech():
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
# Add the tech directory
tech_path = OPTS.openram_tech
sys.path.append(tech_path)
@ -453,22 +501,25 @@ def print_time(name, now_time, last_time=None, indentation=2):
global OPTS
# Don't print during testing
if not OPTS.is_unit_test or OPTS.debug_level>0:
if not OPTS.is_unit_test or OPTS.debug_level > 0:
if last_time:
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
else:
time = now_time.strftime('%m/%d/%Y %H:%M:%S')
debug.print_raw("{0} {1}: {2}".format("*"*indentation,name,time))
debug.print_raw("{0} {1}: {2}".format("*"*indentation, name, time))
def report_status():
""" Check for valid arguments and report the info about the SRAM being generated """
"""
Check for valid arguments and report the
info about the SRAM being generated
"""
global OPTS
# Check if all arguments are integers for bits, size, banks
if type(OPTS.word_size)!=int:
if type(OPTS.word_size) != int:
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int:
if type(OPTS.num_words) != int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
if type(OPTS.write_size) is not int and OPTS.write_size is not None:
debug.error("{0} is not an integer in config file.".format(OPTS.write_size))
@ -478,30 +529,29 @@ def report_status():
if OPTS.write_size is not None:
if (OPTS.word_size % OPTS.write_size != 0):
debug.error("Write size needs to be an integer multiple of word size.")
# If write size is more than half of the word size, then it doesn't need a write mask. It would be writing
# If write size is more than half of the word size,
# then it doesn't need a write mask. It would be writing
# the whole word.
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2):
debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size))
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")
debug.print_raw("Technology: {0}".format(OPTS.tech_name))
total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks
debug.print_raw("Total size: {} bits".format(total_size))
if total_size>=2**14:
if total_size >= 2**14:
debug.warning("Requesting such a large memory size ({0}) will have a large run-time. ".format(total_size) +
"Consider using multiple smaller banks.")
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words,
OPTS.num_banks))
OPTS.num_words,
OPTS.num_banks))
if (OPTS.write_size != OPTS.word_size):
debug.print_raw("Write size: {}".format(OPTS.write_size))
debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports))
OPTS.num_r_ports,
OPTS.num_w_ports))
if OPTS.netlist_only:
debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).")
@ -518,7 +568,7 @@ def report_status():
if OPTS.analytical_delay:
debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).")
else:
if OPTS.spice_name!="":
if OPTS.spice_name != "":
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist:
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")

View File

@ -5,13 +5,11 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import globals
import design
from math import log
import design
from tech import GDS,layer,spice,parameter
from tech import GDS, layer, spice, parameter
import utils
class dff(design.design):
"""
Memory address flip-flop
@ -19,7 +17,9 @@ class dff(design.design):
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
(width, height) = utils.get_libcell_size("dff",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
def __init__(self, name="dff"):

View File

@ -10,6 +10,7 @@ import debug
import design
from math import log
from math import sqrt
from math import ceil
import math
import contact
from sram_factory import factory
@ -31,7 +32,7 @@ class hierarchical_decoder(design.design):
self.cell_height = height
self.rows = rows
self.num_inputs = int(math.log(self.rows, 2))
self.num_inputs = math.ceil(math.log(self.rows, 2))
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_netlist()
@ -338,14 +339,15 @@ class hierarchical_decoder(design.design):
for i in range(len(self.predec_groups[0])):
for j in range(len(self.predec_groups[1])):
row = len(self.predec_groups[0])*j + i
name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name,
mod=self.nand2))
pins =["out_{0}".format(i),
"out_{0}".format(j + len(self.predec_groups[0])),
"Z_{0}".format(row),
"vdd", "gnd"]
self.connect_inst(pins)
if (row < self.rows):
name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name,
mod=self.nand2))
pins =["out_{0}".format(i),
"out_{0}".format(j + len(self.predec_groups[0])),
"Z_{0}".format(row),
"vdd", "gnd"]
self.connect_inst(pins)
# Row Decoder NAND GATE array for address inputs >5.
@ -356,16 +358,17 @@ class hierarchical_decoder(design.design):
row = (len(self.predec_groups[0])*len(self.predec_groups[1])) * k \
+ len(self.predec_groups[0])*j + i
name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name,
mod=self.nand3))
if (row < self.rows):
name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name,
mod=self.nand3))
pins = ["out_{0}".format(i),
"out_{0}".format(j + len(self.predec_groups[0])),
"out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
"Z_{0}".format(row),
"vdd", "gnd"]
self.connect_inst(pins)
pins = ["out_{0}".format(i),
"out_{0}".format(j + len(self.predec_groups[0])),
"out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
"Z_{0}".format(row),
"vdd", "gnd"]
self.connect_inst(pins)
def create_decoder_inv_array(self):
@ -527,10 +530,11 @@ class hierarchical_decoder(design.design):
for index_B in self.predec_groups[1]:
for index_A in self.predec_groups[0]:
# FIXME: convert to connect_bus?
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
if (row_index < self.rows):
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
row_index = row_index + 1
elif (self.num_inputs > 5):
@ -538,12 +542,13 @@ class hierarchical_decoder(design.design):
for index_B in self.predec_groups[1]:
for index_A in self.predec_groups[0]:
# FIXME: convert to connect_bus?
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
predecode_name = "predecode_{}".format(index_C)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C"))
if (row_index < self.rows):
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A"))
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B"))
predecode_name = "predecode_{}".format(index_C)
self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C"))
row_index = row_index + 1
def route_vdd_gnd(self):

View File

@ -5,17 +5,14 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from tech import drc, parameter
import debug
import design
import contact
from math import log
from math import sqrt
import math
from vector import vector
from sram_factory import factory
from globals import OPTS
class wordline_driver(design.design):
"""
Creates a Wordline Driver
@ -58,26 +55,20 @@ class wordline_driver(design.design):
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
# This is just used for measurements,
# so don't add the module
self.inv = factory.create(module_type="pdriver",
fanout=self.cols,
neg_polarity=True)
self.add_mod(self.inv)
self.inv_no_output = factory.create(module_type="pinv",
route_output=False)
self.add_mod(self.inv_no_output)
self.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2)
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
"""
Add a pin for each row of vdd/gnd which
are must-connects next level up.
"""
# Find the x offsets for where the vias/pins should be placed
a_xoffset = self.nand_inst[0].rx()
@ -86,7 +77,9 @@ class wordline_driver(design.design):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
(gate_offset, y_dir) = self.get_gate_offset(0,
self.inv.height,
num)
# Route both supplies
for name in ["vdd", "gnd"]:
@ -97,11 +90,9 @@ class wordline_driver(design.design):
pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name, pin_pos)
def create_drivers(self):
self.nand_inst = []
self.inv2_inst = []
self.nand_inst = []
self.inv2_inst = []
for row in range(self.rows):
name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".format(row)
@ -119,8 +110,7 @@ class wordline_driver(design.design):
self.connect_inst(["wl_bar_{0}".format(row),
"wl_{0}".format(row),
"vdd", "gnd"])
def place_drivers(self):
nand2_xoffset = 2*self.m1_width + 5*self.m1_space
inv2_xoffset = nand2_xoffset + self.nand2.width
@ -136,8 +126,8 @@ class wordline_driver(design.design):
y_offset = self.inv.height*row
inst_mirror = "R0"
nand2_offset=[nand2_xoffset, y_offset]
inv2_offset=[inv2_xoffset, y_offset]
nand2_offset = [nand2_xoffset, y_offset]
inv2_offset = [inv2_xoffset, y_offset]
# add nand 2
self.nand_inst[row].place(offset=nand2_offset,
@ -146,17 +136,16 @@ class wordline_driver(design.design):
self.inv2_inst[row].place(offset=inv2_offset,
mirror=inst_mirror)
def route_layout(self):
""" Route all of the signals """
# Wordline enable connection
en_pin=self.add_layout_pin(text="en",
layer="metal2",
offset=[self.m1_width + 2*self.m1_space,0],
width=self.m2_width,
height=self.height)
en_offset = [self.m1_width + 2 * self.m1_space, 0]
en_pin = self.add_layout_pin(text="en",
layer="metal2",
offset=en_offset,
width=self.m2_width,
height=self.height)
for row in range(self.rows):
nand_inst = self.nand_inst[row]
@ -165,7 +154,7 @@ class wordline_driver(design.design):
# en connection
a_pin = nand_inst.get_pin("A")
a_pos = a_pin.lc()
clk_offset = vector(en_pin.bc().x,a_pos.y)
clk_offset = vector(en_pin.bc().x, a_pos.y)
self.add_segment_center(layer="metal1",
start=clk_offset,
end=a_pos)
@ -175,7 +164,7 @@ class wordline_driver(design.design):
# Nand2 out to 2nd inv
zr_pos = nand_inst.get_pin("Z").rc()
al_pos = inv2_inst.get_pin("A").lc()
# ensure the bend is in the middle
# ensure the bend is in the middle
mid1_pos = vector(0.5*(zr_pos.x+al_pos.x), zr_pos.y)
mid2_pos = vector(0.5*(zr_pos.x+al_pos.x), al_pos.y)
self.add_path("metal1", [zr_pos, mid1_pos, mid2_pos, al_pos])
@ -183,10 +172,14 @@ class wordline_driver(design.design):
# connect the decoder input pin to nand2 B
b_pin = nand_inst.get_pin("B")
b_pos = b_pin.lc()
# needs to move down since B nand input is nearly aligned with A inv input
up_or_down = self.m2_space if row%2 else -self.m2_space
input_offset = vector(0,b_pos.y + up_or_down)
mid_via_offset = vector(clk_offset.x,input_offset.y) + vector(0.5*self.m2_width+self.m2_space+0.5*contact.m1m2.width,0)
# needs to move down since B nand input is
# nearly aligned with A inv input
up_or_down = self.m2_space if row % 2 else -self.m2_space
input_offset = vector(0, b_pos.y + up_or_down)
base_offset = vector(clk_offset.x, input_offset.y)
contact_offset = vector(0.5 * self.m2_width + self.m2_space + 0.5 * contact.m1m2.width, 0)
mid_via_offset = base_offset + contact_offset
# must under the clk line in M1
self.add_layout_pin_segment_center(text="in_{0}".format(row),
layer="metal1",
@ -194,24 +187,27 @@ class wordline_driver(design.design):
end=mid_via_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=mid_via_offset,
directions=("V","V"))
directions=("V", "V"))
# now connect to the nand2 B
self.add_path("metal2", [mid_via_offset, b_pos])
contact_offset = b_pos - vector(0.5 * contact.m1m2.height, 0)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=b_pos - vector(0.5*contact.m1m2.height,0),
directions=("H","H"))
offset=contact_offset,
directions=("H", "H"))
# output each WL on the right
wl_offset = inv2_inst.get_pin("Z").rc()
self.add_layout_pin_segment_center(text="wl_{0}".format(row),
layer="metal1",
start=wl_offset,
end=wl_offset-vector(self.m1_width,0))
end=wl_offset - vector(self.m1_width, 0))
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
"""
Follows the clk_buf to a wordline signal adding
each stages stage effort to a list.
"""
stage_effort_list = []
stage1_cout = self.inv.get_cin()
@ -225,7 +221,10 @@ class wordline_driver(design.design):
return stage_effort_list
def get_wl_en_cin(self):
"""Get the relative capacitance of all the enable connections in the bank"""
#The enable is connected to a nand2 for every row.
"""
Get the relative capacitance of all
the enable connections in the bank
"""
# The enable is connected to a nand2 for every row.
total_cin = self.nand2.get_cin() * self.rows
return total_cin

View File

@ -0,0 +1,304 @@
# See LICENSE for licensing information.
#
#Copyright (c) 2019 Regents of the University of California and The Board
#of Regents for the Oklahoma Agricultural and Mechanical College
#(acting for and on behalf of Oklahoma State University)
#All rights reserved.
#
import design
from tech import drc, parameter, spice
import debug
import math
from tech import drc
from vector import vector
from globals import OPTS
from sram_factory import factory
class pwrite_driver(design.design):
"""
The pwrite_driver is two tristate inverters that drive the bitlines.
The data input is first inverted before one tristate.
The inverted enable is also generated to control one tristate.
"""
def __init__(self, name, size=0):
debug.error("pwrite_driver not implemented yet.", -1)
debug.info(1, "creating pwrite_driver {}".format(name))
design.design.__init__(self, name)
self.size = size
self.beta = parameter["beta"]
self.pmos_width = self.beta*self.size*parameter["min_tx_size"]
self.nmos_width = self.size*parameter["min_tx_size"]
# The tech M2 pitch is based on old via orientations
self.m2_pitch = self.m2_space + self.m2_width
# Width is matched to the bitcell,
# Height will be variable
self.bitcell = factory.create(module_type="bitcell")
self.width = self.bitcell.width
# Creates the netlist and layout
# Since it has variable height, it is not a pgate.
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
self.DRC_LVS()
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_insts()
def create_layout(self):
self.place_modules()
self.route_wires()
self.route_supplies()
def add_pins(self):
self.add_pin("din", "INPUT")
self.add_pin("bl", "OUTPUT")
self.add_pin("br", "OUTPUT")
self.add_pin("en", "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
# Tristate inverter
self.tri = factory.create(module_type="ptristate_inv", height="min")
self.add_mod(self.tri)
debug.check(self.tri.width<self.width,"Could not create tristate inverter to match bitcell width")
#self.tbuf = factory.create(module_type="ptristate_buf", height="min")
#self.add_mod(self.tbuf)
#debug.check(self.tbuf.width<self.width,"Could not create tristate buffer to match bitcell width")
# Inverter for din and en
self.inv = factory.create(module_type="pinv", under_rail_vias=True)
self.add_mod(self.inv)
def create_insts(self):
# Enable inverter
self.en_inst = self.add_inst(name="en_inv", mod=self.inv)
self.connect_inst(["en", "en_bar", "vdd", "gnd"])
# Din inverter
self.din_inst = self.add_inst(name="din_inv", mod=self.inv)
self.connect_inst(["din", "din_bar", "vdd", "gnd"])
# Bitline tristate
self.bl_inst = self.add_inst(name="bl_tri", mod=self.tri)
self.connect_inst(["din_bar", "bl", "en", "en_bar", "vdd", "gnd"])
# Bitline bar tristate
self.br_inst = self.add_inst(name="br_tri", mod=self.tri)
self.connect_inst(["din", "br", "en", "en_bar", "vdd", "gnd"])
def place_modules(self):
# Add enable to the right
self.din_inst.place(vector(0, 0))
# Add BR tristate above
self.br_inst.place(vector(0, self.en_inst.uy()+self.br_inst.height), mirror="MX")
# Add BL tristate buffer
#print(self.bl_inst.width,self.width)
self.bl_inst.place(vector(self.width,self.br_inst.uy()), mirror="MY")
# Add din to the left
self.en_inst.place(vector(self.width, self.bl_inst.uy()+self.en_inst.height), rotate=180)
self.height = self.en_inst.uy()
def route_bitlines(self):
"""
Route the bitlines to the spacing of the bitcell
( even though there may be a column mux )
"""
# Second from left track and second from right track
right_x = self.width + self.m2_pitch
left_x = -self.m2_pitch
bl_xoffset = left_x
bl_out=vector(bl_xoffset, self.height)
bl_in=self.bl_inst.get_pin("out").center()
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bl_in)
bl_mid = vector(bl_out.x,bl_in.y)
self.add_path("metal2", [bl_in, bl_mid, bl_out])
self.add_layout_pin_rect_center(text="bl",
layer="metal2",
offset=bl_out)
br_xoffset = right_x
br_out=vector(br_xoffset, self.height)
br_in=self.br_inst.get_pin("out").center()
self.add_via_center(layers=("metal1","via1","metal2"),
offset=br_in)
br_mid = vector(br_out.x,br_in.y)
self.add_path("metal2", [br_in, br_mid, br_out])
self.add_layout_pin_rect_center(text="br",
layer="metal2",
offset=br_out)
#br_xoffset = b.get_pin("br".cx()
#self.br_inst.get_pin("br")
def route_din(self):
# Left
track_xoff = self.get_m2_track(1)
din_loc = self.din_inst.get_pin("A").center()
self.add_via_stack("metal1", "metal2", din_loc)
din_track = vector(track_xoff,din_loc.y)
br_in = self.br_inst.get_pin("in").center()
self.add_via_stack("metal1", "metal2", br_in)
br_track = vector(track_xoff,br_in.y)
din_in = vector(track_xoff,0)
self.add_path("metal2", [din_in, din_track, din_loc, din_track, br_track, br_in])
self.add_layout_pin_rect_center(text="din",
layer="metal2",
offset=din_in)
def route_din_bar(self):
# Left
track_xoff = self.get_m4_track(self.din_bar_track)
din_bar_in = self.din_inst.get_pin("Z").center()
self.add_via_stack("metal1", "metal3", din_bar_in)
din_bar_track = vector(track_xoff,din_bar_in.y)
bl_in = self.bl_inst.get_pin("in").center()
self.add_via_stack("metal1", "metal3", bl_in)
bl_track = vector(track_xoff,bl_in.y)
din_in = vector(track_xoff,0)
self.add_wire(("metal3","via3","metal4"), [din_bar_in, din_bar_track, bl_track, bl_in])
self.add_layout_pin_rect_center(text="din",
layer="metal4",
offset=din_in)
def route_en_bar(self):
# Enable in track
track_xoff = self.get_m4_track(self.en_bar_track)
# This M2 pitch is a hack since the A and Z pins align horizontally
en_bar_loc = self.en_inst.get_pin("Z").uc()
en_bar_track = vector(track_xoff, en_bar_loc.y)
self.add_via_stack("metal1", "metal3", en_bar_loc)
# This is a U route to the right down then left
bl_en_loc = self.bl_inst.get_pin("en_bar").center()
bl_en_track = vector(track_xoff, bl_en_loc.y)
self.add_via_stack("metal1", "metal3", bl_en_loc)
br_en_loc = self.br_inst.get_pin("en_bar").center()
br_en_track = vector(track_xoff, bl_en_loc.y)
self.add_via_stack("metal1", "metal3", br_en_loc)
# L shape
self.add_wire(("metal3","via3","metal4"),
[en_bar_loc, en_bar_track, bl_en_track])
# U shape
self.add_wire(("metal3","via3","metal4"),
[bl_en_loc, bl_en_track, br_en_track, br_en_loc])
def route_en(self):
# Enable in track
track_xoff = self.get_m4_track(self.en_track)
# The en pin will be over the vdd rail
vdd_yloc = self.en_inst.get_pin("vdd").cy()
self.add_layout_pin_segment_center(text="en",
layer="metal3",
start=vector(0,vdd_yloc),
end=vector(self.width,vdd_yloc))
en_loc = self.en_inst.get_pin("A").center()
en_rail = vector(en_loc.x, vdd_yloc)
self.add_via_stack("metal1", "metal2", en_loc)
self.add_path("metal2", [en_loc, en_rail])
self.add_via_stack("metal2", "metal3", en_rail)
# Start point in the track on the pin rail
en_track = vector(track_xoff, vdd_yloc)
self.add_via_stack("metal3", "metal4", en_track)
# This is a U route to the right down then left
bl_en_loc = self.bl_inst.get_pin("en").center()
bl_en_track = vector(track_xoff, bl_en_loc.y)
self.add_via_stack("metal1", "metal3", bl_en_loc)
br_en_loc = self.br_inst.get_pin("en").center()
br_en_track = vector(track_xoff, bl_en_loc.y)
self.add_via_stack("metal1", "metal3", br_en_loc)
# U shape
self.add_wire(("metal3","via3","metal4"),
[en_track, bl_en_track, bl_en_loc, bl_en_track, br_en_track, br_en_loc])
def get_m4_track(self,i):
return 0.5*self.m4_space + i*(self.m4_width+self.m4_space)
def get_m3_track(self,i):
return 0.5*self.m3_space + i*(self.m3_width+self.m3_space)
def get_m2_track(self,i):
return 0.5*self.m2_space + i*(self.m2_width+self.m2_space)
def route_wires(self):
# M4 tracks
self.din_bar_track = 2
self.en_track = 0
self.en_bar_track = 1
self.route_bitlines()
self.route_din()
self.route_din_bar()
self.route_en()
self.route_en_bar()
def route_supplies(self):
for inst in [self.en_inst, self.din_inst, self.bl_inst, self.br_inst]:
# Continous vdd rail along with label.
vdd_pin=inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
# Continous gnd rail along with label.
gnd_pin=inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
return 5*3

View File

@ -7,42 +7,44 @@
#
from direction import direction
from pin_layout import pin_layout
from vector3d import vector3d
from vector import vector
import grid_utils
from tech import drc
import debug
class pin_group:
"""
A class to represent a group of rectangular design pin.
It requires a router to define the track widths and blockages which
determine how pin shapes get mapped to tracks.
A class to represent a group of rectangular design pin.
It requires a router to define the track widths and blockages which
determine how pin shapes get mapped to tracks.
It is initially constructed with a single set of (touching) pins.
"""
def __init__(self, name, pin_set, router):
self.name = name
# Flag for when it is routed
self.routed = False
# Flag for when it is enclosed
self.enclosed = False
# Remove any redundant pins (i.e. contained in other pins)
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set))
# This is a list because we can have a pin group of disconnected sets of pins
# This is a list because we can have a pin
# group of disconnected sets of pins
# and these are represented by separate lists
self.pins = set(irredundant_pin_set)
self.router = router
# These are the corresponding pin grids for each pin group.
self.grids = set()
# These are the secondary grids that could or could not be part of the pin
# These are the secondary grids that could
# or could not be part of the pin
self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group.
# These are blockages for other nets but unblocked for routing this group.
# These are also blockages if we used a simple enclosure to route to a rail.
# These are blockages for other nets but unblocked
# for routing this group. These are also blockages if we
# used a simple enclosure to route to a rail.
self.blockages = set()
# This is a set of pin_layout shapes to cover the grids
@ -51,16 +53,16 @@ class pin_group:
def __str__(self):
""" override print function output """
total_string = "(pg {} ".format(self.name)
pin_string = "\n pins={}".format(self.pins)
total_string += pin_string
grids_string = "\n grids={}".format(self.grids)
total_string += grids_string
grids_string = "\n secondary={}".format(self.secondary_grids)
total_string += grids_string
if self.enclosed:
enclosure_string = "\n enclose={}".format(self.enclosures)
total_string += enclosure_string
@ -71,7 +73,7 @@ class pin_group:
def __repr__(self):
""" override repr function output """
return str(self)
def size(self):
return len(self.grids)
@ -80,7 +82,7 @@ class pin_group:
def is_routed(self):
return self.routed
def remove_redundant_shapes(self, pin_list):
"""
Remove any pin layout that is contained within another.
@ -88,39 +90,40 @@ class pin_group:
"""
local_debug = False
if local_debug:
debug.info(0,"INITIAL: {}".format(pin_list))
debug.info(0, "INITIAL: {}".format(pin_list))
# Make a copy of the list to start
new_pin_list = pin_list.copy()
remove_indices = set()
# This is n^2, but the number is small
for index1,pin1 in enumerate(pin_list):
for index1, pin1 in enumerate(pin_list):
# If we remove this pin, it can't contain other pins
if index1 in remove_indices:
continue
for index2,pin2 in enumerate(pin_list):
# Can't contain yourself, but compare the indices and not the pins
for index2, pin2 in enumerate(pin_list):
# Can't contain yourself,
# but compare the indices and not the pins
# so you can remove duplicate copies.
if index1==index2:
if index1 == index2:
continue
# If we already removed it, can't remove it again...
if index2 in remove_indices:
continue
if pin1.contains(pin2):
if local_debug:
debug.info(0,"{0} contains {1}".format(pin1,pin2))
debug.info(0, "{0} contains {1}".format(pin1, pin2))
remove_indices.add(index2)
# Remove them in decreasing order to not invalidate the indices
for i in sorted(remove_indices, reverse=True):
del new_pin_list[i]
if local_debug:
debug.info(0,"FINAL : {}".format(new_pin_list))
debug.info(0, "FINAL : {}".format(new_pin_list))
return new_pin_list
def compute_enclosures(self):
@ -130,23 +133,32 @@ class pin_group:
# Enumerate every possible enclosure
pin_list = []
for seed in self.grids:
(ll, ur) = self.enclose_pin_grids(seed, direction.NORTH, direction.EAST)
(ll, ur) = self.enclose_pin_grids(seed,
direction.NORTH,
direction.EAST)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure)
(ll, ur) = self.enclose_pin_grids(seed, direction.EAST, direction.NORTH)
(ll, ur) = self.enclose_pin_grids(seed,
direction.EAST,
direction.NORTH)
enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure)
debug.check(len(pin_list) > 0,
"Did not find any enclosures.")
# Now simplify the enclosure list
# Now simplify the enclosure list
new_pin_list = self.remove_redundant_shapes(pin_list)
return new_pin_list
debug.check(len(new_pin_list) > 0,
"Did not find any enclosures.")
return new_pin_list
def compute_connector(self, pin, enclosure):
"""
Compute a shape to connect the pin to the enclosure shape.
"""
Compute a shape to connect the pin to the enclosure shape.
This assumes the shape will be the dimension of the pin.
"""
if pin.xoverlaps(enclosure):
@ -154,9 +166,9 @@ class pin_group:
plc = pin.lc()
prc = pin.rc()
elc = enclosure.lc()
erc = enclosure.rc()
ymin = min(plc.y,elc.y)
ymax = max(plc.y,elc.y)
# erc = enclosure.rc()
ymin = min(plc.y, elc.y)
ymax = max(plc.y, elc.y)
ll = vector(plc.x, ymin)
ur = vector(prc.x, ymax)
elif pin.yoverlaps(enclosure):
@ -164,9 +176,9 @@ class pin_group:
pbc = pin.bc()
puc = pin.uc()
ebc = enclosure.bc()
euc = enclosure.uc()
xmin = min(pbc.x,ebc.x)
xmax = max(pbc.x,ebc.x)
# euc = enclosure.uc()
xmin = min(pbc.x, ebc.x)
xmax = max(pbc.x, ebc.x)
ll = vector(xmin, pbc.y)
ur = vector(xmax, puc.y)
else:
@ -180,7 +192,7 @@ class pin_group:
ll = vector(xmin, ymin)
ur = vector(xmax, ymax)
if ll.x==ur.x or ll.y==ur.y:
if ll.x == ur.x or ll.y == ur.y:
return None
p = pin_layout(pin.name, [ll, ur], pin.layer)
return p
@ -195,20 +207,20 @@ class pin_group:
for shape in enclosures:
if shape.xcontains(pin):
edge_list.append(shape)
# Sort them by their bottom edge
edge_list.sort(key=lambda x: x.by(), reverse=True)
# Find the bottom edge that is next to the pin's top edge
above_item = None
for item in edge_list:
if item.by()>=pin.uy():
if item.by() >= pin.uy():
above_item = item
else:
break
# There was nothing
if above_item==None:
# There was nothing
if not above_item:
return None
# If it already overlaps, no connector needed
if above_item.overlaps(pin):
@ -219,7 +231,7 @@ class pin_group:
return p
def find_below_connector(self, pin, enclosures):
"""
"""
Find the enclosure that is below the pin
and make a connector to it's upper edge.
"""
@ -228,31 +240,31 @@ class pin_group:
for shape in enclosures:
if shape.xcontains(pin):
edge_list.append(shape)
# Sort them by their upper edge
edge_list.sort(key=lambda x: x.uy())
# Find the upper edge that is next to the pin's bottom edge
bottom_item = None
for item in edge_list:
if item.uy()<=pin.by():
if item.uy() <= pin.by():
bottom_item = item
else:
break
# There was nothing to the left
if bottom_item==None:
if not bottom_item:
return None
# If it already overlaps, no connector needed
if bottom_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, bottom_item)
return p
def find_left_connector(self, pin, enclosures):
"""
"""
Find the enclosure that is to the left of the pin
and make a connector to it's right edge.
"""
@ -261,31 +273,31 @@ class pin_group:
for shape in enclosures:
if shape.ycontains(pin):
edge_list.append(shape)
# Sort them by their right edge
edge_list.sort(key=lambda x: x.rx())
# Find the right edge that is to the pin's left edge
left_item = None
for item in edge_list:
if item.rx()<=pin.lx():
if item.rx() <= pin.lx():
left_item = item
else:
break
# There was nothing to the left
if left_item==None:
if not left_item:
return None
# If it already overlaps, no connector needed
if left_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, left_item)
return p
def find_right_connector(self, pin, enclosures):
"""
"""
Find the enclosure that is to the right of the pin
and make a connector to it's left edge.
"""
@ -294,79 +306,79 @@ class pin_group:
for shape in enclosures:
if shape.ycontains(pin):
edge_list.append(shape)
# Sort them by their right edge
edge_list.sort(key=lambda x: x.lx(), reverse=True)
# Find the left edge that is next to the pin's right edge
right_item = None
for item in edge_list:
if item.lx()>=pin.rx():
if item.lx() >= pin.rx():
right_item = item
else:
break
# There was nothing to the right
if right_item==None:
if not right_item:
return None
# If it already overlaps, no connector needed
if right_item.overlaps(pin):
return None
# Otherwise, make a connector to the item
p = self.compute_connector(pin, right_item)
return p
def find_smallest_connector(self, pin_list, shape_list):
"""
Compute all of the connectors between the overlapping pins and enclosure shape list..
Compute all of the connectors between the overlapping
pins and enclosure shape list.
Return the smallest.
"""
smallest = None
for pin in pin_list:
for enclosure in shape_list:
new_enclosure = self.compute_connector(pin, enclosure)
if smallest == None or new_enclosure.area()<smallest.area():
if not smallest or new_enclosure.area() < smallest.area():
smallest = new_enclosure
return smallest
def find_smallest_overlapping(self, pin_list, shape_list):
"""
Find the smallest area shape in shape_list that overlaps with any
Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width.
"""
smallest_shape = None
for pin in pin_list:
overlap_shape = self.find_smallest_overlapping_pin(pin,shape_list)
overlap_shape = self.find_smallest_overlapping_pin(pin, shape_list)
if overlap_shape:
overlap_length = pin.overlap_length(overlap_shape)
if smallest_shape == None or overlap_shape.area()<smallest_shape.area():
# overlap_length = pin.overlap_length(overlap_shape)
if not smallest_shape or overlap_shape.area() < smallest_shape.area():
smallest_shape = overlap_shape
return smallest_shape
return smallest_shape
def find_smallest_overlapping_pin(self, pin, shape_list):
"""
Find the smallest area shape in shape_list that overlaps with any
Find the smallest area shape in shape_list that overlaps with any
pin in pin_list by a min width.
"""
smallest_shape = None
zindex=self.router.get_zindex(pin.layer_num)
(min_width,min_space) = self.router.get_layer_width_space(zindex)
zindex = self.router.get_zindex(pin.lpp[0])
(min_width, min_space) = self.router.get_layer_width_space(zindex)
# Now compare it with every other shape to check how much they overlap
for other in shape_list:
overlap_length = pin.overlap_length(other)
if overlap_length > min_width:
if smallest_shape == None or other.area()<smallest_shape.area():
if not smallest_shape or other.area() < smallest_shape.area():
smallest_shape = other
return smallest_shape
def overlap_any_shape(self, pin_list, shape_list):
"""
Does the given pin overlap any of the shapes in the pin list.
@ -378,16 +390,15 @@ class pin_group:
return False
def max_pin_layout(self, pin_list):
"""
"""
Return the max area pin_layout
"""
biggest = pin_list[0]
for pin in pin_list:
if pin.area() > biggest.area():
biggest = pin
return pin
def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST):
@ -398,19 +409,18 @@ class pin_group:
dir1 and dir2 should be two orthogonal directions.
"""
offset1= direction.get_offset(dir1)
offset2= direction.get_offset(dir2)
offset1 = direction.get_offset(dir1)
offset2 = direction.get_offset(dir2)
# We may have started with an empty set
if not self.grids:
return None
debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
# Start with the ll and make the widest row
row = [ll]
# Move in dir1 while we can
while True:
next_cell = row[-1] + offset1
# Can't move if not in the pin shape
# Can't move if not in the pin shape
if next_cell in self.grids and next_cell not in self.router.blocked_grids:
row.append(next_cell)
else:
@ -419,7 +429,7 @@ class pin_group:
while True:
next_row = [x+offset2 for x in row]
for cell in next_row:
# Can't move if any cell is not in the pin shape
# Can't move if any cell is not in the pin shape
if cell not in self.grids or cell in self.router.blocked_grids:
break
else:
@ -431,74 +441,87 @@ class pin_group:
# Add a shape from ll to ur
ur = row[-1]
return (ll,ur)
return (ll, ur)
def enclose_pin(self):
"""
If there is one set of connected pin shapes,
this will find the smallest rectangle enclosure that overlaps with any pin.
If there is one set of connected pin shapes,
this will find the smallest rectangle enclosure that
overlaps with any pin.
If there is not, it simply returns all the enclosures.
"""
self.enclosed = True
# Compute the enclosure pin_layout list of the set of tracks
self.enclosures = self.compute_enclosures()
# Find a connector to every pin and add it to the enclosures
for pin in self.pins:
# If it is contained, it won't need a connector
if pin.contained_by_any(self.enclosures):
continue
# Find a connector in the cardinal directions
# If there is overlap, but it isn't contained, these could all be None
# These could also be none if the pin is diagonal from the enclosure
# If there is overlap, but it isn't contained,
# these could all be None
# These could also be none if the pin is
# diagonal from the enclosure
left_connector = self.find_left_connector(pin, self.enclosures)
right_connector = self.find_right_connector(pin, self.enclosures)
above_connector = self.find_above_connector(pin, self.enclosures)
below_connector = self.find_below_connector(pin, self.enclosures)
connector_list = [left_connector, right_connector, above_connector, below_connector]
filtered_list = list(filter(lambda x: x!=None, connector_list))
if (len(filtered_list)>0):
connector_list = [left_connector,
right_connector,
above_connector,
below_connector]
filtered_list = list(filter(lambda x: x != None, connector_list))
if (len(filtered_list) > 0):
import copy
bbox_connector = copy.copy(pin)
bbox_connector = copy.copy(pin)
bbox_connector.bbox(filtered_list)
self.enclosures.append(bbox_connector)
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector.
# This could only happen when there was no enclosure in any cardinal direction from a pin
# Now, make sure each pin touches an enclosure.
# If not, add another (diagonal) connector.
# This could only happen when there was no enclosure
# in any cardinal direction from a pin
if not self.overlap_any_shape(self.pins, self.enclosures):
connector = self.find_smallest_connector(self.pins, self.enclosures)
if connector==None:
debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures))
connector = self.find_smallest_connector(self.pins,
self.enclosures)
if not connector:
debug.error("Could not find a connector for {} with {}".format(self.pins,
self.enclosures))
self.router.write_debug_gds("no_connector.gds")
import pdb; pdb.set_trace()
self.enclosures.append(connector)
# At this point, the pins are overlapping, but there might be more than one!
# At this point, the pins are overlapping,
# but there might be more than one!
overlap_set = set()
for pin in self.pins:
overlap_set.update(self.transitive_overlap(pin, self.enclosures))
# Use the new enclosures and recompute the grids that correspond to them
if len(overlap_set)<len(self.enclosures):
# Use the new enclosures and recompute the grids
# that correspond to them
if len(overlap_set) < len(self.enclosures):
self.enclosures = overlap_set
self.grids=set()
# Also update the grid locations with the new (possibly pruned) enclosures
self.grids = set()
# Also update the grid locations with the new
# (possibly pruned) enclosures
for enclosure in self.enclosures:
(sufficient,insufficient) = self.router.convert_pin_to_tracks(self.name,enclosure)
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
enclosure)
self.grids.update(sufficient)
debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
self.pins,
self.grids,
self.enclosures))
debug.info(3, "Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
self.pins,
self.grids,
self.enclosures))
def transitive_overlap(self, shape, shape_list):
"""
Given shape, find the elements in shape_list that overlap transitively.
I.e. if shape overlaps A and A overlaps B, return both A and B.
I.e. if shape overlaps A and A overlaps B, return both A and B.
"""
augmented_shape_list = set(shape_list)
@ -512,31 +535,29 @@ class pin_group:
for cur_shape in augmented_shape_list:
if old_shape.overlaps(cur_shape):
connected_set.add(cur_shape)
# Remove the original shape
connected_set.remove(shape)
# if len(connected_set)<len(shape_list):
# import pprint
# print("S: ",shape)
# pprint.pprint(shape_list)
# pprint.pprint(connected_set)
return connected_set
def add_enclosure(self, cell):
"""
Add the enclosure shape to the given cell.
"""
for enclosure in self.enclosures:
debug.info(2,"Adding enclosure {0} {1}".format(self.name, enclosure))
debug.info(2, "Adding enclosure {0} {1}".format(self.name,
enclosure))
cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(),
width=enclosure.width(),
height=enclosure.height())
def perimeter_grids(self):
"""
@ -551,11 +572,11 @@ class pin_group:
# If we aren't completely enclosed, we are on the perimeter
if neighbor_count < 4:
perimeter_set.add(g1)
return perimeter_set
def adjacent(self, other):
"""
"""
Chck if the two pin groups have at least one adjacent pin grid.
"""
# We could optimize this to just check the boundaries
@ -566,9 +587,8 @@ class pin_group:
return False
def adjacent_grids(self, other, separation):
"""
"""
Determine the sets of grids that are within a separation distance
of any grid in the other set.
"""
@ -580,11 +600,11 @@ class pin_group:
adj_grids.add(g1)
return adj_grids
def convert_pin(self):
"""
Convert the list of pin shapes into sets of routing grids.
The secondary set of grids are "optional" pin shapes that could be
The secondary set of grids are "optional" pin shapes that
should be either blocked or part of the pin.
"""
pin_set = set()
@ -592,53 +612,59 @@ class pin_group:
blockage_set = set()
for pin in self.pins:
debug.info(2," Converting {0}".format(pin))
# Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin)
debug.info(2, " Converting {0}".format(pin))
# Determine which tracks the pin overlaps
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin)
pin_set.update(sufficient)
partial_set.update(insufficient)
# Blockages will be a super-set of pins since it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
# Blockages will be a super-set of pins since
# it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks)
# If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
if len(shared_set) > 0:
debug.info(2, "Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
if len(shared_set) > 0:
debug.info(2, "Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing blocks {}".format(shared_set))
if len(shared_set) > 0:
debug.info(2, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks
if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0):
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0):
# debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins:
debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
# Determine which tracks the pin overlaps
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin,
expansion=1)
pin_set.update(sufficient)
partial_set.update(insufficient)
if len(pin_set)==0 and len(partial_set)==0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
if len(pin_set) == 0 and len(partial_set) == 0:
debug.error("Unable to find unblocked pin {} {}".format(self.name,
self.pins))
self.router.write_debug_gds("blocked_pin.gds")
# Consider all the grids that would be blocked
self.grids = pin_set | partial_set
# Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set
self.grids = pin_set | partial_set
if len(self.grids) < 0:
debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))
self.router.write_debug_gds("blocked_pin.gds")
# Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set
debug.info(2," pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_grids))
debug.info(2, " pins {}".format(self.grids))
debug.info(2, " secondary {}".format(self.secondary_grids))

File diff suppressed because it is too large Load Diff

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from tech import drc,layer
from tech import drc, layer
from contact import contact
from pin_group import pin_group
from vector import vector
import debug
import math
class router_tech:
"""
This is a class to hold the router tech constants.
@ -25,9 +25,9 @@ class router_tech:
self.layers = layers
self.rail_track_width = rail_track_width
if len(self.layers)==1:
if len(self.layers) == 1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0]
self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]]
self.horiz_lpp = self.vert_lpp = layer[self.layers[0]]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -40,8 +40,8 @@ class router_tech:
via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height)
self.horiz_layer_number = layer[self.horiz_layer_name]
self.vert_layer_number = layer[self.vert_layer_name]
self.horiz_lpp = layer[self.horiz_layer_name]
self.vert_lpp = layer[self.vert_layer_name]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -68,8 +68,18 @@ class router_tech:
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire]
def get_zindex(self,layer_num):
if layer_num==self.horiz_layer_number:
def same_lpp(self, lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
def get_zindex(self, lpp):
if self.same_lpp(lpp, self.horiz_lpp):
return 0
else:
return 1

View File

@ -55,7 +55,7 @@ class supply_grid_router(router):
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
def route(self, vdd_name="vdd", gnd_name="gnd"):
"""
"""
Add power supply rails and connect all pins to these rails.
"""
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
@ -75,7 +75,6 @@ class supply_grid_router(router):
start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
# Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now()
# Block everything

View File

@ -112,7 +112,7 @@ class sram():
# Write the config file
start_time = datetime.datetime.now()
from shutil import copyfile
copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py')
copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
print_time("Config", datetime.datetime.now(), start_time)

View File

@ -17,7 +17,8 @@ import debug
class library_drc_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import verify
(gds_dir, gds_files) = setup_files()

View File

@ -17,7 +17,8 @@ import debug
class library_lvs_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import verify
(gds_dir, sp_dir, allnames) = setup_files()

View File

@ -18,7 +18,8 @@ import debug
class contact_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
stack_name = ":".join(map(str, layer_stack))

View File

@ -17,7 +17,8 @@ import debug
class path_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import wire_path
import tech
import design

View File

@ -18,7 +18,8 @@ import debug
class ptx_1finger_nmos_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking min size NMOS with 1 finger")

View File

@ -18,7 +18,8 @@ import debug
class ptx_1finger_pmos_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking min size PMOS with 1 finger")

View File

@ -18,7 +18,8 @@ import debug
class ptx_3finger_nmos_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking three fingers NMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_3finger_pmos_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking three fingers PMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_4finger_nmos_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking three fingers NMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import tech
debug.info(2, "Checking three fingers PMOS")

View File

@ -17,7 +17,8 @@ import debug
class wire_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import wire
import tech
import design

View File

@ -18,7 +18,8 @@ import debug
class replica_pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import dummy_pbitcell
OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class pand2_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
global verify
import verify

View File

@ -18,7 +18,8 @@ import debug
class pand3_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
global verify
import verify

View File

@ -19,7 +19,8 @@ from sram_factory import factory
class pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports=1
OPTS.num_w_ports=1

View File

@ -18,7 +18,8 @@ import debug
class pbuf_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing inverter/buffer 4x 8x")
a = factory.create(module_type="pbuf", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pdriver_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing inverter/buffer 4x 8x")
# a tests the error message for specifying conflicting conditions

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 8x inverter")
tx = factory.create(module_type="pinv", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 1x beta=3 size inverter")
tx = factory.create(module_type="pinv", size=1, beta=3)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 1x size inverter")
tx = factory.create(module_type="pinv", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 2x size inverter")
tx = factory.create(module_type="pinv", size=2)

View File

@ -18,7 +18,8 @@ import debug
class pinvbuf_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing inverter/buffer 4x 8x")
a = factory.create(module_type="pinvbuf", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pnand2_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 2-input nand gate")
tx = factory.create(module_type="pnand2", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pnand3_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 3-input nand gate")
tx = factory.create(module_type="pnand3", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pnor2_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Checking 2-input nor gate")
tx = factory.create(module_type="pnor2", size=1)

View File

@ -18,7 +18,8 @@ import debug
class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check precharge in single port
debug.info(2, "Checking precharge for handmade bitcell")

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import header, openram_test
import sys
import os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 04_pwrite_driver_test")
class pwrite_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 1x pwrite_driver")
tx = factory.create(module_type="pwrite_driver", size=1)
self.local_check(tx)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -18,7 +18,8 @@ import debug
class replica_pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import replica_pbitcell
OPTS.bitcell = "pbitcell"

View File

@ -20,7 +20,8 @@ import debug
class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check single level column mux in single port
debug.info(2, "Checking column mux")

View File

@ -20,8 +20,8 @@ import debug
class bitcell_1rw_1r_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"

View File

@ -20,7 +20,8 @@ import debug
class array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="bitcell_array", cols=4, rows=4)

View File

@ -16,7 +16,8 @@ import debug
class dummy_row_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing dummy row for 6t_cell")
a = factory.create(module_type="dummy_array", rows=1, cols=4)

View File

@ -19,7 +19,8 @@ import debug
class pbitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell"

View File

@ -16,7 +16,8 @@ import debug
class replica_bitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_decoder_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# Doesn't require hierarchical decoder
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
@ -34,14 +35,30 @@ class hierarchical_decoder_test(openram_test):
a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=17)
self.local_check(a)
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=23)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=65)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=341)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)
@ -57,14 +74,34 @@ class hierarchical_decoder_test(openram_test):
a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=17)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=23)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=65)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
factory.reset()
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=341)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_predecode2x4_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4")

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_predecode3x8_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8")

View File

@ -17,7 +17,8 @@ import debug
class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import single_level_column_mux_array
# check single level column mux array in single port

View File

@ -18,7 +18,8 @@ import debug
class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check precharge array in single port
debug.info(2, "Checking 3 column precharge")

View File

@ -20,7 +20,8 @@ import debug
class wordline_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check wordline driver for single port
debug.info(2, "Checking driver")

View File

@ -18,7 +18,8 @@ import debug
class sense_amp_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")

View File

@ -18,7 +18,8 @@ import debug
class write_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")

View File

@ -20,7 +20,8 @@ import debug
class write_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4")
@ -58,4 +59,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())
unittest.main(testRunner=debugTestRunner())

View File

@ -20,7 +20,8 @@ import debug
class write_mask_and_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check write driver array for single port
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4")

View File

@ -18,7 +18,8 @@ import debug
class dff_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing dff_array for 3x3")
a = factory.create(module_type="dff_array", rows=3, columns=3)

View File

@ -18,7 +18,8 @@ import debug
class dff_buf_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing dff_buf_array for 3x3")
a = factory.create(module_type="dff_buf_array", rows=3, columns=3)

View File

@ -18,7 +18,8 @@ import debug
class dff_buf_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing dff_buf 4x 8x")
a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8)

View File

@ -18,7 +18,8 @@ import debug
class tri_gate_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
a = factory.create(module_type="tri_gate_array", columns=8, word_size=8)

View File

@ -18,7 +18,8 @@ import debug
class delay_chain_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing delay_chain")
a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4])

View File

@ -16,7 +16,8 @@ import debug
class replica_bitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"

View File

@ -16,7 +16,8 @@ import debug
class replica_bitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])

View File

@ -16,7 +16,8 @@ import debug
class replica_column_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)

View File

@ -22,7 +22,8 @@ import debug
class control_logic_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import control_logic
import tech

View File

@ -18,7 +18,8 @@ import debug
class control_logic_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import control_logic
import tech

View File

@ -16,7 +16,8 @@ import debug
class port_address_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16)

View File

@ -16,7 +16,8 @@ import debug
class port_data_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,

View File

@ -18,7 +18,8 @@ import debug
class port_data_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=16,

View File

@ -18,7 +18,8 @@ import debug
class bank_select_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(1, "No column mux, rw control logic")
a = factory.create(module_type="bank_select", port="rw")

View File

@ -19,7 +19,8 @@ import debug
class multi_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,

View File

@ -19,7 +19,8 @@ import debug
class multi_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"

View File

@ -19,7 +19,8 @@ import debug
class psingle_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_1w_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,

View File

@ -18,7 +18,8 @@ import debug
class single_bank_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config

View File

@ -18,8 +18,9 @@ import debug
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
class psram_1bank_2mux_1rw_1w_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"

View File

@ -21,7 +21,8 @@ import debug
class psram_1bank_2mux_1rw_1w_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
@ -58,4 +59,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())
unittest.main(testRunner=debugTestRunner())

View File

@ -18,8 +18,9 @@ import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"

View File

@ -18,8 +18,9 @@ import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error")
class psram_1bank_2mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"

View File

@ -17,8 +17,9 @@ import debug
class psram_1bank_4mux_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_2mux_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -18,8 +18,9 @@ import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_2mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,

View File

@ -21,7 +21,8 @@ import debug
class sram_1bank_2mux_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=8,
write_size=4,
@ -51,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())
unittest.main(testRunner=debugTestRunner())

View File

@ -21,7 +21,8 @@ import debug
class sram_1bank_32b_1024_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
@ -50,4 +51,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())
unittest.main(testRunner=debugTestRunner())

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_4mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=64,

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_8mux_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_8mux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=2,
num_words=128,

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_nomux_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_nomux_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16,

View File

@ -21,7 +21,8 @@ import debug
class sram_1bank_nomux_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=8,
write_size=4,
@ -51,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())
unittest.main(testRunner=debugTestRunner())

View File

@ -19,7 +19,8 @@ import debug
class sram_2bank_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
c = sram_config(word_size=16,
num_words=32,

View File

@ -18,7 +18,8 @@ import debug
class timing_sram_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True

Some files were not shown because too many files have changed in this diff Show More